3.树莓派4b+ubuntu18.04(ros版本melodic)+arduino mega自制两轮差速小车,实现建图导航功能

ros_arduino_bridge中PID调试源码分析

1.diff_controller.h 中的PID调试代码:

cpp 复制代码
/* 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 */
float Kp = 1.5;
float Kd = 3.0;
float Ki = 0.1;
int Ko = 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 doPID(SetPointInfo * p) {
  long Perror;
  long output;
  int input;

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

  //Serial.println(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 = (Kp * Perror - Kd * (input - p->PrevInput) + p->ITerm) / Ko;
  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 += Ki * 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 */
  //分别调试左右轮
  doPID(&rightPID);
  doPID(&leftPID);

  /* Set the motor speeds accordingly */
  setMotorSpeeds(leftPID.output, rightPID.output);
}

2.PID调试

调试时,需要在 diff_controller.h 中打印 input 的值,然后通过串口绘图器输入命令: m 参数1 参数2,根据绘图结果调试:Kp、Ki和Kd的值。

可以串口发送指令 u kp: ki: kd:ko:更改pid参数。节省烧录程序的时间

相关推荐
Robot_Nav27 分钟前
VSCode 调试 ROS1/ROS2 等项目完整指南
vscode·机器人·ros
code_pgf1 天前
Orin NX 16GB 的 package 安装命令清单 + Docker/工作区目录结构 + bringup 顺序
运维·docker·容器·ros
weixin_426689201 天前
VSCODE 树莓派C语言开发环境建立
vscode·树莓派
纽约恋情1 天前
【ROS入门】12. ROS中tf坐标系广播与监听的编程实现
机器人·ros
衡动科技2 天前
Ubuntu 22.04/24.04 安装 ROS2 完整教程(Humble / Jazzy)
ubuntu·树莓派·ros2
maxmaxma2 天前
ROS 2 少年创客营:Day 2
机器人·ros
kyle~2 天前
DDS(Data Distribution Service)分布式实时数据分发标准
分布式·ros·dds
ChengQianO3 天前
ROS2 导航播报 & 轨迹模拟 —— 计划
linux·ubuntu·ros
困死,根本不会4 天前
树莓派 SSH 连接排错实录:从 IP 网段到主机密钥变更,再到 VNC 自启动
开发语言·ssh·php·树莓派
困死,根本不会4 天前
Windows下模拟树莓派:使用ble-serial创建虚拟串口实现手机蓝牙通信
windows·python·单片机·嵌入式硬件·树莓派