ROS小车3

ros_arduino_bridge功能包集

请尽量自行在源码上修改。

文件树及说明:这里引用创客智造

├── README.md
├── ros_arduino_bridge                      # metapackage (元包)
│   ├── CMakeLists.txt
│   └── package.xml
├── ros_arduino_firmware                    #固件包,更新到Arduino
│   ├── CMakeLists.txt
│   ├── package.xml
│   └── src
│       └── libraries                       #库目录
│           ├── MegaRobogaiaPololu          #针对Pololu电机控制器,MegaRobogaia编码器的头文件定义
│           │   ├── commands.h              #定义命令头文件
│           │   ├── diff_controller.h       #差分轮PID控制头文件
│           │   ├── MegaRobogaiaPololu.ino  #PID实现文件
│           │   ├── sensors.h               #传感器相关实现,超声波测距,Ping函数
│           │   └── servos.h                #伺服器头文件
│           └── ROSArduinoBridge            #Arduino相关库定义
│               ├── commands.h              #定义命令
│               ├── diff_controller.h       #差分轮PID控制头文件
│               ├── encoder_driver.h        #编码器驱动头文件,定义插脚(pins)
│               ├── encoder_driver.ino      #编码器驱动实现, 读取编码器数据,重置编码器等
│               ├── motor_driver.h          #电机驱动头文件
│               ├── motor_driver.ino        #电机驱动实现,初始化控制器,设置速度
│               ├── ROSArduinoBridge.ino    #核心功能实现,
│               ├── sensors.h               #传感器头文件及实现
│               ├── servos.h                #伺服器头文件,定义插脚,类
│               └── servos.ino              #伺服器实现
├── ros_arduino_msgs                        #消息定义包
│   ├── CMakeLists.txt
│   ├── msg                                 #定义消息
│   │   ├── AnalogFloat.msg                 #定义模拟IO浮点消息
│   │   ├── Analog.msg                      #定义模拟IO数字消息
│   │   ├── ArduinoConstants.msg            #定义常量消息
│   │   ├── Digital.msg                     #定义数字IO消息
│   │   └── SensorState.msg                 #定义传感器状态消息
│   ├── package.xml
│   └── srv                                 #定义服务
│       ├── AnalogRead.srv                  #模拟IO输入
│       ├── AnalogWrite.srv                 #模拟IO输出
│       ├── DigitalRead.srv                 #数字IO输入
│       ├── DigitalSetDirection.srv     #数字IO设置方向
│       ├── DigitalWrite.srv                #数字IO输入
│       ├── ServoRead.srv                   #伺服电机输入
│       └── ServoWrite.srv                  #伺服电机输出
└── ros_arduino_python                      #ROS相关的Python包,用于上位机,树莓派等开发板或电脑等。
    ├── CMakeLists.txt
    ├── config                              #配置目录
    │   └── arduino_params.yaml             #定义相关参数,端口,rate,PID,sensors等默认参数。由arduino.launch调用
    ├── launch
    │   └── arduino.launch                  #启动文件
    ├── nodes
    │   └── arduino_node.py                 #python文件,实际处理节点,由arduino.launch调用,即可单独调用。
    ├── package.xml
    ├── setup.py
    └── src                                 #Python类包目录
        └── ros_arduino_python
            ├── arduino_driver.py           #Arduino驱动类
            ├── arduino_sensors.py          #Arduino传感器类
            ├── base_controller.py          #基本控制类,订阅cmd_vel话题,发布odom话题
            └── __init__.py                 #类包默认空文件  
        
        

各部分源码:

arduino下位机部分:(如果不能运行,可能是注释的问题)

  • commands.h  命令:
/* Define single-letter commands that will be sent by the PC over the
   serial link.
*/

#ifndef COMMANDS_H
#define COMMANDS_H

