Go Down

Topic: Steppers control problem on Adfruit MotorShield v.2 +Ethernet (Read 2127 times) previous topic - next topic

danyhaardcore

Good day
While doing my project I came across the problem i can't resolve myself. I've been trying multiple ways..and no success.

I'm trying to control 2 steppers Nema 17 (bipolar, 12V) with an Arduino Mega 2560+Adafruit Motorshield v.2 + Ethernet shield.

Web server (node) has 3 software buttons: All_Fwd, All_Stop and All_Bwd. I have managed to do forward and stop (by stepper.setMaxSpeed(1.0) which lowers down the speed, byt never stops rotation).
Simultaneous operation of both steppers required.
I will post some code, may be you can help me with it, please

Code: [Select]

#include <SPI.h>
#include <Ethernet.h>
#include <AccelStepper.h>
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"

Adafruit_MotorShield AFMSmove(0x60); // Default address, no jumpers

Adafruit_StepperMotor *myStepper1 = AFMSmove.getStepper(200, 1);
Adafruit_StepperMotor *myStepper2 = AFMSmove.getStepper(200, 2);

void forwardstep1() { 
 myStepper1->onestep(BACKWARD, DOUBLE);
}
 void forwardstep2() { 
  myStepper2->onestep(FORWARD, DOUBLE);
}
AccelStepper stepper1(forwardstep1, forwardstep1);

/* Some bla-bla-bla*/

void setup()
{
  AFMSmove.begin(); // Start the move shield
  Serial.begin(9600);
  Serial.println("ProtocolRunner: Hello! Serial interface started");
  setupTcpServer();
  setupShutdownTimeoutWatchdog();
 }
void loop() {
  loopShutdownTimeoutWatchdog();
  loopStatus();
  loopTcpServer();
  loopCommands();
  setupMotors(); 
 
}

void setupMotors() {
 
    stepper1.setMaxSpeed(1.0);
    stepper1.setAcceleration(50.0);
    stepper1.moveTo(2000);
    stepper2.setMaxSpeed(1.0);
    stepper2.setAcceleration(50.0);
    stepper2.moveTo(2000);
       stepper1.run();
       stepper2.run();

}
void shutdownAllMotors() {
   
  stepper1.setMaxSpeed(1.0);
  stepper2.setMaxSpeed(1.0);

}
void fullSpeedAllMotors() {
 
     stepper1.setMaxSpeed(200.0);
    stepper1.setAcceleration(50.0);
    stepper1.moveTo(500.0);
    stepper2.setMaxSpeed(200.0);
    stepper2.setAcceleration(50.0);
    stepper2.moveTo(500.0);
   
  }

