From a7ca67ca6e709bafb7609f7dbe9817fc9b757f50 Mon Sep 17 00:00:00 2001 From: Daniel Kohler <11864045+ddkohler@users.noreply.github.com> Date: Fri, 23 Jan 2026 12:34:01 -0600 Subject: [PATCH 1/5] more care with multiplexers take time writing direction, reading home --- firmware/firmware.ino | 44 +++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/firmware/firmware.ino b/firmware/firmware.ino index adab3b5..9daf978 100644 --- a/firmware/firmware.ino +++ b/firmware/firmware.ino @@ -24,6 +24,7 @@ int motors[6] = {2, 3, 4, 5, 6, 7}; // variables int i = 0; // for looping int u = 1; // microstepping amount +int selected = 0; // selected motor #define INPUT_SIZE 100 // TODO: make this a reasonable value #define sep " " char input[INPUT_SIZE + 1]; @@ -67,6 +68,8 @@ void setup() { } void loop() { + // each loop we check all motors and perform a step on each line if needed + // interval comparison avoids overflow issues unsigned long waited = millis() - prev; @@ -76,18 +79,23 @@ void loop() { if (remaining[i] > 0) { stepMotor(i); --remaining[i]; - } + } else if (home_after[i]) { // ready to home after moving off interrupt setSelect(i); setDirection(HIGH); home_after[i] = false; remaining[i] = -1; } - if (remaining[i] == -1) { // motor currently homing - setSelect(i); + else if (remaining[i] == -1) { // motor currently homing stepMotor(i); // interrupt is low when blocked - if (digitalRead(HOME) == 0) remaining[i] = 0; + setSelect(i); + int homed = digitalRead(HOME); + // read homed again to make sure + if (homed == 0) { + delay(2); + if (homed == 0) remaining[i] = 0; + } } } } @@ -135,11 +143,18 @@ void serialEvent() { // occurs whenever new data comes in the hardware serial R } } else if (*code == 'Q') { // query motor status - setSelect(index); - if (digitalRead(FAULT) == 0) Serial.println('F'); - else if (remaining[index] == 0) Serial.println('R'); + // // ignore faults for now + // setSelect(index); + // if (digitalRead(FAULT) == 0) Serial.println('F'); + if (remaining[index] == 0 and not home_after[index]) Serial.println('R'); else Serial.println('B'); } + else if (*code == '?') { + setSelect(index); + if (digitalRead(HOME)==0) Serial.println('H'); + else Serial.println('N'); + Serial.println(String(remaining[index])); + } else if (*code == 'U') { // set microstep integer u = index; setM(); @@ -152,20 +167,25 @@ void serialEventRun(void) { } void setDirection(int dir) { - // direction is latched in using TI SN74HC259 // facing the motor... // LOW = counter clockwise // HIGH = clockwise digitalWrite(G, LOW); // allow value to be written + delayMicroseconds(50); digitalWrite(D, dir); + delayMicroseconds(50); digitalWrite(G, HIGH); // lock in value } void setSelect(int index) { // selection reveals HOME and DIR pins for a specific motor - digitalWrite(S0, bitRead(index, 0)); - digitalWrite(S1, bitRead(index, 1)); - digitalWrite(S2, bitRead(index, 2)); + if (index != selected) { + digitalWrite(S0, bitRead(index, 0)); + digitalWrite(S1, bitRead(index, 1)); + digitalWrite(S2, bitRead(index, 2)); + delayMicroseconds(50); + selected = index; + } } void setM() { @@ -208,7 +228,7 @@ void setM() { void stepMotor(int index) { digitalWrite(motors[index], HIGH); - delay(1); + delay(2); digitalWrite(motors[index], LOW); } From d55605387498c8a4b2b2e11e6c0bbe00c7af206e Mon Sep 17 00:00:00 2001 From: Daniel Kohler <11864045+ddkohler@users.noreply.github.com> Date: Mon, 26 Jan 2026 12:30:39 -0600 Subject: [PATCH 2/5] Update firmware.ino --- firmware/firmware.ino | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/firmware/firmware.ino b/firmware/firmware.ino index 9daf978..66ddd24 100644 --- a/firmware/firmware.ino +++ b/firmware/firmware.ino @@ -36,6 +36,10 @@ int number = 0; int remaining[6]; bool home_after[6] = {false, false, false, false, false, false}; unsigned long prev = 0; +int interval = 5; // wait time for main loop; can be extended if needed +int default_interval = 5; +int homed = false; +int ms_step = 2; // delay between up and down steps void setup() { // initialize pins @@ -73,8 +77,9 @@ void loop() { // interval comparison avoids overflow issues unsigned long waited = millis() - prev; - if (waited >= 5){ + if (waited >= interval){ prev += waited; + interval = default_interval; // reset interval for (i = 0; i <= 5; i++){ if (remaining[i] > 0) { stepMotor(i); @@ -90,12 +95,8 @@ void loop() { stepMotor(i); // interrupt is low when blocked setSelect(i); - int homed = digitalRead(HOME); - // read homed again to make sure - if (homed == 0) { - delay(2); - if (homed == 0) remaining[i] = 0; - } + // read homed twice to make sure + if (carefulReadHome()) remaining[i] = 0; } } } @@ -129,7 +130,7 @@ void serialEvent() { // occurs whenever new data comes in the hardware serial R // first, we must handle the special case where the motor // is already at the interrupt setSelect(index); - if (digitalRead(HOME) == 0) { // interrupt is low when blocked + if (carefulReadHome()) { // interrupt is low when blocked // issue instruction to move 1/4 turn counter-clockwise setDirection(LOW); remaining[index] = 100 * u; @@ -171,9 +172,7 @@ void setDirection(int dir) { // LOW = counter clockwise // HIGH = clockwise digitalWrite(G, LOW); // allow value to be written - delayMicroseconds(50); digitalWrite(D, dir); - delayMicroseconds(50); digitalWrite(G, HIGH); // lock in value } @@ -183,11 +182,28 @@ void setSelect(int index) { digitalWrite(S0, bitRead(index, 0)); digitalWrite(S1, bitRead(index, 1)); digitalWrite(S2, bitRead(index, 2)); - delayMicroseconds(50); selected = index; } } +bool carefulReadHome() { + // blocking, careful measurement of HOME status + // wait for 5 consistent measurements (with delay) + while (true) { + homed = 0; + for (i = 0; i < 5; i++){ + delay(1); + homed += digitalRead(HOME); + Serial.println(String(homed)); + } + if (homed % 5 == 0) break; + else Serial.println("retry"); // how often does this happen? + } + if (homed == 5) Serial.println("I am not homed!"); + else Serial.println("I am homed!"); + return (homed == 0); +} + void setM() { // set the microstepping control pins // for these controllers M0 uses three-state logic @@ -228,7 +244,10 @@ void setM() { void stepMotor(int index) { digitalWrite(motors[index], HIGH); - delay(2); + delay(ms_step); digitalWrite(motors[index], LOW); + // ensure we have a minimum delay equal to the delay between HIGH and LOW writing + // BUG: if we are already late, we may not actually add enough to interval + if ((millis() - prev) <= ms_step) interval = (millis() - prev) + ms_step; } From da5d39ca0bbedc1e9c888b6c0fd236e7305722a1 Mon Sep 17 00:00:00 2001 From: Daniel Kohler <11864045+ddkohler@users.noreply.github.com> Date: Mon, 26 Jan 2026 15:36:26 -0600 Subject: [PATCH 3/5] reproducible homing --- firmware/firmware.ino | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/firmware/firmware.ino b/firmware/firmware.ino index 66ddd24..acb1b5e 100644 --- a/firmware/firmware.ino +++ b/firmware/firmware.ino @@ -21,8 +21,10 @@ int HOME = 11; int FAULT = 12; int motors[6] = {2, 3, 4, 5, 6, 7}; + // variables int i = 0; // for looping +int j = 0; // second loop variable int u = 1; // microstepping amount int selected = 0; // selected motor #define INPUT_SIZE 100 // TODO: make this a reasonable value @@ -84,7 +86,9 @@ void loop() { if (remaining[i] > 0) { stepMotor(i); --remaining[i]; + Serial.println(String(remaining[i])); } + else if (home_after[i]) { // ready to home after moving off interrupt setSelect(i); setDirection(HIGH); @@ -96,7 +100,7 @@ void loop() { // interrupt is low when blocked setSelect(i); // read homed twice to make sure - if (carefulReadHome()) remaining[i] = 0; + if (carefulReadHome()) remaining[i] = 1; // go one past the limit to avoid unstable readings } } } @@ -104,6 +108,7 @@ void loop() { void serialEvent() { // occurs whenever new data comes in the hardware serial RX // read serial into input char array + Serial.println("serial event"); byte size = Serial.readBytesUntil('\n', input, INPUT_SIZE); input[size] = 0; // parse input @@ -117,6 +122,7 @@ void serialEvent() { // occurs whenever new data comes in the hardware serial R Serial.println("INVALID"); return; } + Serial.println(String(index)); // call appropriate function if (*code == 'M') { // move relative setSelect(index); @@ -162,6 +168,7 @@ void serialEvent() { // occurs whenever new data comes in the hardware serial R } } + void serialEventRun(void) { // this runs inside of the main loop, essentially if (Serial.available()) serialEvent(); @@ -191,7 +198,7 @@ bool carefulReadHome() { // wait for 5 consistent measurements (with delay) while (true) { homed = 0; - for (i = 0; i < 5; i++){ + for (j = 0; j < 5; j++){ delay(1); homed += digitalRead(HOME); Serial.println(String(homed)); @@ -199,8 +206,8 @@ bool carefulReadHome() { if (homed % 5 == 0) break; else Serial.println("retry"); // how often does this happen? } - if (homed == 5) Serial.println("I am not homed!"); - else Serial.println("I am homed!"); + if (homed == 5) Serial.println("HOME=HIGH"); + else Serial.println("HOME=LOW"); return (homed == 0); } @@ -246,8 +253,8 @@ void stepMotor(int index) { digitalWrite(motors[index], HIGH); delay(ms_step); digitalWrite(motors[index], LOW); + interval += ms_step; // ensure time between the low-to-high step // ensure we have a minimum delay equal to the delay between HIGH and LOW writing // BUG: if we are already late, we may not actually add enough to interval - if ((millis() - prev) <= ms_step) interval = (millis() - prev) + ms_step; } From cb154951ec11a634a72c98d526c64f51f9bb223b Mon Sep 17 00:00:00 2001 From: Daniel Kohler <11864045+ddkohler@users.noreply.github.com> Date: Mon, 26 Jan 2026 15:42:00 -0600 Subject: [PATCH 4/5] remove debug serial comms --- firmware/firmware.ino | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/firmware/firmware.ino b/firmware/firmware.ino index acb1b5e..db03014 100644 --- a/firmware/firmware.ino +++ b/firmware/firmware.ino @@ -86,7 +86,7 @@ void loop() { if (remaining[i] > 0) { stepMotor(i); --remaining[i]; - Serial.println(String(remaining[i])); + // Serial.println(String(remaining[i])); } else if (home_after[i]) { // ready to home after moving off interrupt @@ -108,7 +108,7 @@ void loop() { void serialEvent() { // occurs whenever new data comes in the hardware serial RX // read serial into input char array - Serial.println("serial event"); + // Serial.println("serial event"); byte size = Serial.readBytesUntil('\n', input, INPUT_SIZE); input[size] = 0; // parse input @@ -122,7 +122,7 @@ void serialEvent() { // occurs whenever new data comes in the hardware serial R Serial.println("INVALID"); return; } - Serial.println(String(index)); + // Serial.println(String(index)); // call appropriate function if (*code == 'M') { // move relative setSelect(index); @@ -156,10 +156,10 @@ void serialEvent() { // occurs whenever new data comes in the hardware serial R if (remaining[index] == 0 and not home_after[index]) Serial.println('R'); else Serial.println('B'); } - else if (*code == '?') { + else if (*code == '?') { // special code for debug setSelect(index); - if (digitalRead(HOME)==0) Serial.println('H'); - else Serial.println('N'); + if (digitalRead(HOME)==0) Serial.println('HOME=LOW'); + else Serial.println('HOME=HIGH'); Serial.println(String(remaining[index])); } else if (*code == 'U') { // set microstep integer @@ -201,13 +201,13 @@ bool carefulReadHome() { for (j = 0; j < 5; j++){ delay(1); homed += digitalRead(HOME); - Serial.println(String(homed)); + // Serial.println(String(homed)); } if (homed % 5 == 0) break; - else Serial.println("retry"); // how often does this happen? + // else Serial.println("retry"); // how often does this happen? } - if (homed == 5) Serial.println("HOME=HIGH"); - else Serial.println("HOME=LOW"); + // if (homed == 5) Serial.println("HOME=HIGH"); + // else Serial.println("HOME=LOW"); return (homed == 0); } From 4927013f43971360da5fcfb944b50a404c6649e0 Mon Sep 17 00:00:00 2001 From: Daniel Kohler <11864045+ddkohler@users.noreply.github.com> Date: Tue, 27 Jan 2026 11:37:16 -0600 Subject: [PATCH 5/5] bugfixes consolidate wait times to be only function of ms_step some doc additions --- firmware/firmware.ino | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/firmware/firmware.ino b/firmware/firmware.ino index db03014..c0d694d 100644 --- a/firmware/firmware.ino +++ b/firmware/firmware.ino @@ -24,9 +24,13 @@ int motors[6] = {2, 3, 4, 5, 6, 7}; // variables int i = 0; // for looping -int j = 0; // second loop variable +int j = 0; // for nested loop int u = 1; // microstepping amount int selected = 0; // selected motor +bool home_after[6] = {false, false, false, false, false, false}; +unsigned long prev = 0; // for keeping tme +int homed = false; // for carefulReadHome +int ms_step = 4; // delay for up -> down steps; delay between down -> up is at least this long #define INPUT_SIZE 100 // TODO: make this a reasonable value #define sep " " char input[INPUT_SIZE + 1]; @@ -36,12 +40,6 @@ char c_number = '0'; int index = 0; int number = 0; int remaining[6]; -bool home_after[6] = {false, false, false, false, false, false}; -unsigned long prev = 0; -int interval = 5; // wait time for main loop; can be extended if needed -int default_interval = 5; -int homed = false; -int ms_step = 2; // delay between up and down steps void setup() { // initialize pins @@ -79,9 +77,8 @@ void loop() { // interval comparison avoids overflow issues unsigned long waited = millis() - prev; - if (waited >= interval){ + if (waited >= ms_step){ prev += waited; - interval = default_interval; // reset interval for (i = 0; i <= 5; i++){ if (remaining[i] > 0) { stepMotor(i); @@ -100,7 +97,7 @@ void loop() { // interrupt is low when blocked setSelect(i); // read homed twice to make sure - if (carefulReadHome()) remaining[i] = 1; // go one past the limit to avoid unstable readings + if (carefulReadHome()) remaining[i] = 1*u; // go one past the limit to avoid unstable readings } } } @@ -133,6 +130,7 @@ void serialEvent() { // occurs whenever new data comes in the hardware serial R else if (*code == 'H') { // home motor // home is defined as the location where the interrupt // is first tripped when approaching clockwise + // (technically, we go one full step after the first tripped position) // first, we must handle the special case where the motor // is already at the interrupt setSelect(index); @@ -194,7 +192,7 @@ void setSelect(int index) { } bool carefulReadHome() { - // blocking, careful measurement of HOME status + // measure HOME carefully // wait for 5 consistent measurements (with delay) while (true) { homed = 0; @@ -253,8 +251,6 @@ void stepMotor(int index) { digitalWrite(motors[index], HIGH); delay(ms_step); digitalWrite(motors[index], LOW); - interval += ms_step; // ensure time between the low-to-high step - // ensure we have a minimum delay equal to the delay between HIGH and LOW writing - // BUG: if we are already late, we may not actually add enough to interval + prev = millis(); // reset timer to ensure there is an appropriate delay between the HIGH and LOW write }