Stepper Motor Angle and Speed Control

Hi !

I was wondering if someone would like to share or help me out with some Stepper motor code?

I would like to be able to controll the stepper motor manually with an PS2 joystick or with an compass sensor.

The PS2 joystick have the read values between 245 - 512 - 774.

I want the speed of the motor to be variable for smooth running like: MotorspeedC = 512 -joystickR or likwise.

I´m running an arduino uno with an A4988 driver board that have Step,Dir and Enable controll.

I would also make the code easy adjustable to controll the motor position with an compass.

Best Regards
Andreas

Hi Andreas and welcome to the forum,
what have you tried so far? Do you have a schematic already?
Maybe my MobaTools library can help.

Hi MicroBahner !

Thank you for the quick answer !

This is the code so far..
The only thing i have got to work is the joystick and button read and some speedvalues.

const int stepPin = 3;
const int dirPin = 4;
const int enPin = 2;

int currentAngle = 0;
int angle = 0;
float stepPerAngle = 1.8;
int numstep;
 
 int joyXY;
 int joyLR;
 int joyLRmap;
 int button1 = 2;
 int button1status; 
 const int ledPin =  LED_BUILTIN;
int speedC = 0;
int speedCC = 0;
int DIR = 0;
int step_ = 0;
int Pause =0;
int motorspeed = 500;

 




void setup() {
  Serial.begin (9600);
  pinMode(button1, INPUT_PULLUP);  
  pinMode(ledPin, OUTPUT); 

  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(enPin, OUTPUT);

  digitalWrite (enPin,HIGH);
  digitalWrite (dirPin,LOW);

}

void loop() {

  button1status = digitalRead(button1);
  joyXY = analogRead(A0);
  joyLR = analogRead(A1);
  


  // if the joystic is in the middle ===> stop the motor
if( (joyLR > 500) && (joyLR < 523) )
{
digitalWrite(ledPin, HIGH);
digitalWrite(enPin, HIGH);
Pause = 1;

}
else 
{ digitalWrite(ledPin, LOW);

}

speedC = (512 - joyLR) ;
speedCC = (joyLR - 512);



if ((joyLR < 523))
{ DIR = 1;}
else{DIR = 0;
step_ = (step_-1);
}


if ((joyLR > 500))
{ DIR = 1;}
else{DIR = 0;
step_ = (step_+1);
}





{
  for(int x = 0; x < step_; x++) {
    digitalWrite(enPin,LOW);
    digitalWrite(stepPin,HIGH); 
    delayMicroseconds(motorspeed); 
    digitalWrite(stepPin,LOW); 
    delayMicroseconds(motorspeed); 

    delay(100); // One second delay

  
}
 


}


 










Serial.print( "CurrentAngle ");
Serial.print(currentAngle);
   Serial.print ( " step ");
  Serial.print (step_);
 
    Serial.print ( " DIR ");
  Serial.print (DIR); 
  
    Serial.print ( " SpeedCC ");
  Serial.print (speedCC); 
  
    Serial.print ( " SpeedC ");
  Serial.print (speedC); 
  Serial.print (" joyLRmap = ");
  Serial.print (joyLRmap);  
  Serial.print (" joyXY = ");
  Serial.print (joyXY);
  Serial.print(" joyLR = ");
  Serial.print (joyLR);
  Serial.print(" Button = ");
  Serial.println (button1status);
  

  
  
  

}

Does your motor turn? And do you have a link to your motor specs? It is important to adjust the motor current at the A4988 according to your motor.

P.S. please use code tags ( the </> button at the top of your posting window ) when posting code. You can still edit your posting: mark all the code and press the </> button.

Hi !

I have an nema17 to test with and with example code i can get it running.
200steps/rotation.

Is the right way to controll the motorspeed by changing the "delayMircoseconds" between stepPin HIGH and LOW?

I want to controll an angle value that the stepper will follow, and when the joystick is engaged it will increase or decreese the set angle value.

When i get the compass running it will be easy for it to yust set an new angle value.

Could you help me out with som basic code to get me starting in the right way? :slight_smile:

Best Regards
Andreas

Nema17 does not define anything about the electrical specifications of your motor. It only defines the dimensions of the mounting flange. You need the electrical specifications to adjust your A4988 correctly and to select an adequate power supply.

No. The speed is defined by the number of steps per time. Therefore the delay between step HIGH and the next step HIGH is important. When it goes LOW in between is rather unimportant. The spec of the A4988 defines the minimum HIGH/LOW times.

