tangled
alpha
login
or
join now
dunkirk.sh
/
myrus
0
fork
atom
a scrappy gimbal that insults you in shakespearean english
0
fork
atom
overview
issues
pulls
pipelines
feat: add blot firmware
Kieran Klukas
1 year ago
100c7fa5
db76e47b
+456
1 changed file
expand all
collapse all
unified
split
blot.ino
+456
blot.ino
···
1
1
+
#include <Servo.h>
2
2
+
3
3
+
#define SPU 80 // 20 teeth pulley, 16 microstep, 2mm a tooth belt, 16*200 microsteps per turn == (16*200)/(20*2) == 80
4
4
+
#define PIN_SERVO D6
5
5
+
6
6
+
Servo servo;
7
7
+
8
8
+
typedef uint8_t (*CallbackFunction)(uint8_t*, int, uint8_t*);
9
9
+
10
10
+
struct EventCallback {
11
11
+
String event;
12
12
+
CallbackFunction callback;
13
13
+
};
14
14
+
15
15
+
16
16
+
float pos[] = {0, 0};
17
17
+
18
18
+
const int motor1StepPin = D10;
19
19
+
const int motor1DirPin = D9;
20
20
+
const int motor2StepPin = D8;
21
21
+
const int motor2DirPin = D7;
22
22
+
23
23
+
const int enablePin = D1;
24
24
+
25
25
+
void setup() {
26
26
+
servo.attach(PIN_SERVO);
27
27
+
28
28
+
Serial.begin(9600);
29
29
+
30
30
+
// on("light", onLight);
31
31
+
on("go", go);
32
32
+
on("servo", moveServo);
33
33
+
on("motorsOn", motorsOn);
34
34
+
on("motorsOff", motorsOff);
35
35
+
on("moveTowardsOrigin", moveTowardsOrigin);
36
36
+
on("setOrigin", setOrigin);
37
37
+
38
38
+
pinMode(motor1StepPin, OUTPUT);
39
39
+
pinMode(motor1DirPin, OUTPUT);
40
40
+
pinMode(motor2StepPin, OUTPUT);
41
41
+
pinMode(motor2DirPin, OUTPUT);
42
42
+
43
43
+
pinMode(enablePin, OUTPUT); // enable pin
44
44
+
45
45
+
pinMode(PIN_LED, OUTPUT);
46
46
+
47
47
+
startupIndicator(); // once startup is finished, indicate to user
48
48
+
}
49
49
+
50
50
+
void loop() {
51
51
+
readSerial();
52
52
+
}
53
53
+
54
54
+
void startupIndicator() {
55
55
+
// flash LED to indicate board is initialized
56
56
+
for (int i = 0; i < 3; i++) {
57
57
+
digitalWrite(PIN_LED, 0);
58
58
+
delay(200);
59
59
+
digitalWrite(PIN_LED, 1);
60
60
+
delay(200);
61
61
+
}
62
62
+
}
63
63
+
64
64
+
uint8_t onLight(uint8_t* payload, int length, uint8_t* reply) {
65
65
+
uint8_t value = payload[0];
66
66
+
67
67
+
// Serial.println("light it up");
68
68
+
69
69
+
digitalWrite(PIN_LED, value);
70
70
+
71
71
+
return 0;
72
72
+
}
73
73
+
74
74
+
uint8_t motorsOn(uint8_t* payload, int length, uint8_t* reply) {
75
75
+
digitalWrite(enablePin, 0);
76
76
+
return 0;
77
77
+
}
78
78
+
79
79
+
uint8_t motorsOff(uint8_t* payload, int length, uint8_t* reply) {
80
80
+
digitalWrite(enablePin, 1);
81
81
+
return 0;
82
82
+
}
83
83
+
84
84
+
uint8_t moveTowardsOrigin(uint8_t* payload, int length, uint8_t* reply) {
85
85
+
float x = pos[0];
86
86
+
float y = pos[1];
87
87
+
88
88
+
// this ternary may not be neccesary
89
89
+
goTo(
90
90
+
x + ( x < 0 ? 10 : -10),
91
91
+
y + ( y < 0 ? 10 : -10)
92
92
+
);
93
93
+
94
94
+
return 0;
95
95
+
}
96
96
+
97
97
+
uint8_t setOrigin(uint8_t* payload, int length, uint8_t* reply) {
98
98
+
pos[0] = 0;
99
99
+
pos[1] = 0;
100
100
+
101
101
+
return 0;
102
102
+
}
103
103
+
104
104
+
105
105
+
/* ------------------------------------------------------------ */
106
106
+
107
107
+
int bufferIndex = 0;
108
108
+
uint8_t msgBuffer[100];
109
109
+
110
110
+
void readSerial() {
111
111
+
while (Serial.available() > 0) {
112
112
+
uint8_t incoming = Serial.read();
113
113
+
114
114
+
msgBuffer[bufferIndex] = incoming;
115
115
+
116
116
+
if (incoming != 0) {
117
117
+
bufferIndex++;
118
118
+
continue; // Proceed to the next byte if current byte is not null
119
119
+
}
120
120
+
121
121
+
// Serial.print("RECEIVED: ");
122
122
+
// for (int i = 0; i < bufferIndex; i++) {
123
123
+
// Serial.print(msgBuffer[i]);
124
124
+
// Serial.print(", ");
125
125
+
// }
126
126
+
// Serial.println("DONE");
127
127
+
128
128
+
// Now we have a full message, perform COBS decoding
129
129
+
uint8_t decoded[bufferIndex];
130
130
+
cobs_decode(decoded, msgBuffer, bufferIndex);
131
131
+
132
132
+
// Serial.print("DECODED: ");
133
133
+
// for (int i = 0; i < bufferIndex; i++) {
134
134
+
// Serial.print(decoded[i]);
135
135
+
// Serial.print(", ");
136
136
+
// }
137
137
+
// Serial.println("DONE");
138
138
+
139
139
+
// Parse the decoded message
140
140
+
int i = 0;
141
141
+
142
142
+
uint8_t msgLength = decoded[i];
143
143
+
// Serial.print("MSG-LENGTH: ");
144
144
+
// Serial.println(msgLength);
145
145
+
146
146
+
uint8_t msgArr[msgLength];
147
147
+
i++;
148
148
+
while (i < 1 + msgLength) {
149
149
+
msgArr[i-1] = decoded[i];
150
150
+
i++;
151
151
+
}
152
152
+
153
153
+
// Serial.print("MSGARR: ");
154
154
+
// for (int i = 0; i < msgLength; i++) {
155
155
+
// Serial.print(msgArr[i]);
156
156
+
// Serial.print(", ");
157
157
+
// }
158
158
+
// Serial.println("MSGARR-END");
159
159
+
160
160
+
uint8_t payloadLength = decoded[i];
161
161
+
uint8_t payload[payloadLength];
162
162
+
i++;
163
163
+
while (i < 1 + msgLength + 1 + payloadLength) {
164
164
+
payload[i-1-msgLength-1] = decoded[i];
165
165
+
i++;
166
166
+
}
167
167
+
168
168
+
uint8_t msgCount = decoded[i];
169
169
+
170
170
+
// String msg = String((char*)msgArr);
171
171
+
String msg = byteArrayToString(msgArr, msgLength);
172
172
+
173
173
+
// Serial.println(msg);
174
174
+
175
175
+
// printArray("PAYLOAD", payload, payloadLength);
176
176
+
177
177
+
// Serial.print("MSGCOUNT: ");
178
178
+
// Serial.println(msgCount);
179
179
+
180
180
+
bool triggered = triggerEvent(msg, payload, payloadLength, msgCount);
181
181
+
182
182
+
bufferIndex = 0; // Reset the buffer for the next message
183
183
+
}
184
184
+
}
185
185
+
186
186
+
/* ------------------------------------------------------------ */
187
187
+
188
188
+
189
189
+
190
190
+
const int MAX_EVENTS = 255; // Maximum number of events to store, adjust as needed
191
191
+
EventCallback eventCallbacks[MAX_EVENTS];
192
192
+
int eventCount = 0;
193
193
+
194
194
+
const int REPLY_PAYLOAD_LENGTH = 255;
195
195
+
uint8_t reply[REPLY_PAYLOAD_LENGTH];
196
196
+
197
197
+
void on(String event, CallbackFunction callback) {
198
198
+
if (eventCount < MAX_EVENTS) {
199
199
+
eventCallbacks[eventCount].event = event;
200
200
+
eventCallbacks[eventCount].callback = callback;
201
201
+
eventCount = (eventCount + 1) % MAX_EVENTS;
202
202
+
} else {
203
203
+
// Serial.println("Max number of events reached. Wrapping events.");
204
204
+
}
205
205
+
}
206
206
+
207
207
+
bool triggerEvent(String event, uint8_t* payload, int payloadLength, uint8_t msgCount) {
208
208
+
for (int i = 0; i < eventCount; i++) {
209
209
+
if (eventCallbacks[i].event == event) {
210
210
+
// want to pass payload and payloadLength, need to get response payload
211
211
+
uint8_t reply_length = eventCallbacks[i].callback(payload, payloadLength, reply);
212
212
+
213
213
+
sendAck(msgCount, reply, reply_length);
214
214
+
return true;
215
215
+
}
216
216
+
}
217
217
+
218
218
+
// Serial.println(" No event registered.");
219
219
+
return false;
220
220
+
}
221
221
+
222
222
+
const int arrayLength = 7; // + length;
223
223
+
uint8_t byteArray[arrayLength];
224
224
+
225
225
+
void sendAck(uint8_t msgCount, uint8_t* reply, uint8_t length) {
226
226
+
// Serial.println("SEND ACK");
227
227
+
228
228
+
// int arrayLength = 7; // + length;
229
229
+
// static uint8_t byteArray[arrayLength];
230
230
+
231
231
+
byteArray[0] = 0x03;
232
232
+
byteArray[1] = 0x61;
233
233
+
byteArray[2] = 0x63;
234
234
+
byteArray[3] = 0x6B;
235
235
+
byteArray[4] = 0x00;
236
236
+
byteArray[5] = msgCount;
237
237
+
byteArray[6] = 0x0A;
238
238
+
239
239
+
// byteArray[4] = length;
240
240
+
// for (int i = 0; i < length; i++) {
241
241
+
// byteArray[i+5] = reply[i];
242
242
+
// }
243
243
+
// byteArray[5+length] = msgCount;
244
244
+
// byteArray[6+length] = 0x0A;
245
245
+
246
246
+
// Serial.println(msgCount);
247
247
+
// printArray("ACK", byteArray, 5+length);
248
248
+
249
249
+
Serial.write(byteArray, arrayLength);
250
250
+
251
251
+
// uint8_t byteArrayEncoded[arrayLength + 2]; // +2 for possible COBS overhead
252
252
+
// cobs_encode(byteArrayEncoded, byteArray, arrayLength);
253
253
+
// Serial.write(byteArrayEncoded, arrayLength + 2);
254
254
+
255
255
+
// printArray("ENCODED-ACK", byteArray, 5+length);
256
256
+
257
257
+
}
258
258
+
259
259
+
/* ------------------------------------------------------------ */
260
260
+
261
261
+
void cobs_encode(uint8_t *dst, const uint8_t *src, size_t len) {
262
262
+
size_t read_index = 0;
263
263
+
size_t write_index = 1;
264
264
+
size_t code_index = 0;
265
265
+
uint8_t code = 1;
266
266
+
267
267
+
while (read_index < len) {
268
268
+
if (src[read_index] == 0) {
269
269
+
dst[code_index] = code;
270
270
+
code = 1;
271
271
+
code_index = write_index++;
272
272
+
read_index++;
273
273
+
} else {
274
274
+
dst[write_index++] = src[read_index++];
275
275
+
code++;
276
276
+
if (code == 0xFF) {
277
277
+
dst[code_index] = code;
278
278
+
code = 1;
279
279
+
code_index = write_index++;
280
280
+
}
281
281
+
}
282
282
+
}
283
283
+
284
284
+
dst[code_index] = code;
285
285
+
286
286
+
// Add trailing zero
287
287
+
if (write_index < len + 2) {
288
288
+
dst[write_index] = 0;
289
289
+
}
290
290
+
}
291
291
+
292
292
+
void cobs_decode(uint8_t *dst, const uint8_t *src, size_t len) {
293
293
+
size_t i, j, dst_i = 0;
294
294
+
for (i = 0; i < len;) {
295
295
+
uint8_t code = src[i++];
296
296
+
for (j = 1; j < code && i < len; j++) {
297
297
+
dst[dst_i++] = src[i++];
298
298
+
}
299
299
+
if (code < 0xFF && dst_i < len) {
300
300
+
dst[dst_i++] = 0;
301
301
+
}
302
302
+
}
303
303
+
}
304
304
+
305
305
+
/* ------------------------------------------------------------ */
306
306
+
307
307
+
// TODO: THINK THIS IS BUGGY
308
308
+
void cobs_print(const String& message) {
309
309
+
// Convert the message to a byte array
310
310
+
int length = message.length();
311
311
+
uint8_t byteArray[length + 1]; // +1 for the null terminator
312
312
+
message.getBytes(byteArray, length + 1);
313
313
+
314
314
+
// Prepare the buffer for the encoded message
315
315
+
uint8_t encoded[length + 2]; // +2 for possible COBS overhead
316
316
+
317
317
+
// Perform COBS encoding
318
318
+
cobs_encode(encoded, byteArray, length + 1);
319
319
+
320
320
+
// Send the encoded message
321
321
+
Serial.write(encoded, length + 2); // Write the encoded bytes
322
322
+
}
323
323
+
324
324
+
/* ------------------------------------------------------------ */
325
325
+
326
326
+
float read_float(uint8_t* buffer, int index) {
327
327
+
uint8_t byte0 = buffer[index];
328
328
+
uint8_t byte1 = buffer[index+1];
329
329
+
uint8_t byte2 = buffer[index+2];
330
330
+
uint8_t byte3 = buffer[index+3];
331
331
+
332
332
+
uint8_t byteArray[] = {byte0, byte1, byte2, byte3};
333
333
+
float floatValue;
334
334
+
memcpy(&floatValue, &byteArray, sizeof(floatValue));
335
335
+
336
336
+
return floatValue;
337
337
+
}
338
338
+
339
339
+
int read_int(uint8_t* buffer, int index) {
340
340
+
uint8_t byte0 = buffer[index];
341
341
+
uint8_t byte1 = buffer[index+1];
342
342
+
uint8_t byte2 = buffer[index+2];
343
343
+
uint8_t byte3 = buffer[index+3];
344
344
+
345
345
+
uint8_t byteArray[] = {byte0, byte1, byte2, byte3};
346
346
+
int value;
347
347
+
memcpy(&value, &byteArray, sizeof(value));
348
348
+
349
349
+
return value;
350
350
+
}
351
351
+
352
352
+
String byteArrayToString(byte arr[], int length) {
353
353
+
String result = "";
354
354
+
355
355
+
for (int i = 0; i < length; i++) {
356
356
+
result += (char)arr[i]; // Convert each byte to a character and append it to the string
357
357
+
}
358
358
+
359
359
+
return result;
360
360
+
}
361
361
+
362
362
+
/* ------------------------------------------------------------------------ */
363
363
+
364
364
+
#define EPSILON 0.01
365
365
+
366
366
+
void goTo(float x, float y) {
367
367
+
368
368
+
// Serial.println("START GOTO");
369
369
+
370
370
+
// Set your target distances for each motor (in steps)
371
371
+
float motor1Target = (x + y) - pos[0];
372
372
+
float motor2Target = (y - x) - pos[1];
373
373
+
374
374
+
// Set motor direction based on target values
375
375
+
digitalWrite(motor1DirPin, motor1Target >= 0 ? HIGH : LOW);
376
376
+
digitalWrite(motor2DirPin, motor2Target >= 0 ? HIGH : LOW);
377
377
+
378
378
+
// Calculate the relative speeds and maximum duration for both motors
379
379
+
float maxSteps = max(abs(motor1Target), abs(motor2Target));
380
380
+
float motor1Speed = abs(motor1Target) / maxSteps;
381
381
+
float motor2Speed = abs(motor2Target) / maxSteps;
382
382
+
383
383
+
unsigned long stepDuration = 500; // The time it takes to perform one step in microseconds
384
384
+
unsigned long motor1StepInterval = stepDuration / motor1Speed;
385
385
+
unsigned long motor2StepInterval = stepDuration / motor2Speed;
386
386
+
387
387
+
// Initialize variables for step timing
388
388
+
unsigned long motor1PrevStepTime = 0;
389
389
+
unsigned long motor2PrevStepTime = 0;
390
390
+
float motor1Step = 0;
391
391
+
float motor2Step = 0;
392
392
+
393
393
+
// Loop until both motors reach their target steps
394
394
+
while (abs(motor1Target - motor1Step) > EPSILON || abs(motor2Target - motor2Step) > EPSILON) {
395
395
+
396
396
+
397
397
+
unsigned long currentTime = micros();
398
398
+
399
399
+
// Motor 1
400
400
+
if (abs(motor1Target - motor1Step) > EPSILON && ((currentTime - motor1PrevStepTime) >= motor1StepInterval)) {
401
401
+
digitalWrite(motor1StepPin, HIGH);
402
402
+
delayMicroseconds(1);
403
403
+
digitalWrite(motor1StepPin, LOW);
404
404
+
delayMicroseconds(1);
405
405
+
406
406
+
motor1Step += (motor1Target >= 0 ? 1.0 : -1.0)/SPU;
407
407
+
motor1PrevStepTime = currentTime;
408
408
+
}
409
409
+
410
410
+
// Motor 2
411
411
+
if (abs(motor2Target - motor2Step) > EPSILON && ((currentTime - motor2PrevStepTime) >= motor2StepInterval)) {
412
412
+
digitalWrite(motor2StepPin, HIGH);
413
413
+
delayMicroseconds(1);
414
414
+
digitalWrite(motor2StepPin, LOW);
415
415
+
delayMicroseconds(1);
416
416
+
417
417
+
motor2Step += (motor2Target >= 0 ? 1.0 : -1.0)/SPU;
418
418
+
motor2PrevStepTime = currentTime;
419
419
+
}
420
420
+
}
421
421
+
422
422
+
// Serial.println("END GOTO");
423
423
+
424
424
+
pos[0] += motor1Step;
425
425
+
pos[1] += motor2Step;
426
426
+
}
427
427
+
428
428
+
uint8_t go(uint8_t* payload, int length, uint8_t* reply) {
429
429
+
float x = read_float(payload, 0);
430
430
+
float y = read_float(payload, 4);
431
431
+
432
432
+
goTo(x, y);
433
433
+
434
434
+
return 0;
435
435
+
}
436
436
+
437
437
+
uint8_t moveServo(uint8_t* payload, int length, uint8_t* reply) {
438
438
+
int angle = read_int(payload, 0);
439
439
+
440
440
+
servo.writeMicroseconds(angle);
441
441
+
442
442
+
return 0;
443
443
+
}
444
444
+
445
445
+
/* ------ */
446
446
+
447
447
+
void printArray(String label, uint8_t* arr, int arrSize) {
448
448
+
Serial.print(label);
449
449
+
Serial.print("-BEGIN: ");
450
450
+
for (int i = 0; i < arrSize; i++) {
451
451
+
Serial.print(arr[i]);
452
452
+
Serial.print(", ");
453
453
+
}
454
454
+
Serial.print(label);
455
455
+
Serial.println("-END");
456
456
+
}