OK I'm back. I did a number of things today:
- Changed the wires
- Switched drivers and motors to rule out anything faulty
- Removed the motors from their chassis mounts to operate them without any vibrations or load
- Varied RPMs during operation
Here's a couple videos of the thing in action:
- Manual mode - only Motor 1 is spinning in a single direction - works fine under 800 RPMs, no stalls.
- Auto mode - Motor 1 spins in a single direction again, whilst Motor 2 strafes back and forth at short intervals. Motor 1 experiences stalling - I've noted that the stalls seem to occur at particular changeover points where the run commands (in a loop) end after a parameter is met and the program switches to the next loop til a new parameter is met. If I slow the RPMs of Motor 1 down significantly, I can feel the little pauses occurring in Motor 1 while the loop switches. I think it's possible that there's just a few microseconds of time between the loops where Motor 1 isn't receiving a command, and the position is overrun and the whole thing loses its place (I have only basic understanding of how stepper motors function).
So I am now starting to think it's a software issue and would like some help if possible.
Here's an example of what's happening programmatically while that auto mode is running:
case PATTERN_R1:
for (int i = 0; i < s_end_count; i ++) {
stepper2.moveTo(Move_2_A + (s_inc * i));
while (stepper2.distanceToGo() != 0 && stepper1.distanceToGo() != 0 && stepper2.currentPosition() != Move_2_B) {
stepper1.run();
stepper2.run();
}
if (stepper1.distanceToGo() == 0) {Motor_State = SELECTOR_A;}
if (stepper2.currentPosition() == Move_2_B) {Motor_State = PATTERN_L1;}
stepper2.moveTo(Move_2_A);
while (stepper2.distanceToGo() != 0 && stepper1.distanceToGo() != 0 && stepper2.currentPosition() != Move_2_B) {
stepper1.run();
stepper2.run();
}
if (stepper1.distanceToGo() == 0) {Motor_State = SELECTOR_A;}
if (stepper2.currentPosition() == Move_2_B) {Motor_State = PATTERN_L1;}
}
Motor_State = PATTERN_R2;
break;
case PATTERN_R2:
if ((Move_2_B - stepper2.currentPosition()) < s_dist) {
stepper2.moveTo(Move_2_B);
} else {
stepper2.moveTo(stepper2.currentPosition() + s_dist);
};
while (stepper2.distanceToGo() != 0 && stepper1.distanceToGo() != 0 && stepper2.currentPosition() != Move_2_B) {
stepper1.run();
stepper2.run();
}
if (stepper1.distanceToGo() == 0) {Motor_State = SELECTOR_A;}
if (stepper2.currentPosition() == Move_2_B) {Motor_State = PATTERN_R3;}
stepper2.moveTo(stepper2.currentPosition() - (s_dist - s_inc));
while (stepper2.distanceToGo() != 0 && stepper1.distanceToGo() != 0 && stepper2.currentPosition() != Move_2_B) {
if (stepper1.distanceToGo() == 0) {Motor_State = SELECTOR_A;}
stepper1.run();
stepper2.run();
}
if (stepper1.distanceToGo() == 0) {Motor_State = SELECTOR_A;}
if (stepper2.currentPosition() == Move_2_B) {Motor_State = PATTERN_R3;}
break;
case PATTERN_R3:
for (int i = s_end_count; i > 0; i --) {
stepper2.moveTo(Move_2_B - (s_inc * i));
while (stepper2.distanceToGo() != 0 && stepper1.distanceToGo() != 0 && stepper2.currentPosition() != Move_2_A) {
stepper1.run();
stepper2.run();
}
if (stepper1.distanceToGo() == 0) {Motor_State = SELECTOR_A;}
if (stepper2.currentPosition() == Move_2_A) {Motor_State = PATTERN_R1;}
stepper2.moveTo(Move_2_B);
while (stepper2.distanceToGo() != 0 && stepper1.distanceToGo() != 0 && stepper2.currentPosition() != Move_2_A) {
stepper1.run();
stepper2.run();
}
if (stepper1.distanceToGo() == 0) {Motor_State = SELECTOR_A;}
if (stepper2.currentPosition() == Move_2_A) {Motor_State = PATTERN_R1;}
}
Motor_State = PATTERN_L1;
break;
case PATTERN_L1:
for (int i = 0; i < s_end_count; i ++) {
stepper2.moveTo(Move_2_B - (s_inc * i));
while (stepper2.distanceToGo() != 0 && stepper1.distanceToGo() != 0 && stepper2.currentPosition() != Move_2_A) {
stepper1.run();
stepper2.run();
}
if (stepper1.distanceToGo() == 0) {Motor_State = SELECTOR_A;}
if (stepper2.currentPosition() == Move_2_A) {Motor_State = PATTERN_R1;}
stepper2.moveTo(Move_2_B);
while (stepper2.distanceToGo() != 0 && stepper1.distanceToGo() != 0 && stepper2.currentPosition() != Move_2_A) {
stepper1.run();
stepper2.run();
}
if (stepper1.distanceToGo() == 0) {Motor_State = SELECTOR_A;}
if (stepper2.currentPosition() == Move_2_A) {Motor_State = PATTERN_R1;}
}
Motor_State = PATTERN_L2;
break;
case PATTERN_L2:
if ((stepper2.currentPosition() - Move_2_A) < s_dist) {
stepper2.moveTo(Move_2_A);
} else {
stepper2.moveTo(stepper2.currentPosition() - s_dist);
};
while (stepper2.distanceToGo() != 0 && stepper1.distanceToGo() != 0 && stepper2.currentPosition() != Move_2_A) {
stepper1.run();
stepper2.run();
}
if (stepper1.distanceToGo() == 0) {Motor_State = SELECTOR_A;}
if (stepper2.currentPosition() == Move_2_A) {Motor_State = PATTERN_L3;}
stepper2.moveTo(stepper2.currentPosition() + (s_dist - s_inc));
while (stepper2.distanceToGo() != 0 && stepper1.distanceToGo() != 0 && stepper2.currentPosition() != Move_2_A) {
stepper1.run();
stepper2.run();
}
if (stepper1.distanceToGo() == 0) {Motor_State = SELECTOR_A;}
if (stepper2.currentPosition() == Move_2_A) {Motor_State = PATTERN_L3;}
break;
case PATTERN_L3:
for (int i = s_end_count; i > 0; i --) {
stepper2.moveTo(Move_2_A + (s_inc * i));
while (stepper2.distanceToGo() != 0 && stepper1.distanceToGo() != 0 && stepper2.currentPosition() != Move_2_B) {
stepper1.run();
stepper2.run();
}
if (stepper1.distanceToGo() == 0) {Motor_State = SELECTOR_A;}
if (stepper2.currentPosition() == Move_2_B) {Motor_State = PATTERN_R3;}
stepper2.moveTo(Move_2_A);
while (stepper2.distanceToGo() != 0 && stepper1.distanceToGo() != 0 && stepper2.currentPosition() != Move_2_B) {
stepper1.run();
stepper2.run();
}
if (stepper1.distanceToGo() == 0) {Motor_State = SELECTOR_A;}
if (stepper2.currentPosition() == Move_2_B) {Motor_State = PATTERN_R3;}
}
Motor_State = PATTERN_R1;
break;
That's on one of the ESP32's cores operating independently. Ignoring the math and whatnot, you can see it jumps from case to case / loop to loop. The other core is dedicated to receiving serial commands from a touchscreen panel, so it's hard for me to just assign a core to run one motor independently from the other.
My first thought is to try to stop all this case switching business and at least have all the loops occur sequentially...I'm really not a great programmer, or engineer, or anything like that, so I'm sort of just trying things out. I won't be able to get to it til tomorrow so in the meantime, any insight or ideas that may seem worth investigating would be very helpful. Thank you!
Edit: sorry, I forgot to mention that in that video of the auto mode, you see two modes happening - first there's a simple back and forth strafing on Motor 2 that works fine with that 800rpm ceiling on Motor 1. The next is the problem mode, where there's rapid back and forth motion on Motor 2 that stalls Motor 1. The code for the functional simple strafing mode looks like this:
case OSCILLATE_R:
while ((stepper1.distanceToGo() != 0) && (cancel_run == false)) {
stepper2.moveTo(Move_2_B);
while (stepper2.distanceToGo() != 0) {
stepper1.run();
stepper2.run();
};
stepper2.moveTo(Move_2_A);
while (stepper2.distanceToGo() != 0) {
stepper1.run();
stepper2.run();
};
};
if (cancel_run == true) {Motor_State = CANCELLED;}
if (stepper1.distanceToGo() == 0) {Motor_State = SELECTOR_A;}
break;
Two loops, but no case switching.