A stepper - in contrast to a servo - does not know where it is. If you want it to move to an absoulte angle, you must fist determine a starting position - e.g. with an end switch. Do you need an absolute angle position? Or is it only relative - no matter where it starts?
It would help if you tell a bit more about your project.

This is a first attempt with MobaTools :wink: ( has shurely to be improved ):

#include <MobaTools.h>

const int stepPin = 6; //3;
const int dirPin = 5; //4;
const int enPin = 7; //2;

long currentAngle = 0;
int angle = 0;
//float stepPerAngle = 1.8;
int numstep;

int joyXY;
int joyLR;
int joyLRmap;
int button1 = 2;
int button1status;
const int ledPin =  LED_BUILTIN;
int speedC = 0;
int speedCC = 0;
int DIR = 0;
int step_ = 0;
int Pause = 0;
int motorspeed = 500;                         // Rev/Min*10
const int stepsPerRev = 200;                   // steps per revolution
MoToStepper stepper1( stepsPerRev, STEPDIR );  // create a stepper instance

void setup() {
    Serial.begin (115200);
    pinMode(button1, INPUT_PULLUP);
    pinMode(ledPin, OUTPUT);

    stepper1.attach( stepPin, dirPin );
    stepper1.setSpeed(motorspeed );              // rev/min (if stepsPerRev is set correctly)
    stepper1.setRampLen( stepsPerRev / 2);      // Ramp length is 1/2 revolution
    stepper1.attachEnable( enPin, 100, LOW );  // disable motor current in standstill

}

void loop() {

    button1status = digitalRead(button1);
    joyXY = analogRead(A0);
    joyLR = analogRead(A1);
    currentAngle = map ( joyLR, 0, 1024, -360, 360 );


    // if the joystic is in the middle ===> position motor to the middle
    if ( abs(currentAngle) < 20 )  // maybe adjusted
    {
        digitalWrite(ledPin, HIGH);
        stepper1.write(0 );
    }
    else
    {   // move the motor to desired position
        digitalWrite(ledPin, LOW);
        stepper1.write( currentAngle );

    }

    Serial.print( "CurrentAngle ");
    Serial.print(currentAngle);
    Serial.print ( " step ");
    Serial.print (step_);

    Serial.print ( " DIR ");
    Serial.print (DIR);

    Serial.print ( " SpeedCC ");
    Serial.print (speedCC);

    Serial.print ( " SpeedC ");
    Serial.print (speedC);
    Serial.print (" joyLRmap = ");
    Serial.print (joyLRmap);
    Serial.print (" joyXY = ");
    Serial.print (joyXY);
    Serial.print(" joyLR = ");
    Serial.print (joyLR);
    Serial.print(" Button = ");
    Serial.println (button1status);


    delay( 200 );

}

Hi !!

Thank you !! :slight_smile:

The starting position dosent matter, i may be helpful to press and hold the button for more then 3sec to set the the current angle to 0.

The motor should not turn more then 400 degres, ( it is cables attached to an axle so the cables dont break)

So when powering on the first thing i will do i to maually move it with the joystick to were the cables are straight and the press and hold the button for 3 sec to set current pos to zero.

When the joystick is not engaged the motor does not have to move in to an zero position yust hold and stay still.

The motorspeed should be variable to how much the joystick is engaged, the readings is from Left Max 245 0 = 512 Right MAX 773

Best Regards
Andreas

I don't really understand what you want to do. Which device is controlling the angle and which is controlling the speed?

You have 2 analog inputs:

What do you want them to control?
An exact description of the requirements is the basis for any programming.

Hi !

Ok ! i will try to be more specific!

My joystick have 2 pots i will only use one of them, joyLR (A1)

I will clean the code and add an Project discription after the code.

Best Regards

#include <MobaTools.h>

const int stepPin = 6; //3;
const int dirPin = 5; //4;
const int enPin = 7; //2;

long currentAngle = 0;
int angle = 0;
//float stepPerAngle = 1.8;
int numstep;

int joyLR;
int button1 = 2;
int button1status;
const int ledPin =  LED_BUILTIN;
int speedC = 0;
int speedCC = 0;
int step_ = 0;
int motorspeed = 500;                         // Rev/Min*10
const int stepsPerRev = 200;                   // steps per revolution
MoToStepper stepper1( stepsPerRev, STEPDIR );  // create a stepper instance