/* web part bla bla bla*/

 } else if (strcmp(cmd, "full speed") == 0) {
      fullSpeedAllMotors();
      Serial.println("Setting all motors to full speed.");

    } else if (strcmp(cmd, "all stop") == 0) {
      shutdownAllMotors();
      Serial.println("Stopping all motors");
 /*bla bla bla*/



Code is partly taken from https://github.com/akey7/remote-control-motors with an intention to rewrite it for steppers.

I assume the problem is that stepper.run() is outside of void loop{}.
However, putting it inside loops the motor. And i can't control pins as in example, I assume

Can someone be so kind to help?

Thank you

Robin2

I assume the problem is that stepper.run() is outside of void loop{}.
Yes, that is the problem

Quote
However, putting it inside loops the motor. And i can't control pins as in example, I assume
You have not posted the code with stepper.run() in the correct place so I cannot comment.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

danyhaardcore

You have not posted the code with stepper.run() in the correct place so I cannot comment.

And which place is correct. If stepper.run() included in void loop{}, both steppers run continiously and non-stop. If I exclude them, I can't run thm backwards and completely stop as well.
Can you clarify, where is my mistake?

Thanks

Robin2

Can you clarify, where is my mistake?
Not without seeing your code.

stepper.run() does nothing when the motor has reached its destination.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

danyhaardcore

Not without seeing your code.
Please find a code below. As advised previously, by this code i can move forvard and "stop" (not realy stop but set sped to 1" both motors. I was trying to replace shutdownAllMotors() with something which makes motors go backward..and no reaction.

Code: [Select]


#include <SPI.h>
#include <Ethernet.h>
#include <AccelStepper.h>
#include <MultiStepper.h>
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
Adafruit_MotorShield AFMSmove(0x60); // Default address, no jumpers
Adafruit_StepperMotor *myStepper1 = AFMSmove.getStepper(200, 1);
Adafruit_StepperMotor *myStepper2 = AFMSmove.getStepper(200, 2);

   void forwardstep1() { 
 myStepper1->onestep(BACKWARD, DOUBLE);
}
 void forwardstep2() { 
  myStepper2->onestep(FORWARD, DOUBLE);
}

AccelStepper stepper1(forwardstep1, forwardstep1);
AccelStepper stepper2(forwardstep2, forwardstep2);

// Number of pins that motors are conneted to (length of the array below)
// The #define lets me staticially allocate the array below for the
// structures.
const int kNumberOfMotors = 4;

// Minimum and maximum duty cycles for the motors. I determined these
// by experimentation, and they may need to be tweaked for other motors.
const int kMinPwmDutyCycle = 75;
const int kMaxPwmDutyCycle = 224;


// These are for values entered over the TCP interface. They are mapped
// to the PwmDutyCycle values above by convertSpeedToPwmDutyCycle().
const int kMinSpeed = 0;
const int kMaxSpeed = 100.0;

// Number of milliseconds to operate motors without a command
// on the TCP server. If no commands are reeived after this timeout,
// all motors will shut down.
const unsigned long kShutdownTimeoutMillis = 60000;
unsigned long timestampOfLastCommand;

/*** END motor operation variables ***/


/*** BEGIN network customization ***/

const int serverPort = 17;
EthernetServer server(serverPort);
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0xD7, 0xD2 };
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress ip(192, 168, 0, 33);

/*** END network customization ***/


/*** BEGIN Buffer declaration ***/

// These are buffer declarations to hold strings for TCP/IP input and output
//
// statusBuffer holds status messages to be written to TCP/IP
//
// tcpReadBuffer holds data as it is received bt TCP/IP
//
// tcpShouldDisconnect is true if the TCP/IP interface should disconnect. Not
// a buffer, but does deal with its management
//
// All the text handling is through C strings.

#define BUFFER_SIZE 256

char statusBuffer[BUFFER_SIZE];
char tcpReadBuffer[BUFFER_SIZE];
bool tcpShouldDisconnect;

/*** END Buffer declaration ***/


/*** BEGIN Main setup and loop functions ***/

// setup() calls all the subsystem setup functions.

void setup()
{
  AFMSmove.begin(); // Start the move shield
  Serial.begin(9600);
  Serial.println("ProtocolRunner: Hello! Serial interface started");
  setupTcpServer();
  setupShutdownTimeoutWatchdog();

 }
void loop() {
  loopShutdownTimeoutWatchdog();
  loopStatus();
  loopTcpServer();
  loopCommands();
  setupMotors();
     
   
}
void setupMotors() {
 
       stepper1.moveTo(200);
        stepper2.moveTo(200);
       stepper1.run();
       stepper2.run();

}
void shutdownAllMotors() {
  //for(int i=0; i<kNumberOfMotors; i++) {
    //motor[i].dutyCycle = 0;
     stepper1.setMaxSpeed(1.0);
     stepper2.setMaxSpeed(1.0);
   
}
void fullSpeedAllMotors() {

    stepper1.setMaxSpeed(200.0);
    stepper1.setAcceleration(50.0);
    stepper1.moveTo(500.0);
    stepper2.setMaxSpeed(200.0);
    stepper2.setAcceleration(50.0);
    stepper2.moveTo(500.0);
   
  }

/*** BEGIN TCP Server handling functions ***/

// Network settings
// BE SURE TO CHANGE THESE TO MATCH YOUR INTERFACE AND IP ADDRESS
// AND PORT OF YOUR ETHERNET MODULE!
//
// Also, the SD Card reader is EXPLICITLY DISABLED by setting pin
// 4 to high

void setupTcpServer() {
  //pinMode(4, OUTPUT);
  //digitalWrite(4, HIGH);
  Ethernet.begin(mac, ip, gateway, subnet);
  server.begin();
  Serial.print("ProtocolRunner: Server operational at ");
  Serial.print(Ethernet.localIP());
  Serial.print(" port ");
  Serial.println(serverPort);
  tcpShouldDisconnect = false;
}

// Services the TCP/IP interface and copies bytes received into
// tcpReceivedBuffer. This buffer is then read during the command parsing
// to extract commands to operate the motors.

void loopTcpServer() {
  unsigned tcpReadBufferCursor = 0;
  EthernetClient client = server.available();

  for (int i=0; i<BUFFER_SIZE; i++) {
    tcpReadBuffer[i] = '\0';
  }

  if (client) {

    while (client.connected()) {

      if (tcpShouldDisconnect) {
        client.stop();
        tcpShouldDisconnect = false;
      }

      if(client.available()) {
        char symbol = client.read();

        if (symbol == '\r') {
          //Serial.print("TCP: ");
          //Serial.println("Ignoring \\r");

        } else if (symbol == '\n') {
          //Serial.print("TCP command: ");
          //Serial.println(tcpReadBuffer);
          //client.println("whatever");
          client.println(statusBuffer);
          break;

        } else {
          if (tcpReadBufferCursor < BUFFER_SIZE) {
            tcpReadBuffer[tcpReadBufferCursor] = symbol;
            tcpReadBufferCursor++;

          } else {
            Serial.println("TCP: Buffer overflow caught!");
          }
        }
      }
    }
  }
}
/*** END TCP Server handling functions ***/


/*** BEGIN Status looping function ***/

// Creates the strings for status reports to report back to client.
void loopStatus() {
  snprintf(statusBuffer, BUFFER_SIZE, "READY,motorCount=%d,kShutdownTimeoutMillis=%u", kNumberOfMotors, kShutdownTimeoutMillis);
}

/*** END Status looping function ***/


/*** BEGIN command handling functions ***/
/*void setupCommands() {
}*/

// Pasrses and executes commands received over TCP/IP
void loopCommands() {
  if (strlen(tcpReadBuffer) > 0) {
    Serial.print("Command ");
    Serial.print(strlen(tcpReadBuffer));
    Serial.print(": ");
    Serial.println(tcpReadBuffer);

    char *cmd;
    cmd = strtok(tcpReadBuffer, ",");

    // Update the timestamp of the command.
    //
    // TODO: Actually, should probably be
    // refactored into the individual successful command executions
    // for maximum security
    resetShutdownTimeoutWatchdog();

    // This is somewhat buggy, because a disconnect doesn't seem to happen
    // without an extra carriage return.
    if (strcmp(cmd, "QUIT") == 0) {
      Serial.println("Disconnect requested");
      tcpShouldDisconnect = true;

    } else if (strcmp(cmd, "status") == 0) {
      Serial.println("Dummy status command");

    } else if (strcmp(cmd, "motor") == 0) {
      char *szMotorNumber = strtok(NULL, ",");
      char *szMotorSpeed = strtok(NULL, ",");
      int motorNumber = atoi(szMotorNumber);
      int motorSpeed = atoi(szMotorSpeed);

      if (!(motorNumber >= 0 && motorNumber < kNumberOfMotors)) {
        motorNumber = 0;
        Serial.println("Bad motor number requested");
      }

//      motor[motorNumber].dutyCycle = convertSpeedToPwmDutyCycle(motorSpeed);

      /*Serial.print("Motor ");
      Serial.print(motorNumber);
      Serial.print(" duty_cycle ");
      Serial.print(duty_cycle);
      Serial.println(" requested");*/

    } else if (strcmp(cmd, "full speed") == 0) {
      fullSpeedAllMotors();
      Serial.println("Setting all motors to full speed.");

    } else if (strcmp(cmd, "all stop") == 0) {
     shutdownAllMotors();
      Serial.println("Stopping all motors");

    } else {
      Serial.println("User gave an unrecognized command.");
    }
  }
}
/*** END command handling functions ***/

/*** BEGIN watchdog  and shutdown function  ***/

//  kShutdownTimeoutMillis and timestampOfLastCommand establish a timeout
//  for motor operations in case connections break and we don't want the
//  motors to run forever (or at least until the batteries run out)

void loopShutdownTimeoutWatchdog() {
  if (millis() - timestampOfLastCommand > kShutdownTimeoutMillis) {
    Serial.println("Shutting down because of watchdog");
    shutdownAllMotors();
    resetShutdownTimeoutWatchdog();
  }
}

void setupShutdownTimeoutWatchdog() {
  resetShutdownTimeoutWatchdog();
}

void resetShutdownTimeoutWatchdog() {
  timestampOfLastCommand = millis();
  Serial.println("Shutdown timeout watchdog reset");
}

/*** BEGIN watchdog  and shutdown function  ***/

Robin2

I don't understand what your overall program is trying to do. My suspicion is that you have it unnecessarily complex/

More specifically I cant make sense of this
Code: [Select]
void loop() {
//  SNIP
setupMotors();
}

void setupMotors() {
 
stepper1.moveTo(200);
stepper2.moveTo(200);
stepper1.run();
stepper2.run();
}

Every time stepper.run() is called it can move at most 1 step. Much of the time it won't move at all. So why are you setting the destination to 200 each time. moveTo() takes an absolute position and you only need to set it once. This code should mean that the motor will run to position 200 and then stay there.

To stop the motor movin you have a choice of strategies. You can either stop calling stepper.run() or you can set the destination to the current position so the library thinks the motor does not need to make any further moves.

I can't understand why you have the functions called loopShutdownTimeoutWatchdog() and similar. Can you explain in English what you are trying to achieve - in other words, describe how the program would appear to someone else if it was working properly.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

MarkT

There are two modes of use of AccelStepper - you can either select specific speed to run
continuously (setSpeed/runSpeed), or you can set a given number of steps to move
(move, moveTo and run).  If you just want to start and stop the motor, use the former - ie
have runSpeed() in loop(), not run().
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

danyhaardcore

I can't understand why you have the functions called loopShutdownTimeoutWatchdog() and similar. Can you explain in English what you are trying to achieve - in other words, describe how the program would appear to someone else if it was working properly.

As it has been stated in first post, the code is not mine, taken as an example from link, provided previously. I thought it would be easier :)
Initial idea was quite simple: connect Mega to Motor shield v.2 and Ethernet shield, and controlling two stepper motors via LAN.
- if button FWD pressed, both motors should rotate forward simultaneously.
- if button Stop pressed, both motors should be stopped.
- if button Back pressed, both motors should rotate backward simultaneously.

