搭建ROS小车底盘-第三篇下位机主程序
搭建ROS小车底盘-第三篇下位机主程序
说明
- 介绍下位机主程序的工作流程及对应源码
工作流程
- 实时读取上位机的指令并作出对应的响应(支持的指令见源文件commands.h)
- GET_BAUDRATE 获取串口通讯的比特率
- READ_ENCODERS 读取左右轮编码器的计数
- MOTOR_SPEEDS 设置左右轮的期望速度
- RESET_ENCODERS 重置编码器的计数
- UPDATE_PID 更新PID参数
- READ_PIDOUT 读取PID计算的PWM值,为后续调整PID参数提供参考
- READ_PIDIN 读取一个PID周期内编码器的计数,为后续调整PID参数提供参考
- 在每个PID周期内,比较左右轮期望速度和实际速度的差异,调整PWM的。
- 如果AUTO_STOP_INTERVAL毫秒内上位机没有期望速度,就会停止小车运动。
主程序源码
- 原教程少定义了命令,会导致出错,此为更正版本
- ROSArduinoBridge.ino源码:
#define BAUDRATE 115200
#define MAX_PWM 255
#include "Arduino.h"
#include "commands.h"
#include "motor_driver.h"
#include "encoder_driver.h"
#include "diff_controller.h"
#define PID_RATE 30 // Hz
const int PID_INTERVAL = 1000 / PID_RATE;
unsigned long nextPID = PID_INTERVAL;
#define AUTO_STOP_INTERVAL 2000
long lastMotorCommand = AUTO_STOP_INTERVAL;
/* Variable initialization */
int arg = 0;
int index = 0;
char chr;
char cmd;
char argv1[16];
char argv2[16];
long arg1;
long arg2;
void resetCommand() {
cmd = NULL;
memset(argv1, 0, sizeof(argv1));
memset(argv2, 0, sizeof(argv2));
arg1 = 0;
arg2 = 0;
arg = 0;
index = 0;
}
int runCommand() {
int i = 0;
char *p = argv1;
char *str;
int pid_args[4];
arg1 = atoi(argv1);
arg2 = atoi(argv2);
switch (cmd) {
case GET_BAUDRATE:
Serial.println(BAUDRATE);
break;
case READ_PIDIN:
Serial.print( readPidIn(LEFT));
Serial.print(" ");
Serial.println( readPidIn(RIGHT));
break;
case READ_PIDOUT:
Serial.print( readPidOut(LEFT));
Serial.print(" ");
Serial.println( readPidOut(RIGHT));
break;
case READ_ENCODERS:
Serial.print(readEncoder(LEFT));
Serial.print(" ");
Serial.println(readEncoder(RIGHT));
break;
case RESET_ENCODERS:
resetEncoders();
resetPID();
Serial.println("OK");
break;
case MOTOR_SPEEDS:
lastMotorCommand = millis();
if (arg1 == 0 && arg2 == 0) {
setMotorSpeeds(0, 0);
moving = 0;
}
else moving = 1;
leftPID.TargetTicksPerFrame = arg1;
rightPID.TargetTicksPerFrame = arg2;
Serial.println("OK");
break;
case UPDATE_PID:
while ((str = strtok_r(p, ":", &p)) != '\0') {
pid_args[i] = atoi(str);
i++;
}
Kp = pid_args[0];
Kd = pid_args[1];
Ki = pid_args[2];
Ko = pid_args[3];
Serial.println("OK");
break;
case ANALOG_READ:
Serial.println(analogRead(arg1));
break;
case DIGITAL_READ:
Serial.println(digitalRead(arg1));
break;
case ANALOG_WRITE:
analogWrite(arg1, arg2);
Serial.println("OK");
break;
case DIGITAL_WRITE:
if (arg2 == 0) digitalWrite(arg1, LOW);
else if (arg2 == 1) digitalWrite(arg1, HIGH);
Serial.println("OK");
break;
case PIN_MODE:
if (arg2 == 0) pinMode(arg1, INPUT);
else if (arg2 == 1) pinMode(arg1, OUTPUT);
Serial.println("OK");
break;
default:
Serial.println("Invalid Command");
break;
}
}
unsigned long time = 0, old_time = 0;
void setup() {
Serial.begin(BAUDRATE);
initEncoders();
initMotorController();
resetPID();
}
void loop() {
while (Serial.available() > 0) {
chr = Serial.read();
if (chr == 13) {
if (arg == 1) argv1[index] = NULL;
else if (arg == 2) argv2[index] = NULL;
runCommand();
resetCommand();
}
else if (chr == ' ') {
if (arg == 0) arg = 1;
else if (arg == 1) {
argv1[index] = NULL;
arg = 2;
index = 0;
}
continue;
}
else {
if (arg == 0) {
cmd = chr;
}
else if (arg == 1) {
argv1[index] = chr;
index++;
}
else if (arg == 2) {
argv2[index] = chr;
index++;
}
}
}
if (millis() > nextPID) {
updatePID();
nextPID += PID_INTERVAL;
}
if ((millis() - lastMotorCommand) > AUTO_STOP_INTERVAL) {
;
setMotorSpeeds(0, 0);
moving = 0;
}
}
- 原教程少定义了命令,会导致出错,此为更正版本
- commands.h源码:
#define GET_BAUDRATE 'b'
#define READ_ENCODERS 'e'
#define MOTOR_SPEEDS 'm'
#define RESET_ENCODERS 'r'
#define UPDATE_PID 'u'
#define READ_PIDOUT 'f'
#define READ_PIDIN 'i'
#define PIN_MODE 'c'
#define DIGITAL_READ 'd'
#define ANALOG_READ 'a'
#define DIGITAL_WRITE 'w'
#define ANALOG_WRITE 'x'
#define LEFT 0
#define RIGHT 1
#define FORWARDS true
#define BACKWARDS false
获取最新文章: 扫一扫右上角的二维码加入“创客智造”公众号