void setup() {
    Serial.begin (115200);
    pinMode(button1, INPUT_PULLUP);
    pinMode(ledPin, OUTPUT);

    stepper1.attach( stepPin, dirPin );
    stepper1.setSpeed(motorspeed );              // rev/min (if stepsPerRev is set correctly)
    stepper1.setRampLen( stepsPerRev / 2);      // Ramp length is 1/2 revolution
    stepper1.attachEnable( enPin, 100, LOW );  // disable motor current in standstill

}

void loop() {

    button1status = digitalRead(button1);
    
    joyLR = analogRead(A1);
    currentAngle = map ( joyLR, 0, 1024, -360, 360 );


    // if the joystic is in the middle ===> position motor to the middle
    if ( abs(currentAngle) < 20 )  // maybe adjusted
    {
        digitalWrite(ledPin, HIGH);
        stepper1.write(0 );
    }
    else
    {   // move the motor to desired position
        digitalWrite(ledPin, LOW);
        stepper1.write( currentAngle );

    }

    Serial.print( "CurrentAngle ");
    Serial.print(currentAngle);
    Serial.print ( " step ");
    Serial.print (step_);
    Serial.print ( " DIR ");
    Serial.print (DIR);
    Serial.print ( " SpeedCC ");
    Serial.print (speedCC);
    Serial.print ( " SpeedC ");
    Serial.print (speedC);
    Serial.print (" joyLRmap = ");
    Serial.print (joyLRmap);
    Serial.print (" joyXY = ");
    Serial.print (joyXY);
    Serial.print(" joyLR = ");
    Serial.print (joyLR);
    Serial.print(" Button = ");
    Serial.println (button1status);


    delay( 200 );

}

// Project Description
//
// To be able to control an steppermotor with an Arduino and A4988 Driver
// Link to Stepper: https://www.omc-stepperonline.com/precision-planetary-gearbox/nema-17- 
   stepper-motor-l39mm-gear-raio-501-high-precision-planetary-gearbox-17hs15-1684s-hg50.html
// 
// The outputshaft on the stepper has an pulley to another axle with an pulley 1:1
//Button function = Mode select.
// Mode 1, press and hold 3 sec = reset the counter that keeps count on max rotaion ( 400degress ) ( to keep cables attached to rotating axle safe.  
// Mode 2, press once to activate future mode that let an compass sensor set the angle of the stepper. 
// Mode 3, Manual mode= Motor angle i manually controlled by the joystick with the 400 degress saftey funcion. 
// Joystick function, when pushed left = rotate counterclockwise CC AnalogReadValue 245 to 500,  when pushed right = rotate clockwise AnalogReadValue C 524-774. In deadzone 501-523 keep stepper still, no rotating. 
// Joystick function, the stepperspeed is controlled by how much the joystick is engaged in either direction. Joystick Pushed little motor rotate slow, joystick pushed mutch motor rotate fast.  
//
//Mode 2: Compass function, the compass sensor will save the compass direction  when button is pressed once, the motor should try to hold this angle.  
// Example, i maually controll the motor angle with the joystic, then when i press the button the compass  is for example pointing in north angle the motor should stand still, when the compass sensor reads an angle shift (rotation of the compass) the motor should adjust so that it points to were the compass was pointing when the button was pressed. The motor speed in this mode should be as fast as possible or linear to how much difference there is between saved compass angle and current motorangle.


Ok, than I missunderstood completely. I thought you want to define the angle with your joystick where the stepper should be positioned to.
From the datasheet of your stepper I see that is has a 50:1 gearbox. Theat means 1 revolution is not 200 steps, but 10000 steps.
What speed do you want to achieve? With a gearbox it will be rather slow.

What about the compass. This will than define the angle to be positioned and not the speed? How should this work together with the joystick?

Hi !! Thank you for the help !! :slight_smile:

I have updated the Project description !

I may have to switch out the motor to an with an lower gear ratio if it turns to slowly. I can try with the 50:1 to begin with.

If i takes 4 Sec to make the output shaft make an 360 rotation it should be fast enugh.

I tried the code you write with the Moba and it work perfect !! Just not the function i wanted.

Best Regards
Andreas

Hi Andreas,
yes, my fault, because I misunderstood you. I'll try a better approch as a starting point for you...

Well with no project discription and my bad discription i think you did great ! :slight_smile:

