diff --git a/code/cane_control/cane_control.ino b/code/cane_control/cane_control.ino new file mode 100644 index 0000000000000000000000000000000000000000..8215a49421851085cf596190b52e0486a82a2c71 --- /dev/null +++ b/code/cane_control/cane_control.ino @@ -0,0 +1,184 @@ +#include <TMC2209.h> +#include <AccelStepper.h> +#include <Adafruit_SSD1306.h> + +#define PIN_STEP1 28 +#define PIN_DIR1 29 +#define PIN_STEP2 26 +#define PIN_DIR2 27 +#define PIN_BTN 2 +#define PIN_ENC_A 3 +#define PIN_ENC_B 4 +#define READ_FAST(pin) ((sio_hw->gpio_in & (1 << pin)) > 0) + +#define SCREEN_WIDTH 128 // OLED display width, in pixels +#define SCREEN_HEIGHT 64 // OLED display height, in pixels + +#define LENGTH_MIN (0.05) +#define LENGTH_MAX (4000.0) + +#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) +#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32 + +#define SERIAL_BAUD_RATE 115200 +#define RUN_CURRENT_PERCENT 80 +#define STALL_GUARD_THRESHOLD 80 +#define HOMING_VELOCITY 400 + +#define MOVE_SPEED 800 +#define MOVE_ACC 1200 + +HardwareSerial & serial_stream = Serial1; + +Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); + +AccelStepper stepper1(AccelStepper::DRIVER, PIN_STEP1, PIN_DIR1); +AccelStepper stepper2(AccelStepper::DRIVER, PIN_STEP2, PIN_DIR2); + +TMC2209 stepper_driver1; +TMC2209 stepper_driver2; + +int state_now = 0b00; +int state_prev = 0b00; + +int lookup_move[] = {0,-1,1,-2,1,0,2,-1,-1,2,0,1,-2,1,-1,0}; + +float length = 5.00; + +int counter = 0; +int active = false; +bool update_screen = true; + +int k = 0; + +inline void update_knob() { + int key = (state_now << 2) | state_prev; + if (!active) { + k += lookup_move[key]; + if (k >= 4) { + length += 0.05; + k -= 4; + if (length > LENGTH_MAX) { + length = LENGTH_MAX; + } + } else if (k <= -4) { + length -= 0.05; + k += 4; + if (length < LENGTH_MIN) { + length = LENGTH_MIN; + } + } + update_screen = true; + } + state_prev = state_now; +} + +void pin_AB_change() { + state_now = (READ_FAST(PIN_ENC_B) << 1) | READ_FAST(PIN_ENC_A); + update_knob(); +} + +void homing() { + stepper_driver2.moveAtVelocity(-HOMING_VELOCITY); + delay(200); + stepper_driver2.moveAtVelocity(HOMING_VELOCITY); + delay(100); + bool done = false; + while (!done) { + uint16_t stall_guard_result = stepper_driver2.getStallGuardResult(); + done = stall_guard_result < STALL_GUARD_THRESHOLD; + } + stepper_driver2.moveAtVelocity(0); + stepper_driver2.enable(); +} + +void setup() { + Serial.begin(0); + + pinMode(PIN_ENC_A, INPUT); + pinMode(PIN_ENC_B, INPUT); + pinMode(PIN_BTN, INPUT_PULLUP); + + display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS); + display.setTextSize(1); // Normal 1:1 pixel scale + display.setTextColor(SSD1306_WHITE); // Draw white text + display.display(); + delay(100); + display.clearDisplay(); + display.cp437(true); + + stepper_driver1.setup(serial_stream, SERIAL_BAUD_RATE, TMC2209::SERIAL_ADDRESS_1); + stepper_driver1.setRunCurrent(RUN_CURRENT_PERCENT); + stepper_driver1.setMicrostepsPerStep(4); + + delay(50); + + stepper_driver2.setup(serial_stream, SERIAL_BAUD_RATE, TMC2209::SERIAL_ADDRESS_0); + stepper_driver2.setRunCurrent(RUN_CURRENT_PERCENT); + stepper_driver2.setMicrostepsPerStep(4); + stepper_driver2.enable(); + + delay(50); + + display.clearDisplay(); + display.setCursor(0, 0); + display.print("Homing..."); + display.display(); + + homing(); + + stepper1.setMaxSpeed(MOVE_SPEED); + stepper1.setAcceleration(MOVE_ACC); + + stepper2.setMaxSpeed(MOVE_SPEED); + stepper2.setAcceleration(MOVE_ACC); + + state_now = READ_FAST(PIN_ENC_A) | (READ_FAST(PIN_ENC_B) << 1); + state_prev = state_now; + + attachInterrupt(digitalPinToInterrupt(PIN_ENC_A), pin_AB_change, CHANGE); + attachInterrupt(digitalPinToInterrupt(PIN_ENC_B), pin_AB_change, CHANGE); +} + +void loop() { + static int btn_pressed = false; + + int btn_pressed_now = !digitalRead(PIN_BTN); + + if (btn_pressed_now && !btn_pressed) { + active = !active; + update_screen = true; + if (active) { + stepper_driver1.enable(); + } else { + stepper_driver1.disable(); + } + } + + if (active) { + stepper1.moveTo(800); + stepper1.runToPosition(); + stepper1.setCurrentPosition(0); + active = false; + update_screen = true; + } + + if (update_screen) { + update_screen = false; + display.clearDisplay(); + display.setCursor(0, 0); + display.printf("Length: %8.2f in\n", length); + + display.setCursor(0, 16); + display.printf("Counter: %7d cuts\n", counter); + + display.setCursor(0, 40); + display.println(active ? "RUNNING..." : "STOPPED"); + display.setCursor(0, 56); + display.println(active ? "[ press to stop ]" : "[ press to start ]"); + display.display(); + } + + delay(1); + btn_pressed = btn_pressed_now; +}