forked from euphy/polargraph_server_a1
-
Notifications
You must be signed in to change notification settings - Fork 1
/
exec.ino
428 lines (375 loc) · 11.5 KB
/
exec.ino
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
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
/**
* Polargraph Server. - CORE
* Written by Sandy Noble
* Released under GNU License version 3.
* http://www.polargraph.co.uk
* https://github.com/euphy/polargraph_server_a1
Exec.
This is one of the core files for the polargraph server program.
Purposes are getting a little more blurred here. This file contains
the basic decision tree that branches based on command.
It has a set of the most general-purpose drawing commands, but only
methods that are directly called - none of the geometry or conversion
routines are here.
*/
/** This method looks only for the basic command set
*/
boolean exec_executeBasicCommand(String &com)
{
boolean executed = true;
if (com.startsWith(CMD_CHANGELENGTH))
exec_changeLength();
#ifdef VECTOR_LINES
else if (com.startsWith(CMD_CHANGELENGTHDIRECT))
exec_changeLengthDirect();
#endif
else if (com.startsWith(CMD_CHANGEPENWIDTH))
exec_changePenWidth();
else if (com.startsWith(CMD_SETMOTORSPEED))
exec_setMotorSpeed();
else if (com.startsWith(CMD_SETMOTORACCEL))
exec_setMotorAcceleration();
#ifdef PIXEL_DRAWING
else if (com.startsWith(CMD_DRAWPIXEL))
pixel_drawSquarePixel();
else if (com.startsWith(CMD_DRAWSCRIBBLEPIXEL))
pixel_drawScribblePixel();
else if (com.startsWith(CMD_CHANGEDRAWINGDIRECTION))
pixel_changeDrawingDirection();
else if (com.startsWith(CMD_TESTPENWIDTHSQUARE))
pixel_testPenWidth();
#endif
else if (com.startsWith(CMD_SETPOSITION))
exec_setPosition();
#ifdef PENLIFT
else if (com.startsWith(CMD_PENDOWN))
penlift_penDown();
else if (com.startsWith(CMD_PENUP))
penlift_penUp();
else if (com.startsWith(CMD_SETPENLIFTRANGE))
exec_setPenLiftRange();
#endif
else if (com.startsWith(CMD_SETMACHINESIZE))
exec_setMachineSizeFromCommand();
else if (com.startsWith(CMD_SETMACHINEMMPERREV))
exec_setMachineMmPerRevFromCommand();
else if (com.startsWith(CMD_SETMACHINESTEPSPERREV))
exec_setMachineStepsPerRevFromCommand();
else if (com.startsWith(CMD_SETMACHINESTEPMULTIPLIER))
exec_setMachineStepMultiplierFromCommand();
else if (com.startsWith(CMD_GETMACHINEDETAILS))
exec_reportMachineSpec();
else if (com.startsWith(CMD_RESETEEPROM))
eeprom_resetEeprom();
else
executed = false;
return executed;
}
void exec_reportMachineSpec()
{
eeprom_dumpEeprom();
Serial.print(F("PGSIZE,"));
Serial.print(machineWidth);
Serial.print(COMMA);
Serial.print(machineHeight);
Serial.println(CMD_END);
Serial.print(F("PGMMPERREV,"));
Serial.print(mmPerRev);
Serial.println(CMD_END);
Serial.print(F("PGSTEPSPERREV,"));
Serial.print(motorStepsPerRev);
Serial.println(CMD_END);
Serial.print(F("PGSTEPMULTIPLIER,"));
Serial.print(stepMultiplier);
Serial.println(CMD_END);
Serial.print(F("PGLIFT,"));
Serial.print(downPosition);
Serial.print(COMMA);
Serial.print(upPosition);
Serial.println(CMD_END);
Serial.print(F("PGSPEED,"));
Serial.print(currentMaxSpeed);
Serial.print(COMMA);
Serial.print(currentAcceleration);
Serial.println(CMD_END);
}
void exec_setMachineSizeFromCommand()
{
int width = atoi(inParam1);
int height = atoi(inParam2);
// load to get current settings
int currentValue = width;
EEPROM_readAnything(EEPROM_MACHINE_WIDTH, currentValue);
if (currentValue != width)
if (width > 10)
{
EEPROM_writeAnything(EEPROM_MACHINE_WIDTH, width);
}
EEPROM_readAnything(EEPROM_MACHINE_HEIGHT, currentValue);
if (currentValue != height)
if (height > 10)
{
EEPROM_writeAnything(EEPROM_MACHINE_HEIGHT, height);
}
// reload
eeprom_loadMachineSize();
}
void exec_setMachineMmPerRevFromCommand()
{
EEPROM_writeAnything(EEPROM_MACHINE_MM_PER_REV, (float)atof(inParam1));
eeprom_loadMachineSpecFromEeprom();
}
void exec_setMachineStepsPerRevFromCommand()
{
EEPROM_writeAnything(EEPROM_MACHINE_STEPS_PER_REV, atoi(inParam1));
eeprom_loadMachineSpecFromEeprom();
}
void exec_setMachineStepMultiplierFromCommand()
{
EEPROM_writeAnything(EEPROM_MACHINE_STEP_MULTIPLIER, atoi(inParam1));
eeprom_loadMachineSpecFromEeprom();
}
void exec_setPenLiftRange()
{
int down = atoi(inParam1);
int up = atoi(inParam2);
#ifdef DEBUG_PENLIFT
Serial.print(F("Down: "));
Serial.println(down);
Serial.print(F("Up: "));
Serial.println(up);
#endif
if (inNoOfParams == 3)
{
// 3 params (C45,<downpos>,<uppos>,1,END) means save values to EEPROM
EEPROM_writeAnything(EEPROM_PENLIFT_DOWN, down);
EEPROM_writeAnything(EEPROM_PENLIFT_UP, up);
eeprom_loadPenLiftRange();
}
else if (inNoOfParams == 2)
{
// 2 params (C45,<downpos>,<uppos>,END) means just do a range test
penlift_movePen(up, down, penLiftSpeed);
delay(200);
penlift_movePen(down, up, penLiftSpeed);
delay(200);
penlift_movePen(up, down, penLiftSpeed);
delay(200);
penlift_movePen(down, up, penLiftSpeed);
delay(200);
}
}
/* Single parameter to set max speed, add a second parameter of "1" to make it persist.
*/
void exec_setMotorSpeed()
{
exec_setMotorSpeed((float)atof(inParam1));
if (inNoOfParams == 2 && atoi(inParam2) == 1)
EEPROM_writeAnything(EEPROM_MACHINE_MOTOR_SPEED, currentMaxSpeed);
}
void exec_setMotorSpeed(float speed)
{
currentMaxSpeed = speed;
motorA.setMaxSpeed(currentMaxSpeed);
motorB.setMaxSpeed(currentMaxSpeed);
Serial.print(F("New max speed: "));
Serial.println(currentMaxSpeed);
}
/* Single parameter to set acceleration, add a second parameter of "1" to make it persist.
*/
void exec_setMotorAcceleration()
{
exec_setMotorAcceleration((float)atof(inParam1));
if (inNoOfParams == 2 && atoi(inParam2) == 1)
EEPROM_writeAnything(EEPROM_MACHINE_MOTOR_ACCEL, currentAcceleration);
}
void exec_setMotorAcceleration(float accel)
{
currentAcceleration = accel;
motorA.setAcceleration(currentAcceleration);
motorB.setAcceleration(currentAcceleration);
Serial.print(F("New accel: "));
Serial.println(currentAcceleration);
}
void exec_changePenWidth()
{
penWidth = atof(inParam1);
Serial.print(F("Changed Pen width to "));
Serial.print(penWidth);
Serial.println(F("mm"));
}
void exec_setPosition()
{
long targetA = multiplier(atol(inParam1));
long targetB = multiplier(atol(inParam2));
motorA.setCurrentPosition(targetA);
motorB.setCurrentPosition(targetB);
impl_engageMotors();
reportPosition();
}
void exec_changeLengthRelative()
{
long lenA = multiplier(atol(inParam1));
long lenB = multiplier(atol(inParam2));
changeLengthRelative(lenA, lenB);
}
void exec_changeLength()
{
float lenA = multiplier((float)atof(inParam1));
float lenB = multiplier((float)atof(inParam2));
changeLength(lenA, lenB);
}
#ifdef VECTOR_LINES
void exec_changeLengthDirect()
{
float endA = multiplier((float)atof(inParam1));
float endB = multiplier((float)atof(inParam2));
int maxSegmentLength = atoi(inParam3);
float startA = motorA.currentPosition();
float startB = motorB.currentPosition();
if (endA < 20 || endB < 20 || endA > getMaxLength() || endB > getMaxLength())
{
Serial.print(MSG_E_STR);
Serial.println(F("This point falls outside the area of this machine. Skipping it."));
}
else
{
exec_drawBetweenPoints(startA, startB, endA, endB, maxSegmentLength);
}
}
/**
This moves the gondola in a straight line between p1 and p2. Both input coordinates are in
the native coordinates system.
The fidelity of the line is controlled by maxLength - this is the longest size a line segment is
allowed to be. 1 is finest, slowest. Use higher values for faster, wobblier.
*/
void exec_drawBetweenPoints(float p1a, float p1b, float p2a, float p2b, int maxSegmentLength)
{
// ok, we're going to plot some dots between p1 and p2. Using maths. I know! Brave new world etc.
// First, convert these values to cartesian coordinates
// We're going to figure out how many segments the line
// needs chopping into.
float c1x = getCartesianXFP(p1a, p1b);
float c1y = getCartesianYFP(c1x, p1a);
float c2x = getCartesianXFP(p2a, p2b);
float c2y = getCartesianYFP(c2x, p2a);
// test to see if it's on the page
// AND ALSO TO see if the current position is on the page.
// Remember, the native system can easily specify points that can't exist,
// particularly up at the top.
if (c2x > 20
&& c2x<pageWidth-20
&& c2y > 20
&& c2y <pageHeight-20
&& c1x > 20
&& c1x<pageWidth-20
&& c1y > 20
&& c1y <pageHeight-20
)
{
reportingPosition = false;
float deltaX = c2x-c1x; // distance each must move (signed)
float deltaY = c2y-c1y;
// float totalDistance = sqrt(sq(deltaX) + sq(deltaY));
int linesegs = 1; // assume at least 1 line segment will get us there.
if (abs(deltaX) > abs(deltaY))
{
// slope <=1 case
while ((abs(deltaX)/linesegs) > maxSegmentLength)
{
linesegs++;
}
}
else
{
// slope >1 case
while ((abs(deltaY)/linesegs) > maxSegmentLength)
{
linesegs++;
}
}
// reduce delta to one line segments' worth.
deltaX = deltaX/linesegs;
deltaY = deltaY/linesegs;
// render the line in N shorter segments
long runSpeed = 0;
usingAcceleration = false;
while (linesegs > 0)
{
// Serial.print("Line segment: " );
// Serial.println(linesegs);
// compute next new location
c1x = c1x + deltaX;
c1y = c1y + deltaY;
// convert back to machine space
float pA = getMachineA(c1x, c1y);
float pB = getMachineB(c1x, c1y);
// do the move
runSpeed = desiredSpeed(linesegs, runSpeed, currentAcceleration*4);
// Serial.print("Setting speed:");
// Serial.println(runSpeed);
motorA.setSpeed(runSpeed);
motorB.setSpeed(runSpeed);
changeLength(pA, pB);
// one line less to do!
linesegs--;
}
// reset back to "normal" operation
reportingPosition = true;
usingAcceleration = true;
reportPosition();
}
else
{
Serial.print(MSG_E_STR);
Serial.println(F("Line is not on the page. Skipping it."));
}
// outputAvailableMemory();
}
// Work out and return a new speed.
// Subclasses can override if they want
// Implement acceleration, deceleration and max speed
// Negative speed is anticlockwise
// This is called:
// after each step
// after user changes:
// maxSpeed
// acceleration
// target position (relative or absolute)
float desiredSpeed(long distanceTo, float currentSpeed, float acceleration)
{
float requiredSpeed;
if (distanceTo == 0)
return 0.0f; // We're there
// sqrSpeed is the signed square of currentSpeed.
float sqrSpeed = sq(currentSpeed);
if (currentSpeed < 0.0)
sqrSpeed = -sqrSpeed;
float twoa = 2.0f * acceleration; // 2ag
// if v^^2/2as is the the left of target, we will arrive at 0 speed too far -ve, need to accelerate clockwise
if ((sqrSpeed / twoa) < distanceTo)
{
// Accelerate clockwise
// Need to accelerate in clockwise direction
if (currentSpeed == 0.0f)
requiredSpeed = sqrt(twoa);
else
requiredSpeed = currentSpeed + fabs(acceleration / currentSpeed);
if (requiredSpeed > currentMaxSpeed)
requiredSpeed = currentMaxSpeed;
}
else
{
// Decelerate clockwise, accelerate anticlockwise
// Need to accelerate in clockwise direction
if (currentSpeed == 0.0f)
requiredSpeed = -sqrt(twoa);
else
requiredSpeed = currentSpeed - fabs(acceleration / currentSpeed);
if (requiredSpeed < -currentMaxSpeed)
requiredSpeed = -currentMaxSpeed;
}
//Serial.println(requiredSpeed);
return requiredSpeed;
}
#endif