Author Topic: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)  (Read 60878 times)

Offline kvom

  • Hero Member
  • *****
  • Posts: 520
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #50 on: January 09, 2010, 09:31:33 AM »
Quote
My issue is that I have used a lot of messy delay code in my "void CupDisplay" function. Anyone know a better way to do it?

I recoded your program to make it a bit less "messy";  Hope this helps.  Unfortunately the website messes up the formatting a bit.

Quote
// define which pins our buttons are on
#define button1 PORTA.b0
#define button2 PORTA.b1
#define button3 PORTA.b2
#define YourLED1 PORTB.b0
#define YourLED2 PORTB.b1
#define YourLED3 PORTB.b2

// 3 buttons 1,2,3 linked to YourLED1, YourLED2, YourLED3
// When button is pressed corresponding LED lights and computer counts CupLED1-3
// CupLED1-3 lights.
// if YourLED = CupLED  you win - flashing. Game Resets
// else...you loose. Game Resets
char buttonPressed;   // a variable that saves our button press
char cup;
char LED[4] = {0b00000000, 0b00000001, 0b00000010, 0b00000100};
char portvals[10] = {1,2,4,2,1,2,4,2,1,2};
int delays[10] = {300,300,400,400,400,500,500,500,650,750};
void cupDisplay ()
{
  for (int i=0; i<10; i++)
    {
      PORTC = portvals;
      delay_ms = delays;
    }
  PORTC = LED[cup];
  delay_ms(1000);
  if (buttonPressed == cup)
    {
      for (int i=0; i<4; i++)
   {
     PORTB = PORTC = 7;
     delay_ms(250);
     PORTB = PORTC = 0;
     delay_ms(250);
   }
    }
  else
    {
      PORTB = PORTC = 7;
      delay_ms(2000);
    }
}

char ReadButtons ()
{
  if (button1)
    return 1;
  if (button2)
    return 2;
  if (button3)
    return 3;
  return 0;
}

void main()
{
    int adc;                // somewhere to put the ADC we read

    // PIC's have lots of hardware - in this case in order to use PORTB
    // we have to turn off the ADC's
    // All ports digital
    ADCON1 = 0x0F;
    CMCON = 0x07;
    // set all the pins on PORT B to 'off' before we start
    PORTA = PORTB = PORTC = 0;
    // set the tri-state buffer. Pins set to '1' are input, '0' are output
    // we've done this in binary to make it easier to see
    // each number is 1 pin, right hand is pin 0, left is pin 7
    TRISA = 0b11111111;
    TRISB = 0b00000000;
    TRISC = 0b00000000;
   
    // ============= Code Proper Starts ========

    while (1)    // loop forever
      {
   while ((buttonPressed = ReadButtons()) == 0);

   cup = 1;
   while (ReadButtons() > 0)     // counts while buttons are pressed
     {
       cup++;
       if (cup > 3)
         cup = 1;
     }

   switch (buttonPressed}
   {
   case 1:
       YourLED1 = 1;
       break;
   case 2:
       YourLED2= 1;
       break;
   case 3:
       YourLED3= 1;
   }
   cupDisplay ();
   PORTA = PORTB = PORTC = 0;
      }
}

Offline raynerd

  • Madmodder Committee
  • Hero Member
  • *****
  • Posts: 2893
  • Country: gb
    • Raynerds Projects - Raynerd.co.uk
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #51 on: January 09, 2010, 01:04:45 PM »
Thanks for your suggestions, I have the speed running off a variable resistor/pot so it is basically just a twist knob to alter the speed at any point.

I like the idea of auto traverse with one button press from one side to the other and then perhaps wait for a button pressed for the return. I doubt without a multi axis cnc you would wish for it to traverse from one side to the other continuously? Maybe - and I bet it would be easy to code in the function. Also, regarding Tims suggestion of rapid traverse, I could include a button which sets an auto fast speed with a one press it returns it back to the other limit and then auto knocks off, returning back to the variable speed set by the pot for the cut.

Any more suggestions welcome!

Kvom - I really appreciate the time taken for you to run through my code. I have actually done some bits of it already myself. I had removed the duplicated "if" statements at the bottom of my code and replaced it with the "switch" statement as you have. I also managed to have a go at a loop for the delay and display sequence. I knew I should be using the for statement and have seen through googling that the use of i for a variable is common for a count. I couldn`t get it to work properly with the delays because I hadn`t put them in a delay array as you have. I totally see now why it was not working and your corrections have really helped me understand how I should have done that, thanks!