Hi Andreas,
well, here is a second try. I used some more classes of MobaTools. Setting the zero point by a 3 second press is implemented, but the modes have to be added. I'm not sure about the 400 degree angle limit. Is it 400 degrees in both directions or 400 degrees in total? But you can simply adjust that by changing the '400' to '200'.
I hope this fits better to your needs. Now it's your turn :wink:
regards
Franz-Peter

#include <MobaTools.h>

// hardware related definitiona
// Set pins according to your hardware
// ( button and enable was set to the same pin in your first attempt )
const int stepPin = 6; //3;
const int dirPin = 5; //4;
const int enPin = 7; //2;
const byte buttonPins[] = {2};
const byte joyLRPin = A1;
const int ledPin =  LED_BUILTIN;
//----------------------------

const long maxAngle = 400;          // this is the max angle in every direction.
const int maxSpeed = 2500;          // max Speed is 2500 steps/sec ( depends what the motor can do )
const int minSpeed = 10;            // lowest Speed
const int stepsPerRev = 200 * 50;   // steps per revolution with gear box
//-----------------------------

// limits for joystick
const int joyLimits[] = { 245, 500, 524, 774 };
//const int joyLimits[] = { 0, 500, 524, 1024 };
//------------------------------------------------------------------------------

int joyLR;
int joyLRmap;

int motorSpeed = 500;                         // Steps/sec

// create MobaTools objects
MoToStepper stepper1( stepsPerRev, STEPDIR );       // create a stepper instance
MoToButtons myButtons( buttonPins, 1, 20, 3000 );   // manage buttons(s), longpress is 3 seconds
MoToTimebase printTimer;                            // Timer to print in regular intervals without blocking sketch
MoToTimebase joyTimer;                              // Timer to read joystick in regular intervals without blocking sketch

void setup() {
    Serial.begin (115200);
    printTimer.setBasetime( 1000 );           // print values every second
    joyTimer.setBasetime( 100 );              // read joystick 10 times a second

    pinMode(ledPin, OUTPUT);

    // initiate stepper
    stepper1.attach( stepPin, dirPin );
    stepper1.setSpeed(motorSpeed );              // rev/min (if stepsPerRev is set correctly)
    stepper1.setRampLen( 100 );                  // set ramp length to what the motor needs to not loose steps
    stepper1.attachEnable( enPin, 100, LOW );  // disable motor current in standstill

}

void loop() {

    myButtons.processButtons();
    
    if (joyTimer.tick() ) {
        // read joystick and set stepper speed accordingly

        joyLR = analogRead(joyLRPin);
        // if the joystic is in the middle ===> sti
        if ( joyLR > joyLimits[1] && joyLR < joyLimits[2] ) // neutral area
        {
            digitalWrite(ledPin, HIGH);
            stepper1.rotate(0 );      // stop stepper if joystick in the middle
        }
        else
        {   // move the motor in desired direction
            digitalWrite(ledPin, LOW);
            if ( joyLR >= joyLimits[2] ) {
                // move towards max angle
                motorSpeed = map ( joyLR , joyLimits[2], joyLimits[3] , minSpeed, maxSpeed ); // Values may be adjusted to the joystick
                stepper1.setSpeedSteps( motorSpeed * 10 );
                stepper1.write( maxAngle );
            } else {
                // move towards min angle
                motorSpeed = map ( joyLR , joyLimits[1], joyLimits[0] , minSpeed, maxSpeed ); // Values may be adjusted to the joystick
                stepper1.setSpeedSteps( motorSpeed * 10 );
                stepper1.write( -maxAngle );

            }
        }
    }

    if ( myButtons.longPress(0) ) {
        // button pressed long -> set referencepoint
        Serial.println( "Set referencepoint" );
        stepper1.setZero();
    }

    if ( printTimer.tick() ) {
        // debug printing every second
        Serial.print( "CurrentAngle "); Serial.print(stepper1.read() );
        Serial.print ( " step ");       Serial.print (stepper1.readSteps() );

        Serial.print ( " DIR "); 
           if (joyLR >= joyLimits[2]) Serial.print ( "right") ;
           else if (joyLR <= joyLimits[1]) Serial.print( "left");
           else Serial.print( "stop");

        Serial.print ( " SpeedCC ");    Serial.print (motorSpeed);

        Serial.print(" joyLR = ");      Serial.print (joyLR);

        Serial.print(" Button= ");      Serial.println (myButtons.state(0));
    }
}

Hi !!

