yea.
in that last step might as well step all the motors
With the Bresenham algorithm, the math takes care of itself.
What step would be the best choice for a 1/20 movement step? At step 19, 0, or maybe in the middle at step 9?
Dave
here's an approach that uses fixed-pt integer math
the lower 5-bits are used as a fractional increment, 2^B * n / N where B is the binary-pt, 5, n the required # of steps and N the max # of steps of any motor. The increment for the motor requiring N steps is a value of 1Q5 = 2^B = 32. (hope this is understandable)
there will be N iterations. the step [] value for each motor incremented by the above. A step (*'d below) is made if the value >= 2^(B-1), half. Of course the motor requiring N steps is incremented each iteration. The other motors are incremented when their step value is >= 2^(B-1), 16
i see the total # of steps being made for each case and sometimes the last step is made sooner than the last iteration which i believe is correct.
i think this approach is avoids the use of floats and is probably simpler than Bresenham's algorithm and more easily undersood. of course the value of B can be adjusted as needed as well as the size of the integer to accommodate the larges # of steps, N
20 7 12 13
32 11 19 20 binary increment
0 32 * 11 19 * 20 *
1 32 * 22 * 6 8
2 32 * 1 25 * 28 *
3 32 * 12 12 16 *
4 32 * 23 * 31 * 4
5 32 * 2 18 * 24 *
6 32 * 13 5 12
7 32 * 24 * 24 * 32 *
8 32 * 3 11 20 *
9 32 * 14 30 * 8
10 32 * 25 * 17 * 28 *
11 32 * 4 4 16 *
12 32 * 15 23 * 4
13 32 * 26 * 10 24 *
14 32 * 5 29 * 12
15 32 * 16 * 16 * 32 *
16 32 * -5 3 20 *
17 32 * 6 22 * 8
18 32 * 17 * 9 28 *
19 32 * -4 28 * 16 *
20 7 12 13 total # of steps
function syncInt () {
printf "syncInt:\n"
B = 5 #/ binary pt
N = fld [1]
printf " "
for (f = 1; f <= F; f++)
printf " %9d", fld [f]
printf "\n"
printf " "
for (f = 1; f <= F; f++)
printf " %9d", binInc [f] = int(2^B * fld [f] / N)
printf " binary increment\n"
for (n = 0; n < N; n++) {
printf " %3d", n
for (f = 1; f <= F; f++) {
steps [f] += binInc [f]
printf " %7d", steps [f]
c = " "
if (steps [f] >= 2^(B-1)) {
steps [f] -= 2^B
pos [f]++
c = "*"
}
printf " %s", c
}
printf "\n"
}
printf " "
for (f = 1; f <= F; f++)
printf " %9d", pos [f]
printf " total # of steps \n"
printf "\n"
}
If you use B=1 and multiply everything by N, (increment 2^1*n/N*N=2n, step and decrement by N if sum>=N* 2^(1-1)=N it is still almost exactly Bresenham. (Wait?!?--what are you decrementing by when you step?)
Bresenham's algorithm isn't particularly difficult--it does the dividing with elementary school adding and subtracting: if you have a n/N ratio, you add 'n' each time the controlling axis takes a step, and whenever you've got 'N' in the accumulator, subtract 'N' and act. With n/N=7/20, at the end of 20 iterations, you've added 7 twenty times to make 140, and subtracted 20 and stepped 7 times to use up 140. A class of elementary school kids could handle counting this out with jellybeans. Especially if you gave them a 20 jellybean box.
const int N = 20;
int n[] = {N, 7, 12, 13, 1, N-1};
const int num = sizeof(n) / sizeof(n[0]);
int D[num];
void setup(void){
Serial.begin(115200);
Serial.print("It/n:");
// Initialize to center the sub-steps
for (int j = 0; j < num; ++j) {
D[j] = N / 2 + n[j]; // center
Serial.print("\t+=");
Serial.print(n[j]);
}
Serial.println();
for (int i = 0; i < N; ++i) {
Serial.print("i:");
Serial.print(i);
for (int j = 0; j < num; ++j) {
Serial.print("\t");
Serial.print(D[j]);
if (D[j] > N) {
D[j] -= N;
Serial.print("*-");
Serial.print(N);
}
D[j] += n[j];
// Serial.print("\t");
}
Serial.println();
}
}
void loop() {
}
gives:
| It/n: | +=20 | +=7 | +=12 | +=13 | +=1 | +=19 |
|---|---|---|---|---|---|---|
| i:0 | 30*-20 | 17 | 22*-20 | 23*-20 | 11 | 29*-20 |
| i:1 | 30*-20 | 24*-20 | 14 | 16 | 12 | 28*-20 |
| i:2 | 30*-20 | 11 | 26*-20 | 29*-20 | 13 | 27*-20 |
| i:3 | 30*-20 | 18 | 18 | 22*-20 | 14 | 26*-20 |
| i:4 | 30*-20 | 25*-20 | 30*-20 | 15 | 15 | 25*-20 |
| i:5 | 30*-20 | 12 | 22*-20 | 28*-20 | 16 | 24*-20 |
| i:6 | 30*-20 | 19 | 14 | 21*-20 | 17 | 23*-20 |
| i:7 | 30*-20 | 26*-20 | 26*-20 | 14 | 18 | 22*-20 |
| i:8 | 30*-20 | 13 | 18 | 27*-20 | 19 | 21*-20 |
| i:9 | 30*-20 | 20 | 30*-20 | 20 | 20 | 20 |
| i:10 | 30*-20 | 27*-20 | 22*-20 | 33*-20 | 21*-20 | 39*-20 |
| i:11 | 30*-20 | 14 | 14 | 26*-20 | 2 | 38*-20 |
| i:12 | 30*-20 | 21*-20 | 26*-20 | 19 | 3 | 37*-20 |
| i:13 | 30*-20 | 8 | 18 | 32*-20 | 4 | 36*-20 |
| i:14 | 30*-20 | 15 | 30*-20 | 25*-20 | 5 | 35*-20 |
| i:15 | 30*-20 | 22*-20 | 22*-20 | 18 | 6 | 34*-20 |
| i:16 | 30*-20 | 9 | 14 | 31*-20 | 7 | 33*-20 |
| i:17 | 30*-20 | 16 | 26*-20 | 24*-20 | 8 | 32*-20 |
| i:18 | 30*-20 | 23*-20 | 18 | 17 | 9 | 31*-20 |
| i:19 | 30*-20 | 10 | 30*-20 | 30*-20 | 10 | 30*-20 |
(cool! -- pasting tab-delimited data into a code block in the forum makes a Markdown table that you can remove the code tags to get a formatted table)
Bresenham did add a couple complications to center small fractions like 1/20 or 2/20 within the series and to speed the calculations: Initialize the accumulators with -N/2+n to make the decision rule be if(sum>0) and also multiply everything by two (use Q*.1 numbers?) to deal with the potential 1/2 fraction from centering within odd Ns. But the elementary schoolchildren might not handle the summing with negative jellybeans reliably.
First of all, since I used more than two steppers, I decided to use "int" value instead of "bool".
Does specifying the "if(joint1.distanceToGo())" definition in each "void newPosition()" cause a loop? Does the "joint" defined in it target the previous step or the first one? That's why I emphasized this part in my previous comment. The problem is exactly this;
Steppers do not transition from newPosition2 to newPosition3. It enters the loop between newPosition1 and newPosition2. Therefore, there is no transition to the newPosition3. Maybe I am having a problem with finishedMotion=0; part. It seemed to me that it was performing the same operation by rewinding in the directory it was located in somewhere.
Maybe there is something wrong with the "void loop" part. Maybe I need to add something different, I don't know.
In addition; I know that it is necessary to define each movement sequentially by adding general definitions to the "void setup" and a few steps (void newPosition) in different methods to carry out the next steps. Finally, we must write the "joints" into the "loop" so that all steppers work at the same time. I guess there is nothing wrong with the logic so far.
Full Code:
int finishedMotion = 0;
void setup() {
Serial.begin(250000);
// Configure each stepper
joint1.setMaxSpeed(500.0); //Safe Value: 500
joint1.setAcceleration(400.0); //Safe Value: 400
joint1.moveTo(0); //Safe Value: 400
joint2.setMaxSpeed(500.0); //Safe Value: 500
joint2.setAcceleration(400.0); //Safe Value: 400
joint2.moveTo(0); //Safe Value: 400
joint3.setMaxSpeed(3500.0); //Safe Value: 3500
joint3.setAcceleration(3500.0); //Safe Value: 3500
joint3.moveTo(0); //Safe Value: 4000
joint4.setMaxSpeed(500.0); //Safe Value: 500
joint4.setAcceleration(400.0); //Safe Value: 400
joint4.moveTo(0); //Safe Value: 400
joint5.setMaxSpeed(500.0); //Safe Value: 500
joint5.setAcceleration(400.0); //Safe Value: 400
joint5.moveTo(0); //Safe Value: 400
}
void newPosition1(){
if(joint1.distanceToGo() || joint2.distanceToGo() || joint3.distanceToGo() || joint4.distanceToGo() || joint5.distanceToGo() ) {
; // still moving
} else {
finishedMotion = 1;
}
if(finishedMotion){
delay(2000);
//set new target
joint1.moveTo(400);
joint2.moveTo(400);
joint3.moveTo(4000);
joint4.moveTo(400);
joint5.moveTo(400);
finishedMotion = 0;
}
}
void newPosition2(){
if(joint1.distanceToGo() || joint2.distanceToGo() || joint3.distanceToGo() || joint4.distanceToGo() || joint5.distanceToGo() ) {
;
} else {
finishedMotion = 2;
}
if(finishedMotion){
delay(3000);
joint1.moveTo(0);
joint2.moveTo(150);
joint3.moveTo(2000);
joint4.moveTo(200);
joint5.moveTo(200);
finishedMotion = 0;
}
}
void newPosition3(){
if(joint1.distanceToGo() || joint2.distanceToGo() || joint3.distanceToGo() || joint4.distanceToGo() || joint5.distanceToGo() ) {
;
} else {
finishedMotion = 3;
}
if(finishedMotion){
delay(3000);
joint1.moveTo(-400);
joint2.moveTo(400);
joint3.moveTo(4000);
joint4.moveTo(400);
joint5.moveTo(400);
finishedMotion = 0;
}
}
void newPosition4(){
if(joint1.distanceToGo() || joint2.distanceToGo() || joint3.distanceToGo() || joint4.distanceToGo() || joint5.distanceToGo() ) {
;
} else {
finishedMotion = 4;
}
if(finishedMotion){
delay(3000);
joint1.moveTo(0);
joint2.moveTo(0);
joint3.moveTo(0);
joint4.moveTo(0);
joint5.moveTo(0);
finishedMotion = 0;
}
}
void loop() {
joint1.run();
joint2.run();
joint3.run();
joint4.run();
joint5.run();
newPosition1();
newPosition2();
newPosition3();
newPosition4();
}
No, an if doesn't cause a loop. You can cause looping with while(){}, for(...) etc, or you can depend on the arduino repeatedly calling your loop() function after it is done with setup. Arduino has this code in its main() definition:
Note that loop() is called in an infinite for(;;){...} loop.
If you need to transition between motions, sequentially, you can either lay out the re-targeting and subsequent motions sequentially in setup(){..} or write your re-targeting and motions in such a way that the computer can understand when to run the steppers and when to retarget.
Up above in #3 I was aiming at two sequential motions and nothing else, with advice for something like this completely untested code:
#include <AccelStepper.h>
// Joint 1
#define E1_STEP_PIN 36
#define E1_DIR_PIN 34
#define E1_ENABLE_PIN 30
// Joint 2
#define Z_STEP_PIN 46
#define Z_DIR_PIN 48
#define Z_ENABLE_PIN 62
#define Z_MIN_PIN 18
#define Z_MAX_PIN 19
// Joint 3
#define Y_STEP_PIN 60
#define Y_DIR_PIN 61
#define Y_ENABLE_PIN 56
#define Y_MIN_PIN 14
#define Y_MAX_PIN 15
// Joint 4
#define X_STEP_PIN 54
#define X_DIR_PIN 55
#define X_ENABLE_PIN 38
// Joint 5
#define E0_STEP_PIN 26
#define E0_DIR_PIN 28
#define E0_ENABLE_PIN 24
// EG X-Y position bed driven by 2 steppers
AccelStepper joint1(1, E1_STEP_PIN, E1_DIR_PIN);
AccelStepper joint2(1, Z_STEP_PIN, Z_DIR_PIN);
AccelStepper joint3(1, Y_STEP_PIN, Y_DIR_PIN);
AccelStepper joint4(1, X_STEP_PIN, X_DIR_PIN);
AccelStepper joint5(1, E0_STEP_PIN, E0_DIR_PIN);
//test with uint8 converted to long
unsigned int x = 1000;
void setup() {
Serial.begin(250000);
// Configure each stepper
joint1.setMaxSpeed(500.0); //Safe Value: 500
joint1.setAcceleration(400.0); //Safe Value: 400
joint1.moveTo(400); //Safe Value: 400
joint2.setMaxSpeed(500.0); //Safe Value: 500
joint2.setAcceleration(400.0); //Safe Value: 400
joint2.moveTo(400); //Safe Value: 400
joint3.setMaxSpeed(3500.0); //Safe Value: 3500
joint3.setAcceleration(3500.0); //Safe Value: 3500
joint3.moveTo(4000); //Safe Value: 4000
joint4.setMaxSpeed(500.0); //Safe Value: 500
joint4.setAcceleration(400.0); //Safe Value: 400
joint4.moveTo(400); //Safe Value: 400
joint5.setMaxSpeed(500.0); //Safe Value: 500
joint5.setAcceleration(400.0); //Safe Value: 400
joint5.moveTo(400); //Safe Value: 400
while{ joint1.distanceToGo() || joint2.distanceToGo() || joint3.distanceToGo() || joint4.distanceToGo() || joint5.distanceToGo() ){
joint1.run();
joint2.run();
joint3.run();
joint4.run();
joint5.run();
}
// Re-Configure each stepper
joint1.setMaxSpeed(500.0); //Safe Value: 500
joint1.setAcceleration(400.0); //Safe Value: 400
joint1.moveTo(-400); //Safe Value: 400
joint2.setMaxSpeed(500.0); //Safe Value: 500
joint2.setAcceleration(400.0); //Safe Value: 400
joint2.moveTo(-400); //Safe Value: 400
joint3.setMaxSpeed(3500.0); //Safe Value: 3500
joint3.setAcceleration(3500.0); //Safe Value: 3500
joint3.moveTo(-4000); //Safe Value: 4000
joint4.setMaxSpeed(500.0); //Safe Value: 500
joint4.setAcceleration(400.0); //Safe Value: 400
joint4.moveTo(-400); //Safe Value: 400
joint5.setMaxSpeed(500.0); //Safe Value: 500
joint5.setAcceleration(400.0); //Safe Value: 400
joint5.moveTo(-400); //Safe Value: 400
... repeat as necessary
}
void loop() {
// empty because it is all handled sequentially in setup()
}
The above code runs the two motions sequentially and then stays in an endless loop().
If you want more motions than 2, it might make sense to define some arrays holding the different motion's targets, accelerations, and maximum speeds and use a state machine within loop() to switch between the motions. Perhaps with some bits like those in this completely untested code:
int targets[][5] = {{0,0,0,0,0},
{400,400,4000,400,400},
{0,150,2000,200,200},
...
};
int motionNumber = 0;
...
void loop() {
joint1.run();
joint2.run();
joint3.run();
joint4.run();
joint5.run();
if( ! (joint1.distanceToGo() || joint2.distanceToGo() || joint3.distanceToGo() || joint4.distanceToGo() || joint5.distanceToGo() ) ) {
//set new target
if(motionNumber < 5){ // don't advance past the final target
motionNumber = motionNumber+1;
}
// Configure each stepper
joint1.moveTo(targets[motionNumber][0];
joint2.moveTo(targets[motionNumber][0];
joint3.moveTo(targets[motionNumber][0];
joint4.moveTo(targets[motionNumber][0];
joint5.moveTo(targets[motionNumber][0];
...
}
}
As is, your #25 code runs loop repeatedly, steps the motors as needed, and then the newPosition*() commands retarget if there isn't distance to go. Their logical tests don't care about order. newPosition1() is only checking if the motors are stopped, and them being stopped after moving to newPosition2 is good enough for newPosition1() to trigger.
I'd add a Serial.print("1"); in newPosition1(), etc... and probably see how the flow is happening.
Another fix would be to rewrite your if() conditions to check that the expected preceding motion finished before setting the new target. For example:
void newPosition1(){
if(currentMotion == 0 && !(joint1.distanceToGo() || joint2.distanceToGo() || joint3.distanceToGo() || joint4.distanceToGo() || joint5.distanceToGo() ) ) {
currentMotion = 1;
delay(2000);
//set new target
joint1.moveTo(400);
joint2.moveTo(400);
joint3.moveTo(4000);
joint4.moveTo(400);
joint5.moveTo(400);
}
}
...
Man, thanks a lot. Both code methods worked. However, one stepper in the arrays definition created a synchronization mismatch. It works but something seems to be going wrong. That's why I used the code with the "currentMotion" command you last shared. As you said, i need to check that the expected preceding motion finished before setting the new target. This little command solved the problem.