From a29c85628c0237c93e93316e0c5c1d1eb2342878 Mon Sep 17 00:00:00 2001 From: mattmcw Date: Thu, 25 May 2023 10:43:45 -0400 Subject: [PATCH] Add bones of the dual stepper motor, JK compatible projector firmware. --- .../IteadDualStepperShield.cpp | 81 +++++++++++ .../IteadDualStepperShield.h | 42 ++++++ ino/mcopy_projector_firmware/McopySerial.cpp | 70 ++++++++++ ino/mcopy_projector_firmware/McopySerial.h | 86 ++++++++++++ .../mcopy_projector_firmware.ino | 132 ++++++++++++++++++ scripts/ino.sh | 1 + 6 files changed, 412 insertions(+) create mode 100644 ino/mcopy_projector_firmware/IteadDualStepperShield.cpp create mode 100644 ino/mcopy_projector_firmware/IteadDualStepperShield.h create mode 100644 ino/mcopy_projector_firmware/McopySerial.cpp create mode 100644 ino/mcopy_projector_firmware/McopySerial.h create mode 100644 ino/mcopy_projector_firmware/mcopy_projector_firmware.ino diff --git a/ino/mcopy_projector_firmware/IteadDualStepperShield.cpp b/ino/mcopy_projector_firmware/IteadDualStepperShield.cpp new file mode 100644 index 0000000..f564e9b --- /dev/null +++ b/ino/mcopy_projector_firmware/IteadDualStepperShield.cpp @@ -0,0 +1,81 @@ + +#include "IteadDualStepperShield.h" + +IteadDualStepperShield::IteadDualStepperShield () {} + +void IteadDualStepperShield::setup () { + pinMode(_directionA, OUTPUT); + pinMode(_directionB, OUTPUT); + pinMode(_stepA, OUTPUT); + pinMode(_stepB, OUTPUT); + setDir(0, 1); + setDir(1, 1); +} + +void IteadDualStepperShield::setDir (uint8_t motor, uint8_t dir) { + if (motor == 0) { + directionA = dir; + digitalWrite(_directionA, directionA > 0 ? HIGH : LOW); + } else if (motor == 1) { + directionB = dir; + digitalWrite(_directionB, directionB > 0 ? HIGH : LOW); + } +} + +void IteadDualStepperShield::setSpeed (uint8_t motor, uint16_t rpm) { + uint32_t usPerStep = 60000000 / ((uint32_t) revsteps * (uint32_t) rpm); + if (motor == 0) { + _usStepA = usPerStep; + } else if (motor == 1) { + _usStepB = usPerStep; + } +} + +void IteadDualStepperShield::_micro (uint8_t motor) { + uint8_t stepPin = motor == 0 ? _stepA : _stepB; + uint32_t usStep = motor == 0 ? _usStepA : _usStepB; + digitalWrite(stepPin, HIGH); + delayMicroseconds(usStep); + digitalWrite(stepPin, LOW); + delayMicroseconds(usStep); +} + +//full +void IteadDualStepperShield::_single (uint8_t motor) { + uint8_t stepPin = motor == 0 ? _stepA : _stepB; + uint32_t usStep = motor == 0 ? _usStepA : _usStepB; + for (uint8_t i = 0; i < _microsteps; i++) { + digitalWrite(stepPin, HIGH); + delayMicroseconds(usStep); + digitalWrite(stepPin, LOW); + delayMicroseconds(usStep); + } +} +void IteadDualStepperShield::_both () { + for (uint8_t i = 0; i < _microsteps; i++) { + digitalWrite(_stepA, HIGH); + digitalWrite(_stepB, HIGH); + delayMicroseconds(_usStepA); + digitalWrite(_stepA, LOW); + digitalWrite(_stepB, LOW); + delayMicroseconds(_usStepA); + } +} +void IteadDualStepperShield::step (uint8_t motor, uint16_t steps, uint8_t dir) { + uint8_t stepPin = motor == 0 ? _stepA : _stepB; + setDir(motor, dir); + for (int i = 0; i < steps; i++) { + _single(stepPin); + } +} +void IteadDualStepperShield::onestep (uint8_t motor, uint8_t dir) { + uint8_t stepPin = motor == 0 ? _stepA : _stepB; + setDir(motor, dir); + _single(stepPin); +} + +void IteadDualStepperShield::stepBoth (uint16_t steps) { + for (int i = 0; i < steps; i++) { + _both(); + } +} \ No newline at end of file diff --git a/ino/mcopy_projector_firmware/IteadDualStepperShield.h b/ino/mcopy_projector_firmware/IteadDualStepperShield.h new file mode 100644 index 0000000..cf69790 --- /dev/null +++ b/ino/mcopy_projector_firmware/IteadDualStepperShield.h @@ -0,0 +1,42 @@ +#ifndef IteadDualStepperShield_h +#define IteadDualStepperShield_h + + +#include + +class IteadDualStepperShield { + private: + const uint8_t _microsteps = 8; //8 or 16 + const uint8_t _directionA = 3; + const uint8_t _directionB = 7; + const uint8_t _stepA = 2; + const uint8_t _stepB = 6; + + void _single(uint8_t motor); + void _micro(uint8_t motor); + void _both(); + + uint32_t _usStepA = 300; + uint32_t _usStepB = 300; + + public: + IteadDualStepperShield(); + + uint16_t revsteps = 200; // # steps per revolution + + volatile uint8_t directionA = 1; + volatile uint8_t directionB = 1; + void setup(); + + void setDir(uint8_t motor, uint8_t dir); + void setSpeed(uint8_t motor, uint16_t speed); + + //full + void step(uint8_t motor, uint16_t steps, uint8_t dir); + void stepBoth(uint16_t steps); + void onestep(uint8_t motor, uint8_t dir); + + void release(); +}; + +#endif \ No newline at end of file diff --git a/ino/mcopy_projector_firmware/McopySerial.cpp b/ino/mcopy_projector_firmware/McopySerial.cpp new file mode 100644 index 0000000..7662948 --- /dev/null +++ b/ino/mcopy_projector_firmware/McopySerial.cpp @@ -0,0 +1,70 @@ +/// mcopy Serial Library + +#include "McopySerial.h" + +McopySerial::McopySerial () {} + +void McopySerial::begin (char identity) { + id = identity; + Serial.begin(baud); + Serial.flush(); + Serial.setTimeout(serialDelay); +} + +char McopySerial::loop () { + if (Serial.available()) { + cmdChar = (char) Serial.read(); + _internal(); + } else { + cmdChar = 'z'; + } + return cmdChar; +} + +void McopySerial::_internal () { + if (cmdChar == DEBUG) { + debug(!debugOn); + } else if (cmdChar == CONNECT) { + _connect(); + } else if (cmdChar == MCOPY_IDENTIFIER) { + _identify(); + } +} + +void McopySerial::_connect () { + connected = true; + Serial.println(CONNECT); + log("connect()"); +} + +void McopySerial::_identify () { + identified = true; + Serial.println(id); + log("identify()"); +} + +void McopySerial::debug (bool state) { + debugOn = state; + log("debug()"); +} + +void McopySerial::confirm (char cmd) { + Serial.println(cmd); +} + +void McopySerial::log (String message) { + if (debugOn) { + Serial.println(message); + } +} + +String McopySerial::getString () { + while (Serial.available() == 0) { + //Wait for value string + } + return Serial.readString(); +} + +void McopySerial::print (String message) { + Serial.println(message); +} \ No newline at end of file diff --git a/ino/mcopy_projector_firmware/McopySerial.h b/ino/mcopy_projector_firmware/McopySerial.h new file mode 100644 index 0000000..0762c6d --- /dev/null +++ b/ino/mcopy_projector_firmware/McopySerial.h @@ -0,0 +1,86 @@ +#ifndef MCOPY_SERIAL +#define MCOPY_SERIAL + +#include + +class McopySerial { + + private: + + const uint16_t serialDelay = 5; + const uint16_t baud = 57600; + + volatile bool debugOn = false; + volatile char cmdChar = 'z'; + volatile char id; + + void _internal (); + void _connect (); + void _identify (); + + public: + + volatile bool connected = false; + volatile bool identified = false; + + /* CMD FLAGS */ + const char BLACK = 'b'; + const char CAMERA = 'c'; + const char CAMERA_BACKWARD = 'f'; + const char CAMERA_CAPPER_IDENTIFIER = '8'; + const char CAMERA_CAPPER_PROJECTOR_IDENTIFIER = '9'; + const char CAMERA_CAPPER_PROJECTORS_IDENTIFIER = '0'; + const char CAMERA_EXPOSURE = 'G'; + const char CAMERA_FORWARD = 'e'; + const char CAMERA_IDENTIFIER = 'k'; + const char CAMERA_PROJECTORS_IDENTIFIER = '5'; + const char CAMERA_SECOND = '3'; + const char CAMERA_SECOND_BACKWARD = '2'; + const char CAMERA_SECOND_FORWARD = '1'; + const char CAMERA_SECOND_IDENTIFIER = 'y'; + const char CAMERA_TIMED = 'n'; + const char CAMERAS = '4'; + const char CAMERAS_IDENTIFIER = 'a'; + const char CAMERAS_PROJECTOR_IDENTIFIER = '6'; + const char CAMERAS_PROJECTORS_IDENTIFIER = '7'; + const char CAPPER_IDENTIFIER = 'C'; + const char CAPPER_OFF = 'B'; + const char CAPPER_ON = 'A'; + const char CONNECT = 'i'; + const char DEBUG = 'd'; + const char ERROR = 'E'; + const char LIGHT = 'l'; + const char LIGHT_IDENTIFIER = 'o'; + const char MCOPY_IDENTIFIER = 'm'; + const char PROJECTOR = 'p'; + const char PROJECTOR_BACKWARD = 'h'; + const char PROJECTOR_CAMERA_IDENTIFIER = 's'; + const char PROJECTOR_CAMERA_LIGHT_IDENTIFIER = 'r'; + const char PROJECTOR_FORWARD = 'g'; + const char PROJECTOR_IDENTIFIER = 'j'; + const char PROJECTOR_LIGHT_IDENTIFIER = 'q'; + const char PROJECTOR_SECOND = 'w'; + const char PROJECTOR_SECOND_BACKWARD = 'v'; + const char PROJECTOR_SECOND_FORWARD = 'u'; + const char PROJECTOR_SECOND_IDENTIFIER = 't'; + const char PROJECTORS = 'x'; + const char PROJECTORS_IDENTIFIER = 'd'; + const char STATE = 'H'; + const char TAKEUP_BACKWARD = 'F'; + const char TAKEUP_FORWARD = 'D'; + /* END CMD FLAGS */ + + McopySerial(); + + void begin(char identity); + char loop(); + void confirm(char cmd); + String getString(); + void print(String message); + + void debug (bool state); + void log (String message); + +}; + +#endif diff --git a/ino/mcopy_projector_firmware/mcopy_projector_firmware.ino b/ino/mcopy_projector_firmware/mcopy_projector_firmware.ino new file mode 100644 index 0000000..9eac67f --- /dev/null +++ b/ino/mcopy_projector_firmware/mcopy_projector_firmware.ino @@ -0,0 +1,132 @@ +/* + + JK-compatible projector element + + Hardware + + Arduino Uno + Itead Dual Stepper Shield + 2x NEMA17 Stepper Motors + + Wiring + + (Will vary from motor to motor) + X01A - Green + X01B - Black + X02A - Blue + X02B - Red + + Y01A - Green + Y01B - Black + Y02A - Blue + Y02B - Red +*/ + +#include "McopySerial.h" +#include "IteadDualStepperShield.h" + +//CAMERA CONSTANTS +const int BUTTON = 7; +const int LED_FWD = 8; +const int LED_BWD = 9; + +const int PROJECTOR_MOMENT = 240; +const int PROJECTOR_STEPS = 25; + +//VARIABLES +volatile int projectorFrame = -1; +volatile char cmdChar = 'z'; +volatile long now; +volatile bool direction = true; +volatile long start; + +McopySerial mcopy; +IteadDualStepperShield steppers; + +void setup () { + steppers.setup(); + steppers.setSpeed(0, 2000); + steppers.setSpeed(1, 2000); + + pins(); + digitalWrite(LED_FWD, HIGH); + digitalWrite(LED_BWD, HIGH); + mcopy.begin(mcopy.PROJECTOR_IDENTIFIER); + delay(42); + digitalWrite(LED_FWD, LOW); + digitalWrite(LED_BWD, LOW); +} + +void loop () { + now = millis(); + cmdChar = mcopy.loop(); + cmd(cmdChar); + if (digitalRead(BUTTON) == LOW) { + projector(); + } +} + +void pins () { + pinMode(LED_FWD, OUTPUT); + pinMode(LED_BWD, OUTPUT); + pinMode(BUTTON, INPUT_PULLUP); + + digitalWrite(LED_FWD, LOW); + digitalWrite(LED_BWD, LOW); +} + +void cmd (char val) { + if (val == mcopy.CAMERA_FORWARD) { + projector_direction(true); + } else if (val == mcopy.CAMERA_BACKWARD) { + projector_direction(false); + } else if (val == mcopy.PROJECTOR) { + projector(); + } else if (val == mcopy.STATE) { + state(); + } +} + +void projector_direction (boolean state) { + direction = state; + if (state) { + mcopy.confirm(mcopy.PROJECTOR_FORWARD); + mcopy.log("projector_direction(true)"); + steppers.setDir(0, 1); + steppers.setDir(1, 1); + } else { + mcopy.confirm(mcopy.PROJECTOR_BACKWARD); + mcopy.log("projector_direction(false)"); + steppers.setDir(0, 0); + steppers.setDir(1, 0); + } +} + +void projector_timing_start () { + start = millis(); +} + +void projector_timing_end () { + long end = millis(); + if (projectorFrame == -1) { + projectorFrame = (end - start); + } else { + //rolling mean + projectorFrame = (projectorFrame + (end - start) / 2); + } +} + +void projector () { + int LED = direction ? LED_FWD : LED_BWD; + digitalWrite(LED, HIGH); + steppers.stepBoth(PROJECTOR_STEPS); + mcopy.confirm(mcopy.PROJECTOR); + digitalWrite(LED, LOW); +} + +void state () { + String stateString = String(mcopy.CAMERA_EXPOSURE); + stateString += String(cameraFrame); + stateString += String(mcopy.STATE); + mcopy.print(stateString); +} diff --git a/scripts/ino.sh b/scripts/ino.sh index 8746d08..106f6c7 100644 --- a/scripts/ino.sh +++ b/scripts/ino.sh @@ -22,6 +22,7 @@ SKETCHES=( mcopy_cam_relay mcopy_JKMM100 components/mcopy_light + mcopy_projector_firmware ) for sketch in "${SKETCHES[@]}"; do