Stepper Absolute Position ... how to

Thanks aufruf,
I will give an accurate look !

"void AccelStepper::moveTo ( long absolute ) "

Silverdog63:
My idea is to zero the motor at the start and then change the height in two manners: absolute (the case where I need help) and relative (I just tell the motor to move X mm).

I think a lot of CNC machines start by moving the stepper until a limit switch is pressed. That gives you a known position.

Absolute is easy enough. You just have to remember where you are. So if you are at 10 and you want to go to 30, you move relative +20. Easy, right? Each time you move you add or subtract to/from the remembered position so you keep knowing where you are.

Yes Nick,
you are absolutely right.
My difficulty is to translate this in Arduino language ... I know there is the way but I don't know how.
I set the postion in the MENWIZ menu, then I call the action "ABSheight"

s2=menu.addMenu(MW_SUBMENU,s1,F("Saw Height"));                         //add a terminal node in the menu tree (that is "variable"); (should move at a certain mm height)
    s3=menu.addMenu(MW_VAR,s2,F("Absolute Height"));
      s3->addVar(MW_AUTO_INT,&HeightZ,0,100,1);     //int type, fd binded variable, rage 0-100, step 1
        s3=menu.addMenu(MW_VAR,s2,F("ABSheight"));
        s3->addVar(MW_ACTION,ABSheight);

And everything works fine (I tried it with relative move )
My problem is the inability to write the funtion "remembered position", I know there is the way to "remember" the position .... something like "OldPosition = HeightZ" then recall "OldPosition" and subtract the new one but I can't find where I saw something similar and I not able to create it correctly.

something like "OldPosition = HeightZ" then recall "OldPosition"

You normally do that at the end of the section of code is it is ready for the next time. Then you need to generate a new value for HeightZ and then go into that section of code again.

The problem is that you are posting small snippets of code that do not show us the whole picture. Try and write a short piece of code that shows your problem. In doing that you will probably see where you are going wrong. If not post it and we can show you.

You might be best off tacking some simpler projects just to get the hang of programming in C++.

Stuff like saving a variable and getting it back is pretty straightforwards, don't obscure that by trying to do everything at once.

Nick & Mike,
Thanks, I understand that the full sketch is needed, I cutted all the unnecessary part to make it smaller.
the involved part is quite short but I wanted to post a compiling sketch, so the buttons control is in there.

#include <Wire.h>
#include <LiquidCrystal.h>
#include <buttons.h>
#include <MENWIZ.h>
#include <EEPROM.h>
#include <AccelStepper.h>
#include <AFMotor.h> //not needed if not using motor shield 

// Create global object for menu and lcd
menwiz menu;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// Stepper Motor Parameters
AF_Stepper motor1(200, 2);
const int stepsPerRevolution = 200;

void forwardstep1() {  
  motor1.onestep(FORWARD, SINGLE);
}
void backwardstep1() {  
  motor1.onestep(BACKWARD, SINGLE);
}



boolean wr=0;                         // Instantiate global variables to bind to menu

const int buttonPin = A0;             // 4 button switch circuit input connected to analog pin 0
const int led13Pin = 13;              // the number of the LED output pin
int stepCount = 0;                    // number of steps the motor has taken
int HeightZ;                           //ABS Height Variable = mm
int MoveREL;                            //Rel Move Variable = mm
boolean buttonBlock = 0;
boolean buttonAct = 0;                // flag 1
boolean stopMenu = 0;                 // flag 2
byte buttonPressed = 0;               // which button was pressed
byte lastButtonPressed = 0;           // prev button pressed
int buttonValue = 0;                  // read value from analog port for the 4 navigation pushbuttons
long menuOffTime = 0;                 //used for timer

extern byte MW_navbtn;                //needed to run the software key navigation in Menwiz
AccelStepper stepper1(forwardstep1, backwardstep1);
//AccelStepper stepper2(forwardstep2, backwardstep2);