#define ANALOG_READ    'a' // 模拟读取
#define GET_BAUDRATE   'b' // 获取波特率
#define PIN_MODE       'c' // 接口模式
#define DIGITAL_READ   'd' // 数字读取
#define READ_ENCODERS  'e' // 读取编码器数据 输出为:左数据,右数据
#define MOTOR_SPEEDS   'm' // 设置马达速度,脉冲计数 如: m 20 20 会以一个很的速度转动
#define PING           'p' // 无用
#define RESET_ENCODERS 'r' // 重设编码器读数
#define SERVO_WRITE    's' // 舵机相关,我这里没有用到
#define SERVO_READ     't' // 舵机相关,我这里没有用到
#define UPDATE_PID     'u' // 更新pid参数
#define DIGITAL_WRITE  'w' // 数字端口设置
#define ANALOG_WRITE   'x' // 模拟端口设置
#define READ_PIDOUT  'f'   // 读取pid计算出的速度(脉冲数计数)
#define READ_PIDIN  'i'    // 读取进入pid的速度

#define LEFT            0
#define RIGHT           1

#define FORWARDS true   //FORWARDS前进代表bool真值true
#define BACKWARDS false //BACKWARDS后退代表bool假值false

#endif
  • ROSArduinoBridge.ino源码:
//这是在官方包基础上修改来的


#define USE_BASE      // Enable the base controller code 是否使用base controller
//#undef USE_BASE     // Disable the base controller code

/* Define the motor controller and encoder library you are using */
//定义电机控制方式,使用ifdef 的方式,和正常的if 语句类似
#ifdef USE_BASE
/* The Pololu VNH5019 dual motor driver shield */
//#define POLOLU_VNH5019

/* The Pololu MC33926 dual motor driver shield */
//#define POLOLU_MC33926

/* The RoboGaia encoder shield */
//#define ROBOGAIA

/* Encoders directly attached to Arduino board */
//#define ARDUINO_ENC_COUNTER

/* L298 Motor driver*/
#define L298_MOTOR_DRIVER //这里只是借用名称,之后需要自己更改驱动
#endif

//#define USE_SERVOS  // Enable use of PWM servos as defined in servos.h
#undef USE_SERVOS     // Disable use of PWM servos //不适用SERVOS

/* Serial port baud rate */
#define BAUDRATE     57600 //波特率

/* Maximum PWM signal */
#define MAX_PWM        255 //最大pwm

#if defined(ARDUINO) && ARDUINO >= 100 //不知到用处
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

/* Include definition of serial commands */
#include "commands.h"

/* Sensor functions */
//#include "sensors.h" //不使用

/* Include servo support if required */
#ifdef USE_SERVOS
#include <Servo.h>
#include "servos.h"
#endif

#ifdef USE_BASE
/* Motor driver function definitions */
#include "motor_driver.h"//加载电机控制头文件

/* Encoder driver function definitions */
#include "encoder_driver.h"//加载编码器控制头文件

/* PID parameters and functions */
#include "diff_controller.h"//加载PID控制

/* Run the PID loop at 30 times per second */
#define PID_RATE           30     // Hz //看英文注释

/* Convert the rate into an interval */
const int PID_INTERVAL = 1000 / PID_RATE; //看英文注释

/* Track the next time we make a PID calculation */
unsigned long nextPID = PID_INTERVAL;

/* Stop the robot if it hasn't received a movement command
  in this number of milliseconds */
#define AUTO_STOP_INTERVAL 2000
long lastMotorCommand = AUTO_STOP_INTERVAL;
#endif

/* Variable initialization */

// A pair of varibles to help parse serial commands (thanks Fergs)
int arg = 0;
int index = 0;

// Variable to hold an input character
char chr;

// Variable to hold the current single-character command
char cmd;

// Character arrays to hold the first and second arguments
char argv1[16];
char argv2[16];

// The arguments converted to integers
long arg1;
long arg2;

/* Clear the current command parameters */
void resetCommand() {
  cmd = NULL;
  memset(argv1, 0, sizeof(argv1));
  memset(argv2, 0, sizeof(argv2));
  arg1 = 0;
  arg2 = 0;
  arg = 0;
  index = 0;
}

