Stepper Motor Angle and Speed Control

The MoToButtons class is described in chapter 3.6, and you can find the 'clicked()' method at the end of page 15 of the english documentation:

uint8_t myButtons.clicked( uint8_t buttonNbr );
Returns whether the button was single or double clicked. The return value is:

NOCLICK (=0) if nothing has been clicked.
SINGLECLICK (=1) when a single click is detected.
DOUBLECLICK (=2) when a double click is detected.

After calling the method, the event is deleted, i.e. further calls return NOCLICK. The event is
also deleted if the pushbutton was pressed again before the method was called.
Note that a click is also interpreted as a 'shortPress'. So a click will also generate a 'shortPress'
event ( see above ). As a rule, you should either query on 'clicked' or on 'shortPress'.
If a line with #define CLICK_NO_SHORT is inserted before the #include <MobaTools.h>,
the 'shortPress' event is also deleted if a single or double click was detected when calling
'clicked'. ( see also the example 'Button_I2C' )

If you want to be able to abort any function mode with your joystick, you must query the stick independend from the mode. That means the query must not be inside the function switch, but the function switch must be inside the query.

Try this:

#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;
    }

    if (joyTimer.tick() ) {
        // read joystick and set stepper speed accordingly
        joyLR = analogRead(joyLRPin);
        // if the joystic is not in the middle ===> its activ
        bool joyActive = !(joyLR > joyLimits[1] && joyLR < joyLimits[2]);

        switch ( function ) {
            case 1:  // mode 1 - joystick control
                if ( !joyActive ) // 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 position reached or joystick is active
                if ( !stepper1.moving()  || joyActive ) function = 1;
                break;
            case 3: // return to reference point,
                // switch back to joystick control if reached or joystick is active
                if ( !stepper1.moving() || joyActive ) function = 1;
                break;
        }
    }

    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);
    }
}

Hi !!

I have tried the code now and the changes you did on function abort when joystick is active worked perfect !! :slight_smile:

I adjusted the Vref pot on the A4988 to match the 1.68A stepper i“m using, Vref=1.5x8x0,1 and it is very strong with the 50:1 gear ratio. A bit to slow in fact, the max speed is about 1500 over 1500 it starts losing steps and sounds bad. The lowest speed i can run is about 500, slower it sounds bad.

When uploading new software the enablePin on the a4988 gets low and the motor is active, i measured the current on in one of the coil to 1A, is it a bad thing that the motor is in this state or could i use this function to hold the angle?

I cant get Function 2 and 3 to follow the " const int minSpeed = 500" when Function 2 or 3 is activated the speed is very low and the motor sounds bad.

The A4988 driver may not be the best choice for this motor and application or i“m just jusing it wrong :slight_smile: Maybe this one TMC 2226 vould be a better choice : https://cdn-3d.niceshops.com/upload/file/TMC2226_V1.0_Instruction_Manual.pdf

And once again thank you so much for helping me out!

1.68A is pretty much for an A9488. I think it needs cooling i this case. The DRV8825 is capable of a little bit more amps.

You could use microstepping. There is less noise, but it will be even slower - you must use higher steprates.

The speed for function 2+3 is set when the fucnstion is activated. You can change to a higher value.

            stepper1.setSpeedSteps( 2000 );   // Speed when moving home
            stepper1.write(0);

Remember that setSpeedSteps needs the steprate in steps/10sec. You can use values up to 25000.

These drivers can drive your stepper very silently. But as far as I know only when using microstepping ( makes it slower ).

Hi !!

I changed the stepper1.setSpeedSteps( 2000 ); // Speed when moving home to 20000 and it worked perfect !

I placed an order for some DRV 8825, as you said the TMC are just quiet in microstepping.

I also will also order an motor with 30:1 gear ratio to get the speed up a bit more, unfortunaly they were out of stock now, https://www.omc-stepperonline.com/precision-planetary-gearbox/nema-17-stepper-motor-l39mm-gear-raio-301-high-precision-planetary-gearbox-17hs15-1684s-hg30.html

"You could use microstepping. There is less noise, but it will be even slower - you must use higher steprates."

How do i use higher steprates?

