Want to control stepper motor angle via serial

this code work normal but i want to change angle via serial not make it constant angle



int PUL             =4;                                       //define Pulse pin
int DIR             =3;                                       //define Direction pin
int ENA             =2;                                       //define Enable Pin

int steps_pr        = 6400;                                   //steps per revolution      ( changable ) --<<<<<<<<<<<<<<<<<<<<< set based on stepper DIP config
int long target_    = 90;                                     // move by degree           ( changable ) --<<<<<<<<<<<<<<<<<<<<< test 2 function 
int rotation_amt    = 0;                                      // rotation number          ( changable ) --<<<<<<<<<<<<<<<<<<<<< 
//-----------------------------------------------(   test 1 functions only) rotation counter only   )----------------------------

bool  test_done       = false;                                // test code finishes exicution 
int   step_           = 0;                                    // current step
int   rot_            = 0;                                    // current rotation
// ----------------------------------------------(    degree specification    )--------------------------------------------------


float step_per_degree       = 6400/360.0;                     // the number of steps in a degree 
int long  cur_step          = 0;                              // the current step (holder) must be intiger
float calculated_step       = step_per_degree * target_;      // (180*17.7777~8 ) = 3,200.00~ 
int long  rounded_step      = abs(round(calculated_step));    // calc rounded 
bool  test2_done            = false;                          // test code finishes exicution 





void setup() {
  pinMode (PUL, OUTPUT);  // set out pins 
  pinMode (DIR, OUTPUT);
  pinMode (ENA, OUTPUT);
  digitalWrite(ENA,LOW);  // dissable on start 
  Serial.begin(9600);     // serial open 
}

// example portion!
void test() {
      if (step_ < steps_pr) {
        step_++;
        digitalWrite(DIR,LOW);
        digitalWrite(ENA,HIGH);
        digitalWrite(PUL,HIGH);
        delayMicroseconds(50);            // no less than 50 ( under torque issue.. nema 23 works )
        digitalWrite(PUL,LOW);
        delayMicroseconds(50);
      }
      if (step_ >= steps_pr){
        rot_++;
        step_ = 0;
        Serial.println("rotation #: ");   // serial read out 
        Serial.println(rot_);
      }
      if (rot_ >= rotation_amt ) {
       test_done = true;
      }
}

// example portion! -- specific degree 
void test2() {
  // handle - number case ( not the best way, but its a test )
  if (target_ < 0 ) {
  digitalWrite(DIR,HIGH);
  }
  if (target_ > 0 ) {
  digitalWrite(DIR,LOW);
  }
  if ( cur_step < rounded_step ) {
        cur_step++; 
       // digitalWrite(DIR,LOW);
        digitalWrite(ENA,HIGH);
        digitalWrite(PUL,HIGH);
        delayMicroseconds(50);            // no less than 50 ( under torque issue.. nema 23 works )
        digitalWrite(PUL,LOW);
        delayMicroseconds(50);
  }
   if (cur_step >= rounded_step){
      test2_done = true;
   }
}


// stop processes after completion!
void loop() {
  if (test_done != true){
    test();
  }
  if (test2_done != true && test_done == true ){
    test2();               
  }
  if  (test2_done == true && test_done == true ){
    digitalWrite(ENA,LOW);                // disable after finish ( stops holding torque )
  }
}

Try something like Txtzyme:

...and maybe add a command that translates angle into steps.

i use arduino uno

^^^ This fits on an Uno.

did a small serial command parser..

Serial Command Parser..

could allow for ex. ANGLE=2..

maybe it helps..
~q

Wrap your step in a function:

int doStep(int8_t direction){
        if(direction > 0){
           digitalWrite(DIR,LOW);
           ++cur_step;
        } else {
           digitalWrite(DIR,HIGH);
           --cur_step;
        }
        digitalWrite(ENA,HIGH);
        digitalWrite(PUL,HIGH);
        delayMicroseconds(50);            // no less than 50 ( under torque issue.. nema 23 works )
        digitalWrite(PUL,LOW);
        delayMicroseconds(50);
}