Amazing! :slight_smile:

The code you writed works perfect !!

The stepper im using for testing now is only 200steps/revolution so i changed that to get it runnning.

I tried to add an if statment to the button (shortpress) and it works to print out "return to refrencepoint" But im not able to get the stepper to return to Refrencepoint. I tried using the

stepper1.stepsToDo();

but nothing happend,

The thing i want to happen when the button is pressed short is to get the motor return to refrencepoint.

When i get the compass sensor running i will read out an angle, when i press the button twice i want the stepper to move hold the angle set when pushing twice on the button. What function is best to use for this task? If button pressed twice set compass refrence point, if compas direction change the stepper should move the same amount of rotation.

Once again Thank you som much for helping me with this !
Best Regards
Andreas

#include <MobaTools.h>

// hardware related definitiona
// Set pins according to your hardware
// ( button and enable was set to the same pin in your first attempt )
const int stepPin = 6; //3;
const int dirPin = 5; //4;
const int enPin = 7; //2;
const byte buttonPins[] = {2};
const byte joyLRPin = A1;
const int ledPin =  LED_BUILTIN;
//----------------------------

const long maxAngle = 400;          // this is the max angle in every direction.
const int maxSpeed = 2500;          // max Speed is 2500 steps/sec ( depends what the motor can do )
const int minSpeed = 10;            // lowest Speed
const int stepsPerRev = 200;   // steps per revolution with gear box 200 * 50
//-----------------------------

// limits for joystick
const int joyLimits[] = { 245, 500, 524, 774 };
//const int joyLimits[] = { 0, 500, 524, 1024 };
//------------------------------------------------------------------------------

int joyLR;
int joyLRmap;

int motorSpeed = 500;                         // Steps/sec

// create MobaTools objects
MoToStepper stepper1( stepsPerRev, STEPDIR );       // create a stepper instance
MoToButtons myButtons( buttonPins, 1, 20, 3000 );   // manage buttons(s), longpress is 3 seconds
MoToTimebase printTimer;                            // Timer to print in regular intervals without blocking sketch
MoToTimebase joyTimer;                              // Timer to read joystick in regular intervals without blocking sketch

void setup() {
    Serial.begin (115200);
    printTimer.setBasetime( 1000 );           // print values every second
    joyTimer.setBasetime( 100 );              // read joystick 10 times a second

    pinMode(ledPin, OUTPUT);

    // initiate stepper
    stepper1.attach( stepPin, dirPin );
    stepper1.setSpeed(motorSpeed );              // rev/min (if stepsPerRev is set correctly)
    stepper1.setRampLen( 100 );                  // set ramp length to what the motor needs to not loose steps
    stepper1.attachEnable( enPin, 100, LOW );  // disable motor current in standstill

}

void loop() {

    myButtons.processButtons();
    
    if (joyTimer.tick() ) {
        // read joystick and set stepper speed accordingly

        joyLR = analogRead(joyLRPin);
        // if the joystic is in the middle ===> sti
        if ( joyLR > joyLimits[1] && joyLR < joyLimits[2] ) // neutral area
        {
            digitalWrite(ledPin, HIGH);
            stepper1.rotate(0 );      // stop stepper if joystick in the middle
        }
        else
        {   // move the motor in desired direction
            digitalWrite(ledPin, LOW);
            if ( joyLR >= joyLimits[2] ) {
                // move towards max angle
                motorSpeed = map ( joyLR , joyLimits[2], joyLimits[3] , minSpeed, maxSpeed ); // Values may be adjusted to the joystick
                stepper1.setSpeedSteps( motorSpeed * 10 );
                stepper1.write( maxAngle );
            } else {
                // move towards min angle
                motorSpeed = map ( joyLR , joyLimits[1], joyLimits[0] , minSpeed, maxSpeed ); // Values may be adjusted to the joystick
                stepper1.setSpeedSteps( motorSpeed * 10 );
                stepper1.write( -maxAngle );

            }
        }
    }

    if ( myButtons.longPress(0) ) {
        // button pressed long -> set referencepoint
        Serial.println( "Set referencepoint" );
        stepper1.setZero();
    }


    if ( myButtons.shortPress(0) ) {
        // button pressed short -> return stepper to refrencepoint
        Serial.println( "Return to refrencepointt" );
        stepper1.stepsToDo();
    }


    

    if ( printTimer.tick() ) {
        // debug printing every second
        Serial.print( "CurrentAngle "); Serial.print(stepper1.read() );
        Serial.print ( " step ");       Serial.print (stepper1.readSteps() );

        Serial.print ( " DIR "); 
           if (joyLR >= joyLimits[2]) Serial.print ( "right") ;
           else if (joyLR <= joyLimits[1]) Serial.print( "left");
           else Serial.print( "stop");

        Serial.print ( " SpeedCC ");    Serial.print (motorSpeed);

        Serial.print(" joyLR = ");      Serial.print (joyLR);

        Serial.print(" Button= ");      Serial.println (myButtons.state(0));
    }
}