Maybe this motor with the DRV8825 and microstepping will be a bit more quiet.

Best Regards !

You wrote that your motor cannot get up with steprates higer 1500 steps/sec. When using halfsteps the speed ist half as much, so you need 3000 steps/sec to gain the same speed.
The maximum with MobaTools 'out of the box' is 2500 steps/sec for an AVR processor ( UNO, Nano, Mega ). But up to 6 steppers can run at this speed. If you have only one stepper, you can reach steprates up to 5000 steps/sec by changing a define in MobaTools.h.
Change CYCLETIME for AVR processors to 100:

...
#elif defined ARDUINO_ARCH_AVR ////////////////////////////////////////////////////////
//#define NO_TIMER3             // never use Timer 3
#define CYCLETIME       100     // Min. irq-periode in us ( default is 200 ), 
...

After that you can set maxSpeed to 5000.

Hi !

I tried the DRV8825 and with microstepping it was a bit more quiet but not as silent as i want.

I“m considering to switch out the geared stepper for something else to make it silent.
The benefit of using the planetary geard stepper is that i dont need to have any brakes och use the stepper to hold the shaft locked due to its internal mechanical resistance.
The downside is the slow speed and long motor body.

I have looked at these closed loop stepper: https://www.omc-stepperonline.com/ts-series-1-2-nm-170oz-in-1-axis-closed-loop-stepper-cnc-kit-nema-23-motor-and-driver-w-2m-cable.html

The youtube videos i can find about it the motor runs totaly silient. With the high microstepping i can get it to be slow enough and hopfully strong enough.

The downside is the none internal resistance to hold motor position but the encoder and driver looks like it can handle that by itself.

I have looked att O drive and simpleFOC and some brushless motor with encoder wich looks cool and also silent but a bit more components to work with.

Any advices about choosing an motor/driver options?

Best Regards
Andreas

Hi !

I have got an self calibrating sensor now the Adafruit BNO055 : Overview | Adafruit BNO055 Absolute Orientation Sensor | Adafruit Learning System

I“m using the map to change the value from 0.00-360.00 to -360-360 to controll the value compassAngle1 and that value i use in function 2 " move stepper to compassAngle1.

i“m having two problems with that function, the first it that when the compass angle is 0 or 360 the stepper has to take an full rotation.
The other problem is that when i Singleclick the stepper moves to the compassAngle1 and then returns to function 1, i want the stepper to keep holding the compassAngle1 ( function2) position in 60 seconds or if the manual function is activated.

When i Singleclick and activates "function 2" i want to take the compass reading (event.orientation.x) and save that value when function 2 is activated, i do that with "compassAnglePos"
Then i want to hold the axleposition in compassAnglePos direction even if the motor mount rotates. I understand that i have to calculate the difference between compassAnglePos and the event.orientation.x to adjust the axlepositon i just dont know how? :slight_smile:

#include <MobaTools.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.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;
//----------------------------
/* Set the delay between fresh samples */
#define BNO055_SAMPLERATE_DELAY_MS (100)

// Check I2C device address and correct line below (by default address is 0x29 or 0x28)
//                                   id, address
Adafruit_BNO055 bno = Adafruit_BNO055(55, 0x28);



int compassAngle = 12;             // compassAngle for testing**
int compassAngle1 = 0;             // compassAngle adjusted from BNO055 Reading** BNO055 Read value 0.00-360.00
int compassAnglePos = 0;            // compassAngle when Singleclick ( function 2 is activated) 
int compassAngleAdjusted = 0;  

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

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