and then use it with the serial data parsed by Txtzyme:

      case 'A': // step to Angle `x`
        {
          int32_t stepsToGo = x * step_per_degree - cur_step;
          int8_t inc = stepsToGo > 0 ? 1 : -1;
          while (stepsToGo) {
            stepsToGo-=inc;
            doStep(inc);
          }
        }
        break;
      case 'b': // step backward by Angle 'x'
      case 'f': // step forward by Angle 'x'
        {
          int32_t stepsToGo = x * step_per_degree;
          while (stepsToGo) {
            --stepsToGo;
            doStep(ch == 'f' ? 1 : -1);
          }
        }
        break;
        case 'D': // set Delay micros between steps
           stepDelay = x;
           break;


Here's an example:

Try feeding this Txtzyme-stepper setup something complex like:

180A 5{45b 1000m 500D 90f 1000m 5000D _boop_}

A demo-code where you type in <500>
the 500 is the value that will be received in the arduino the "<" and ">" were stripped off
and then the character-sequence "5" "0" "0" is converted into an integer-value

The demo-code uses this value to set the stepper-speed
at this place you have to modify the code to set the angle.

The code uses the mobatools-library which offers direct angle-setting
read the documentation of the mobatools
about the command

myStepper.write(angle)
// a comlex functionality doing multiple things "in parallel"
// requires quite a lot of lines of code
// at the end of this file the structure of the code is epxlained

#define ProjectName "MobaTools serial receive Speed Start Stop Bounce "

// define IO-states for inputs with pull-up-resistors
// pull-up-resistors invert the logig
#define unPressed HIGH
//#define pressed   LOW

const byte ToggleButtonPin = 4;
const byte dirPin          = 5;
const byte stepPin         = 6;
// ( 1600 steps / revolution = 1/8 Microstep )
const int STEPS_REVOLUTION = 1600;

const long baudrate = 115200;

#include <MobaTools.h> // stepper-motor-library

MoToStepper myStepper( STEPS_REVOLUTION, STEPDIR );

const long  targetPos = 8000; // stepper moves between 0 and targetpos
long nextPos;

//Array for storing serial received data
const unsigned int numChars = 128;
char receivedChars[numChars];
boolean newData = false;

unsigned int StepperSpeed = 1000;

bool activationMode = false;


void setup() {
  Serial.begin(baudrate); // adjust baudrate in the serial monitor to match the number
  Serial.println( F("Setup-Start") );
  printFileNameDateTime();

  pinMode (LED_BUILTIN, OUTPUT);  // used for indicating logging active or not
  digitalWrite(LED_BUILTIN, LOW);
  // wire button between IO-pin and GND
  // Pull-up-resistor inverts the logic
  // unpressed: IO-pin detects HIGH
  // pressed:   IO-Pin detects LOW
  pinMode(ToggleButtonPin, INPUT_PULLUP);
  SetUpStepperMotor();
  Serial.print( F("start / stop button must be conected to IO-PIN no ") );
  Serial.println(ToggleButtonPin);
  Serial.println( F("send speed-commands through serial monitor with <speed>") );
  Serial.println( F("example <500>") );
  
  Serial.println( F("press button to start / stop steppermotor") );
}


void loop () {

  recvWithStartEndMarkers(); // non-blocking checking if serial data is received
  // receive with Start- / Endmarker means the data must have
  // a leading "<" and a trailing ">" for switching newData to true
  if (newData) { // if a valid command is received
    newData = false;
    SetStepperMotorSpeed();
  }

  activationMode = GetToggleSwitchState(); // must be executed all the time
  execute_if_Active(activationMode);       // function that does what its name says
}


void SetUpStepperMotor() {
  myStepper.attach( stepPin, dirPin );
  //myStepper.attachEnable( enaPin, 10, LOW );        // Enable Pin aktivieren ( LOW=aktiv )

  // the maximum steprate pulses per second is limited
  // due to the kind of how the step-pulses are created with a timer-interrupt
  // Arduino Uno, Mega Nano 2500 steps / second
  // ESP8266 6250 steps / second
  // STM32F103 20000 steps / second
  // ESP32 30000 steps / second
  Serial.print("myStepper.setSpeed( ");
  Serial.print(StepperSpeed);
  Serial.println(" );");
  myStepper.setSpeed( StepperSpeed );
  myStepper.setRampLen( 100 );                       // Rampenlänge 100 Steps bei 20U/min
  Serial.print( F("step-pin is IO-pin no ") );
  Serial.println(stepPin);

  Serial.print( F("dir-pin is IO-pin no ") );
  Serial.println(dirPin);
}


