RF-Positioning-System V0.1
by Max Heinekamp
Loading...
Searching...
No Matches
stepper.cpp
Go to the documentation of this file.
1
12
13#include "stepper.h"
14#include "flash.h"
15
16extern FLASH flash_memory;
17
22 stepper(&MOTOR_SERIAL_PORT, R_SENSE, address),
23 direction(false) {
24}
25
27 pinMode(step_pin, OUTPUT);
28 pinMode(enable_pin, OUTPUT);
29
30 // Enable the stepper driver
31 digitalWrite(enable_pin, LOW);
32
33 // Retrieve stepper settings from flash memory
34 int microsteps = flash_memory.preferences.getInt("MICROSTEPS", MICROSTEPS);
35 int hold_current = flash_memory.preferences.getInt("HOLD-CURRENT", HOLD_CURRENT);
36 int rms_current = flash_memory.preferences.getInt("RMS-CURRENT", RMS_CURRENT);
37
38 stepper.begin();
39 //stepper.en_spreadCycle(true); // Enable spreadCycle mode
40 stepper.toff(5); // Enables driver in software
41 stepper.rms_current(rms_current); // Set motor RMS current
42 stepper.ihold(hold_current); // Set hold current to 25% of run current
43 stepper.microsteps(microsteps); // Set microsteps to 1/16th
44 stepper.pwm_autoscale(true); // Needed for stealthChop
45 stepper.shaft(direction); // Set motor direction
46}
47
49 digitalWrite(step_pin, HIGH);
50 delayMicroseconds(STEP_DELAY);
51 digitalWrite(step_pin, LOW);
52}
53
54void STEPPER::SetDirection(bool dir) {
55 stepper.shaft(dir);
56 direction = dir;
57}
58
60 return direction;
61}
62
64 int rms_current = flash_memory.preferences.getInt("RMS-CURRENT", RMS_CURRENT);
65 stepper.rms_current(rms_current);
66 updateHoldCurrent(); // rms_current() overwrites IHOLD internally; reapply the stored hold current
67}
68
70 int hold_current = flash_memory.preferences.getInt("HOLD-CURRENT", HOLD_CURRENT);
71 stepper.ihold(hold_current);
72}
73
75 return stepper.rms_current();
76}
77
79 return stepper.ihold();
80}
81
83 int microsteps = flash_memory.preferences.getInt("MICROSTEPS", MICROSTEPS);
84 stepper.microsteps(microsteps);
85}
86
87void STEPPER::move(float targetSpeed, float acceleration, float angle, int steps_revolution) {
88 float currentSpeed = 0;
89 float stepInterval = 0;
90 unsigned long lastStepTime = 0;
91 unsigned long currentTime;
92 int stepsTaken = 0;
93
94 // Convert angle to steps
95 float steps_degree = (float)steps_revolution / 360.0;
96 float steps = angle * steps_degree;
97 steps += steps_remainder;
98 int steps_rounded = (int)floorf(steps);
99 steps_remainder = steps - steps_rounded;
100
101 if (steps_rounded <= 0) return; // No movement needed
102
103 // Compute max reachable speed for triangular profile
104 float maxReachableSpeed = sqrt(acceleration * steps_rounded);
105
106 // Limit target speed if we don't have enough steps to reach it
107 if (targetSpeed > maxReachableSpeed) {
108 targetSpeed = maxReachableSpeed;
109 }
110
111 // Now compute acceleration distance for (possibly reduced) targetSpeed
112 float accelTime = targetSpeed / acceleration;
113 float accelDist = 0.5 * acceleration * accelTime * accelTime;
114
115 // Determine if there's a cruise phase
116 float cruiseDist = steps_rounded - 2 * accelDist;
117 bool hasCruise = cruiseDist > 0;
118
119 while (stepsTaken < steps_rounded) {
120 currentTime = micros();
121
122 // Determine current speed based on phase
123 float phaseTime;
124 if (stepsTaken < accelDist) {
125 // Acceleration phase
126 phaseTime = sqrt(2.0 * stepsTaken / acceleration);
127 currentSpeed = acceleration * phaseTime;
128 } else if (hasCruise && stepsTaken < (steps_rounded - accelDist)) {
129 // Cruising at target speed
130 currentSpeed = targetSpeed;
131 } else {
132 // Deceleration phase
133 int stepsRemaining = steps_rounded - stepsTaken;
134 phaseTime = sqrt(2.0 * stepsRemaining / acceleration);
135 currentSpeed = acceleration * phaseTime;
136 }
137
138 // Avoid division by zero or too slow speeds
139 if (currentSpeed < 1) currentSpeed = 1;
140
141 stepInterval = 1000000.0 / currentSpeed;
142
143 if ((micros() - lastStepTime) >= stepInterval) {
144 // Perform step pulse
145 lastStepTime = micros();
146 digitalWrite(step_pin, HIGH);
147 delayMicroseconds(4);
148 digitalWrite(step_pin, LOW);
149 stepsTaken++;
150 }
151 }
152
153 // Update the current position depending on the direction
154 if(direction) {
155 current_position -= angle; // Update the current position in degrees
156 } else {
157 current_position += angle; // Update the current position in degrees
158 }
159
160 // Ensure the current position rolls over within the range [0, 360)
161 while (current_position < 0) {
162 current_position += 360;
163 }
164 while (current_position >= 360) {
165 current_position -= 360;
166 }
167 }
168
169 void STEPPER::move(float targetSpeed, float acceleration, float angle, int steps_revolution, STEPPER* stepper2, int stepper2_ratio) {
170 float currentSpeed = 0;
171 float stepInterval = 0;
172 unsigned long lastStepTime = 0;
173 unsigned long currentTime;
174 int stepsTaken = 0;
175 bool updatedStepper2Direction = false;
176
177 //Check if stpper2 is set to rotate in the same direction
178 if (stepper2->GetDirection() == direction) {
179 stepper2->SetDirection(!direction);
180 updatedStepper2Direction = true;
181 }
182
183 // Convert angle to steps
184 float steps_degree = (float)steps_revolution / 360.0;
185 float steps = angle * steps_degree;
186 steps += steps_remainder;
187 int steps_rounded = (int)floorf(steps);
188 steps_remainder = steps - steps_rounded;
189
190 if (steps_rounded <= 0) return; // No movement needed
191
192 // Compute max reachable speed for triangular profile
193 float maxReachableSpeed = sqrt(acceleration * steps_rounded);
194
195 // Limit target speed if we don't have enough steps to reach it
196 if (targetSpeed > maxReachableSpeed) {
197 targetSpeed = maxReachableSpeed;
198 }
199
200 // Now compute acceleration distance for (possibly reduced) targetSpeed
201 float accelTime = targetSpeed / acceleration;
202 float accelDist = 0.5 * acceleration * accelTime * accelTime;
203
204 // Determine if there's a cruise phase
205 float cruiseDist = steps_rounded - 2 * accelDist;
206 bool hasCruise = cruiseDist > 0;
207
208 while (stepsTaken < steps_rounded) {
209 currentTime = micros();
210
211 // Determine current speed based on phase
212 float phaseTime;
213 if (stepsTaken < accelDist) {
214 // Acceleration phase
215 phaseTime = sqrt(2.0 * stepsTaken / acceleration);
216 currentSpeed = acceleration * phaseTime;
217 } else if (hasCruise && stepsTaken < (steps_rounded - accelDist)) {
218 // Cruising at target speed
219 currentSpeed = targetSpeed;
220 } else {
221 // Deceleration phase
222 int stepsRemaining = steps_rounded - stepsTaken;
223 phaseTime = sqrt(2.0 * stepsRemaining / acceleration);
224 currentSpeed = acceleration * phaseTime;
225 }
226
227 // Avoid division by zero or too small a speed
228 if (currentSpeed < 1) currentSpeed = 1;
229
230 stepInterval = 1000000.0 / currentSpeed;
231
232 if ((micros() - lastStepTime) >= stepInterval) {
233 lastStepTime = micros();
234 step();
235
236 if(stepsTaken % stepper2_ratio == 0) {
237 stepper2->step();
238 }
239
240 stepsTaken++;
241 }
242 }
243
244 //Update stepper 2 remainder
245 int residual = stepsTaken % stepper2_ratio;
246 stepper2->steps_remainder = (float)residual / (float)stepper2_ratio;
247
248 // Restore the original direction of stepper2 if it was changed
249 if (updatedStepper2Direction) {
250 stepper2->SetDirection(!stepper2->GetDirection());
251 }
252
253 // Update the current position depending on the direction
254 if(direction) {
255 current_position -= angle; // Update the current position in degrees
256 } else {
257 current_position += angle; // Update the current position in degrees
258 }
259
260 // Ensure the current position rolls over within the range [0, 360)
261 while (current_position < 0) {
262 current_position += 360;
263 }
264 while (current_position >= 360) {
265 current_position -= 360;
266 }
267 }
268
269 void STEPPER::absoluteMove(float targetSpeed, float acceleration, float angle, int steps_revolution) {
270 // Calculate required movement angle based on current position
271 float requiredAngle = angle - current_position;
272
273 // Ensure the angle is within the range [0, 360)
274 while (requiredAngle < 0 || requiredAngle >= 360) {
275 if (requiredAngle < 0) {
276 requiredAngle += 360; // Wrap around to positive angle
277 } else if (requiredAngle >= 360) {
278 requiredAngle -= 360; // Wrap around to negative angle
279 }
280 }
281
282 // Determine the direction based on the required angle
283 if (requiredAngle > 180) {
284 SetDirection(true); // CCW
285 requiredAngle = 360 - requiredAngle; // Adjust angle for CCW direction
286 } else {
287 SetDirection(false); // CW
288 }
289
290 // Move the motor to the target position
291 move(targetSpeed, acceleration, requiredAngle, steps_revolution);
292
293 // Set current position to new location
294 current_position = angle;
295 }
296
297 void STEPPER::absoluteMove(float targetSpeed, float acceleration, float angle, int steps_revolution, STEPPER* stepper2, int stepper2_ratio) {
298 // Calculate required movement angle based on current position
299 float requiredAngle = angle - current_position;
300
301 // Ensure the angle is within the range [0, 360)
302 while (requiredAngle < 0 || requiredAngle >= 360) {
303 if (requiredAngle < 0) {
304 requiredAngle += 360; // Wrap around to positive angle
305 } else if (requiredAngle >= 360) {
306 requiredAngle -= 360; // Wrap around to negative angle
307 }
308 }
309
310 // Determine the direction based on the required angle
311 if (requiredAngle > 180) {
312 SetDirection(true); // CCW
313 requiredAngle = 360 - requiredAngle; // Adjust angle for CCW direction
314 } else {
315 SetDirection(false); // CW
316 }
317
318 // Move the motor to the target position
319 move(targetSpeed, acceleration, requiredAngle, steps_revolution, stepper2, stepper2_ratio);
320
321 // Set current position to new location
322 current_position = angle;
323 }
324
325
326
327 void STEPPER::runStepperSCurve(float targetSpeed, float maxJerk, int distance) {
328 int stepsTaken = 0;
329 float pos = 0;
330 float vel = 0;
331 float acc = 0;
332 float jerk = maxJerk;
333
334 unsigned long lastStepTime = 0;
335 unsigned long lastUpdateTime = micros();
336
337 const float dt = 0.001; // 1ms update time in seconds
338
339 while (stepsTaken < distance) {
340 unsigned long now = micros();
341 if ((now - lastUpdateTime) < dt * 1e6) continue; // maintain dt
342 lastUpdateTime = now;
343
344 // Compute S-curve profile
345 // Phase 1: Ramp up acceleration (jerk > 0)
346 // Phase 2: Hold acceleration (jerk = 0)
347 // Phase 3: Ramp down acceleration (jerk < 0)
348 // Phase 4: Reverse for deceleration
349
350 // Compute stopping distance to avoid overshooting
351 float stoppingDist = (vel * vel) / (2 * acc + 1e-6); // avoid divide-by-zero
352
353 // Jerk logic: decide whether to accelerate, cruise, or decelerate
354 if (vel < targetSpeed && pos < (distance - stoppingDist)) {
355 acc += jerk * dt;
356 } else if (vel > 0) {
357 acc -= jerk * dt;
358 }
359
360 // Clamp acceleration and velocity
361 float maxAcc = sqrt(targetSpeed * maxJerk);
362 if (acc > maxAcc) acc = maxAcc;
363 if (acc < -maxAcc) acc = -maxAcc;
364
365 vel += acc * dt;
366 if (vel < 0) vel = 0;
367
368 pos += vel * dt;
369
370 // Time between steps
371 float stepInterval = 1e6 / (vel + 1e-3); // in microseconds
372
373 if ((micros() - lastStepTime) >= stepInterval && stepsTaken < distance) {
374 // Send one step pulse (insert actual step control here)
375 // e.g., digitalWrite(stepPin, HIGH); delayMicroseconds(2); digitalWrite(stepPin, LOW);
376 lastStepTime = micros();
377 digitalWrite(step_pin, HIGH);
378 delayMicroseconds(4);
379 digitalWrite(step_pin, LOW);
380 stepsTaken++;
381 }
382 }
383 }
384
385 int STEPPER::Debug() {
386 delay(10); // Give the driver time to respond
387 uint32_t status = stepper.DRV_STATUS();
388 delay(10); // Give time before next read
389 return (int)status;
390}
This class handles access to the flash memory of the ESP32. It is also used to initialize the flash m...
Definition flash.h:19
int enable_pin
Pin that is connected to the enable pin of the driver.
Definition stepper.h:188
uint8_t getHoldCurrent()
Get the actual hold current currently applied by the stepper driver.
Definition stepper.cpp:78
STEPPER(int address, int step_pin, int enable_pin)
Construct a new STEPPER object.
Definition stepper.cpp:18
void setup()
Set up the stepper driver and configure it.
Definition stepper.cpp:26
void move(float targetSpeed, float acceleration, float position, int steps_revolution)
Move the motor a given angle with a given acceleration and distance.
Definition stepper.cpp:87
void updateHoldCurrent()
Update the hold current of the stepper driver from the current flash value.
Definition stepper.cpp:69
int address
SPI address of the stepper driver.
Definition stepper.h:175
void updateRMSCurrent()
Update the RMS current of the stepper driver from the current flash value.
Definition stepper.cpp:63
void updateMicrosteps()
Update the microsteps of the stepper driver from the current flash value.
Definition stepper.cpp:82
float current_position
This stores the current position of the motor in degrees.
Definition stepper.h:194
float steps_remainder
This stores the fractional step that needs to be carried over to the next move.
Definition stepper.h:206
int step_pin
Pin that is connected to the step pin of the driver.
Definition stepper.h:181
void step()
Step the motor one step.
Definition stepper.cpp:48
TMC2209Stepper stepper
Stepper driver object. This is the object that interfaces with the stepper driver library.
Definition stepper.h:163
uint16_t getRMSCurrent()
Get the actual RMS current currently applied by the stepper driver.
Definition stepper.cpp:74
void SetDirection(bool dir)
Set the direction of the stepper motor.
Definition stepper.cpp:54
bool GetDirection()
Get the current direction of the stepper motor.
Definition stepper.cpp:59
void runStepperSCurve(float targetSpeed, float maxJerk, int distance)
Run the stepper motor using an S-curve profile.
Definition stepper.cpp:327
void absoluteMove(float targetSpeed, float acceleration, float angle, int steps_revolution)
Move the motor to a target location based on an absolute angle with a given speed and acceleration.
Definition stepper.cpp:269
bool direction
Direction of the motor. This is used to set the direction of the motor.
Definition stepper.h:170
Handles the flash memory for the ESP32.