To move to the reference point you must call stepper1.write(0);.
But it's not as easy in this case, because your joystick is always controling the stepper and thus interferes with the write command.
Now you need the mode concept, where you can determine which device is controling the stepper.

Hi !

I have tried to build an Mode/Function selection with use of the Moba Tools,

Function 1 and Function 2 works fine, Function 3 works sort of, when i let go the off second push the Function 3 lets go and switches to function 1.

So it would be better to let an Desired angle value, set by ( Function 1 joystick ) or ( Function 2 compass ) to controll the stepper1.write( " Desierd angle"); ?

Best Regards
Andreas


}

void loop() {

  
    myButtons.processButtons();

  if ( myButtons.longPress(0) ) {
        // button pressed long -> set referencepoint
        Serial.println( "Set referencepoint" );
      
        Function = 1; 
    }

   
   if ( myButtons.shortPress(0) ) {
        // button pressed short -> return stepper to refrencepoint
        Serial.println( "Return to refrencepoint" );
     
        Function = 2; 
    }
       // button pressed twice short-> Activate function that lets the compass reading refrence set the angle of steper. 
       if ( myButtons.pressed(0)) {

      releaseIndex = 1 - releaseIndex;
      releaseTimes[releaseIndex] = millis();

      if (abs(releaseTimes[0] - releaseTimes[1]) < 800) {
          releaseTimes[0] = 0;
          releaseTimes[1] = 0;
          laserIndex = 1 - laserIndex;
          
          Function = 3;
      }
 

 }

       
 
Serial.println (Function);

}

Well, it is a bit complicated to distinguish between so much modes with only one button. But 3 is possible: The MoToButtons class can distinguish between click ( a 'short shortpress' ) double click and long press. So your mode selection could be ( set zero with long press, select compass withh single click, return to reference point with double click):

#include <MobaTools.h>

// hardware related definitiona
// Set pins according to your hardware
const int stepPin = 6; //3;
const int dirPin = 5; //4;
const int enPin = 7; //2;
const byte buttonPins[] = {2};
const byte joyLRPin = A1;
const int ledPin =  LED_BUILTIN;
//----------------------------

const long maxAngle = 400;          // this is the max angle in every direction.
const int maxSpeed = 2500;          // max Speed is 2500 steps/sec ( depends what the motor can do )
const int minSpeed = 10;            // lowest Speed
const int stepsPerRev = 200 * 50;   // steps per revolution with gear box
//-----------------------------

// limits for joystick
//const int joyLimits[] = { 245, 500, 524, 774 };
const int joyLimits[] = { 0, 500, 524, 1024 };
//------------------------------------------------------------------------------

int joyLR;
byte function = 1;                            // default is joystick
int motorSpeed = 500;                         // Steps/sec

// create MobaTools objects
MoToStepper stepper1( stepsPerRev, STEPDIR );       // create a stepper instance
MoToButtons myButtons( buttonPins, 1, 20, 3000 );   // manage buttons(s), longpress is 3 seconds
MoToTimebase printTimer;                            // Timer to print in regular intervals without blocking sketch
MoToTimebase joyTimer;                              // Timer to read joystick in regular intervals without blocking sketch

void setup() {
    Serial.begin (115200);
    printTimer.setBasetime( 1000 );           // print values every second
    joyTimer.setBasetime( 100 );              // read joystick 10 times a second

    pinMode(ledPin, OUTPUT);

    // initiate stepper
    stepper1.attach( stepPin, dirPin );
    stepper1.setSpeed(motorSpeed );              // rev/min (if stepsPerRev is set correctly)
    stepper1.setRampLen( 100 );                  // set ramp length to what the motor needs to not loose steps
    stepper1.attachEnable( enPin, 100, LOW );  // disable motor current in standstill

}

