Skip to content

Commit 5e370eb

Browse files
authored
Merge pull request #44 from RoboticsBrno/motor-posreg
Add motor position regulation
2 parents 336024a + f42c632 commit 5e370eb

5 files changed

Lines changed: 176 additions & 73 deletions

File tree

fw/rbcx-coprocessor/include/Motor.hpp

Lines changed: 111 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,80 @@
33
#include "utils/Debug.hpp"
44
#include "utils/Regulator.hpp"
55

6-
#include <algorithm>
76
#include <stdint.h>
87

98
inline const uint16_t motorLoopFreq = 100;
109

1110
class Motor {
1211
public:
13-
Motor()
14-
: m_velocityReg(INT16_MAX, 150000, 300000, 20000)
15-
, m_positionReg(INT16_MAX, 150000, 300000, 20000)
16-
, m_state(PowerCtrl) {}
17-
18-
std::pair<int16_t, bool> poll(uint16_t encTicks) {
19-
int16_t actualTicksPerLoop = encTicks - m_lastEncTicks;
20-
m_actualPosition += actualTicksPerLoop;
12+
Motor() {
13+
m_lastEncTicks = 0;
14+
reset();
15+
}
16+
17+
void reset() {
18+
m_velocityReg = Regulator(INT16_MAX, 150000, 300000, 20000);
19+
m_positionReg = Regulator(500, 1000, 0, 0);
20+
m_dither = 0;
21+
m_targetVelocity = 0;
22+
m_actualPower = 0;
23+
m_actualPosition = 0;
24+
m_targetPosition = 0;
25+
m_actualTicksPerLoop = 0;
26+
m_posEpsilon = 3;
27+
m_velEpsilon = 3;
28+
m_maxAccel = 2000 / motorLoopFreq;
29+
m_mode = MotorMode_POWER;
30+
}
31+
32+
bool atTargetPosition() const {
33+
return uint32_t(abs(m_actualPosition - m_targetPosition))
34+
<= m_posEpsilon;
35+
}
36+
37+
bool atStandstill() const {
38+
return uint32_t(abs(m_actualTicksPerLoop)) <= m_velEpsilon;
39+
}
40+
41+
MotorMode mode() const { return m_mode; }
42+
void modeChange(MotorMode newMode) { m_mode = newMode; }
43+
44+
void reportStat(CoprocStat_MotorStat& stat) {
45+
stat.mode = m_mode;
46+
stat.position = m_actualPosition;
47+
stat.power = m_actualPower;
48+
stat.velocity = m_actualTicksPerLoop * motorLoopFreq;
49+
};
50+
51+
int16_t poll(uint16_t encTicks) {
52+
m_actualTicksPerLoop = encTicks - m_lastEncTicks;
53+
m_actualPosition += m_actualTicksPerLoop;
2154
m_lastEncTicks = encTicks;
22-
if (m_state == PowerCtrl) {
23-
return std::make_pair(m_targetPower, false);
24-
} else if (m_state == BrakeCtrl) {
25-
return std::make_pair(m_targetBrakingPower, true);
26-
} else if (m_state == VelocityCtrl) {
55+
56+
switch (m_mode) {
57+
case MotorMode_POSITION:
58+
case MotorMode_POSITION_IDLE: {
59+
// DEBUG("i:%ld e:%ld s:%ld -> v:%ld\n", m_positionReg.integrator(),
60+
// m_positionReg.e(), m_actualPosition, m_positionReg.output());
61+
if (atTargetPosition() && atStandstill()) {
62+
m_positionReg.clear();
63+
m_targetVelocity = 0;
64+
modeChange(MotorMode_POSITION_IDLE);
65+
} else {
66+
auto action
67+
= m_positionReg.process(m_targetPosition, m_actualPosition);
68+
69+
// Limit ramp-up to max acceleration
70+
if (action > m_targetVelocity + m_maxAccel) {
71+
m_targetVelocity += m_maxAccel;
72+
} else if (action < m_targetVelocity - m_maxAccel) {
73+
m_targetVelocity -= m_maxAccel;
74+
} else {
75+
m_targetVelocity = action;
76+
}
77+
}
78+
} // fallthrough
79+
case MotorMode_VELOCITY: {
2780
int16_t targetTicksPerLoop = m_targetVelocity / motorLoopFreq;
2881
uint16_t targetTicksRem = abs(m_targetVelocity % motorLoopFreq);
2982
if ((targetTicksRem * 4) / motorLoopFreq > m_dither) {
@@ -33,35 +86,34 @@ class Motor {
3386
m_dither = 0;
3487
}
3588

36-
auto action
37-
= m_velocityReg.process(targetTicksPerLoop, actualTicksPerLoop);
38-
return std::make_pair(action, false);
39-
} else if (m_state == PositionCtrl) {
40-
auto action
41-
= m_positionReg.process(m_targetPosition, m_actualPosition);
42-
return std::make_pair(action, false);
89+
auto action = m_velocityReg.process(
90+
targetTicksPerLoop, m_actualTicksPerLoop);
91+
m_actualPower = action;
92+
} break;
93+
default:
94+
break;
4395
}
44-
return std::make_pair(0, false);
96+
return m_actualPower;
4597
}
4698

4799
void setTargetPower(int16_t power) {
48-
if (m_state != PowerCtrl) {
49-
m_state = PowerCtrl;
100+
if (m_mode != MotorMode_POWER) {
101+
modeChange(MotorMode_POWER);
50102
}
51-
m_targetPower = power;
103+
m_actualPower = power;
52104
}
53105

54106
void setTargetBrakingPower(int16_t brakingPower) {
55-
if (m_state != BrakeCtrl) {
56-
m_state = BrakeCtrl;
107+
if (m_mode != MotorMode_BRAKE) {
108+
modeChange(MotorMode_BRAKE);
57109
}
58-
m_targetBrakingPower = brakingPower;
110+
m_actualPower = brakingPower;
59111
}
60112

61113
void setTargetVelocity(int16_t ticksPerSec) {
62-
if (m_state != VelocityCtrl) {
114+
if (m_mode != MotorMode_VELOCITY) {
63115
m_velocityReg.clear();
64-
m_state = VelocityCtrl;
116+
modeChange(MotorMode_VELOCITY);
65117
}
66118
m_targetVelocity = ticksPerSec;
67119
}
@@ -71,50 +123,52 @@ class Motor {
71123
m_actualPosition = homedTicks;
72124
}
73125

74-
void setTargetPosition(int32_t ticks) {
75-
if (m_state != PositionCtrl) {
126+
void setTargetPosition(
127+
const CoprocReq_MotorReq_SetPosition& req, bool additive) {
128+
if (m_mode != MotorMode_POSITION) {
76129
m_positionReg.clear();
77-
m_state = PositionCtrl;
130+
modeChange(MotorMode_POSITION);
78131
}
79-
m_targetPosition = ticks;
80-
}
81-
82-
void addTargetPosition(int32_t ticksDelta) {
83-
if (m_state != PositionCtrl) {
84-
m_positionReg.clear();
85-
m_state = PositionCtrl;
132+
if (additive) {
133+
m_targetPosition += req.targetPosition;
134+
} else {
135+
m_targetPosition = req.targetPosition;
86136
}
87-
m_targetPosition += ticksDelta;
137+
m_positionReg.setMaxOutput(req.runningVelocity);
88138
}
89139

90-
void setVelocityPid(uint32_t p, uint32_t i, uint32_t d) {
91-
m_velocityReg.setP(p);
92-
m_velocityReg.setI(i);
93-
m_velocityReg.setD(d);
140+
void setVelocityPid(const RegCoefs& coefs) {
141+
m_velocityReg.setP(coefs.p);
142+
m_velocityReg.setI(coefs.i);
143+
m_velocityReg.setD(coefs.d);
94144
m_velocityReg.clear();
95145
}
96146

97-
void setPositionPid(uint32_t p, uint32_t i, uint32_t d) {
98-
m_positionReg.setP(p);
99-
m_positionReg.setI(i);
100-
m_positionReg.setD(d);
147+
void setPositionPid(const RegCoefs& coefs) {
148+
m_positionReg.setP(coefs.p);
149+
m_positionReg.setI(coefs.i);
150+
m_positionReg.setD(coefs.d);
101151
m_positionReg.clear();
102152
}
103153

154+
void setConfig(const MotorConfig& config) {
155+
m_velEpsilon = config.velEpsilon;
156+
m_posEpsilon = config.posEpsilon;
157+
m_maxAccel = config.maxAccel / motorLoopFreq;
158+
}
159+
104160
private:
105161
Regulator m_velocityReg;
106162
Regulator m_positionReg;
107-
int16_t m_targetPower;
108-
int16_t m_targetBrakingPower;
163+
int16_t m_actualPower;
109164
int16_t m_targetVelocity;
110165
int32_t m_targetPosition;
111166
int32_t m_actualPosition;
167+
int16_t m_actualTicksPerLoop;
112168
uint16_t m_dither;
113169
uint16_t m_lastEncTicks;
114-
enum MotorState {
115-
PowerCtrl,
116-
BrakeCtrl,
117-
VelocityCtrl,
118-
PositionCtrl,
119-
} m_state;
170+
uint16_t m_posEpsilon;
171+
uint16_t m_velEpsilon;
172+
uint16_t m_maxAccel;
173+
MotorMode m_mode;
120174
};

fw/rbcx-coprocessor/include/utils/Regulator.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ struct Regulator {
2727
coef_type I() const { return m_i; }
2828
void setD(const coef_type& v) { m_d = v; }
2929
coef_type D() const { return m_d; }
30+
void setMaxOutput(value_type max_output) { m_max_output = max_output; }
31+
value_type maxOutput() { return m_max_output; }
3032

3133
void stop(bool s = true) {
3234
m_stop = s;

fw/rbcx-coprocessor/platformio.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ platform = ststm32@~7.0.0
1717
board = genericSTM32F103VC
1818
framework = stm32cube
1919
lib_deps =
20-
https://github.com/RoboticsBrno/RB3204-RBCX-coproc-comm/archive/703a8cb92b45c5e50f809c58a6e132458ccadc04.zip
20+
https://github.com/RoboticsBrno/RB3204-RBCX-coproc-comm/archive/6715dde5a9b004860dfa17af17f330ded1fa9715.zip
2121

2222
build_flags =
2323
-Iinclude

fw/rbcx-coprocessor/src/DebugLink.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,24 @@ static void debugLinkHandleCommand(const char* cmd) {
278278
dispatcherEnqueueRequest(req);
279279
return;
280280
});
281+
282+
COMMAND("position", {
283+
CoprocReq req = {
284+
.which_payload = CoprocReq_motorReq_tag,
285+
};
286+
auto& c = req.payload.motorReq;
287+
c.which_motorCmd = CoprocReq_MotorReq_setPosition_tag;
288+
if (sscanf(cmd, "%lu %ld %ld", &c.motorIndex,
289+
&c.motorCmd.setPosition.targetPosition,
290+
&c.motorCmd.setPosition.runningVelocity)
291+
!= 3) {
292+
printf("Invalid parameters!\n");
293+
return;
294+
}
295+
296+
dispatcherEnqueueRequest(req);
297+
return;
298+
});
281299
});
282300

283301
COMMAND("leds", {

fw/rbcx-coprocessor/src/MotorController.cpp

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "MotorController.hpp"
22
#include "Bsp.hpp"
3+
#include "ControlLink.hpp"
4+
#include "Dispatcher.hpp"
35
#include "Motor.hpp"
46
#include "utils/Debug.hpp"
57
#include "utils/MutexWrapper.hpp"
@@ -13,6 +15,8 @@
1315
static void setPwmValue(TIM_TypeDef* timer, uint8_t motorIndex, uint16_t value);
1416
static void setMotorPower(uint8_t motorIndex, int32_t power, bool brake);
1517

18+
// Debounce ENC signals at ~3.5us (72MHz fDTS)
19+
static constexpr uint32_t encoderFilter = LL_TIM_IC_FILTER_FDIV32_N8;
1620
static constexpr uint16_t maxPwm = 2000;
1721
static std::array<Motor, 4> motor;
1822
static MutexWrapper motorMut;
@@ -62,11 +66,11 @@ void motorInit() {
6266
encInit.IC1Polarity = LL_TIM_IC_POLARITY_RISING;
6367
encInit.IC1ActiveInput = LL_TIM_ACTIVEINPUT_DIRECTTI;
6468
encInit.IC1Prescaler = LL_TIM_ICPSC_DIV1;
65-
encInit.IC1Filter = LL_TIM_IC_FILTER_FDIV1;
69+
encInit.IC1Filter = encoderFilter;
6670
encInit.IC2Polarity = LL_TIM_IC_POLARITY_RISING;
6771
encInit.IC2ActiveInput = LL_TIM_ACTIVEINPUT_DIRECTTI;
6872
encInit.IC2Prescaler = LL_TIM_ICPSC_DIV1;
69-
encInit.IC2Filter = LL_TIM_IC_FILTER_FDIV1;
73+
encInit.IC2Filter = encoderFilter;
7074
for (auto timer : encoderTimer) {
7175
LL_TIM_ENCODER_Init(timer, &encInit);
7276
LL_TIM_EnableCounter(timer);
@@ -84,8 +88,21 @@ static void taskFunc() {
8488

8589
for (int m : { 0, 1, 2, 3 }) {
8690
uint16_t encTicks = LL_TIM_GetCounter(encoderTimer[m]);
87-
auto action = motor[m].poll(encTicks);
88-
setMotorPower(m, action.first, action.second);
91+
auto& targetMotor = motor[m];
92+
auto modeBefore = targetMotor.mode();
93+
auto action = targetMotor.poll(encTicks);
94+
auto modeAfter = targetMotor.mode();
95+
setMotorPower(m, action, modeAfter == MotorMode_BRAKE);
96+
97+
if (modeBefore == MotorMode_POSITION
98+
&& modeAfter == MotorMode_POSITION_IDLE) {
99+
CoprocStat stat = {
100+
.which_payload = CoprocStat_motorStat_tag,
101+
};
102+
targetMotor.reportStat(stat.payload.motorStat);
103+
stat.payload.motorStat.motorIndex = m;
104+
dispatcherEnqueueStatus(stat);
105+
}
89106
}
90107
}
91108
vTaskDelayUntil(&now, pdMS_TO_TICKS(1000 / motorLoopFreq));
@@ -101,6 +118,14 @@ void motorDispatch(const CoprocReq_MotorReq& request) {
101118
std::scoped_lock lock(motorMut);
102119

103120
switch (request.which_motorCmd) {
121+
case CoprocReq_MotorReq_getState_tag: {
122+
CoprocStat stat = {
123+
.which_payload = CoprocStat_motorStat_tag,
124+
};
125+
targetMotor.reportStat(stat.payload.motorStat);
126+
stat.payload.motorStat.motorIndex = request.motorIndex;
127+
controlLinkTx(stat);
128+
} break;
104129
case CoprocReq_MotorReq_setPower_tag:
105130
targetMotor.setTargetPower(request.motorCmd.setPower);
106131
break;
@@ -117,28 +142,32 @@ void motorDispatch(const CoprocReq_MotorReq& request) {
117142
}
118143
targetMotor.setTargetVelocity(ticksPerSec);
119144
} break;
145+
case CoprocReq_MotorReq_homePosition_tag:
146+
targetMotor.homePosition(request.motorCmd.homePosition);
147+
break;
120148
case CoprocReq_MotorReq_setPosition_tag:
121-
targetMotor.setTargetPosition(request.motorCmd.setPosition);
149+
targetMotor.setTargetPosition(request.motorCmd.setPosition, false);
122150
break;
123151
case CoprocReq_MotorReq_addPosition_tag:
124-
targetMotor.addTargetPosition(request.motorCmd.addPosition);
152+
targetMotor.setTargetPosition(request.motorCmd.addPosition, true);
153+
break;
154+
case CoprocReq_MotorReq_setVelocityRegCoefs_tag:
155+
targetMotor.setVelocityPid(request.motorCmd.setVelocityRegCoefs);
156+
break;
157+
case CoprocReq_MotorReq_setPositionRegCoefs_tag:
158+
targetMotor.setPositionPid(request.motorCmd.setPositionRegCoefs);
159+
break;
160+
case CoprocReq_MotorReq_setConfig_tag:
161+
targetMotor.setConfig(request.motorCmd.setConfig);
125162
break;
126-
case CoprocReq_MotorReq_setVelocityRegCoefs_tag: {
127-
auto& coefs = request.motorCmd.setVelocityRegCoefs;
128-
targetMotor.setVelocityPid(coefs.p, coefs.i, coefs.d);
129-
} break;
130-
case CoprocReq_MotorReq_setPositionRegCoefs_tag: {
131-
auto& coefs = request.motorCmd.setPositionRegCoefs;
132-
targetMotor.setPositionPid(coefs.p, coefs.i, coefs.d);
133-
} break;
134163
}
135164
}
136165

137166
void motorReset() {
138167
std::scoped_lock lock(motorMut);
139168

140169
for (int idx : { 0, 1, 2, 3 }) {
141-
motor[idx].setTargetPower(0);
170+
motor[idx].reset();
142171
setMotorPower(idx, 0, false);
143172
}
144173
}

0 commit comments

Comments
 (0)