ROS自主导航机器人ROS机器人操作系统

ROS机器人底盘(6)-电机PID

2017-11-20  本文已影响182人  PIBOT导航机器人

通过PID对电机转速进行闭环控制

1.PID控制的原理

在工程实际中,PID控制是应用最为广泛控制方式。PID为比例、积分、微分的缩写。当被控制的系统的结构和参数不能完全掌握,或得不到精确的数学模型时,控制理论的其它技术难以采用时,系统控制器的结构和参数必须依靠经验和现场调试来确定,这时应用PID控制技术最为方便。即当我们不完全了解一个系统和被控对象﹐或不能通过有效的测量手段来获得系统参数时,最适合用PID控制技术。PID控制,实际中也有PI和PD控制。PID控制器就是根据系统的误差,利用比例、积分、微分计算出控制量来对系统进行控制。

比例(P)控制

比例控制是一种最简单的控制方式。其控制器的输出与输入误差信号成比例关系。当仅有比例控制时系统输出存在稳态误差(Steady-state error)。

积分(I)控制

在积分控制中,控制器的输出与输入误差信号的积分成正比关系。对一个自动控制系统,如果在进入稳态后存在稳态误差,则称这个控制系统是有稳态误差的或简称有差系统(System with Steady-state Error)。为了消除稳态误差,在控制器中必须引入“积分项”。积分项对误差取决于时间的积分,随着时间的增加,积分项会增大。这样,即便误差很小,积分项也会随着时间的增加而加大,它推动控制器的输出增大使稳态误差进一步减小,直到等于零。因此,比例+积分(PI)控制器,可以使系统在进入稳态后无稳态误差。

微分(D)控制

在微分控制中,控制器的输出与输入误差信号的微分(即误差的变化率)成正比关系。 自动控制系统在克服误差的调节过程中可能会出现振荡甚至失稳。其原因是由于存在有较大惯性组件(环节)或有滞后(delay)组件,具有抑制误差的作用,其变化总是落后于误差的变化。解决的办法是使抑制误差的作用的变化“超前”,即在误差接近零时,抑制误差的作用就应该是零。这就是说,在控制器中仅引入“比例”项往往是不够的,比例项的作用仅是放大误差的幅值,而目前需要增加的是“微分项”,它能预测误差变化的趋势,这样,具有比例+微分的控制器,就能够提前使抑制误差的控制作用等于零,甚至为负值,从而避免了被控量的严重超调。所以对有较大惯性或滞后的被控对象,比例+微分(PD)控制器能改善系统在调节过程中的动态特性。

2.实际模型

对于3WD全向小车,在对整体运动进行解算后得到各个轮子的期望转速Vd,以这个转速作为PID控制的输入,输出为控制电机的PWM值,反馈则为通过编码器反馈值计算出的实际速度V。闭环系统如下:


PID模型

在实际操作中,由于是通过程序进行PID的计算,无法达到连续的积分和微分计算,所以用离散处理。给定PID控制频率,周期性地进行PID控制计算。

主要参数:
pid_interval 控制周期 ms
kp 比例系数
ki 积分系数
kd 微分系数
ko 统一放大缩小比例

3 具体实现

30ms控制周期,C代码如下:
pid.h

#ifndef PIBOT_PID_H_
#define PIBOT_PID_H_

class PID{
    public:
        PID(float* input, float* feedback, float kp, float ki, float kd, unsigned short max_output);
        short compute(float interval);
        void clear();
    private:
        float kp, ki, kd;
        unsigned short max_output;
        float* input;
        float* feedback;

        float error;
        float integra;
        float derivative;

        float previous_error;
};

#endif

pid.cpp

#include "pid.h"

#include "board.h"

PID::PID(float* _input, float* _feedback, float _kp, float _ki, float _kd, unsigned short _max_output)
    :input(_input), feedback(_feedback), kp(_kp), ki(_ki), kd(_kd), max_output(_max_output){

    clear();
}

void PID::clear(){
    error = integra = derivative = previous_error =0;
}

short PID::compute(float interval){
    error = *input - *feedback;

    integra = integra + error*interval;
    derivative = (error - previous_error) / interval;

    previous_error = error;
    
    if (ki != 0)
        if (integra < -max_output/ki)
        {
            //printf("integra clear\r\n");
            integra = -max_output/ki;
        }
        if (integra > max_output/ki)
        {
            //printf("integra clear\r\n");
            integra = max_output/ki;
        }

    float val = error*kp + integra*ki + derivative*kd;

    if (val < -max_output)
        val = -max_output+1;
    else if (val > max_output)
        val = max_output-1;

    return val;
}
上一篇下一篇

猜你喜欢

热点阅读