/* Run a command.  Commands are defined in commands.h */ 
//运行命令,命令在commands.h中被定义
int runCommand() {
  int i = 0;
  char *p = argv1;
  char *str;
  int pid_args[8]; //由于左右电机使用不同的pid参数,一面要4个
  arg1 = atoi(argv1);
  arg2 = atoi(argv2);

  switch (cmd) {
    case READ_PIDIN: //与commands.h中的匹配 这里为添加的,原代码中没有
      Serial.print( readPidIn(LEFT));
      Serial.print(" ");
      Serial.println( readPidIn(RIGHT));
      break;
    case READ_PIDOUT://为了方便之后的PID调整
      Serial.print( readPidOut(LEFT));
      Serial.print(" ");
      Serial.println( readPidOut(RIGHT));
      break;
    case GET_BAUDRATE:
      Serial.println(BAUDRATE);
      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;
      /*case PING:
        Serial.println(Ping(arg1));
        break;*/
#ifdef USE_SERVOS
    case SERVO_WRITE:
      servos[arg1].setTargetPosition(arg2);
      Serial.println("OK");
      break;
    case SERVO_READ:
      Serial.println(servos[arg1].getServo().read());
      break;
#endif

#ifdef USE_BASE
    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:
      /* Reset the auto stop timer */
      lastMotorCommand = millis();
      if (arg1 == 0 && arg2 == 0) {
        setMotorSpeeds(0, 0);
        resetPID();
        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++;
      }
      lKp = pid_args[0];
      lKd = pid_args[1];
      lKi = pid_args[2];
      lKo = pid_args[3];

      rKp = pid_args[4];
      rKd = pid_args[5];
      rKi = pid_args[6];
      rKo = pid_args[7];

      Serial.println("OK");
      break;
#endif
    default:
      Serial.println("Invalid Command");
      break;
  }
}

/* Setup function--runs once at startup. */
//记得初始化那些函数
void setup() {
  Serial.begin(BAUDRATE);

  // Initialize the motor controller if used */
#ifdef USE_BASE
#ifdef ARDUINO_ENC_COUNTER
  //set as inputs
  DDRD &= ~(1 << LEFT_ENC_PIN_A);
  DDRD &= ~(1 << LEFT_ENC_PIN_B);
  DDRC &= ~(1 << RIGHT_ENC_PIN_A);
  DDRC &= ~(1 << RIGHT_ENC_PIN_B);

  //enable pull up resistors
  PORTD |= (1 << LEFT_ENC_PIN_A);
  PORTD |= (1 << LEFT_ENC_PIN_B);
  PORTC |= (1 << RIGHT_ENC_PIN_A);
  PORTC |= (1 << RIGHT_ENC_PIN_B);

  // tell pin change mask to listen to left encoder pins
  PCMSK2 |= (1 << LEFT_ENC_PIN_A) | (1 << LEFT_ENC_PIN_B);
  // tell pin change mask to listen to right encoder pins
  PCMSK1 |= (1 << RIGHT_ENC_PIN_A) | (1 << RIGHT_ENC_PIN_B);

  // enable PCINT1 and PCINT2 interrupt in the general interrupt mask
  PCICR |= (1 << PCIE1) | (1 << PCIE2);
#endif
  initEncoders();
  initMotorController();
  resetPID();
#endif

  /* Attach servos if used */
#ifdef USE_SERVOS
  int i;
  for (i = 0; i < N_SERVOS; i++) {
    servos[i].initServo(
      servoPins[i],
      stepDelay[i],
      servoInitPosition[i]);
  }
#endif
}