Can you advise how to do this (motor control part only)?
Thank you

Robin2

As it has been stated in first post, the code is not mine, taken as an example from link, provided previously. I thought it would be easier :)
I suspect it would make more sense just to write your own code from scratch. There are plenty of examples on the AccelStepper website.

Write a short program that makes the motors run forwards for (say) 1000 steps and then backwards for 1000 steps.

Write another short program that sets a variable to 'F' 'S' or 'B' depending on which button is pressed.

Then you just need to join the two bits together.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

danyhaardcore

Then you just need to join the two bits together.
Thank you. I've managed to make them work , however the speed can't be set more then 200. Why?

Code: [Select]

#include <SPI.h>
#include <Ethernet.h>
#include <AccelStepper.h>
#include <MultiStepper.h>
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"

Adafruit_MotorShield AFMSmove(0x60); // Default address, no jumpers
Adafruit_StepperMotor *myStepper1 = AFMSmove.getStepper(200, 1);
Adafruit_StepperMotor *myStepper2 = AFMSmove.getStepper(200, 2);

 void forwardstep1() { 
 myStepper1->step(BACKWARD, DOUBLE);
}
 void forwardstep2() { 
 myStepper2->step(FORWARD, DOUBLE);
}

 void backwardstep1() { 
 myStepper1->onestep(FORWARD, DOUBLE);
}
 void backwardstep2() { 
 myStepper2->onestep(BACKWARD, DOUBLE);
}