Could you or anyone else explain to me or better still show me how I could change the following code for my x-axis controller so that the actual motor stepping sequence will be carried out on an interrupt? At the present time, the motor stepping sequence ("stepMotor") is a global function and as such the PIC is not scanning anything else while carrying out this function. I believe if I put the stepMotor sequence as an interupt, it will both allow the controller unit to be functional (i.e to scan for other user input operations, stop, or "do something else!") while the motor is running and also, I believe interupts are a better timing sequence and will allow sharper control of the pulse timing. I am not to sure, therefore, if the motorStep sequence is moved to an interupt whether the use of a delay as a speed control will be changed?? Or something to do with the interupt itself being used for timing. I`m all a bit muddled up...

Chris

Quote
// Function:
// Press 'mem', light comes on.
// Move left & right until at position.
// Press 'mem' light starts to flash.
// Press left or right to set that limit, light goes out and unit works as before.
// SHOULD THE MEMORY SETTING BE CHANGED TO WORK THE FOLLOWING?????
//A button that toggles free move or limited.
//at any point in either mode you can simply press the 'memory' button followed
//by left or right to set the limit.

// define which pins our buttons are on
#define right PORTC.b0
#define left PORTC.b1
#define stop PORTC.b2
#define memory PORTC.b3

// define which pins our motor is connected to
#define memoryLed PORTC.b4
#define motorLed PORTC.b5
#define step PORTC.b6
#define direction PORTC.b7

// LCD display config.
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// End LCD module connections


long tablePos = 0;
long limitLeft = -10000;
long limitRight = 10000;
int motorRun = 0;

// mode == 0 : running
// mode == 1 : setting limits
char mode = 0;

//===========================================
// this function moves the motor 1 step
// only moving if it can and also updates the table position

void stepMotor()
{
    if (!mode)                  // we only take note of the limits in mode 0 (otherwise we're setting them)
    {
    // if going right then check right limit - if greater than limit, motorRun = 0, stops motor.
        if (direction)
        {
            if (tablePos >= limitRight)
            {
                motorRun = 0;
                return;
            }
        }
        else
        {
            if (tablePos <= limitLeft)
            {
                motorRun = 0;
                return;
            }
        }
    }

    // these 3 lines step the motor
    step = 1;       // set the step line high
    delay_us(1);    // wait 1 micro second
    step = 0;       // and low again - the motor will now move one step

    // update the table position
    if (direction)
        tablePos++;
    else
        tablePos--;
}

//===========================================
// when the PIC is first switched on it will start to run at "main"

void main()
{
    char motorSpeed = 3;    // 3 = fast, 255 = slow
    char count;             // misc use
    int adc;                // somewhere to put the ADC we read

    // set ADC's
    ADCON0 = 1;         // enable ADC
    ADCON1 = 0b1110;    // enable ADC only for ADC 0

    // set all the pins on PORT B to 'off' before we start
    PORTC = 0;

    // set the tri-state buffer. Pins set to '1' are input, '0' are output
    // we've done this in binary to make it easier to see
    // each number is 1 pin, right hand is pin 0, left is pin 7
    TRISC = 0b00001111;
    TRISB = 0;
    TRISA = 0b11111111;

    while(1)
    {
        if (left) // is left button pressed?
        {  // if we get in here button must be pressed
            direction = 0;  //set direction to 0
            motorRun = 1; // start the motor
        }

        //------------------------------
        // check for right button
        if (right) // right button pressed
        {
            direction = 1;   // set direction to 1
            motorRun = 1; // start the motor
        }

        //------------------------------
        // check for stopping the motor
        if (stop)   // stop button pressed
            motorRun = 0; // stop the motor

        //------------------------------
        // handle setting the limits.
        //------------------------------
        // is memory button pressed?
        if (memory)
        {
            // wait for it to be released
            while (memory);

            // if in 'run' mode, change to 'limit set' mode
            if (!mode)
                mode = 1;
            else
            {
                // in limit set mode - wait for left or right to be pressed
                while (!left && !right) // if neither are pressed then stay here
                {
                    // be clever here and flash the memory light to show we're waiting
                    delay_ms(2);
                    count++;            // count is 8 bits (char) - when it gets to 255, the next time it increments it goes to zero
                    if (count > 128)    // 5ms * 128 is a bit over  1/4 seconds - so light should flash about 2hz
                        memoryLed = 0;
                    else
                        memoryLed = 1;
                }

                // depending on which button was pressed set the appropriate limit
                if (left)
                    limitLeft = tablePos;
                if (right)
                    limitRight = tablePos;

                // wait for left/right to be released and then we're done
                while (left || right);

                // we're finished so go back to 'run' mode
                mode = 0;
            }
        }

        //------------------------------
        // if in 'limit set' mode then light the memory LED
        if (mode == 1)
            memoryLed = 1;
        else
            memoryLed = 0;

        //------------------------------
        // step the motor
        if (motorRun)   // are we moving the motor?
        {
            motorLed = 1;
            stepMotor();

            // read the ADC and set the speed (delay)
            adc = ADC_Read(0);
            adc = adc >> 2;         // divide by 4
            if (adc < 3)
                adc = 3;
            for(count = 0; count < 10; count++)
                Delay_Cyc(adc);
        }
        else
            motorLed = 0;
        }
}

Offline spuddevans

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1618
  • Country: 00
  • Portadown, Northern Ireland
    • My Photo website
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #52 on: January 09, 2010, 01:15:14 PM »
I could include a button which sets an auto fast speed with a one press it returns it back to the other limit and then auto knocks off, returning back to the variable speed set by the pot for the cut.

Why not code it so that the fast-traverse-button activates the fast traverse until a direction button is pressed and then released, ie you press the fast traverse button, press and hold the relevent direction button, then when the button is released then fast traverse function automatically is cancelled, returning the speed to the previously set speed via the pot.

You could code it along the lines of the fast traverse button sets a flag to "1" and then the direction button could test that flag to see if it is set, if it is then it would traverse at the high speed, and then when the direction button is released it would clear the flag thereby cancelling the fast traverse.


Tim
Measure with a micrometer, mark with chalk, cut with an axe  -  MI0TME

Offline BobWarfield

  • Jr. Member
  • **
  • Posts: 26
    • CNC Cookbook
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #53 on: January 09, 2010, 01:20:41 PM »
That's the beauty of it being a computer: you can make it do anything.

I imagine it is not all that much more costly than a regular power feed, yet it has the potential to be a lot more powerful.  Just by changing software and adding a few switches you can provide a variety of functions:

-  Fast jog
-  Slow jog with potentiometer to control speed
-  Speed readout in IPM so you can adjust to match a recommended feed.  Turn the potentiometer until you get the number
-  Or, provide a keypad to enter a feedrate
-  Push a button to set a stop.  Now the stepper will always stop after that many step pulses and you have effectively got a software stop on your feed
-  Interface a handwheel-style pulse generator
-  Simple DRO function.  Push a button to zero, and then the readout will tell you how far you've moved.

The list goes on and on.  It would not be hard to add a couple of circuits so that you can take the step/dir right out of a Mach3 breakout board.  Now you have the ability to either run the g-code via Mach or run as a manual with power feeds.


I've said for a long time the cost of fitting CNC is about the cost of power feeds and a nice DRO.

Cheers,

BW
Try G-Wizard Machinist's Calculator for free:  http://www.cnccookbook.com/CCGWizard.html

Offline raynerd

  • Madmodder Committee
  • Hero Member
  • *****
  • Posts: 2893
  • Country: gb
    • Raynerds Projects - Raynerd.co.uk
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #54 on: January 09, 2010, 03:52:53 PM »
Tim, excellent idea. In C it will be even easier than that:

if (left)
{
     if (fastTraverse)
     motorSpeed = **TopSpeed;
     else
     motorSpeed = **ACD_PotSpeed
Rest of move code.....
}

OK - over simplified but it won`t be far off.