/* Enter the main loop.  Read and parse input from the serial port
   and run any valid commands. Run a PID calculation at the target
   interval and check for auto-stop conditions.
*/
void loop() {
  while (Serial.available() > 0) {

    // Read the next character
    chr = Serial.read();

    // Terminate a command with a CR
    if (chr == 13) {
      if (arg == 1) argv1[index] = NULL;
      else if (arg == 2) argv2[index] = NULL;
      runCommand();
      resetCommand();
    }
    // Use spaces to delimit parts of the command
    else if (chr == ' ') {
      // Step through the arguments
      if (arg == 0) arg = 1;
      else if (arg == 1)  {
        argv1[index] = NULL;
        arg = 2;
        index = 0;
      }
      continue;
    }
    else {
      if (arg == 0) {
        // The first arg is the single-letter command
        cmd = chr;
      }
      else if (arg == 1) {
        // Subsequent arguments can be more than one character
        argv1[index] = chr;
        index++;
      }
      else if (arg == 2) {
        argv2[index] = chr;
        index++;
      }
    }
  }

  // If we are using base control, run a PID calculation at the appropriate intervals
#ifdef USE_BASE
  if (millis() > nextPID) {
    updatePID();
    nextPID += PID_INTERVAL;
  }

  // Check to see if we have exceeded the auto-stop interval
  if ((millis() - lastMotorCommand) > AUTO_STOP_INTERVAL) {
    ;
    setMotorSpeeds(0, 0);
    moving = 0;
  }
#endif

  // Sweep servos
#ifdef USE_SERVOS
  int i;
  for (i = 0; i < N_SERVOS; i++) {
    servos[i].doSweep();
  }
#endif
}
  •  encoder_driver.h源码:
/* *************************************************************
   Encoder driver function definitions - by James Nugen
   ************************************************************ */
long readEncoder(int i);
void resetEncoder(int i);
void resetEncoders();
void initEncoders();//初始化编码器
void encoderRightISR1();//编码器中断服务
void encoderLeftISR1();//编码器中断服务
void encoderRightISR();//编码器中断服务
void encoderLeftISR();//编码器中断服务
  •  encoder_driver.ino源码
/* *************************************************************
   Encoder definitions

   Add an "#ifdef" block to this file to include support for
   a particular encoder board or library. Then add the appropriate
   #define near the top of the main ROSArduinoBridge.ino file.

   ************************************************************ */

#ifdef USE_BASE


#include "motor_driver.h"//包含上面的头文件
#include "commands.h";
/* Wrap the encoder reset function */

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);
}

//编码器无法分辨正反转,使用程序进行判断。这里的direction(LEFT)为电机驱动程序块的
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) {
    left_enc_pos = 0L;
    return;
  } else {
    right_enc_pos = 0L;
    return;
  }
}

/* Wrap the encoder reset function */
//整体封装
void resetEncoders() {
  resetEncoder(LEFT);
  resetEncoder(RIGHT);
}

#endif
  • diff_controller.h源码

这里添加了左右轮的pid算法,适合左右电机差别比较大的情况,pid调整方法请百度

/* Functions and type-defs for PID control.

   Taken mostly from Mike Ferguson's ArbotiX code which lives at:
   
   http://vanadium-ros-pkg.googlecode.com/svn/trunk/arbotix/
*/

/* PID setpoint info For a Motor */
typedef struct {
  double TargetTicksPerFrame;    // target speed in ticks per frame
  long Encoder;                  // encoder count
  long PrevEnc;                  // last encoder count

  /*
  * Using previous input (PrevInput) instead of PrevError to avoid derivative kick,
  * see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-derivative-kick/
  */
  int PrevInput;                // last input
  //int PrevErr;                   // last error

  /*
  * Using integrated term (ITerm) instead of integrated error (Ierror),
  * to allow tuning changes,
  * see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/
  */
  //int Ierror;
  int ITerm;                    //integrated term

  long output;                    // last motor setting
}
SetPointInfo;

SetPointInfo leftPID, rightPID;

/* PID Parameters */
int lKp = 20;
int lKd = 12;
int lKi = 0;
int lKo = 50;

int rKp = 20;
int rKd = 12;
int rKi = 0;
int rKo = 50;

unsigned char moving = 0; // is the base in motion?

/*
* Initialize PID variables to zero to prevent startup spikes
* when turning PID on to start moving
* In particular, assign both Encoder and PrevEnc the current encoder value
* See http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-initialization/
* Note that the assumption here is that PID is only turned on
* when going from stop to moving, that's why we can init everything on zero.
*/
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;
}