AccelStepper fwd1(forwardstep1,forwardstep1);
AccelStepper fwd2(forwardstep2,forwardstep2);
AccelStepper bwd1(backwardstep1,backwardstep1);
AccelStepper bwd2(backwardstep2,backwardstep2);

int dir = 0;
int speed = 1;

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 155, 69, 132, 38 }; // ip in lan
byte gateway[] = { 155, 69, 132, 254 }; // internet access via router
byte subnet[] = { 255, 255, 248, 0 }; //subnet mask
EthernetServer server(80); //server port

String readString;

void setup(){
  AFMSmove.begin();
  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  server.begin();
  Serial.begin(9600);
}
void loop(){
  // Create a client connection
  EthernetClient client = server.available();

if (dir == 1){
fwd1.setSpeed(speed);
fwd2.setSpeed(speed);
fwd1.runSpeed();
fwd2.runSpeed();
Serial.println("dir=1");}
else {
bwd1.setSpeed(speed);
bwd2.setSpeed(speed);
bwd1.runSpeed();
bwd2.runSpeed();
Serial.println("dir=2");}


 
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        //read char by char HTTP request
        if (readString.length() < 100) {

          //store characters to string
          readString += c;
          //Serial.print(c);
        }

        //if HTTP request has ended
        if (c == '\n') {

     
          Serial.println(readString); //print to serial monitor for debuging

          client.println("<HTML>");
          client.println("<HEAD>");
          client.println("<TITLE>Arduino GET test page</TITLE>");
          client.println("</HEAD>");
          client.println("<BODY>");

          client.println("<H1>simultaneous control</H1>");
         
          client.println("<a href=\"/?fwd\">FWD</a>");
          client.println("<a href=\"/?stop\">STOP</a>");
          client.println("<a href=\"/?bwd\">BWD</a>");

          client.println("</BODY>");
          client.println("</HTML>");

 //stopping client
          client.stop();
          delay(1);
         

     
         
          if(readString.indexOf("fwd") >0)//checks for on
          {
              Serial.println("FWD");
             speed = 200;
             dir = 1;
   
          }
          if(readString.indexOf("stop") >0)//checks for off
          {
              Serial.println("STOP");
              speed = 1;
          }
          if(readString.indexOf("bwd") >0)//checks for on
          {
            speed = 200;
             dir = 2;
             Serial.println("BWD");
          }
          //clearing string for next read
          readString="";
         

        }
      }
    }
  }
}