void loop() {

    myButtons.processButtons();

    // select function mode by button presses
    if ( myButtons.longPress(0) ) {
        // button pressed long -> set referencepoint
        Serial.println( "Set referencepoint" );
        stepper1.setZero();
        function = 1;
    }

    switch ( myButtons.clicked(0) ) {
        case NOCLICK:
            ; // do nothing
            break;
        case DOUBLECLICK:
            Serial.println( "Return to refrencepoint" );
            stepper1.setSpeedSteps( 2000 );   // Speed when moving home
            stepper1.write(0);
            function = 3;
            break;
        case SINGLECLICK:
            Serial.println( "Set function 2" );
            function = 2;
            break;
    }

    switch ( function ) {
        case 1:  // mode 1 - joystick control
            if (joyTimer.tick() ) {
                // read joystick and set stepper speed accordingly

                joyLR = analogRead(joyLRPin);
                // if the joystic is in the middle ===> sti
                if ( joyLR > joyLimits[1] && joyLR < joyLimits[2] ) // neutral area
                {
                    digitalWrite(ledPin, HIGH);
                    stepper1.rotate(0 );      // stop stepper if joystick in the middle
                }
                else
                {   // move the motor in desired direction
                    digitalWrite(ledPin, LOW);
                    if ( joyLR >= joyLimits[2] ) {
                        // move towards max angle
                        motorSpeed = map ( joyLR , joyLimits[2], joyLimits[3] , minSpeed, maxSpeed ); // Values may be adjusted to the joystick
                        stepper1.setSpeedSteps( motorSpeed * 10 );
                        stepper1.write( maxAngle );
                    } else {
                        // move towards min angle
                        motorSpeed = map ( joyLR , joyLimits[1], joyLimits[0] , minSpeed, maxSpeed ); // Values may be adjusted to the joystick
                        stepper1.setSpeedSteps( motorSpeed * 10 );
                        stepper1.write( -maxAngle );

                    }
                }
            }
            break;
        case 2: // mode 2 compass control
                // to be implemented
            break;
        case 3: // return to reference point, switch back to joystick control if reached
            if ( !stepper1.moving() ) function = 1;
            break;
    }
    if ( myButtons.longPress(0) ) {
        // button pressed long -> set referencepoint
        Serial.println( "Set referencepoint" );
        stepper1.setZero();
    }

    if ( printTimer.tick() ) {
        // debug printing every second
        Serial.print( "CurrentAngle "); Serial.print(stepper1.read() );
        Serial.print ( " step ");       Serial.print (stepper1.readSteps() );

        Serial.print ( " DIR ");
        if (joyLR >= joyLimits[2]) Serial.print ( "right") ;
        else if (joyLR <= joyLimits[1]) Serial.print( "left");
        else Serial.print( "stop");

        Serial.print ( " SpeedCC ");    Serial.print (motorSpeed);

        Serial.print(" joyLR = ");      Serial.print (joyLR);

        Serial.print(" Button= ");      Serial.println (myButtons.state(0));
    }
}

Hi !!

It works almost perfect !! :slight_smile:

I tried to add the Function 2 compass control, i added int compassAngle = 200; to simulate an compass and make the motor move to that direction when SINGLECLICK ( Function 2) is enabled.

It works but if i activate function 2 or 3 i cant abort the function when pushing the joystick in either direction. So if i dubbleclick and motor starts returning to refrencepoint, i then push the joystick i want to abort the function 2 and set function 1.

Were can i read how the Noclick, doubleclick and noclick functions work? I cant find the functions in the MobaTools documentation. Or is these functions basic arduino stuff?

#include <MobaTools.h>

// hardware related definitiona
// Set pins according to your hardware
const int stepPin = 6; //3;
const int dirPin = 5; //4;
const int enPin = 7; //2;
const byte buttonPins[] = {2};
const byte joyLRPin = A1;
const int ledPin =  LED_BUILTIN;
//----------------------------

int compassAngle = 200;             // compassAngle for testing**

const long maxAngle = 400;          // this is the max angle in every direction.
const int maxSpeed = 2500;          // max Speed is 2500 steps/sec ( depends what the motor can do )
const int minSpeed = 50;            // lowest Speed
const int stepsPerRev = 2000;   // steps per revolution with gear box
//-----------------------------

// limits for joystick
//const int joyLimits[] = { 245, 500, 524, 774 };
const int joyLimits[] = { 0, 500, 524, 1024 };
//------------------------------------------------------------------------------