bool GetToggleSwitchState() {
  // "static" makes variables persistant over function calls
  static bool toggleState     = false;

  static byte buttonStateOld = unPressed;
  unsigned long buttonDebounceTime = 100;
  unsigned long buttonDebounceTimer = 0;

  byte buttonStateNew;

  if ( TimePeriodIsOver(buttonDebounceTimer, buttonDebounceTime) ) {
    // if more time than buttonDebounceTime has passed by
    // this means let pass by some time until
    // bouncing of the button is over
    buttonStateNew = digitalRead(ToggleButtonPin);

    if (buttonStateNew != buttonStateOld) {
      // if button-state has changed
      buttonStateOld = buttonStateNew;
      if (buttonStateNew == unPressed) {
        // if button is released
        toggleState = !toggleState; // toggle state-variable
      } // the attention-mark is the NOT operator
    }   // which simply inverts the boolean state
  }     // !true  = false   NOT true  is false
  //       !false = true    NOT false is true
  return toggleState;
}


void SetStepperMotorSpeed() {

  Serial.print( F("I received #") );
  Serial.print(receivedChars);
  Serial.println( F("#") );

  StepperSpeed = atoi (receivedChars);
  Serial.print("myStepper.setSpeed( ");
  Serial.print(StepperSpeed);
  Serial.println(" );");

  if (StepperSpeed > 0) {
    myStepper.setSpeed( StepperSpeed );
    Serial.print( F("set speed to ") );
    Serial.print(StepperSpeed);
    Serial.println();
  }
  else {
    Serial.println( F("no valid speed-data") );
  }
}


void RunStepperMotor() {
  // if steppermotor has reached target-position and
  // does NOT move anymore
  if ( !myStepper.moving() ) {
    Serial.print( F("arrived at position ") );
    Serial.println(myStepper.currentPosition() );
    Serial.println();
    
    if ( nextPos == 0 ) {   // if is at startposition 0
      nextPos = targetPos; // drive to position max
    }
    else { // if is at endposition
      nextPos = 0; // drive to position zero
    }
    Serial.print( F("moving to position ") );
    Serial.println(nextPos);
    myStepper.moveTo( nextPos ); // start creating step-pulses
  }
}


void execute_if_Active(bool p_IsActivated) {

  if (p_IsActivated) {
    RunStepperMotor();
  }
  else { // DE-activated
    myStepper.stop();
  }

  PrintToSerialMonitor(p_IsActivated); // deactivate through commenting if not wanted
}


// helper-function ignore at first
void printFileNameDateTime() {
  Serial.print( F("File   : ") );
  Serial.println( F(__FILE__) );
  Serial.print( F("Date   : ") );
  Serial.println( F(__DATE__) );
  Serial.print( F("Project: ") );
  Serial.println( F(ProjectName) );
}

// ignore at first
// helper-function for easy to use non-blocking timing
boolean TimePeriodIsOver (unsigned long & expireTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - expireTime >= TimePeriod ) {
    expireTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  }
  else return false;            // not expired
}

// helper-function
void PrintToSerialMonitor(boolean p_IsActivated) {
  static bool lastIsActivated;

  // only in case the activation-mode has CHANGED print ONE time
  if (p_IsActivated != lastIsActivated) {
    // only if state of parameter p_logIsActivated has changed
    if (p_IsActivated) {
      Serial.println();
      Serial.println( F("start executing") );
      Serial.println();
      digitalWrite(LED_BUILTIN, HIGH);
    }
    else { // not activated
      Serial.println();
      Serial.println( F("stopp executing") );
      Serial.println();
      digitalWrite(LED_BUILTIN, LOW);
    }

    lastIsActivated = p_IsActivated; // update variable lastSDlogActive
  }
}