/* PID routine to compute the next motor commands */
void doPIDL(SetPointInfo * p) {
  long Perror;
  long output;
  int input;

  //Perror = p->TargetTicksPerFrame - (p->Encoder - p->PrevEnc);
  input = p->Encoder - p->PrevEnc;
  Perror = p->TargetTicksPerFrame - input;


  /*
  * Avoid derivative kick and allow tuning changes,
  * see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-derivative-kick/
  * see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/
  */
  //output = (Kp * Perror + Kd * (Perror - p->PrevErr) + Ki * p->Ierror) / Ko;
  // p->PrevErr = Perror;
  output = (lKp * Perror - lKd * (input - p->PrevInput) + p->ITerm) / lKo;
  p->PrevEnc = p->Encoder;

  output += p->output;
  // Accumulate Integral error *or* Limit output.
  // Stop accumulating when output saturates
  if (output >= MAX_PWM)
    output = MAX_PWM;
  else if (output <= -MAX_PWM)
    output = -MAX_PWM;
  else
  /*
  * allow turning changes, see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/
  */
    p->ITerm += lKi * Perror;

  p->output = output;
  p->PrevInput = input;
}
void doPIDR(SetPointInfo * p) {
  long Perror;
  long output;
  int input;

  //Perror = p->TargetTicksPerFrame - (p->Encoder - p->PrevEnc);
  input = p->Encoder - p->PrevEnc;
  Perror = p->TargetTicksPerFrame - input;


  /*
  * Avoid derivative kick and allow tuning changes,
  * see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-derivative-kick/
  * see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/
  */
  //output = (Kp * Perror + Kd * (Perror - p->PrevErr) + Ki * p->Ierror) / Ko;
  // p->PrevErr = Perror;
  output = (rKp * Perror - rKd * (input - p->PrevInput) + p->ITerm) / rKo;
  p->PrevEnc = p->Encoder;

  output += p->output;
  // Accumulate Integral error *or* Limit output.
  // Stop accumulating when output saturates
  if (output >= MAX_PWM)
    output = MAX_PWM;
  else if (output <= -MAX_PWM)
    output = -MAX_PWM;
  else
  /*
  * allow turning changes, see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/
  */
    p->ITerm += rKi * Perror;

  p->output = output;
  p->PrevInput = input;
}

/* Read the encoder values and call the PID routine */
void updatePID() {
  /* Read the encoders */
  leftPID.Encoder = readEncoder(LEFT);
  rightPID.Encoder = readEncoder(RIGHT);
  
  /* If we're not moving there is nothing more to do */
  if (!moving){
    /*
    * Reset PIDs once, to prevent startup spikes,
    * see http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-initialization/
    * PrevInput is considered a good proxy to detect
    * whether reset has already happened
    */
    if (leftPID.PrevInput != 0 || rightPID.PrevInput != 0) resetPID();
    return;
  }

  /* Compute PID update for each motor */
  doPIDR(&rightPID);
  doPIDL(&leftPID);

  /* Set the motor speeds accordingly */
  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;
}

  • motor_driver.h源码

按照对应的格式修改

/***************************************************************
   Motor driver function definitions - by James Nugen
   *************************************************************/

#ifdef L298_MOTOR_DRIVER 
  #define RIGHT_MOTOR_BACKWARD 4
  #define LEFT_MOTOR_BACKWARD  8
  #define RIGHT_MOTOR_FORWARD  5
  #define LEFT_MOTOR_FORWARD   9
#endif
//这里用的不是L298N 只是为了方便 这里使用的是蓝宙电子的双路控制板,
//双PWM输入差分法
//例如 PWM1 =40 PWM2=0 正转 PWM1 =0 PWM2=40 反转
void initMotorController();
void setMotorSpeed(int i, int spd);
void setMotorSpeeds(int leftSpeed, int rightSpeed);
boolean direction(int i);
  • motor_driver.ino源码 
/***************************************************************
   Motor driver definitions

   Add a "#elif defined" block to this file to include support
   for a particular motor driver.  Then add the appropriate
   #define near the top of the main ROSArduinoBridge.ino file.

   *************************************************************/