Bob - your totally right and thanks for the nice ideas.

Regards
Chris

Chris

Offline kvom

  • Hero Member
  • *****
  • Posts: 520
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #55 on: January 09, 2010, 06:35:56 PM »
WRT controlling the motor in an interrupt:

Putting a delay in an interrupt routine is poor programming practice.  Interrupts should perform limited functions and return quickly.  Assuming that delay_us() is a system routine, it is almost certainly itself setting a timer interrupt and suspending execution pending that timer.

If I read your code correctly, the outer while loop continuously checks for a button push and then continues with the new or current motor movement.  In any case, your code is not checking for 2 or 3 buttons pressed simultaneously.  In addition to correcting this, you may need to "debounce" the buttons, since a button may remain "pressed" for a short time it's released by a finger.  The code could get a little messy to do this, so the likely easiest solution is to default to motor stop when more than one button is pressed.  Something like this:


   int button= 0;
   if (left)
     button += 1;
   if (right)
     button += 2;
   if (stop) || (button > 2)
     motorRun = 0;
   direction = (button == 1 ? 0 : 1);

Offline raynerd

  • Madmodder Committee
  • Hero Member
  • *****
  • Posts: 2893
  • Country: gb
    • Raynerds Projects - Raynerd.co.uk
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #56 on: January 10, 2010, 08:19:42 AM »
Kvom, I have tried to put the step on an interupt triggered by the clock timer. I totally agree with what you say regarding the delay but apparently since the delay_ms is 1 microsecond, apparently that is about 4 lines of assembler so no time at all. However, I appareciate what you say about the bad practice so I believe I could set the step high at the start of the interupt, then "do some more code" - say the limit stuff and then set the step low. Would that not have the same effect of a super short delay as it runs the code between the step high and the step low?

This code allows the user no control of when the interupt occurs and therefore the stepper pulses. All speed control has been lost now in this re-worked code. By using the ADC or even presets to alter the timer count between triggering the interupt it should be able to control the speed.