Robin2

Thank you. I've managed to make them work , however the speed can't be set more then 200. Why?
Do you mean that a value higher than 200 won't make the motor run faster, or do you mean that you can't put a higher number in the speed variable?

What units is speed in? Is it steps per second?

If the problem is that it won't respond to values higher than 200 I think the problem is most likely due to loop() not repeating fast enough. I suspect you don't need all that CLIENT code in each iteration of loop(). Once per second or once every 5 seconds might be enough.

What motor power supply are you using (volts and amps)?
Post a link to the datasheet for your stepper motor.

It looks like you have two instances of AccelStepper for each motor - one for forwards and one for backwards? Why?  You can make a motor go in either direction with one instance.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

danyhaardcore

Of course, I can enter a number higher than 200, but it won't result in speed icrease. However, Adafruir FAQ explains that in https://learn.adafruit.com/adafruit-motor-shield-v2-for-arduino/faq#faq-21

Units are steps per second. I'll try solution from FAQ above tmrw. Motor description: http://www.ebay.com/itm/2-phase-42mm-Stepper-Motor-NEMA17-1-8degree-12V-0-3A-4-wire-2-2kg-cm-34-L-mm-/171466518630?hash=item27ec337066

It looks like you have two instances of AccelStepper for each motor - one for forwards and one for backwards? Why?  You can make a motor go in either direction with one instance.

I did't manage to. Minus (-) won't work. What do you propose?

Robin2

Of course, I can enter a number higher than 200, but it won't result in speed icrease. However, Adafruir FAQ explains that in
That reads as if you are satisfied (based on the Adafruit FAQ) that 200 is the max. (I don't know anythiing about it). Other stepper motor drivers would certainly allow much higher step rates.

Have you considered what I said about how long it takes for your loop() to repeat?


Quote
I did't manage to. Minus (-) won't work. What do you propose?
Study the documentation

By the way that h-bridge motor shield is a poor choice for controlling a stepper motor. Have a look at Stepper Motor Basics


...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Go Up