I have a complete positioning system that works, this function I added to the stepper library and saved it to a new library, you just have to give a position in degrees and it runs to that point. I added a lot of things like positioning to homing sensor, emergency stop, stop with or without holding the motor on current, speed. It's working fine! To stay in sync and let all the motors having the same speed when one or more motors stop I virtual keep the same time needed to move the motor 1 step to behold the same timing if it is running or not. I will mean, by saying it runs to that point, it moves 1 step and gets out of the routine, the next time if it isn't at position it moves again 1 step so that there will be free idle time to do the rest of the program. If you don't do it that way you've got different speeds while moving more than one motor. I'm finalising this routine, it is working, just the motors are a little bit noisy because I had to put them on halfstep to have the fastest speed possible.
C++ file
void StepDriver::MoveAbsolute(bool safe, bool &run, long destination, int speed, float gearing, bool unlock, bool &homing, int homespeed, bool homesens) {
bool stop;
bool onPos = false;
long steps;
bool flag1 = false;
float resolution = (360.0 / (motor_steps * microsteps));
float stepstodo = (destination / resolution) * gearing;
long lstepstodo = stepstodo;
destout = lstepstodo;
if (!safe)
{
run = false;
if (starthoming)
{
starthoming = false;
homing = false;
}
}
if (homed && starthoming)
{
posout = 0;
busy = false;
}
if (homed)
{
starthoming = false;
setRPM(speed);
}
if (!homed)
run = false;
if (homing)
{
run = false;
homed = false;
starthoming = true;
setRPM(homespeed);
homing = false;
}
if (starthoming && homesens)
{
homed = true;
}
if (safe && run && (posout > destout) && !flag1 && homed)
{
posout--;
steps = -1;
move(steps,true);
busy = true;
flag1 = true;
}
if (safe && run && (posout < destout) && !flag1 && homed)
{
posout++;
steps = +1;
move(steps,true);
busy = true;
flag1 = true;
}
if (safe && !flag1 && !homed && starthoming)
{
posout++;
steps = -1;
move(steps,true);
busy = true;
flag1 = true;
}
if (!flag1)
{
int nsteps = + 1 * (motor_steps * (long)microsteps / 360);
move(nsteps, false);
}
if (posout == destout && homed)
{
busy = false;
onpos = true;
}
else onpos = false;
if (!homed && !starthoming)
{
busy = false;
onpos = false;
stop=true;
}
if (safe && unlock && homed)
{
if (onpos || !run)
// deenergize coil - pause and allow the motor to be moved by hand
stop = true;
else
// energize coil - the motor will hold position
stop = false;
}
if (safe && !unlock && homed)
stop = false;
if (safe && starthoming)
stop = false;
if (!safe)
{
stop = true;
}
if (stop)
{
stopdelay--;
if (stopdelay <= 0)
{
stopdelay = 0;
disable();
}
}
else
{
stopdelay = 100;
enable();
}
pos = abs((posout * resolution)/ gearing);
}
Header file
long pos;
bool onpos;
bool busy;
bool homed;
long destout;
long posout;
bool starthoming;
int stopdelay;
void MoveAbsolute(bool safe, bool &run, long destination, int speed, float gearing, bool unlock, bool &homing, int homespeed, bool homesens);
This is how you execute it
// Home sensor Base
step1.homesens = !digitalRead(BASE_SENS);
// Homing asked
if (homing01 && step1.safe)
{
step1.homing = true;
homing01 = false;
// test
homing02 = true;
}
// Move to position stepper 1
stepper1.MoveAbsolute(step1.safe,
step1.run,
step1.destination,
step1.speed,
step1.gearing,
step1.unlock,
step1.homing,
step1.homespeed,
step1.homesens);
Declerate it
struct stp {
bool safe = false;
bool old_safe = false;
bool run = false;
long destination = 0;
long old_destination = -1;
long old_position = -1;
int speed = 100;
float gearing = 1;
bool unlock = false;
bool old_onpos = false;
bool old_busy = false;
bool old_homed = false;
bool old_run = false;
bool homing = false;
bool old_homing = false;
int homespeed = 25;
bool homesens = false;
} step1, step2, step3, step4, step5, step6, step7;
setup()
void setup()
{
step1.safe = safety;
stepper1.pos = 0;
stepper1.onpos = false;
stepper1.busy = false;
stepper1.homed = false;
step1.speed = 200;
step1.gearing = 4.995;
step1.unlock = true;
// Tell the driver the microstep level we selected.
stepper1.setMicrostep(MICROSTEPS);
}
You can download the library from my project
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
[this comment has been deleted]
I have no experience with stepper motors yet but I have my way around to develop code for speed. But my idea may not be good for motors.
I need to check this out by experimenting myself on my own motors.
Just a question, if you would provide a loop that makes all stepper-motors step one puls without any tasks like updating an GUI and responding to controls. How fast would all the motors be able to execute?
To get a sense of that fastest possible speed.
for (int i=0; i<200; i++){
Stepper1. Step(1)
Stepper2. Step(1)
Stepper3. Step(1)
Stepper4. Step(1)
Stepper5. Step(1)
Stepper6. Step(1)
Stepper7. Step(1)
}
Now imagine you could do something like this (not correct code):
for (int i=0; i<200; i++){
OutByte[Stepper1 | StepperBit2 | StepperBit3 | StepperBit4 | StepperBit5 | StepperBit6 | StepperBit7 ]
Delay();
OutByte[0x00 ]
Delay();
}
Are you sure? yes | no
I know what you mean, but Stepper1.Step(x) is a function that generates a pulse width modulation of pulses to the motor, not just 1 puls. Every stepper motor must have a constant of pulses to move, the width between low and high will be the applitude. The biggest problem to keep every movement at the same speed is that you have to generate this pulsetrain even when there is no movement of the motors. If you don't do it you will get different speeds when motors starts and stops.
http://www.instructables.com/id/Arduino-Hardware-PWM-for-stepper-motor-drives/
It is not that I know everything about it, but in my proffesion I work alot with motion, maybe I am not always correct, so that's the reason I have to study a little bit more to find a good solution. Thanks anyway for the conversation, makes me thinking :-)
Are you sure? yes | no
Maybe we have to think out of the box.
We have 2 situations. The step direction and the step pulse.
During movement only the step pulse must be repeated.
We have 7 motors, 7 bits can be put into one byte. So we can control 7 stepper-motors with one command.
Not all motors will have the same amount of stepper counts within a fixed amount of time. So we need to create a queue of stepper commands to execute.
In the end we only have one motor control thread that executes the queue at fast rate.
We also can have a second thread that prepares the stepper motor commands and inserts it into a queue. But this thread can be more relaxed and calculates the commands when the robot is idle.
In order to make sure to have an abort, pause button, we could freeze the executing thread.
Are you sure? yes | no
The stepper motor works with pulse width modulation, so what's
importent, the sequence of pulses that the motor drive will get, so for
every motor there must be a constant puls signal at a regulare base
(speed) (puls train). The direction is just a signal high or low. To
make the pulse width signals of 7 motors on exactly the same sequence at
all times we need a interrupt driven system, this has been done with
FreeRTOS, there you can set each task to run at a given time. This is
what I am doing now, but for some reason, I have to debug, the processor
is to slow. And that's a shame, I will try to optimize the code.
I know what you try to explane, but when you get everything into one
single byte doesn't solve the problem because we have to make 7 PWM's to
drive the 7 motors. These modulations takes time, and if you want a
stable motor it has to be always the same, no matter what your doing in
the tasks, serial communication, wifi, IO mapping etc... . Correct me if
I am wrong :-)
We can make it faster if we don't matter that the speed of motors will
vary when another motor has stopt or started. I think that's not the
good solution. Or robot is going to be very unstable by different
movements. Or we do every articulation seperatly.
Are you sure? yes | no
void StepDriver::move(long steps, bool action){
if (steps >= 0){
setDirection(1);
} else {
setDirection(-1);
steps = -steps;
}
/*
* We currently try to do a 50% duty cycle so it's easy to see.
* Other option is step_high_min, pulse_duration-step_high_min.
*/
unsigned long pulse_duration = step_pulse / 2;
while (steps--){
if (action) digitalWrite(step_pin, HIGH);
unsigned long next_edge = micros() + pulse_duration;
microWaitUntil(next_edge);
if (action) digitalWrite(step_pin, LOW);
microWaitUntil(next_edge + pulse_duration);
}
}
The above routine creates the PWM, maybe we can optimize this code.
pulse_duration will be the speed (sample time between High and Low signals)
The resolution of the stepper motors can be from 1 step to 1/32 steps, the reason
why the motors are so noisy will be because it's now on 1/2 step. at 1/8 they where
not noisy anymore but with 7 steppers at a time way to slow...
Have to think about it
Are you sure? yes | no
micros() must be alot faster (factor 1:8) then everything will be very smooth.
look at this article.
http://www.freertos.org/FreeRTOS_Support_Forum_Archive/April_2015/freertos_Is_1ms_the_fastst_tick_rate_possible_53daa99dj.html
Maybe we can learn something out of it.
Are you sure? yes | no