If you can change and improve my code then please do.... I don`t really know how to move forward from here....

also the current limit setting idea is too complex, it would much better if it worked like this:

//A button that toggles free move or limited.
//at any point in either mode you can simply press the 'memory' button followed
//by left or right to set the limit.

here is the code...the current limit setting function described at the start:

Quote
// Function:
// Press 'mem', light comes on.
// Move left & right until at position.
// Press 'mem' light starts to flash.
// Press left or right to set that limit, light goes out and unit works as before.

// define which pins our buttons are on
#define right PORTC.b0
#define left PORTC.b1
#define stop PORTBC.b2
#define memory PORTC.b3

// define which pins our motor is connected to
#define memoryLed PORTC.b4
#define motorLed PORTC.b5
#define step PORTC.b6
#define direction PORTC.b7

// LCD display config.
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// End LCD module connections


long tablePos = 0;
long limitLeft = -10000;
long limitRight = 10000;
int motorRun = 0;

// mode == 0 : running
// mode == 1 : setting limits
char mode = 0;

void interupt()
{
    TMR0IF_bit = 0;    // clear TMR0IF
    TMR0L  = 96;       // reset counter
    
    if (motorRun)      // interupt only steps motor if motorRun is true.
    {
    if (!mode)         // we only take note of the limits in mode 0 (otherwise we're setting them)
    {
    // if going right then check right limit - if greater than limit, motorRun = 0, stops motor.
        if (direction)
        {
            if (tablePos >= limitRight)
            {
                motorRun = 0;
                return;
            }
        }
        else
        {
            if (tablePos <= limitLeft)
            {
                motorRun = 0;
                return;
            }
            }
            }
    
    // these 3 lines step the motor
    step = 1;       // set the step line high
    delay_us(1);    // wait 1 micro second
    step = 0;       // and low again - the motor will now move one step
      // update the table position
    if (direction)
        tablePos++;
    else
        tablePos--;
 }
 }
 
//===========================================
// when the PIC is first switched on it will start to run at "main"

void main()
{
    char motorSpeed = 3;    // 3 = fast, 255 = slow
    char count;             // misc use
    int adc;                // somewhere to put the ADC we read

    T0CON  = 0xC4;       // Set TMR0 in 8bit mode, assign prescaler to TMR0
    // set ADC's
    ADCON0 = 1;         // enable ADC
    ADCON1 = 0b1110;    // enable ADC only for ADC 0

    // set all the pins on PORT B to 'off' before we start
    PORTC = 0;

    // set the tri-state buffer. Pins set to '1' are input, '0' are output
    // we've done this in binary to make it easier to see
    // each number is 1 pin, right hand is pin 0, left is pin 7
    TRISC = 0b00001111;
    TRISB = 0;
    TRISA = 0b11111111;

    while(1)
    {
        if (left) // is left button pressed?
        {  // if we get in here button must be pressed
            direction = 0;  //set direction to 0
            motorRun = 1; // start the motor
        }

        //------------------------------
        // check for right button
        if (right) // right button pressed
        {
            direction = 1;   // set direction to 1
            motorRun = 1; // start the motor
        }

        //------------------------------
        // check for stopping the motor
        if (stop)   // stop button pressed
            motorRun = 0; // stop the motor

        //------------------------------
        // handle setting the limits.
        //------------------------------
        // is memory button pressed?
        if (memory)
        {
            // wait for it to be released
            while (memory);

            // if in 'run' mode, change to 'limit set' mode
            if (!mode)
                mode = 1;
            else
            {
                // in limit set mode - wait for left or right to be pressed
                while (!left && !right) // if neither are pressed then stay here
                {
                    // be clever here and flash the memory light to show we're waiting
                    delay_ms(2);
                    count++;            // count is 8 bits (char) - when it gets to 255, the next time it increments it goes to zero
                    if (count > 128)    // 5ms * 128 is a bit over  1/4 seconds - so light should flash about 2hz
                        memoryLed = 0;
                    else
                        memoryLed = 1;
                }

                // depending on which button was pressed set the appropriate limit
                if (left)
                    limitLeft = tablePos;
                if (right)
                    limitRight = tablePos;

                // wait for left/right to be released and then we're done
                while (left || right);

                // we're finished so go back to 'run' mode
                mode = 0;
            }
        }

        //------------------------------
        // if in 'limit set' mode then light the memory LED
        if (mode == 1)
            memoryLed = 1;
        else
            memoryLed = 0;

        //------------------------------
        // step the motor
        if (motorRun)   // are we moving the motor?
        {
            motorLed = 1;
            //INITIATES interupt!
      TMR0L  = 96;         // Timer0 initial value
      INTCON = 0xA0;       // Enable TMRO interrupt

            // read the ADC and set the speed (delay)
            adc = 512;                   // MyADC needs replacing with  ADC_Read(0);
            adc = adc >> 2;         // divide by 4
            if (adc < 3)
                adc = 3;
            for(count = 0; count < 10; count++)
                Delay_Cyc(adc);
        }
        else
            motorLed = 0;
        }
}
« Last Edit: January 10, 2010, 08:24:17 AM by craynerd »

Offline kvom

  • Hero Member
  • *****
  • Posts: 520
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #57 on: January 10, 2010, 09:46:22 AM »
Some thoughts:

From the above, I am assuming that the 1 microsecond delay is necessary to create the proper length pulse to drive the motor.  If so, that is the primary requirement for the program and hence should be in the mainline of the program.  There is no need for any explicit interrupts as the only asynchronous events are button pushes, which are comparatively rare and not needing precision.

So I would use the prior code with the following modifications:

1) Ensure that only one button is pressed at a time

2) Stop the motor any time a button is pressed, and restart only when a good left or right button is pressed.  In cases where the motor is stepping in one direction and the opposite button is pressed, I would treat that as a stop and require two presses to reverse direction.

3) When the memory button is pressed, a second press or stop should turn off the LED without setting either limit.

4) You need to check that the right limit is not set less than the left limit and vice-versa.

Another way to think of this type of problem is to regard it as an "automaton".  An automaton is a machine that has a number of clearly defined states and all the valid transitions between them.  You can draw a diagram where the states are labeled circles and the transitions are directional arrows connecting them.

You might have the following states:

stopped
motor right
motor left
memory
memory left
memory right

The transition events are:

buttons
limits

Then a good way to structure the code is to hold the state in a variable and test it in the main loop via a switch statement.  In each case of the switch, you check for valid transition events, and if found change the state.

For complex situations, automata are a better way to organize the code as opposed to complex nested loops and ifs.  It's easy to locate the code for a given state and modify it without affecting other states, and in addition defining additional states is easier.

Offline raynerd

  • Madmodder Committee
  • Hero Member
  • *****
  • Posts: 2893
  • Country: gb
    • Raynerds Projects - Raynerd.co.uk
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #58 on: January 10, 2010, 02:22:00 PM »
Kvom, These are not my words, these are actually notes I made from someone else giving me advice:

If I want my stepper motor to run at 3000 steps per second, I can`t start it at that or it will stall. I need to accelerate it to that speed and then once there I need to make sure the train of pulses are at the right frequency. If my code can not guarante that frequency I`ll have to run it slower and won`t be able to use the top speed which has already been discussed on here, will be useful for a fast return! The step pulse can be very small - just a microsecond or so  but the important bit is the distance between pulses. For example 1000 steps per second requires a time of 1/1000 of a second between pulses, 3000 requires 1/3000 th of a second etc and since time = 1 / frequency or frequency = 1 / time to run my stepper at 3khz you need a time of 1/3000th of a second between the pulses and since we know how fast a timer runs on the PIC we can calculate a suitable number to put in it so that it'll reach zero (trigger the interupt) in 1/3000th of a second. If we then set up an interrupt on that timer then 1/3000th of a second later, exactly, we'll get an interrupt and in there can step the motor. Since this is an interupt in our main loop we can do other stuff - write position to an lcd, scan the keypad, flash leds or whatever we want and we don't have to worry that the stepper is stepping correctly - the interrupt will do it for us!