void setup()
{
Serial.begin(9600);                  // Output to serial writing

  digitalWrite((A0), HIGH);         // enable the 20k internal pullup for UNO based board for analog port A0

// Motor Speed & Accel
    stepper1.setMaxSpeed(400);
    stepper1.setAcceleration(50);
//++++++++++++++++++++Menu and LCD  
  char b[84];
  _menu *r,*s1,*s2,*s3;

                                      // initialize the menu object ( 4 x rows x 20 colums LCD)
  menu.begin(&lcd,20,4);              //initialize the menwiz menu object passing the lcd object and the colums and rows params 
  menu.addUsrNav(navMenu,4);
  MW_navbtn=4;                        // force 4 or 6 buttons mode for menu navigation -> MW_navbtn=4; or MW_navbtn=6;

//create the menu tree
  r=menu.addMenu(MW_ROOT,NULL,F("MAIN MENU"));                      //create a root menu at first (required)

//------ Sega Squadratrice ---------
s1=menu.addMenu(MW_SUBMENU,r,F("SAW"));                    //add a submenu node 2 to the root menu (control the heigh of my Saw)
  s2=menu.addMenu(MW_SUBMENU,s1,F("Saw Height"));         
    s3=menu.addMenu(MW_VAR,s2,F("Absolute Height"));      //add a terminal node in the menu tree (that is "variable"); (Move AT a certain mm height)
      s3->addVar(MW_AUTO_INT,&HeightZ,0,100,1);           //int type, fd binded variable, rage 0-100, step 1
        s3=menu.addMenu(MW_VAR,s2,F("ABS_Height"));       //Call the Action ABS_Height to move the Stepper in ABS mode
        s3->addVar(MW_ACTION,ABS_Height);                 //Fire the Ation Above
  s2=menu.addMenu(MW_SUBMENU,s1,F("Saw Move"));           //add a terminal node in the menu tree (that is "variable"); (Move OF a certain mm)
    s3=menu.addMenu(MW_VAR,s2,F("Relative Move"));       
     s3->addVar(MW_AUTO_INT,&MoveREL,-100,100,1);          //int type, fd binded variable, rage -100 +100, step 1
        s3=menu.addMenu(MW_VAR,s2,F("MoveSAW"));          //Call the Action moveSAW to move the Stepper in REL mode
        s3->addVar(MW_ACTION,MoveSAW);                    //Fire the Ation Above

  pinMode(led13Pin, OUTPUT);                // initialize the led as a output control pin
}

void loop()    
{
// NAVIGATION MANAGEMENT & DRAWING ON LCD. NOT BLOCKING has to be the first in the void loop
  menu.draw();

  readButtons();
}

//**** HERE IS THE PROBLEMATIC PART *******

//int HeightZ = 0;
int LastHeightZ = 0;
//int NewHeightZ = 0;


void ABS_Height(){     //This is the Absolute Move Action to be implemented
HeightZ = 0;
if (HeightZ > 0) HeightZ = LastHeightZ;
stepper1.moveTo((LastHeightZ - HeightZ) * 50); // move Height1 mm's
lcd.print ("Height mm ");
lcd.print (HeightZ);
delay (5000);
}

//**** FROM HERE EVERITHING IS WORKING ******
void MoveSAW(){                //This is the Relative Movement of the SAW. WORKING ! :-)
stepper1.moveTo(MoveREL * 50); // move the SAW X mm's
lcd.print ("Move ");
lcd.print (MoveREL);
lcd.print (" mm");
delay (5000);
}

// Here is the working coce to use MENWIZ with 4 Analog Pushbottons.
//  ++++++ functions +++++++

void readButtons()

// ++++ Control 4 buttons ++++
{
  lastButtonPressed = buttonPressed;

 // Analog values representing the pushbutton value are depending on the resitor value used.
 
  buttonValue = analogRead(buttonPin); //analog value to simulate the pushed buttons
    
  if(buttonValue >= 850)
  {
    buttonPressed = 0;
    noButtonPressed(); // is calling an extra fucntion
  }
  else  if(buttonValue >= 380 & buttonValue <= 450)
  {
    buttonPressed = 4;
    buttonAct = 1; // set the menu flag1
  }
  else if(buttonValue >= 200 & buttonValue <=300)
  {    
    buttonPressed = 3;
    buttonAct = 1; // set the menu flag1
  }
  else if(buttonValue >= 0 & buttonValue <=50)
  {    
    buttonPressed = 2;
    buttonAct = 1; // set the menu flag1
  }
  else if(buttonValue >= 80 & buttonValue <=150)
  {    
    buttonPressed = 1;
    buttonAct = 1; // set the menu flag1
  }
}

int noButtonPressed()
{
  return MW_BTNULL;
}

