#include #define SPU 80 // 20 teeth pulley, 16 microstep, 2mm a tooth belt, 16*200 microsteps per turn == (16*200)/(20*2) == 80 #define PIN_SERVO D6 Servo servo; typedef uint8_t (*CallbackFunction)(uint8_t*, int, uint8_t*); struct EventCallback { String event; CallbackFunction callback; }; float pos[] = {0, 0}; const int motor1StepPin = D10; const int motor1DirPin = D9; const int motor2StepPin = D8; const int motor2DirPin = D7; const int enablePin = D1; void setup() { servo.attach(PIN_SERVO); Serial.begin(9600); // on("light", onLight); on("go", go); on("servo", moveServo); on("motorsOn", motorsOn); on("motorsOff", motorsOff); on("moveTowardsOrigin", moveTowardsOrigin); on("setOrigin", setOrigin); pinMode(motor1StepPin, OUTPUT); pinMode(motor1DirPin, OUTPUT); pinMode(motor2StepPin, OUTPUT); pinMode(motor2DirPin, OUTPUT); pinMode(enablePin, OUTPUT); // enable pin pinMode(PIN_LED, OUTPUT); startupIndicator(); // once startup is finished, indicate to user } void loop() { readSerial(); } void startupIndicator() { // flash LED to indicate board is initialized for (int i = 0; i < 3; i++) { digitalWrite(PIN_LED, 0); delay(200); digitalWrite(PIN_LED, 1); delay(200); } } uint8_t onLight(uint8_t* payload, int length, uint8_t* reply) { uint8_t value = payload[0]; // Serial.println("light it up"); digitalWrite(PIN_LED, value); return 0; } uint8_t motorsOn(uint8_t* payload, int length, uint8_t* reply) { digitalWrite(enablePin, 0); return 0; } uint8_t motorsOff(uint8_t* payload, int length, uint8_t* reply) { digitalWrite(enablePin, 1); return 0; } uint8_t moveTowardsOrigin(uint8_t* payload, int length, uint8_t* reply) { float x = pos[0]; float y = pos[1]; // this ternary may not be neccesary goTo( x + ( x < 0 ? 10 : -10), y + ( y < 0 ? 10 : -10) ); return 0; } uint8_t setOrigin(uint8_t* payload, int length, uint8_t* reply) { pos[0] = 0; pos[1] = 0; return 0; } /* ------------------------------------------------------------ */ int bufferIndex = 0; uint8_t msgBuffer[100]; void readSerial() { while (Serial.available() > 0) { uint8_t incoming = Serial.read(); msgBuffer[bufferIndex] = incoming; if (incoming != 0) { bufferIndex++; continue; // Proceed to the next byte if current byte is not null } // Serial.print("RECEIVED: "); // for (int i = 0; i < bufferIndex; i++) { // Serial.print(msgBuffer[i]); // Serial.print(", "); // } // Serial.println("DONE"); // Now we have a full message, perform COBS decoding uint8_t decoded[bufferIndex]; cobs_decode(decoded, msgBuffer, bufferIndex); // Serial.print("DECODED: "); // for (int i = 0; i < bufferIndex; i++) { // Serial.print(decoded[i]); // Serial.print(", "); // } // Serial.println("DONE"); // Parse the decoded message int i = 0; uint8_t msgLength = decoded[i]; // Serial.print("MSG-LENGTH: "); // Serial.println(msgLength); uint8_t msgArr[msgLength]; i++; while (i < 1 + msgLength) { msgArr[i-1] = decoded[i]; i++; } // Serial.print("MSGARR: "); // for (int i = 0; i < msgLength; i++) { // Serial.print(msgArr[i]); // Serial.print(", "); // } // Serial.println("MSGARR-END"); uint8_t payloadLength = decoded[i]; uint8_t payload[payloadLength]; i++; while (i < 1 + msgLength + 1 + payloadLength) { payload[i-1-msgLength-1] = decoded[i]; i++; } uint8_t msgCount = decoded[i]; // String msg = String((char*)msgArr); String msg = byteArrayToString(msgArr, msgLength); // Serial.println(msg); // printArray("PAYLOAD", payload, payloadLength); // Serial.print("MSGCOUNT: "); // Serial.println(msgCount); bool triggered = triggerEvent(msg, payload, payloadLength, msgCount); bufferIndex = 0; // Reset the buffer for the next message } } /* ------------------------------------------------------------ */ const int MAX_EVENTS = 255; // Maximum number of events to store, adjust as needed EventCallback eventCallbacks[MAX_EVENTS]; int eventCount = 0; const int REPLY_PAYLOAD_LENGTH = 255; uint8_t reply[REPLY_PAYLOAD_LENGTH]; void on(String event, CallbackFunction callback) { if (eventCount < MAX_EVENTS) { eventCallbacks[eventCount].event = event; eventCallbacks[eventCount].callback = callback; eventCount = (eventCount + 1) % MAX_EVENTS; } else { // Serial.println("Max number of events reached. Wrapping events."); } } bool triggerEvent(String event, uint8_t* payload, int payloadLength, uint8_t msgCount) { for (int i = 0; i < eventCount; i++) { if (eventCallbacks[i].event == event) { // want to pass payload and payloadLength, need to get response payload uint8_t reply_length = eventCallbacks[i].callback(payload, payloadLength, reply); sendAck(msgCount, reply, reply_length); return true; } } // Serial.println(" No event registered."); return false; } const int arrayLength = 7; // + length; uint8_t byteArray[arrayLength]; void sendAck(uint8_t msgCount, uint8_t* reply, uint8_t length) { // Serial.println("SEND ACK"); // int arrayLength = 7; // + length; // static uint8_t byteArray[arrayLength]; byteArray[0] = 0x03; byteArray[1] = 0x61; byteArray[2] = 0x63; byteArray[3] = 0x6B; byteArray[4] = 0x00; byteArray[5] = msgCount; byteArray[6] = 0x0A; // byteArray[4] = length; // for (int i = 0; i < length; i++) { // byteArray[i+5] = reply[i]; // } // byteArray[5+length] = msgCount; // byteArray[6+length] = 0x0A; // Serial.println(msgCount); // printArray("ACK", byteArray, 5+length); Serial.write(byteArray, arrayLength); // uint8_t byteArrayEncoded[arrayLength + 2]; // +2 for possible COBS overhead // cobs_encode(byteArrayEncoded, byteArray, arrayLength); // Serial.write(byteArrayEncoded, arrayLength + 2); // printArray("ENCODED-ACK", byteArray, 5+length); } /* ------------------------------------------------------------ */ void cobs_encode(uint8_t *dst, const uint8_t *src, size_t len) { size_t read_index = 0; size_t write_index = 1; size_t code_index = 0; uint8_t code = 1; while (read_index < len) { if (src[read_index] == 0) { dst[code_index] = code; code = 1; code_index = write_index++; read_index++; } else { dst[write_index++] = src[read_index++]; code++; if (code == 0xFF) { dst[code_index] = code; code = 1; code_index = write_index++; } } } dst[code_index] = code; // Add trailing zero if (write_index < len + 2) { dst[write_index] = 0; } } void cobs_decode(uint8_t *dst, const uint8_t *src, size_t len) { size_t i, j, dst_i = 0; for (i = 0; i < len;) { uint8_t code = src[i++]; for (j = 1; j < code && i < len; j++) { dst[dst_i++] = src[i++]; } if (code < 0xFF && dst_i < len) { dst[dst_i++] = 0; } } } /* ------------------------------------------------------------ */ // TODO: THINK THIS IS BUGGY void cobs_print(const String& message) { // Convert the message to a byte array int length = message.length(); uint8_t byteArray[length + 1]; // +1 for the null terminator message.getBytes(byteArray, length + 1); // Prepare the buffer for the encoded message uint8_t encoded[length + 2]; // +2 for possible COBS overhead // Perform COBS encoding cobs_encode(encoded, byteArray, length + 1); // Send the encoded message Serial.write(encoded, length + 2); // Write the encoded bytes } /* ------------------------------------------------------------ */ float read_float(uint8_t* buffer, int index) { uint8_t byte0 = buffer[index]; uint8_t byte1 = buffer[index+1]; uint8_t byte2 = buffer[index+2]; uint8_t byte3 = buffer[index+3]; uint8_t byteArray[] = {byte0, byte1, byte2, byte3}; float floatValue; memcpy(&floatValue, &byteArray, sizeof(floatValue)); return floatValue; } int read_int(uint8_t* buffer, int index) { uint8_t byte0 = buffer[index]; uint8_t byte1 = buffer[index+1]; uint8_t byte2 = buffer[index+2]; uint8_t byte3 = buffer[index+3]; uint8_t byteArray[] = {byte0, byte1, byte2, byte3}; int value; memcpy(&value, &byteArray, sizeof(value)); return value; } String byteArrayToString(byte arr[], int length) { String result = ""; for (int i = 0; i < length; i++) { result += (char)arr[i]; // Convert each byte to a character and append it to the string } return result; } /* ------------------------------------------------------------------------ */ #define EPSILON 0.01 void goTo(float x, float y) { // Serial.println("START GOTO"); // Set your target distances for each motor (in steps) float motor1Target = (x + y) - pos[0]; float motor2Target = (y - x) - pos[1]; // Set motor direction based on target values digitalWrite(motor1DirPin, motor1Target >= 0 ? HIGH : LOW); digitalWrite(motor2DirPin, motor2Target >= 0 ? HIGH : LOW); // Calculate the relative speeds and maximum duration for both motors float maxSteps = max(abs(motor1Target), abs(motor2Target)); float motor1Speed = abs(motor1Target) / maxSteps; float motor2Speed = abs(motor2Target) / maxSteps; unsigned long stepDuration = 500; // The time it takes to perform one step in microseconds unsigned long motor1StepInterval = stepDuration / motor1Speed; unsigned long motor2StepInterval = stepDuration / motor2Speed; // Initialize variables for step timing unsigned long motor1PrevStepTime = 0; unsigned long motor2PrevStepTime = 0; float motor1Step = 0; float motor2Step = 0; // Loop until both motors reach their target steps while (abs(motor1Target - motor1Step) > EPSILON || abs(motor2Target - motor2Step) > EPSILON) { unsigned long currentTime = micros(); // Motor 1 if (abs(motor1Target - motor1Step) > EPSILON && ((currentTime - motor1PrevStepTime) >= motor1StepInterval)) { digitalWrite(motor1StepPin, HIGH); delayMicroseconds(1); digitalWrite(motor1StepPin, LOW); delayMicroseconds(1); motor1Step += (motor1Target >= 0 ? 1.0 : -1.0)/SPU; motor1PrevStepTime = currentTime; } // Motor 2 if (abs(motor2Target - motor2Step) > EPSILON && ((currentTime - motor2PrevStepTime) >= motor2StepInterval)) { digitalWrite(motor2StepPin, HIGH); delayMicroseconds(1); digitalWrite(motor2StepPin, LOW); delayMicroseconds(1); motor2Step += (motor2Target >= 0 ? 1.0 : -1.0)/SPU; motor2PrevStepTime = currentTime; } } // Serial.println("END GOTO"); pos[0] += motor1Step; pos[1] += motor2Step; } uint8_t go(uint8_t* payload, int length, uint8_t* reply) { float x = read_float(payload, 0); float y = read_float(payload, 4); goTo(x, y); return 0; } uint8_t moveServo(uint8_t* payload, int length, uint8_t* reply) { int angle = read_int(payload, 0); servo.writeMicroseconds(angle); return 0; } /* ------ */ void printArray(String label, uint8_t* arr, int arrSize) { Serial.print(label); Serial.print("-BEGIN: "); for (int i = 0; i < arrSize; i++) { Serial.print(arr[i]); Serial.print(", "); } Serial.print(label); Serial.println("-END"); }