I hope that makes sense...that is my understanding of it mainly taken word for word from an explanation I was given. I appreciate your advice and would quite like to hear your response!

Regarding your other points, I will certainly be using some of those ideas.

Chris

Offline kvom

  • Hero Member
  • *****
  • Posts: 520
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #59 on: January 10, 2010, 05:42:21 PM »
That makes sense to use the interrupt in that case.  So if you set the interrupt at 3Khz, you need to define two additional things:

1) Accelleration time
2) Max speed

Assume it takes 100ms to accellerate to max speed, or 0-3Khz.   One way to do this is to vary the interrupt rate.  Assume 10ms intervals.  For the first interval you set the interrupt rate at 300 Hz and generate a step at each interrupt.  Then increase the rate to 60Hz until the motor is at full speed.  You can define an automaton state of 'accellerating' to handle the rate change.  Obviously you can make the accelleration smoother if you want.


Offline No1_sonuk

  • Full Member
  • ***
  • Posts: 242
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #60 on: January 10, 2010, 07:39:48 PM »
Remember you have a limited number of stack levels.  A hardware interrupt will use one of those, so you have to ensure that you don't use more than the total available minus 1 for the main loop and the interrupt routine combined.  So if you have the normal 8 levels available, don't use more than 7 total for the main loop and the interrupt service routine.

EDIT:-
BTW, the "messy" C instructions is one reason why I'd probably code at least some of this sort of thing in Assembler.  That guarantees the timing is as accurate as the processor can make it.  That is, however, a personal choice, and due mainly to the fact that I've programmed PICs almost exclusively in Assembler for several years.
« Last Edit: January 10, 2010, 07:50:02 PM by No1_sonuk »