int navMenu() // called from menu.draw
{
  /*
   As soon as a button is pushed the first time flag 1 is set to HIGH and if the buttonnumber is not 0 then a timer is started.
   The menu action then should only be performed once.
   After 400 msecs the flag will be set to LOW and a new buttonpush can be processed.
   Menu action is blocked for 400 msec even if the same button is being kept pressed for 2000 msecs by flag2.
   */

  long menublockTime = millis();

  if (buttonAct == 1 && buttonPressed != 0 && stopMenu == 0)  // we have a state were we process a menu navigation step once and block it for 2 secs
  {
    digitalWrite(led13Pin,HIGH);  // set timer led ON
    menuOffTime = menublockTime  + 400; //start the timer. You can change this blocking time to your convenience but do not make it lower aa 200 msecs
    stopMenu = 1;

    switch (buttonPressed)
    {
    case 1: // Up
      return MW_BTU;
      break;
    case 2: // Confirm
      return MW_BTC;
      break;
    case 3: // Down
      return MW_BTD;
      break;    
    case 4: // Escape
      return MW_BTE;
      break;
    }
  }

  if (menuOffTime != 0  &&  menublockTime  > menuOffTime)  //  Reset of the timer so a new menu action can be processed
  {
    buttonAct = 0; // resets the flag 1
    buttonPressed = 0;
    menuOffTime = 0;  // resets timer to zero
    stopMenu = 0;
    digitalWrite(led13Pin,LOW);  // set timer led OFF
  }
}