#ifdef USE_BASE


//这里可以不用看(到下一个注释)
#ifdef POLOLU_VNH5019
/* Include the Pololu library */
#include "DualVNH5019MotorShield.h"

/* Create the motor driver object */
DualVNH5019MotorShield drive;

/* Wrap the motor driver initialization */
void initMotorController() {
  drive.init();
}

/* Wrap the drive motor set speed function */
void setMotorSpeed(int i, int spd) {
  if (i == LEFT) drive.setM1Speed(spd);
  else drive.setM2Speed(spd);
}

// A convenience function for setting both motor speeds
void setMotorSpeeds(int leftSpeed, int rightSpeed) {
  setMotorSpeed(LEFT, leftSpeed);
  setMotorSpeed(RIGHT, rightSpeed);
}
#elif defined POLOLU_MC33926
/* Include the Pololu library */
#include "DualMC33926MotorShield.h"

/* Create the motor driver object */
DualMC33926MotorShield drive;

/* Wrap the motor driver initialization */
void initMotorController() {
  drive.init();
}

/* Wrap the drive motor set speed function */
void setMotorSpeed(int i, int spd) {
  if (i == LEFT) drive.setM1Speed(spd);
  else drive.setM2Speed(spd);
}

// A convenience function for setting both motor speeds
void setMotorSpeeds(int leftSpeed, int rightSpeed) {
  setMotorSpeed(LEFT, leftSpeed);
  setMotorSpeed(RIGHT, rightSpeed);
}
//到这里不用看

#elif defined L298_MOTOR_DRIVER

boolean directionLeft = false;
boolean directionRight = false;
//和编码器配合
boolean direction(int i) {
  if (i == LEFT) {
    return directionLeft;
  } else {
    return directionRight;
  }
}
void initMotorController() {
  pinMode(RIGHT_MOTOR_FORWARD, OUTPUT);
  pinMode(RIGHT_MOTOR_BACKWARD, OUTPUT);
  pinMode(LEFT_MOTOR_FORWARD, OUTPUT);
  pinMode(LEFT_MOTOR_BACKWARD, OUTPUT);
}//这是电机的初始化函数,根据驱动板自行修改

void setMotorSpeed(int i, int spd) {
  unsigned char reverse = 0;

  if (spd < 0)
  {
    spd = -spd;
    reverse = 1;
  }
  if (spd > 255)
    spd = 255;
  //这里是驱动班控制程序,请自行修改
  if (i == LEFT) {
    if (reverse == 0) {
      analogWrite(LEFT_MOTOR_FORWARD, spd);
      analogWrite(LEFT_MOTOR_BACKWARD, 0);
      directionLEFT = FORWARDS;
    }
    else if (reverse == 1) {
      analogWrite(LEFT_MOTOR_BACKWARD, spd);
      analogWrite(LEFT_MOTOR_FORWARD, 0);
      directionLEFT = BACKWARDS;
    }
  }
  else {
    if (reverse == 0) {
      analogWrite(Right_MOTOR_FORWARD, spd);
      analogWrite(Right_MOTOR_BACKWARD, 0);
      directionRight = FORWARDS;
    }
    else if (reverse == 1) {
      analogWrite(Right_MOTOR_BACKWARD, spd);
      analogWrite(Right_MOTOR_FORWARD, 0);
      directionRight = BACKWARDS;
    }
  }//这里的正反转需要自己实验
}

void setMotorSpeeds(int leftSpeed, int rightSpeed) {
  setMotorSpeed(LEFT, leftSpeed);
  setMotorSpeed(RIGHT, rightSpeed);
}
#else
#error A motor driver must be selected!
#endif

#endif

之后可使用arduino串口进行调试,观察电机是否在被控制 ,比如输入 m 20 20,电机会以一个很小的速度转动。要初步调整到左右电机转速相近,方向相同。

 参考链接:https://www.ncnynl.com

猜你喜欢

转载自blog.csdn.net/qq_29735067/article/details/81561261