-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathStepperMotors.h
247 lines (198 loc) · 6.13 KB
/
StepperMotors.h
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
/*
* Copyright (C) 2018 Lakoja on github.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __STEPPER_MOTORS_H__
#define __STEPPER_MOTORS_H__
#include <math.h>
#include "Task.h"
class StepperMotors: public Task
{
private:
const float DEAD_ZONE_SPEED_LOW = 0.02; // have _some_ movement also for very low speeds
uint32_t systemStart;
// the externally (or automatically) requested values
float motorRSpeedDesired = 0;
float motorLSpeedDesired = 0;
double currentPwmRight = 1;
double currentPwmLeft = 1;
uint32_t motorREndTime;
uint32_t motorLEndTime;
uint32_t lastDriveLoopTime = 0;
uint32_t lastCounterOutTime = 0;
bool holding = false;
uint8_t stepPinRight;
uint8_t dirPinRight;
uint8_t sleepPinRight;
uint8_t stepPinLeft;
uint8_t dirPinLeft;
uint8_t sleepPinLeft;
uint16_t motorMaxTurns;
uint16_t stepsPerRotation;
public:
StepperMotors()
{
}
void setup(
uint8_t stepRight,
uint8_t dirRight,
uint8_t sleepRight,
uint8_t stepLeft,
uint8_t dirLeft,
uint8_t sleepLeft,
uint16_t maxRpm,
uint16_t steps)
{
stepPinRight = stepRight;
dirPinRight = dirRight;
sleepPinRight = sleepRight;
stepPinLeft = stepLeft;
dirPinLeft = dirLeft;
sleepPinLeft = sleepLeft;
motorMaxTurns = maxRpm;
stepsPerRotation = steps;
outputPin(stepPinRight);
outputPin(dirPinRight);
outputPin(sleepPinRight);
outputPin(stepPinLeft);
outputPin(dirPinLeft);
outputPin(sleepPinLeft);
// NOTE there are groups of timers at work here: The setting for channel 1 also resets the one for 0.
// Some documentation would have been fine here generally...
// For steppers: control is done with the "tone" (and only when driver enabled)
ledcSetup(0, 600, 8); // precision bits 8: means we have 0..255 as steps, 4: 0..15
ledcSetup(2, 600, 8);
ledcAttachPin(stepPinRight, 0);
ledcAttachPin(stepPinLeft, 2);
// some arbitrary value: only falling flanks matter
ledcWrite(0, 63);
ledcWrite(2, 63);
systemStart = millis();
}
void run()
{
while (true) {
uint32_t now = millis();
if (lastDriveLoopTime > 0) {
uint16_t passed = now - lastDriveLoopTime;
if (now >= motorREndTime) {
motorRSpeedDesired = 0;
}
if (now >= motorLEndTime) {
motorLSpeedDesired = 0;
}
}
double rSpeed = getNonDeadSpeed(motorRSpeedDesired) * motorMaxTurns / 60.0 * stepsPerRotation;
double lSpeed = getNonDeadSpeed(motorLSpeedDesired) * motorMaxTurns / 60.0 * stepsPerRotation;
switchMotorR(rSpeed);
switchMotorL(lSpeed);
if (now - lastCounterOutTime > 1200) {
//Serial.println("R r"+String(rSpeed)+" L r"+String(lSpeed));
lastCounterOutTime = now;
}
lastDriveLoopTime = now;
sleepAfterLoop(4, now);
}
}
void hold() {
holding = !holding;
}
void requestMovement(float forward, float right, uint16_t durationMillis = 1000) {
// This is the only one with value range -1 .. 1
float rightSpeed = forward;
float leftSpeed = forward;
rightSpeed -= right / 2;
leftSpeed += right / 2;
requestRight(rightSpeed, durationMillis);
requestLeft(leftSpeed, durationMillis);
}
void requestRight(float value, uint16_t durationMillis = 1000)
{
// TODO check for value range?
uint32_t now = millis();
motorRSpeedDesired = value;
motorREndTime = now + durationMillis;
}
void requestLeft(float value, uint16_t durationMillis = 1000)
{
uint32_t now = millis();
motorLSpeedDesired = value;
motorLEndTime = now + durationMillis;
}
void requestForward(float value, uint16_t durationMillis = 1000)
{
uint32_t desiredEndTime = millis() + durationMillis;
motorRSpeedDesired = value;
motorREndTime = desiredEndTime;
motorLSpeedDesired = value;
motorLEndTime = desiredEndTime;
}
void requestReverse(float value, uint16_t durationMillis = 1000)
{
uint32_t desiredEndTime = millis() + durationMillis;
motorRSpeedDesired = -value;
motorREndTime = desiredEndTime;
motorLSpeedDesired = -value;
motorLEndTime = desiredEndTime;
}
private:
void outputPin(int num)
{
digitalWrite(num, LOW);
pinMode(num, OUTPUT);
}
void switchMotorR(double pwmValue)
{
// TODO consider getNonDeadSpeed
if (pwmValue != currentPwmRight) {
if (showDebug) {
Serial.print("RRa"+String(pwmValue)+" ");
if (++outCounter % 20 == 0)
Serial.println();
}
int32_t speedInt = round(pwmValue);
ledcWriteTone(0, abs(speedInt));
digitalWrite(dirPinRight, pwmValue >= 0 ? 1 : 0);
digitalWrite(sleepPinRight, holding || pwmValue != 0 ? 1 : 0);
currentPwmRight = pwmValue;
}
}
void switchMotorL(double pwmValue)
{
if (pwmValue != currentPwmLeft) {
int32_t speedInt = round(pwmValue);
ledcWriteTone(2, abs(speedInt));
if (showDebug) { // && random(5) == 4) {
Serial.print("LRai"+String(speedInt)+" ");
if (++outCounter % 20 == 0)
Serial.println();
}
digitalWrite(dirPinLeft, pwmValue >= 0 ? 0 : 1); // inverted to right
digitalWrite(sleepPinLeft, holding || pwmValue != 0 ? 1 : 0);
currentPwmLeft = pwmValue;
}
}
uint16_t outCounter = 0;
bool showDebug = false;
double getNonDeadSpeed(float speed)
{
double nonDeadSpeed = 0;
if (speed != 0) {
float sign = speed < 0 ? -1 : +1;
nonDeadSpeed = sign * DEAD_ZONE_SPEED_LOW + (1 - DEAD_ZONE_SPEED_LOW) * speed;
}
return nonDeadSpeed;
}
};
#endif