int joyLR;
byte function = 1;                            // default is joystick
int motorSpeed = 1500;                         // 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
    sensor_t sensor;
  bno.getSensor(&sensor);
  if(!bno.begin())
  {
    /* There was a problem detecting the BNO055 ... check your connections */
    Serial.print("Ooops, no BNO055 detected ... Check your wiring or I2C ADDR!");
    while(1);
  }

  delay(1000);
  bno.setExtCrystalUse(true);
    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() {
   /* Get a new sensor event */
  sensors_event_t event;
  bno.getEvent(&event);
  myButtons.processButtons();

   compassAngle1 = map (event.orientation.x, 0, 360 ,-360, 360);      // Map value from BNO055 to stepper -360 to 360

  

    // 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 RP" );
            stepper1.setSpeedSteps( 20000 );   // Speed when moving home
            stepper1.write(0);
            function = 3;
            break;
        case SINGLECLICK:
            Serial.println( "Set function 2" );
            stepper1.setSpeedSteps( 20000 );   // Speed when moving home
            stepper1.write(compassAngle1);
            function = 2;
            compassAnglePos = event.orientation.x; 
            compassAngleAdjusted = compassAnglePos;
            break;
    }

        if ( event.orientation.x >= compassAnglePos ) {
      compassAngleAdjusted ++;  
      
   }
   if ( event.orientation.x <= compassAnglePos ) {
      compassAngleAdjusted - 1;  
      
   }



    if (joyTimer.tick() ) {
        // read joystick and set stepper speed accordingly
        joyLR = analogRead(joyLRPin);
        // if the joystic is not in the middle ===> its activ
        bool joyActive = !(joyLR > joyLimits[1] && joyLR < joyLimits[2]);

        switch ( function ) {
            case 1:  // mode 1 - joystick control
                if ( !joyActive ) // 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 position reached or joystick is active
                if ( !stepper1.moving()  || joyActive ) function = 1;
                break;
            case 3: // return to reference point,
                // switch back to joystick control if reached or joystick is active
                if ( !stepper1.moving() || joyActive ) function = 1;
                break;
        }
    }

    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( "compassAngle1 "); Serial.print(compassAngle1);
        Serial.print( "event.orientation.x "); Serial.print(event.orientation.x);
        Serial.print( "compassAnglePos "); Serial.print(compassAnglePos);
        Serial.print( "compassAngleAdjusted "); Serial.println(compassAngleAdjusted);
       
        
    }
}

Best Regards

Andreas

You must change the function2 code to do that. As it is now you directly return to function1 if the stepper has reached the target position:

            case 2: // // Move to angle set by compass for testing "CompassAngle",
                // switch back to joystick control if position reached or joystick is active
                if ( !stepper1.moving()  || joyActive ) function = 1;
                break;

