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


    ros_arduino_bridge中PID调试源码分析

    1.diff_controller.h 中的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 */
    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参数。节省烧录程序的时间

  • 相关阅读:
    5.1 内存CRC32完整性检测
    ACPI规范概览-1
    redis 技术分享
    LeetCode155:最小栈,最简单的中等难度题,时间击败100%,内存也低于官方
    排序算法(Java版)
    RUST 和 GO 如何管理它们的内存
    Matter 1.3版标准新出炉,支持更多智能家居/家电/能源等设备
    Android AAPT: error: resource color 异常原因处理
    《数据库原理与应用》第一版 马春梅……编著 期末复习笔记
    【Python】Python语言基础(中)
  • 原文地址:https://blog.csdn.net/m0_63715549/article/details/139904178