Offline raynerd

  • Madmodder Committee
  • Hero Member
  • *****
  • Posts: 2893
  • Country: gb
    • Raynerds Projects - Raynerd.co.uk
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #61 on: January 11, 2010, 05:33:51 AM »
I`ve got a bit stuck again with this. I have a blurb at the start.

My issue now is that if I want to reset a limit past the previous limit, I can`t get there!! I need to ignore limits while in "limit setting mode" or in terms of the code, while (memory).  I could do that by setting something like;

Quote
while (memory)
{
 mode = 1,
Rest of limit setting code....
}

and then in the interupt pulse section

Quote
while (!mode)        // while not in mode
{
rest of code checking limits // check limits then move onto pulse
}
pulse.       // if we are in mode, it will just pulse and not check limits.

However now my issue is that if I did something like the above code, I need to use left and right to jog the motor to position while ignoring the limits. I then need to set limits. So how do I set limits as I am now using the left right to jog. Does this make sense. I could add another button that removed limits at any point but ideally I wanted to keep it simple by using just the memory button and left right to set limits. Maybe the design of this is not possible. Any thoughts...

updated code below:
Quote
/* X-axis Stepper Controller
The controllers primary functions are to produce a pulse train with a
step pulse of approximately 1 microsecond delay to the "step" pin and define
the "dircection" pin  1/0 to set the motor direction. Limits can be set in both
directions.

Functions:
left and right jog the motor until limit is reached.
To set limits, jog to tableposition of required limit. Hold memory button while
pressing the left or right  to set the corresponding limit. If memoryLED lights,
error and may need correcting - limitLeft >= limitRight

Development:
1.Variable Speed Control via ADC.
2.Rapid Return - pressing (new) button while holding left or right sets max speed
until limit is reached.
3.Limit to Limit - jogs motor between limits continually.
4.Limit to Limit; rapid return - as above but user sets one direction at top speed

Code Development:
1.Ensure that only one button is pressed at a time
2.In cases where the motor is stepping in one direction and the opposite button
is pressed, treat as a stop and require two presses to reverse direction
*/

// define which pins our buttons are on
#define right PORTC.b0
#define left PORTC.b1
#define stop PORTC.b2
#define memory PORTC.b3

// define which pins our motor is connected to
#define memoryLed PORTC.b4
#define motorLed PORTC.b5
#define step PORTC.b6
#define direction PORTC.b7

// LCD display config.
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// End LCD module connections


long tablePos = 0;
long limitLeft = -100000;
long limitRight = 100000;
int motorRun = 0;

void interupt()    // step motor interupt - Only steps if motorRun is set.
{
    TMR0IF_bit = 0;    // clear TMR0IF
    TMR0L  = 96;       // reset counter

    if (motorRun)      // interupt only steps motor if motorRun is set in main.
    {

    // if going right then check right limit - if greater than limit, motorRun = 0, stops motor.
        if (direction)
        {
            if (tablePos >= limitRight)
            {
                motorRun = 0;
                return;
            }
        }
        else
        {
            if (tablePos <= limitLeft)
            {
                motorRun = 0;
                return;
            }
            }

    // these 3 lines step the motor
    step = 1;       // set the step line high
    delay_us(1);    // wait 1 micro second
    step = 0;       // and low again - the motor will now move one step
      // update the table position
    if (direction)
        tablePos++;
    else
        tablePos--;
    }
 }
 
//===========================================
// when the PIC is first switched on it will start to run at "main"

void main()
{
    char motorSpeed = 3;    // 3 = fast, 255 = slow
    char count;             // misc use
    int adc;                // somewhere to put the ADC we read

    // Set TMR0 in 8bit mode, assign prescaler to TMR0
    T0CON  = 0xC4;

    // set ADC's
    ADCON0 = 1;         // enable ADC
    ADCON1 = 0b1110;    // enable ADC only for ADC 0

    // set all the pins on PORT C to 'off' before we start
    PORTC = 0;

    // set the tri-state buffer. Pins set to '1' are input, '0' are output
    // we've done this in binary to make it easier to see
    // each number is 1 pin, right hand is pin 0, left is pin 7
    TRISC = 0b00001111;
    TRISB = 0;
    TRISA = 0b11111111;

    while(1)
    {
    //Sets interupt - triggers into step interupt but if motorRun is not set, motor does not run.
    TMR0L  = 96;         // Timer0 initial value
    INTCON = 0xA0;       // Enable TMRO interrupt

        // Checks left and right buttons - sets direction and motorRun
        if (left)
        {
            direction = 0;
            motorRun = 1;
        }
        if (right)
        {
            direction = 1;
            motorRun = 1;
        }
        // Stop button
        if (stop)
        motorRun = 0; // stop the motor

        // -- ----------------Limit Setting ------------------------
        // -- hold down memory and press left or right to set limit.
        // ---------------------------------------------------------
        while (memory)        // loops here while waiting for limit to be set.
        {
                // set limit left or right
                if (left)
                    limitLeft = tablePos;
                if (right)
                    limitRight = tablePos;
                   
                // wait for left/right to be released
                while (left || right);
        }
       
        // Checks limitLeft is not >= to limitRight
        //  memeryLed = 1 indicated error to user
        if (limitLeft >= limitRight)
        memoryLed = 1;      // COULD I ALSO DO SOMETHING ELSE HERE? maybe reset limit after a delay?
        else
        memoryLed = 0;

        //------------------------------
        // step the motor
        if (motorRun)   // are we moving the motor?
        {
            motorLed = 1;

            /* OLD ADC SPEED CONTROL NOT IN USE
            read the ADC and set the speed (delay)
            adc = 512;                   // MyADC needs replacing with  ADC_Read(0);
            adc = adc >> 2;         // divide by 4
            if (adc < 3)
                adc = 3;
            for(count = 0; count < 10; count++)
            Delay_Cyc(adc); */
        }
        else
            motorLed = 0;
        }
}