You can try this, if you want the stepper to hold its position for 60 seconds before going back to function1 ( try, it's untested! )

            case 2: // // Move to angle set by compass for testing "CompassAngle",
                // switch back to joystick control if position reached or joystick is active
                if ( joyActive || holdTimer.expired() ) function = 1;
                if ( !stepper1.moving()  && !holdTimer.running() ) {
                  holdTimer.setTime( 60000 );
                }

Of course you must define the new timer:

...
MoToTimebase printTimer;                            // Timer to print in regular intervals without blocking sketch
MoToTimebase joyTimer;                              // Timer to read joystick in regular intervals without blocking sketch
MoToTimer holdTimer;                                // Timer for stepper to hold position
...

I can't really imagine that yet. Perhaps a photo of the construction would be helpful. And I have no experience with your sensor.

Hi !!
Now i made som progress with my remote, i want to send the buttonState with the NRF24 to my reciever, and was wondering if the simplest way is to make an int (buttonState) and send the buttonState 0,1,2,3. I want to use an 300 millis to reset the buttonState to 0 when Noclick.

Is there som function in Moba that is easier to use?

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>
#include <MobaTools.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
//-----------------------------
#define CE_PIN 7
#define CSN_PIN 8
const byte buttonPins[] = {2};

//-----------------------------

const byte slaveAddress[5] = {'R','x','A','A','A'}; // Radio Adress
RF24 radio(CE_PIN, CSN_PIN); // Create a Radio
float dataToSend = 123.456;

unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 100; // send once per second

//----------------------------
byte function = 1;                            // function
int buttonState = 0;
//----------------------------



// Set the delay between fresh samples */
#define BNO055_SAMPLERATE_DELAY_MS (100)

// Check I2C device address and correct line below (by default address is 0x29 or 0x28)
//                                   id, address
Adafruit_BNO055 bno = Adafruit_BNO055(55, 0x28);
//------------------------------------------------

// create MobaTools objects
MoToButtons myButtons( buttonPins, 1, 20, 3000 );   // manage buttons(s), longpress is 3 seconds
MoToTimebase printTimer;                            // Timer to print in regular intervals without blocking sketch
//------------------------------------------------
void setup()
{
  Serial.begin(9600);
  printTimer.setBasetime( 500 );           // print values every second

    radio.begin();
    radio.setPALevel(RF24_PA_LOW);
    //radio.setDataRate( RF24_250KBPS );
    radio.setRetries(3,5); // delay, count
    radio.openWritingPipe(slaveAddress);
  
!bno.begin();                          // Initialise the sensor  
bno.setExtCrystalUse(true);            // Initialise the sensor 
}


void loop()
{
//------------------------------------------------
  sensors_event_t event;                // Get a new sensor event 
  bno.getEvent(&event);                 // Get a new sensor event
  dataToSend = event.orientation.x, 0;  // Declare what to send
 
//------------------------------------------------

    currentMillis = millis();
    if (currentMillis - prevMillis >= txIntervalMillis) {
        send();
        prevMillis = millis();
    }
//------------------------------------------------
    
myButtons.processButtons();
// select function mode by button presses
    
    if ( myButtons.longPress(0) ) {         // Set referecepoint when looking forward and motor is manually positioned forward. (Function 4) 
            Serial.println( "Longpress" );            
            function = 4;
            buttonState = 3
            
    }

    switch ( myButtons.clicked(0) ) {
        case NOCLICK:
        if ( buttonState > 0 wait reset to 0 every 300ms ? // How do i reset this ir is there an MOBA function to use?  
         
            break;
        case DOUBLECLICK:     // Activate headtracking (Function 3) 
            Serial.println( "Doubleclick" );
            function = 3;
            buttonState = 2;
            break;
        case SINGLECLICK:     // Return to refrencepoint (Function 1)
            Serial.println( "Singleclick" );
            function = 1;
            buttonState = 1;
            break;
    }    
 

  if ( printTimer.tick() ) {
        // debug printing every second 
  Serial.print(" HeadTrackAngleRaw: ");     Serial.print(event.orientation.x, 0);
  Serial.print(" dataToSend ");     Serial.print(dataToSend); 
   Serial.print(" buttonState ");     Serial.println(buttonState);
   }
   }
    void send() {

    bool rslt;
    rslt = radio.write( &dataToSend, sizeof(dataToSend) );
        // Always use sizeof() as it gives the size as the number of bytes.
        // For example if dataToSend was an int sizeof() would correctly return 2

    }

Best Regards

I'm not quite shure what you want to do. But to reset your buttonState you could use the MoToTimer class. Every time you set your buttonState you also set the timer to 300ms. And if it expires, you set buttonState back to 0.

...
MoToButtons myButtons( buttonPins, 1, 20, 3000 );   // manage buttons(s), longpress is 3 seconds
MoToTimebase printTimer;                            // Timer to print in regular intervals without blocking sketch
MoToTimer rstButtonTimer;                           // Timer to reset buttonState
...
    myButtons.processButtons();

    if ( rstButtonTimer.expired() ) {
        // Timer expired, reset buttonState
        buttonState = 0;
    }
...
        buttonState = 3;
        rstButtonTimer.setTime(300);
...
        case NOCLICK:
            // leave this empty as it is
            //if ( buttonState > 0 wait reset to 0 every 300ms ? // How do i reset this ir is there an MOBA function to use?
            break;
...
            buttonState = 2;
            rstButtonTimer.setTime(300);
...
            buttonState = 1;
            rstButtonTimer.setTime(300);
...

Of course I could not test, but you can give it a try.

Hi !! Thank you for the help it worked out perfect :slight_smile:

Now i have some ( for me advanced ) questions.. I“m trying to figure out how to calculate and move the steppermotor with input from two different compass sensors. I would like some help with the calculations so i can implement that to my existing code.

Rotating sensor mount with an rotating sensor. 

I“m quite stuck in my programming and should need some help with calculation. 

I trying to figure out how to calculate (stepperAngle) when using 2 different functions. 

The first thing i have to do when powering on the system is rotating the stepper manual with an joystick to an desierd angle and pointing the remoteAngle sensor in the same desierd angle,
i then longpress Button to set stepper1.setZero and save an value from remoteAngle and mountAngle ( remotAngleZero, mountAngleZero ) to have some reference values to work with.  
 
Function 1: move stepper to the angle remoteAngle currently is. // The stepper motor should follow the remote compass sensor, so if i look att an specific angle the stepperAngle should rotate to this positon. 
Function 2:  Stepper should keep it“s postion if the sensormount rotates. //So if the mount rotates after function 2 is activated the stepper should adjust it“s positon to were it was when function 2 was activated.  
                                                                           // Stepper should rotate the offset from mountAngleZero and mountAngle if the mountAngle rotates.

I allso want the (stepperAngle) value be smart so the stepper will move the nearest way to Function 1 or Function 2 angle but be limited by the max -400 to 400 degrees movment from (stepper1Zero) 
 
Hardware:
I have an wireless remote with an compass sensor (remoteAngle)

I have an sensormount with an stepper motor that rotates an shaft. The compass (mountAngle) is mounted on the stepper motormount.  
 
 
 float remoteAngle = 0; // sensorvalue from remote compass 0 - 360.00 This sensor can be mounted on my head or arm. 
 float mountAngle = 0; // senorvalue from sensor mount 0 - 360.00  This sensor is mounted to stepper motor mount. (will not rotate whit stepper motor shaft)  
 int stepperAngle = 0; // stepper motor will rotate to this positon, -400 to 400 is the rotation limmit.
 float remotAngleZero  0; // Save Refrencepoint  
 float mountAngleZero  0; // Save Refrencepoint 
 stepper1.zero // stepper zero Refrencepoint.  
 stepper1.read //  stepper current positon -400 to 400 0 when pointing forward 
 button // button to activate function 1 or 2. 

void setup() {


}

void loop() {
  // put your main code here, to run repeatedly:

}

Best Regards

Hi !! Now i have changed the code and the change to function 2 worked almost perfect ! When function 2 is activated the stepper moves to:
stepper1.write(compassAngle1);

i want stepper1.write(compassAngle1) to write the compassAngle1 value every 200ms because the compassAngle1 value changes when the mount is rotated.
What is the best solution to that ?

  switch ( myButtons.clicked(0) ) {
        case NOCLICK:
            ; // do nothing
            break;
        case DOUBLECLICK:
            Serial.println( "Return RP" );
            stepper1.setSpeedSteps( 20000 );   // Speed when moving home
            stepper1.write(0);
            function = 3;
            break;
        case SINGLECLICK:
            Serial.println( "Set function 2 Spotlock" );
            stepper1.setSpeedSteps( 20000 );   // Speed when moving home
            mountAngleSpotlock = mountAngle; // Save spotlock activated angle
            stepper1.write(compassAngle1);
            function = 2;
           
            break;
    }

    



    if (joyTimer.tick() ) {
        // read joystick and set stepper speed accordingly
        joyLR = analogRead(joyLRPin);
        // if the joystic is not in the middle ===> its activ
        bool joyActive = !(joyLR > joyLimits[1] && joyLR < joyLimits[2]);

        switch ( function ) {
            case 1:  // mode 1 - joystick control
                if ( !joyActive ) // 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 "compassAngle1",
              //  // switch back to joystick control if position reached or joystick is active
               // if ( !stepper1.moving()  || joyActive ) function = 1;
                if ( joyActive || holdTimer.expired() ) function = 1;
                if ( !stepper1.moving()  && !holdTimer.running() ) {
                   holdTimer.setTime( 6000 );           
                  }
                 break;
           
            
            
            case 3: // return to reference point,
                // switch back to joystick control if reached or joystick is active
                if ( !stepper1.moving() || joyActive ) function = 1;
                break;
        }
    }

Best Regards
Andreas

Hi Andreas,
This

comes across with the hold time for function 2 after the stepper has reached the compass position:

If the stepper is always moving, the timer will never be started.

To update the position every 200ms you could use an additional BaseTimer or you use a bool variable. Because of your joystick timer the switch case block is called only every 100ms. If you call stepper1.write(compassAngle1) every second pass ( by toggling your bool ), you will update it every 200ms.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.