I add a brief description of the sketch:
This Sketch use MENWIZ menu system, an LCD 20x4 (or 16x2), and four Analog buttons (A0 pin) to control a Stepper Motor. All the interface part (Menu, LCD,Buttons is tested and working flawlessly) (well maybe it's not well written or clean but it works.) The actions "ABS_Height" and "MoveSaw" are working. I'm not sure about the stepper movement as I am waiting for the Stepper Controller ( I have a motor shield that I can't use with all the other stuff). I tested the motor command in a separated enviroment and they seem to work.
Thanks for the attention.
Sergio

Using Tools + Auto Format before posting code is a good idea.

Removing commented out code before posting code is a good idea.

Stating what the code does is a good idea.

Stating what you expect the code to do is a good idea.

Serial.begin() with no Serial.print()s is a bad idea. Serial.begin() with Serial.print()s is a good idea.

Showing that serial output is a good idea.

Now that you have a (few) good idea(s) what to do, would you like to try again?

Let me try again (I got an hint)
in the first part of the sketch I add:

int HeightZ = 0;                      //ABS Height Variable = mm
int LastHeightZ =0;
int NewHeightZ;
int MoveREL;                          //Rel Move Variable = mm

Then in the last part of the sketch after void loop ...

void ABS_Height(){     //This is the Absolute Move Action to be implemented
NewHeightZ = (HeightZ - LastHeightZ);
stepper1.moveTo(NewHeightZ* 50); // move Height1 mm's
lcd.print ("Height mm ");
lcd.print (HeightZ);
delay (5000);
LastHeightZ = HeightZ; // this set the current position HeightZ as LastHeighZ
//I think that "LastHeightZ" would be better named "ActualHeightZ" or
// "CurrentHeightZ" it will have a more straightforward meaning
}

What do you think ? does this make sense ?

NewHeightZ == (HeightZ - LastHeightZ);

This is an equality test, not an assignment.

LastHeightZ == HeightZ; // this set the current position HeightZ as LastHeighZ

So is this.

//I think that "LastHeightZ" would be better named "ActualHeightZ" or
// "CurrentHeightZ" it will have a more straightforward meaning

I agree.

Your
indenting
is
still
awful!

Thanks Paul,

PaulS:
Serial.begin() with no Serial.print()s is a bad idea. Serial.begin() with Serial.print()s is a good idea.

Sorry but I am a bit slow on the uptake .. "Serial.begin(9600);" I thought that in the void setup I have to put this line to open the comunication with the pc, but I see I am not using any comunication in this sketch (I did it in previous versions to debug some part of the sketch where I used also serial.println) so I can eliminate it, correct ?

Now that you have a (few) good idea(s) what to do, would you like to try again?

Well I got an hint on the italian forum so I tried again ... without hint there is the danger of an infinite "loop" :slight_smile:

PaulS:

NewHeightZ == (HeightZ - LastHeightZ);

This is an equality test, not an assignment.

LastHeightZ == HeightZ; // this set the current position HeightZ as LastHeighZ

So is this.

... :blush:
Well I cancelled any trace in the previous post :slight_smile:

Your
indenting
is
still
awful!

:blush:
Ok I will do some homework

A few post ago Mike asked:

Grumpy_Mike:
Are you dealing in units of mm?
That is quite coarse for a miller, your motors are capable of finer control. If you use ints then you have to use some arbitrary units like 1/1000 th of a mm so you can cope with fractional movement.

.... and I answered "maybe I should use float" .... then Mike:

No using floats brings rounding errors, you need to use int to keep it accurate. Just let the int stand for a small value.

Well, if I want to use decimal numbers how do I have to do ? I would like to set my height from 0 to 100 in 0.1 mm steps.

Here a part of my sketch ...

int HeightZ = 0;                      //ABS Height Variable = mm
int ActualHeightZ = 0;
int NewHeightZ;
  s1=menu.addMenu(MW_SUBMENU,r,F("SAW"));               // add a submenu node 2 to the root menu (control the heigh of my Saw)
   s2=menu.addMenu(MW_SUBMENU,s1,F("Saw Height"));      // (Move AT a certain mm height)
    s3=menu.addMenu(MW_VAR,s2,F("Absolute Height"));    // add a terminal node in the menu tree (that is "variable")
     s3->addVar(MW_AUTO_INT,&HeightZ,0,100,1);

oh, just for the record ...This is my solution, I had to change also the relative movement to have it working together with the absolute move:

void ABS_Height()                   // Absolute Height Function
 {
  NewHeightZ = (HeightZ - ActualHeightZ);
  stepper1.moveTo(NewHeightZ* 50);  // move Height1 mm's
   lcd.print ("Height mm ");
   lcd.print (HeightZ);
   delay (5000);
  ActualHeightZ = HeightZ;
 }


void MoveSAW()                      // This is the Relative Movement of the SAW
 {
  stepper1.moveTo(MoveREL * 50);    // move the SAW X mm's
   lcd.print ("Move ");
   lcd.print (MoveREL);
   lcd.print (" mm");
   delay (5000);
  ActualHeightZ = (HeightZ+MoveREL);
   lcd.print ("Height ");
   lcd.print (ActualHeightZ);
   lcd.print (" mm");
   delay (5000);
 }

Silverdog63:
Well, if I want to use decimal numbers how do I have to do ? I would like to set my height from 0 to 100 in 0.1 mm steps.

If you want a resolution of 0.1mm then make your units 0.1mm. This is known as 'fixed point' as distinct from 'floating point'.

If you want a resolution of 0.1mm then make your units 0.1mm.

Well I would say if you want 0.1mm resolution then make your units equal to 0.01mm or even 0.001 so that you don't get bitten by rounding errors.

Grumpy_Mike:
Well I would say if you want 0.1mm resolution then make your units equal to 0.01mm or even 0.001 so that you don't get bitten by rounding errors.

No, not that much! I am working with wood so 0.1 it's enough, I just want to make my movment in 0.1 step, ex move the height of 40.5 mm changing the variable from INT to FLOAt is ok ?or there is some other solution ?
thanks

changing the variable from INT to FLOAt is ok ?

Sorry I dnon't know how many times you need telling
DO NOT USE A FLOAT!!!!!
You will suffer from rounding errors. Mathematical operations will not be commutative.
What do you not understand about using an int with the numbers greater than your resolution?

What do you not understand about using an int with the numbers greater than your resolution?

What I don't understand maybe is the nature of INT ... I consider integer number the number with no decimals so 1, 2, 3 ..... but 0.5 is a decimal number ...
so my question is: can I define my function as INT and have decimal values ? like 10.5 10.8 ecc. ecc ?

Think of it like this. A millimeter is 0.001 of a meter. So in a sense it is a fractional meter. But if you deal in integral millimeters (store them in an int) then you won't get any rounding problems.

But you can define your own unit. Eg. a micrometer being 0.000001 of a meter. Of course, since an int only goes up to 32767 you might need to be cautious about how big your values might get, but you could always store them in a long, which goes up to 2147483647.

So if you use micrometers, then 1000000 micrometers represents a meter.

can I define my function as INT and have decimal values ? like 10.5 10.8 ecc. ecc ?

In my example of micrometers, if you want 1.5 meters then you would use 1500000 micrometers.

Thanks Nick, understood