void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static unsigned int ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  // If data is in the receive-buffer .available() > 0
  // .available() returns how MANY bytes are in the receive-buffer
  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();

    if (recvInProgress == true) { // if startmarker is found set flag to true
      if (rc != endMarker) {      // if the received byte is NOT the endmarker
        receivedChars[ndx] = rc;  // append the received byte at the end of char-array
        ndx++;                    // increase array-index by 1
        if (ndx >= numChars) {    // if message is longer than max number of chars the arraybuffer can hold
          ndx = numChars - 1;     // reduce array-index => byte is trhown away
        }
      } // if (rc != endMarker) {
      else { // it IS the endmarker
        receivedChars[ndx] = '\0'; // terminate the string through adding a zero
        recvInProgress = false;    // receiving of command is finished
        ndx = 0;
        newData = true;            // command is ready to be used
      }
    } // if (recvInProgress == true) {

    else if (rc == startMarker) {  // if the byte is the startmarker
      recvInProgress = true;       // set boolean flag receive in progress to true
    }
  } // while (Serial.available() > 0 && newData == false) {
}

/* OVERVIEW: ###################################################
  this demo-code does quite a lot of things

  the code has a hierachical structure
  the code is organised in SUB-units where each SUB-unit is
  doing a senseful unit of things like

  - receive serial data
  - Set StepperMotorSpeed
  - check if start/stop-button is pressed
  - depending on beeing in state "active" or "inactive"
    drive stepper-motor or not
  - create step-pulses to make the stepper-motor drive back and forth

  - helper-functios for
    - print source-code-filename to serial monitor
    - measure how much time has passed by since a referencetime
      (non-blocking timing)
    - print info to serial monitor to make visible what the code is doing


  in more Detail: ################################################

  toggle-switch:
  there is the function GetToggleSwitchState()
  GetToggleSwitchState() returns a "true"  or a "false"
  this transforms a momentary pushbutton into a toggle-switch
  press push-button => toggle-switch is in ON-position
  press push-button => toggle-switch is in OFF-position
  push-ON, Push-OFF, Push-ON, Push-OFF etc. etc.

  In function loop the state of GetToggleSwitchState()
  is checked ALL the time. Depending on variable activationMode
  beeing true or false the
  function execute_if_Active() is creating step-pulses
  or just pausing -----------------------------------------------


  receive serial data:
  The function recvWithStartEndMarkers()
  is checking for newly arrived serial data
  it is doing this in a receive byte for byte
  and NON-blocking manner.
  NON-blocking is important that the code stays responsive to
  button-presses ALL the time
  If the code receives bytes that do not follow the pattern
  leading startmarker "<"  trailing endmarker ">" the received bytes
  are just thrown away -------------------------------------------


  set steppermotor speed:
  If a complete command like "<500>" is received the variable newData
  is set true and then the function SetStepperMotorSpeed()
  processes the command.
  In case the command is invalid the steppermotor-speed stays the same
  in case the command is valid the stepper-motor-speed is changed
  -----------------------------------------------------------------

  some helper-functions:

*/

best regards Stefan

1 Like

consider

// 

const unsigned StepPerRev = 6400;
int posAng0 = 100;      // for example
int pos;

char buf [80];
char s   [80];

// -----------------------------------------------------------------------------
void
step (
    int nStep )
{
    sprintf (s, "%s: %d", __func__, nStep);
    Serial.println (s);

}

// -------------------------------------
void
moveToAng (
    float  angTarg )
{
    Serial.print   ("moveToAng: ");
    Serial.println (angTarg, 2);

    moveToPos (angTarg * StepPerRev / 360 + posAng0);
}

// -------------------------------------
void
moveToPos (
    int  posTarg )
{
    sprintf (s, "%s: %d", __func__, posTarg);
    Serial.println (s);

    step (posTarg - pos);
    pos = posTarg;
}

// -----------------------------------------------------------------------------
void loop()
{
    if (Serial.available ())  {
        int n = Serial.readBytesUntil ('\n', buf, sizeof(buf)-1);
        buf [n] = '\0';
        Serial.println (buf);

        char c;
        char t [10];
        sscanf (buf, "%c %s", &c, t);

        if ('a' == c)
            moveToAng (atof(t));
        else if ('p' == c)
            moveToPos (atof(t));
    }
}

// -------------------------------------
void setup ()
{
    Serial.begin (9600);
}
1 Like

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