Offline kvom

  • Hero Member
  • *****
  • Posts: 520
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #62 on: January 11, 2010, 07:57:20 AM »
You could do limit resetting by memory-stop sequence.  Using the automaton model each button press is a 2-part state.  When you detect a press you enter a state waiting for a release, at which point you enter the state signalled by that button.  Here's some pseudo code:

  switch (state)
  {
     case stop:
       if (memory)  // memory button pressed
       {
          state = memory1;
          break;
        }

      case memory1:
        if (!memory)  // button released
        {
          state = memory2;
          break;
        }

      case memory2:
        // turn on LED if not already on
        // check for next keypress: memory, left, right, stop
        break;

    }
« Last Edit: January 11, 2010, 08:04:38 AM by kvom »

Offline No1_sonuk

  • Full Member
  • ***
  • Posts: 242
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #63 on: January 11, 2010, 08:11:57 AM »
WRT setting limits:
You could do it so that you hold the memory button and both jog buttons together (like the MS CTRL-ALT-DEL combination) to disable the limits, then do it again to enable the limits after setting them as you already have set up.
If you don't reset the limit numbers when they're disabled, that also gives you the option to temporarily disable the limits at any time.

Having said that, a separate switch for limit enable/disable would make the code FAR simpler.  Even easier if it's a toggle switch.  Using a toggle switch would mean you'd only need to check the state of the switch when one of the limits is reached, rather than having to continuously monitor a pushbutton and store the result in a flag variable.  It also gives a physical indication of its status.

WRT this:
Quote
4.Limit to Limit; rapid return - as above but user sets one direction at top speed
Could be a bad idea if you're cutting - backlash, tool flex, etc. could mean you would cut on the way back.  On a lathe, that might make a shiny-smooth surface going one way, only to cut a shallow "thread" on the way back!  If it stopped and waited for the user to press a button, that'd give the option to move the work or cutter before the rapid traverse.

Offline raynerd

  • Madmodder Committee
  • Hero Member
  • *****
  • Posts: 2893
  • Country: gb
    • Raynerds Projects - Raynerd.co.uk
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #64 on: January 18, 2010, 06:07:21 PM »
A bit of an update. I`ve been doing some updates to my mill at the moment but I`m hoping I should have some time over the next week to get a first simple prototype built. Quite a bit to do yet.




Offline raynerd

  • Madmodder Committee
  • Hero Member
  • *****
  • Posts: 2893
  • Country: gb
    • Raynerds Projects - Raynerd.co.uk
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #65 on: January 24, 2010, 06:32:30 PM »
Getting there... the oldham coupling is now in place and motor fully mounted. I`m just waiting for a driver and then I can have a trial. Mean while I`ll keep updating the code...


Offline raynerd

  • Madmodder Committee
  • Hero Member
  • *****
  • Posts: 2893
  • Country: gb
    • Raynerds Projects - Raynerd.co.uk
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #66 on: August 31, 2010, 07:45:26 PM »
Not been touched since Jan 29th !!!

Well....I just got around to having a code that works to an extent. It needs lots of tidying but it works!!



Cheers Kwackers for the help!!!  :headbang: :ddb: :ddb:

Next job is to tidy the code and then build it on its own circuit.

Offline spuddevans

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1618
  • Country: 00
  • Portadown, Northern Ireland
    • My Photo website
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #67 on: September 01, 2010, 03:33:49 AM »
Well done Chris  :ddb: :ddb: :ddb: :clap: :clap: :clap:



Tim
Measure with a micrometer, mark with chalk, cut with an axe  -  MI0TME

Offline raynerd

  • Madmodder Committee
  • Hero Member
  • *****
  • Posts: 2893
  • Country: gb
    • Raynerds Projects - Raynerd.co.uk
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #68 on: September 09, 2010, 08:13:08 AM »
Finally finished it!  :headbang:




Very pleased with it. There is a lot that could be improved but it will stay as it is certainly for a few months while I get on with other things.

Basic functions & instructions for use:

Central Green LED - flashes to show controller in ON
Left Blue LED - lights when motor is moving
Right Red LED - Lights when in memory mode when we can move beyond limits and programme them