int joyLR;
byte function = 1;                            // default is joystick
int motorSpeed = 500;                         // Steps/sec

// create MobaTools objects
MoToStepper stepper1( stepsPerRev, STEPDIR );       // create a stepper instance
MoToButtons myButtons( buttonPins, 1, 20, 3000 );   // manage buttons(s), longpress is 3 seconds
MoToTimebase printTimer;                            // Timer to print in regular intervals without blocking sketch
MoToTimebase joyTimer;                              // Timer to read joystick in regular intervals without blocking sketch

void setup() {
    Serial.begin (115200);
    printTimer.setBasetime( 1000 );           // print values every second
    joyTimer.setBasetime( 100 );              // read joystick 10 times a second

    pinMode(ledPin, OUTPUT);

    // initiate stepper
    stepper1.attach( stepPin, dirPin );
    stepper1.setSpeed(motorSpeed );              // rev/min (if stepsPerRev is set correctly)
    stepper1.setRampLen( 100 );                  // set ramp length to what the motor needs to not loose steps
    stepper1.attachEnable( enPin, 100, LOW );  // disable motor current in standstill

}

void loop() {

    myButtons.processButtons();

    // select function mode by button presses
    if ( myButtons.longPress(0) ) {
        // button pressed long -> set referencepoint
        Serial.println( "Set referencepoint" );
        stepper1.setZero();
        function = 1;
    }

    switch ( myButtons.clicked(0) ) {
        case NOCLICK:
            ; // do nothing
            break;
        case DOUBLECLICK:
            Serial.println( "Return to refrencepoint" );
            stepper1.setSpeedSteps( 2000 );   // Speed when moving home
            stepper1.write(0);
            function = 3;
            break;
        case SINGLECLICK:
            Serial.println( "Set function 2" );
             stepper1.setSpeedSteps( 2000 );   // Speed when moving home
             stepper1.write(compassAngle);  
            function = 2;
            break;
    }

    switch ( function ) {
        case 1:  // mode 1 - joystick control
            if (joyTimer.tick() ) {
                // read joystick and set stepper speed accordingly

                joyLR = analogRead(joyLRPin);
                // if the joystic is in the middle ===> sti
                if ( joyLR > joyLimits[1] && joyLR < joyLimits[2] ) // neutral area
                {
                    digitalWrite(ledPin, HIGH);
                    stepper1.rotate(0 );      // stop stepper if joystick in the middle
                }
                else
                {   // move the motor in desired direction
                    digitalWrite(ledPin, LOW);
                    if ( joyLR >= joyLimits[2] ) {
                        // move towards max angle
                        motorSpeed = map ( joyLR , joyLimits[2], joyLimits[3] , minSpeed, maxSpeed ); // Values may be adjusted to the joystick
                        stepper1.setSpeedSteps( motorSpeed * 10 );
                        stepper1.write( maxAngle );
                    } else {
                        // move towards min angle
                        motorSpeed = map ( joyLR , joyLimits[1], joyLimits[0] , minSpeed, maxSpeed ); // Values may be adjusted to the joystick
                        stepper1.setSpeedSteps( motorSpeed * 10 );
                        stepper1.write( -maxAngle );

                    }
                }
            }
            break;
        case 2: // // Move to angle set by compass for testing "CompassAngle", switch back to joystick control if reached
               if ( !stepper1.moving() ) function = 1; 
            break;
        case 3: // return to reference point, switch back to joystick control if reached
            if ( !stepper1.moving() ) function = 1;
            break;
    }
    if ( myButtons.longPress(0) ) {
        // button pressed long -> set referencepoint
        Serial.println( "Set referencepoint" );
        stepper1.setZero();
    }

    if ( printTimer.tick() ) {
        // debug printing every second
        Serial.print( "CurrentAngle "); Serial.print(stepper1.read() );
        Serial.print ( " step ");       Serial.print (stepper1.readSteps() );

        Serial.print ( " DIR ");
        if (joyLR >= joyLimits[2]) Serial.print ( "right") ;
        else if (joyLR <= joyLimits[1]) Serial.print( "left");
        else Serial.print( "stop");

        Serial.print ( " SpeedCC ");    Serial.print (motorSpeed);

        Serial.print(" joyLR = ");      Serial.print (joyLR);

        Serial.print(" Button= ");      Serial.print (myButtons.state(0));

        Serial.print(" Function= ");      Serial.println (function);
    }
}