ros小车(二)arduino代码
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
diff_controller.h
typedef struct {
double TargetTicksPerFrame; // target speed in ticks per frame
long Encoder; // encoder count
long PrevEnc; // last encoder count
int PrevInput; // last input
int ITerm; //integrated term
long output; // last motor setting
}
SetPointInfo;
SetPointInfo leftPID, rightPID;
int Kp = 20;
int Kd = 12;
int Ki = 0;
int Ko = 50;
unsigned char moving = 0; // is the base in motion?
void resetPID(){
leftPID.TargetTicksPerFrame = 0.0;
leftPID.Encoder = readEncoder(LEFT);
leftPID.PrevEnc = leftPID.Encoder;
leftPID.output = 0;
leftPID.PrevInput = 0;
leftPID.ITerm = 0;
rightPID.TargetTicksPerFrame = 0.0;
rightPID.Encoder = readEncoder(RIGHT);
rightPID.PrevEnc = rightPID.Encoder;
rightPID.output = 0;
rightPID.PrevInput = 0;
rightPID.ITerm = 0;
}
void doPID(SetPointInfo * p) {
long Perror;
long output;
int input;
input = p->Encoder - p->PrevEnc;
Perror = p->TargetTicksPerFrame - input;
output = (Kp * Perror - Kd * (input - p->PrevInput) + p->ITerm) / Ko;
p->PrevEnc = p->Encoder;
output += p->output;
if (output >= MAX_PWM)
output = MAX_PWM;
else if (output <= -MAX_PWM)
output = -MAX_PWM;
else
p->ITerm += Ki * Perror;
p->output = output;
p->PrevInput = input;
}
void updatePID() {
leftPID.Encoder = readEncoder(LEFT);
rightPID.Encoder = readEncoder(RIGHT);
if (!moving){
if (leftPID.PrevInput != 0 || rightPID.PrevInput != 0) resetPID();
return;
}
doPID(&rightPID);
doPID(&leftPID);
setMotorSpeeds(leftPID.output, rightPID.output);
}
long readPidIn(int i) {
long pidin=0;
if (i == LEFT){
pidin = leftPID.PrevInput;
}else {
pidin = rightPID.PrevInput;
}
return pidin;
}
long readPidOut(int i) {
long pidout=0;
if (i == LEFT){
pidout = leftPID.output;
}else {
pidout = rightPID.output;
}
return pidout;
}
encoder_driver.h
long readEncoder(int i);
void resetEncoder(int i);
void resetEncoders();
void initEncoders();
void encoderRightISR();
void encoderLeftISR();
encoder_driver.ino
#include "motor_driver.h"
#include "commands.h"
/* encode */
volatile long left_enc_pos = 0L;
volatile long right_enc_pos = 0L;
int left_rotate = 0;
int right_rotate = 0;
void initEncoders(){
//两个电机编码器连线
pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(19, INPUT);
pinMode(18, INPUT);
attachInterrupt(0, encoderLeftISR, CHANGE);
attachInterrupt(1, encoderLeftISR, CHANGE);
attachInterrupt(4, encoderRightISR, CHANGE);
attachInterrupt(5, encoderRightISR, CHANGE);
}
void encoderLeftISR(){
if(direction(LEFT) == BACKWARDS){
left_enc_pos--;
}else{
left_enc_pos++;
}
}
void encoderRightISR(){
if(direction(RIGHT) == BACKWARDS){
right_enc_pos--;
}else{
right_enc_pos++;
}
}
long readEncoder(int i) {
long encVal = 0L;
if (i == LEFT) {
noInterrupts();
encVal = left_enc_pos;
interrupts();
}
else {
noInterrupts();
encVal = right_enc_pos;
interrupts();
}
return encVal;
}
/* Wrap the encoder reset function */
void resetEncoder(int i) {
if (i == LEFT){
noInterrupts();
left_enc_pos=0L;
interrupts();
return;
} else {
noInterrupts();
right_enc_pos=0L;
interrupts();
return;
}
}
void resetEncoders() {
resetEncoder(LEFT);
resetEncoder(RIGHT);
}
motor_driver.h
void initMotorController();
void setMotorSpeed(int i, int spd);
void setMotorSpeeds(int leftSpeed, int rightSpeed);
motor_driver.ino
#include "commands.h"
// motor one
int enA = 11;
int in1 = 7;
int in2 = 8;
// motor two
int enB = 6;
int in3 = 9;
int in4 = 10;
boolean directionLeft = false;
boolean directionRight = false;
boolean direction(int i){
if(i == LEFT){
return directionLeft;
}else{
return directionRight;
}
}
void initMotorController() {
// set all the motor control pins to outputs
pinMode(enA, OUTPUT);
pinMode(enB, OUTPUT);
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
pinMode(in3, OUTPUT);
pinMode(in4, OUTPUT);
}
void setMotorSpeed(int i, int spd) {
if(spd>MAX_PWM){
spd=MAX_PWM;
}
if(spd<-MAX_PWM){
spd=-1*MAX_PWM;
}
if (i == LEFT){
if(spd>=0){
directionLeft = FORWARDS;
digitalWrite(in2, HIGH);
digitalWrite(in1, LOW);
analogWrite(enA, spd);
}else if(spd < 0){
directionLeft = BACKWARDS;
digitalWrite(in1, HIGH);
digitalWrite(in2, LOW);
analogWrite(enA, -spd);
}
}
else {
if(spd>=0){
directionRight = FORWARDS;
digitalWrite(in3, HIGH);
digitalWrite(in4, LOW);
analogWrite(enB, spd);
}else if(spd<0){
directionRight = BACKWARDS;
digitalWrite(in4, HIGH);
digitalWrite(in3, LOW);
analogWrite(enB, -spd);
}
}
}
void setMotorSpeeds(int leftSpeed, int rightSpeed) {
setMotorSpeed(LEFT, leftSpeed);
setMotorSpeed(RIGHT, rightSpeed);
}
ROSArduinoBridge.ino
#define BAUDRATE 9600
#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;
}
}
代码放在一块进行上传,上传后才可以进行使用ros_arduino_bridge
本文作者: 永生
本文链接: https://yys.zone/detail/?id=135
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!
发表评论
评论列表 (0 条评论)
暂无评论,快来抢沙发吧!