-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSyringePumpControlBoardCode.cpp
More file actions
373 lines (314 loc) · 11.3 KB
/
Copy pathSyringePumpControlBoardCode.cpp
File metadata and controls
373 lines (314 loc) · 11.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
/*
============================================================================
POSEIDON SYRINGE PUMP FIRMWARE — Octopus V1.1 / 8 x TMC2209 Expanded Port
============================================================================
Targets a BigTreeTech Octopus V1.1 (STM32F446ZE) running up to EIGHT
TMC2209 driver modules in STEP/DIR/ENABLE ("standalone") mode.
The packet framing architecture scales the original 3-pump design to
fully utilize MOTOR0 through MOTOR7 sockets.
NOTE: Verify the pin table below against your board's schematic/silkscreen
before flashing — a swapped enable pin or wrong polarity can damage a
TMC2209 driver.
============================================================================
*/
#include <AccelStepper.h>
// ----------------------------------------------------------------------
// Motor / motion constants
// ----------------------------------------------------------------------
#define MOTOR_STEPS 200 // full steps/rev of the pump stepper motors
#define MICROSTEPS 16 // MUST match the physical MS1/MS2 jumpers
#define TOTAL_STEPS (MOTOR_STEPS * MICROSTEPS)
#define DEFAULT_SPEED 1000.0 // default steps/sec
#define DEFAULT_ACCEL 5000.0 // default steps/sec^2
// ----------------------------------------------------------------------
// Octopus V1.1 MOTOR0 through MOTOR7 socket pins
// Confirmed against BigTreeTech pin definitions for STM32F446ZE
// (double-check against your own board revision before relying on this)
// ----------------------------------------------------------------------
#define M0_STEP_PIN PF13
#define M0_DIR_PIN PF12
#define M0_ENABLE_PIN PF14
#define M1_STEP_PIN PG0
#define M1_DIR_PIN PG1
#define M1_ENABLE_PIN PF15
#define M2_STEP_PIN PF11
#define M2_DIR_PIN PG3
#define M2_ENABLE_PIN PG5
#define M3_STEP_PIN PG4
#define M3_DIR_PIN PC1
#define M3_ENABLE_PIN PA0
#define M4_STEP_PIN PF9
#define M4_DIR_PIN PF10
#define M4_ENABLE_PIN PG2
#define M5_STEP_PIN PC13
#define M5_DIR_PIN PF0
#define M5_ENABLE_PIN PF1
#define M6_STEP_PIN PE2
#define M6_DIR_PIN PE3
#define M6_ENABLE_PIN PE4
#define M7_STEP_PIN PE6
#define M7_DIR_PIN PA14
#define M7_ENABLE_PIN PE5
// TMC2209 ENABLE pins are active-LOW
#define DRIVER_ENABLE_ACTIVE_LOW true
#define BAUD_RATE 230400 // USB-CDC ignores the baud value, but kept for protocol matching
// ----------------------------------------------------------------------
// AccelStepper instances — 8 independent axes
// ----------------------------------------------------------------------
AccelStepper stepper1(AccelStepper::DRIVER, M0_STEP_PIN, M0_DIR_PIN);
AccelStepper stepper2(AccelStepper::DRIVER, M1_STEP_PIN, M1_DIR_PIN);
AccelStepper stepper3(AccelStepper::DRIVER, M2_STEP_PIN, M2_DIR_PIN);
AccelStepper stepper4(AccelStepper::DRIVER, M3_STEP_PIN, M3_DIR_PIN);
AccelStepper stepper5(AccelStepper::DRIVER, M4_STEP_PIN, M4_DIR_PIN);
AccelStepper stepper6(AccelStepper::DRIVER, M5_STEP_PIN, M5_DIR_PIN);
AccelStepper stepper7(AccelStepper::DRIVER, M6_STEP_PIN, M6_DIR_PIN);
AccelStepper stepper8(AccelStepper::DRIVER, M7_STEP_PIN, M7_DIR_PIN);
AccelStepper steppers[8] = {stepper1, stepper2, stepper3, stepper4, stepper5, stepper6, stepper7, stepper8};
const int enablePins[8] = {M0_ENABLE_PIN, M1_ENABLE_PIN, M2_ENABLE_PIN, M3_ENABLE_PIN, M4_ENABLE_PIN, M5_ENABLE_PIN, M6_ENABLE_PIN, M7_ENABLE_PIN};
// ----------------------------------------------------------------------
// Serial packet parsing state (Expanded array flags for 8 channels)
// ----------------------------------------------------------------------
const byte buffSize = 128; // Increased buffer room for long optional string chains
char inputBuffer[buffSize];
const char startMarker = '<';
const char endMarker = '>';
byte bytesRecvd = 0;
boolean readInProgress = false;
boolean newDataFromPC = false;
char mode[buffSize] = {0};
char setting[buffSize] = {0};
char motorIDStr[buffSize] = {0};
int motors[8] = {0};
float value = 0.0;
char dir[buffSize] = {0};
float distances[8] = {0};
float oldDistanceLeft[8] = {0};
unsigned long curMillis;
// Forward Declarations
void getDataFromPC();
void parseData();
void executeThisFunction();
void replyToPC();
void sendDistanceToPC(int mIndex);
void updateSettings();
void runFew();
void stopAll();
int array_sum(int *array, int len);
void clearVariables();
bool parsePacketFields(); // returns false if the packet was malformed
// ============================================================================
void setup() {
Serial.begin(BAUD_RATE);
// Configure and actively enable all eight TMC2209 drivers.
for (int i = 0; i < 8; i++) {
pinMode(enablePins[i], OUTPUT);
digitalWrite(enablePins[i], DRIVER_ENABLE_ACTIVE_LOW ? LOW : HIGH); // active low enable
steppers[i].setMaxSpeed(DEFAULT_SPEED);
steppers[i].setAcceleration(DEFAULT_ACCEL);
}
#ifdef LED_BUILTIN
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
delay(300);
digitalWrite(LED_BUILTIN, LOW);
#endif
Serial.println("<Arduino is ready>");
}
// ============================================================================
void loop() {
curMillis = millis();
getDataFromPC();
// Real-time tracking loop feedback to PC if axes are running
for (int i = 0; i < 8; i++) {
if (steppers[i].distanceToGo() != 0) {
sendDistanceToPC(i);
}
}
}
// ----------------------------------------------------------------------
// Read serial byte buffer streams enclosed between < and >
// ----------------------------------------------------------------------
void getDataFromPC() {
if (Serial.available() > 0) {
char x = Serial.read();
if (x == endMarker) {
readInProgress = false;
newDataFromPC = true;
inputBuffer[bytesRecvd] = 0;
return parseData();
}
if (readInProgress) {
inputBuffer[bytesRecvd] = x;
bytesRecvd++;
if (bytesRecvd == buffSize) {
bytesRecvd = buffSize - 1;
}
}
if (x == startMarker) {
bytesRecvd = 0;
readInProgress = true;
}
}
}
// ----------------------------------------------------------------------
/*
Command format scaled for up to 8 motors:
<Mode, Setting, MotorIDs, Value, Direction, p1_opt, p2_opt, ..., p8_opt>
*/
bool parsePacketFields() {
char *strtokIndx;
strtokIndx = strtok(inputBuffer, ",");
if (strtokIndx == NULL) return false;
strcpy(mode, strtokIndx);
strtokIndx = strtok(NULL, ",");
if (strtokIndx == NULL) return false;
strcpy(setting, strtokIndx);
strtokIndx = strtok(NULL, ",");
if (strtokIndx == NULL) return false;
String motorstr(strtokIndx);
strcpy(motorIDStr, strtokIndx);
// Clear out targeted flags
for (int i = 0; i < 8; i++) motors[i] = 0;
// Search through string identifier flags for motor mappings '1' through '8'
for (int i = 0; i < 8; i++) {
char searchTarget = '1' + i;
if (motorstr.indexOf(searchTarget) >= 0) {
motors[i] = 1;
}
}
strtokIndx = strtok(NULL, ",");
if (strtokIndx == NULL) return false;
value = atof(strtokIndx);
strtokIndx = strtok(NULL, ",");
if (strtokIndx == NULL) return false;
strcpy(dir, strtokIndx);
// Parse trailing distinct positioning strings for all 8 pumps if provided
for (int i = 0; i < 8; i++) {
strtokIndx = strtok(NULL, ",");
if (strtokIndx != NULL) {
distances[i] = atof(strtokIndx);
} else {
distances[i] = value; // Fallback to uniform standard raw global parameter value
}
}
return true;
}
void parseData() {
if (!parsePacketFields()) {
// Malformed packet (too few comma-separated fields) — ignore it instead
// of dereferencing a NULL pointer.
Serial.println("<ERROR: malformed packet>");
return;
}
if (strcmp(setting, "RUN") == 0) {
for (int i = 0; i < 8; i++) distances[i] = 999999.0;
}
newDataFromPC = true;
replyToPC();
return executeThisFunction();
}
void clearVariables() {
// Protocol structural fidelity cleanup loop placeholder matching base implementation
value = 0.0;
}
// ----------------------------------------------------------------------
void executeThisFunction() {
if (strcmp(mode, "STOP") == 0) {
return stopAll();
} else if (strcmp(mode, "SETTING") == 0) {
return updateSettings();
} else if (strcmp(mode, "RUN") == 0) {
if (strcmp(setting, "DIST") == 0) {
return runFew();
}
}
}
// ----------------------------------------------------------------------
void replyToPC() {
if (newDataFromPC) {
newDataFromPC = false;
Serial.print("<mode: ");
Serial.print(mode);
Serial.print(" ,setting: ");
Serial.print(setting);
Serial.print(" ,motorIDs: ");
Serial.print(motorIDStr);
Serial.print(" ,value: ");
Serial.print(value);
Serial.print(" ,direction: ");
Serial.print(dir);
Serial.println(">");
}
}
void sendDistanceToPC(int mIndex) {
if (steppers[mIndex].distanceToGo() != oldDistanceLeft[mIndex]) {
Serial.print("<DISP");
Serial.print(mIndex + 1); // convert array tracking offset to human indexing output
Serial.print("|");
Serial.print(steppers[mIndex].distanceToGo());
Serial.print(">");
}
oldDistanceLeft[mIndex] = steppers[mIndex].distanceToGo();
}
// ----------------------------------------------------------------------
void updateSettings() {
for (int i = 0; i < 8; i++) {
if (motors[i] == 1) {
steppers[i].setCurrentPosition(0);
if (strcmp(setting, "SPEED") == 0) steppers[i].setMaxSpeed(value);
else if (strcmp(setting, "ACCEL") == 0) steppers[i].setAcceleration(value);
}
}
clearVariables();
}
// ----------------------------------------------------------------------
int array_sum(int *array, int len) {
int s = 0;
for (int i = 0; i < len; i++) s += array[i];
return s;
}
void runFew() {
int direction = 1;
if (strcmp(dir, "B") == 0) direction = -1;
for (int i = 0; i < 8; i++) {
if (motors[i] == 1) {
float toMove = direction * distances[i];
steppers[i].move(toMove);
}
}
int stepperStatus[8] = {0};
// Keep execution loop active until targeted configurations report zero distance states
while (array_sum(stepperStatus, 8) != array_sum(motors, 8)) {
for (int i = 0; i < 8; i++) {
if (motors[i] == 1) {
if (stepperStatus[i] == 0) {
steppers[i].run();
// Stream live position feedback while the move is actually happening
// (previously this only ran after the move finished, so the PC
// never saw intermediate progress).
sendDistanceToPC(i);
}
if (steppers[i].distanceToGo() == 0) {
stepperStatus[i] = 1;
}
}
}
getDataFromPC(); // Monitor unexpected serial inputs during operations
}
clearVariables();
}
void stopAll() {
for (int i = 0; i < 8; i++) {
steppers[i].stop();
}
}
/*
============================================================================
TMC2209 Software UART control via TMCStepper library (Optional reference)
============================================================================
If software-configured run currents or StealthChop overrides are desired,
uncomment the TMCStepper includes below, add the hardware-mapped UART RX/TX pins,
and call .begin() methods inside the main setup execution block.
#include <TMCStepper.h>
#define R_SENSE 0.11f // match exact sense resistors of driver layout
*/