9#define RX_BUFFER_SIZE 24
12#define CIRC_BUFFER_SIZE 16
15#define CMD_VCTR_SIZE 8
21#define SERVO_DUTY_CYCLE_LOWER_BOUND 2.5
24#define SERVO_DUTY_CYCLE_UPPER_BOUND 12.5
27#define PID_THRESHOLD 0.90
30char rxBuffer[RX_BUFFER_SIZE];
41 char name[ARG_LENGTH];
42 char value[ARG_LENGTH];
56 char cmdName[ARG_LENGTH];
57 void (*function)(void);
71 void (*function)(void);
77volatile uint8_t cmdWriteIdx = 0;
78volatile uint8_t cmdReadIdx = 0;
79volatile uint8_t cmdCount = 0;
84volatile long encoderPos;
85double pulsesPerRev = 580.0;
86uint32_t interval = 20000;
92double lastInput = 0.0;
94double integralMax = 100.0;
95double integralMin = -100.0;
97uint8_t motorSpeed = 0;
99extern TIM_HandleTypeDef htim3;
100extern TIM_HandleTypeDef htim15;
101extern TIM_HandleTypeDef htim16;
102extern TIM_HandleTypeDef htim17;
106void ParseCommand(
void);
109void SelectInputChannel(uint8_t);
110void SelectOutputChannel(uint8_t);
111void ComputePID(
void);
112void setPWMPulse(
int,
float);
113float clamp(
float,
float,
float);
114float map(
float,
float,
float,
float,
float);
121void ParseCommand(
void) {
123 char *input = (
char*) rxBuffer;
124 char *token = strtok(input,
" ");
132 strcpy(command.cmdName, token);
133 token = strtok(NULL,
" ");
136 while (token != NULL && argIndex < CMD_VCTR_SIZE) {
137 if (token[0] ==
'-') {
139 strcpy(command.args[argIndex].name, token);
140 token = strtok(NULL,
" ");
144 strcpy(command.args[argIndex].value, token);
149 token = strtok(NULL,
" ");
153 if (cmdCount < CIRC_BUFFER_SIZE) {
154 circBuffer[cmdWriteIdx] = command;
155 cmdWriteIdx = (cmdWriteIdx + 1) % CIRC_BUFFER_SIZE;
171 float dutyCycle = -1;
175 for (
int i = 0; i < CMD_VCTR_SIZE; i++) {
177 if (strcmp(cmdVctr->args[i].name,
"-i") == 0) {
178 inputChnl = atoi(cmdVctr->args[i].value);
181 else if (strcmp(cmdVctr->args[i].name,
"-o") == 0) {
182 outputChnl = atoi(cmdVctr->args[i].value);
185 else if (strcmp(cmdVctr->args[i].name,
"-d") == 0) {
186 dutyCycle = atof(cmdVctr->args[i].value);
188 else if (strcmp(cmdVctr->args[i].name,
"-t") == 0) {
189 time = atof(cmdVctr->args[i].value);
194 SelectInputChannel((uint8_t) inputChnl - 1);
197 SelectOutputChannel((uint8_t) outputChnl - 1);
200 setPWMPulse(inputChnl - 1, dutyCycle);
204 uint32_t target = time * 1000000;
205 uint32_t lastTime = __HAL_TIM_GET_COUNTER(&htim16);
206 uint32_t previousCounter = lastTime;
207 uint32_t overflow = 0;
208 uint32_t elapsed = 0;
211 while (elapsed <= target) {
212 uint32_t currentCounter = __HAL_TIM_GET_COUNTER(&htim16);
214 if (currentCounter < previousCounter) {
220 elapsed = (overflow * 0x10000 + currentCounter - lastTime);
221 previousCounter = currentCounter;
225 setPWMPulse(inputChnl - 1, 0.0);
238 target = atof(cmdVctr->args[0].value) * pulsesPerRev;
239 uint32_t lastTime = __HAL_TIM_GET_COUNTER(&htim16);
241 while (encoderPos != (target * PID_THRESHOLD)) {
242 uint32_t now = __HAL_TIM_GET_COUNTER(&htim16);
243 uint32_t elapsed = now >= lastTime ? (now - lastTime) : ((0xFFFF - lastTime) + now + 1);
245 if (elapsed >= interval) {
252 HAL_GPIO_WritePin(PH1_GPIO_Port, PH1_Pin, GPIO_PIN_SET);
253 HAL_GPIO_WritePin(PH2_GPIO_Port, PH2_Pin, GPIO_PIN_RESET);
256 HAL_GPIO_WritePin(PH1_GPIO_Port, PH1_Pin, GPIO_PIN_RESET);
257 HAL_GPIO_WritePin(PH2_GPIO_Port, PH2_Pin, GPIO_PIN_SET);
258 motorSpeed = -output;
261 motorSpeed = clamp(motorSpeed, 0, 255);
262 __HAL_TIM_SET_COMPARE(&htim17, TIM_CHANNEL_1, motorSpeed);
266 HAL_GPIO_WritePin(PH1_GPIO_Port, PH1_Pin, GPIO_PIN_RESET);
267 HAL_GPIO_WritePin(PH2_GPIO_Port, PH2_Pin, GPIO_PIN_RESET);
268 __HAL_TIM_SET_COMPARE(&htim17, TIM_CHANNEL_1, 0);
272 uint32_t now = __HAL_TIM_GET_COUNTER(&htim16);
273 uint32_t deltaMicros = now - lastTime;
276 double deltaTime = deltaMicros / 1000000.0;
277 double error = target - input;
278 integral += error * deltaTime;
280 if (integral > integralMax) integral = integralMax;
281 if (integral < integralMin) integral = integralMin;
283 double derivative = (input - lastInput) / deltaTime;
285 output = Kp * error + Ki * integral + Kd * derivative;
287 if (output > 255) output = 255;
288 if (output < -255) output = -255;
302float clamp(
float input,
float lowerBound,
float upperBound) {
303 return input < lowerBound
323float map(
float value,
float fromLower,
float fromUpper,
float toLower,
float toUpper) {
324 return (value - fromLower) * (toUpper - toLower) / (fromUpper - fromLower) + toLower;
337void setPWMPulse(
int inputChannel,
float dutyCycle) {
340 if (inputChannel == 0) {
341 dutyCycle = map(dutyCycle, 0, 100, SERVO_DUTY_CYCLE_LOWER_BOUND, SERVO_DUTY_CYCLE_UPPER_BOUND);
344 uint8_t pulse = (uint8_t)((dutyCycle / 100.0) * 255);
347 if (inputChannel == 0) {
348 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, pulse);
349 }
else if (inputChannel == 1) {
350 __HAL_TIM_SET_COMPARE(&htim15, TIM_CHANNEL_1, pulse);
Structure for storing command arguments.
Definition cli.h:40
Structure for storing commands.
Definition cli.h:69
Structure for storing commands.
Definition cli.h:55