Button Left-Green = Table moves left
Button Right-Green = Table move right
Press Red-Stop = Table Stops
Press Speed = speed scrolls between 0-9 (preset at 5 on PIC startup)

Limits are preset at startup to +10,000 and -10,000 steps,
To Set Limits:
Hold both Black buttons, RightLimitSet and LeftLimitSet together and release (the ones next to each green button) - controller goes into memory mode.
In memory mode movement is not restricted by limits. At any current table positon, either, left memory or right,memory button alone can be pressed to set the associated limit.

Moving between limits::
Hold LeftGreen AND LeftMemory and release - table moves to the left, hits the left limit and moves between the limits continuously.
Hold RightGreen and RightMemory and release - table moves to the right, hits the right limits and moves between the limits continuously.

Offline Bluechip

  • Madmodder Committee
  • Hero Member
  • *****
  • Posts: 1513
  • Country: england
  • Derbyshire UK
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #69 on: September 10, 2010, 04:49:51 AM »
Hi Chris

No-one seems to have replied yet.. not very polite of 'em. No matter ... I'm impressed     :bow:

Been faffing with PICs for some months now, with MPASM..

Keep writing code that works, then find some code examples on the web to do exactly the same thing, but with about 1/10th of the instructions.  :doh:

Seem to recall you did this with a C compiler. Which did you use ?.

Need to get a grip of C I think.

BTW. What thickness of steel will the LED cut ??  :lol:
Not a blue one is it? I've got some that chuck out no end of light, even at 10 mA. Especially if you look directly at them. Had to shut them down to < 3mA ... even then too bright axially ..
 
Dave BC
I have a few modest talents. Knowing what I'm doing isn't one of them.

Offline slowcoach

  • Full Member
  • ***
  • Posts: 230
  • Country: england
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #70 on: September 10, 2010, 06:34:11 AM »
Very impressive, good job  :bow: :bow:

Rob  :thumbup:

Offline spuddevans

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1618
  • Country: 00
  • Portadown, Northern Ireland
    • My Photo website
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #71 on: September 10, 2010, 07:39:44 AM »
Well done Chris  :clap: :clap: :clap: A nice and tidy unit.


Tim
Measure with a micrometer, mark with chalk, cut with an axe  -  MI0TME

Offline raynerd

  • Madmodder Committee
  • Hero Member
  • *****
  • Posts: 2893
  • Country: gb
    • Raynerds Projects - Raynerd.co.uk
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #72 on: September 10, 2010, 03:48:14 PM »
Cheers Guys....yep, it is working well. I had it running earlier today and am quite please with it but I`m actually going to have another hour and reprogramme the chip. I`ve been looking at the data sheets and think I can swap the 16f887 for 18f4520 using the same board and circuit and then use the 18f to convert the current "step" position to a measurement, inch and mm.

BlueChip - I was advised to use C code when I was first introduced to PICs. I wouldn`t change it one bit - C seems excellent! I spoke to a bloke who was into coding in Assembler a few months back, quite a random meeting but and he pratted around for ages showing me some assembler code and man, the number of lines of code he had to do for a simple programe! I could have done it in literally a couple of lines. OK - I don`t have a clue what is happening as much as he does inside the PIC itself but I suppose you have to decide if that matters. To be honest, the few times that I will want a PIC, I`m interested in the function I get from it, not how it is running. I know this is ignorant, but for the time I can afford to invest in it, its good enough for what I want. Great thing about C, is it is pretty much just English!

I use MikroC compiler for my code:
http://www.mikroe.com/eng/products/view/411/mikroc-for-pic/


It is great because I`ve also got Mikroelectronica`s EasyPIC 6 dev board. That being said, you can just use MikroC to generate your hex and then blow it to your chip any way you like.

Regarding those blue LEDs, yes it doubles as a lazer cutter. I`ve managed to put a hole in the ceiling above the controller.!

Chris

Rob.Wilson

  • Guest
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #73 on: September 10, 2010, 04:15:41 PM »
Very cool Chris  :bow: :clap: :bow: :clap: :bow: :clap: :dremel:


Rob  :thumbup:

Offline Bluechip

  • Madmodder Committee
  • Hero Member
  • *****
  • Posts: 1513
  • Country: england
  • Derbyshire UK
Re: X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
« Reply #74 on: September 11, 2010, 04:47:18 AM »
Hi Chris

Tks for the info.

Couldn't work out just what they wanted from your link   :scratch:

As I have the 'lite' C18 with the MPLAB, I might have a go with that.
I doubt if I need it to be optimised for the bit of code I do.

I used to fool around with the 16F84 years ago, used ASM with that, as there was nowt else at the time as far as I'm aware. So, just plugged away with ASM when I returned a few months ago. I find it simple but tedious ..

Have fun ...

Dave BC





 
I have a few modest talents. Knowing what I'm doing isn't one of them.