I'm driving a stepper (position control) with a Huzzah32 and a DC Motor Featherwing.
It works well for one motor at low speeds but I get very non-linear and (almost not increasing) behavior beyond 250 steps/sec. This limit is even lower (approx 100s/s?) with two steppers running in parallel.
After some research I suspect this coming from the i2c rate (I'll come to that later).
I'm using the AccelStepper library (together with the Adafruit_Motor_Shield_V2_Library 1.0.11) as it is usually mentionned as quite reliable; I might switch to another library if needed but from what I understood so far the limitation does not come from AccelStepper.
I don't even have a stepper plugged, just observing how fast the position is changing according to the library.
Strangely could not see a difference between SINGLE and DOUBLE step types.
I wrote a test sketch to measure the time needed to travel a given distance at various maxspeeds (with a proportionnaly strong acceleration) to evaluate the real speed.
(for some reason the first travel is a bit slower, I take the second one and check that it remains consistent over the next ones)
Here are my results (with one motor):
1000 steps traveled in...
40.07sec for 25.00 steps/sec
20.07sec for 50.00 steps/sec
10.08sec for 100.00 steps/sec
6.74sec for 150.00 steps/sec
5.08sec for 200.00 steps/sec
4.08sec for 250.00 steps/sec
(all good so far)
====
3.93sec for 260.00 steps/sec => real speed = 254
3.79sec for 300.00 steps/sec => real speed = 263
3.73sec for 1000.00 steps/sec => real speed = 268
3.72sec for 2000.00 steps/sec => real speed = 269
Here's my test code
Code: Select all
#include <Wire.h>
#include <AccelStepper.h>
#include <Adafruit_MotorShield.h>
Adafruit_MotorShield AFMSbot(0x61); // Rightmost jumper closed
Adafruit_MotorShield AFMStop(0x60); // Default address, no jumpers
Adafruit_StepperMotor *myStepper1 = AFMStop.getStepper(200, 1);
Adafruit_StepperMotor *myStepper2 = AFMStop.getStepper(200, 2);
void forwardstep1() {
myStepper1->onestep(FORWARD, DOUBLE); // replace with quickstep(FORWARD)
}
void backwardstep1() {
myStepper1->onestep(BACKWARD, DOUBLE); // replace with quickstep(BACKWARD)
}
void forwardstep2() {
myStepper2->onestep(FORWARD, DOUBLE);
}
void backwardstep2() {
myStepper2->onestep(BACKWARD, DOUBLE);
}
AccelStepper stepper1(forwardstep1, backwardstep1);
AccelStepper stepper2(forwardstep2, backwardstep2);
float speed_1 = 250;
float speed_2 = 100;
long lastTime1 = 0;
long lastTime2 = 0;
long dist = 1000;
bool useStepper2 = false;
void setup()
{
Serial.begin(115200);
AFMSbot.begin(); // Start the bottom shield
AFMStop.begin(); // Start the top shield
//Wire.setClock(400000L); // i2c overclocking
stepper1.setMaxSpeed(speed_1);
stepper1.setAcceleration(10*speed_1);
stepper1.moveTo(dist);
stepper2.setMaxSpeed(speed_2);
stepper2.setAcceleration(10*speed_2);
stepper2.moveTo(dist);
delay(1000); // for serial console
Serial.println("-------- START---------");
Serial.println(String(dist)+" steps traveled in...");
}
void loop()
{
// Change direction at the limits
if (stepper1.distanceToGo() == 0)
{
float dt1 = 0.001f*(millis() - lastTime1);
Serial.println(String(dt1)+ "sec for "+String(speed_1)+" steps/sec");
lastTime1 = millis();
stepper1.moveTo(stepper1.currentPosition()>0?0:dist);
}
stepper1.run();
if (useStepper2)
{
if (stepper2.distanceToGo() == 0)
{
float dt2 = 0.001f*(millis() - lastTime2);
Serial.println(String(dt2)+ "sec for "+String(speed_2)+" steps/sec");
lastTime2 = millis();
stepper2.moveTo(stepper2.currentPosition()>0?0:dist);
}
stepper2.run();
}
/*
long pos1 = stepper1.currentPosition();
long pos2 = stepper2.currentPosition();
float speed1 = stepper1.speed();
float speed2 = stepper2.speed();
Serial.println(String(speed1) + " - " + String(pos1) + " / " + String(pos2) + " - " + String(speed2));
*/
}
This issue is not documented but described in two forum posts, which provide two hacks to raise up the threshold: i2C overclocking and quickstep method.
viewtopic.php?f=31&t=149633&p=742083&hi ... or#p738675
viewtopic.php?f=31&t=57041&start=15#p292119
I could reproduce Bill's results, namely reaching about 700-800steps/sec by overclocking the i2c bus from 100kHz to 400kHz with
Code: Select all
Wire.setClock(400000L);
I could not see the difference between quickstep and onestep(DOUBLE) code, but it works so I probably missed it. By the ways I don't see the difference either between onestep(SINGLE) and onestep(DOUBLE), which might explain why I had the same behavior with both. Is the library flawd on that ?
So I guess 5 rounds/seconds is the maximum stepper speed with the featherwing ?
Why is the reliability so bad with 2 motors and how to mitigate it ?
Will the library behave differently with a motor plugged ? I would say no, the only difference being that depending on the load and power supply the real motor might miss steps, but the virtual position should not be affected, am I right ?
I actually had many questions initially but answered most of them by writing this post >< but if anyone has other suggestions, you are very welcome !
I also hope this recap will be useful to someone using the featherwing.
Cheers