lengmian 发表于 2012-7-28 08:15:11

两轮小车走直线是要分别对左右两个电机进行PID控制吗

我正在做一个小车,前面一个轮子是万向轮做的,后面两个轮子分别用两个电机进行控制,
现在的情况是左右两个电机给相同大小的pwm,但是两个电机稳定后的转速不同,
我的电机转速测量是用光电开关测频率的方法得到的,用示波器检测过比较准确的,
现在通过这样一个算法:
如果左轮比右轮速度快,那么左轮pwm-1,右轮pwm+1,空载的情况下,小车左右两个轮子速度接近,一会儿左面的大些,一会儿右面的大些,但放到地上以后就直接跑偏了,{:mad:}
我现在想知道如果我用PID算法的话,是不是分别对两个小车进行PID控制呢?{:3_57:}

tiancaigao7 发表于 2012-7-28 08:25:27

用PID专门控制左右两个轮子的转速差,这个转速差叠加在一个恒定的转速上就可以实现转向和直行控制。

lengmian 发表于 2012-7-28 08:29:59

tiancaigao7 发表于 2012-7-28 08:25 static/image/common/back.gif
用PID专门控制左右两个轮子的转速差,这个转速差叠加在一个恒定的转速上就可以实现转向和直行控制。 ...

就是给一个转速差定值,然后用PID去控制使转速差趋于这个定值?楼主,我是新手,您仔细说说,得到的PID控制参量叠加在哪一个轮子的pwm上呢?现在就是想找一个恒定的转速,左右两轮转速不一样啊

tiancaigao7 发表于 2012-7-28 09:40:24

恒定的速度就是你的前进速度,假设你的两个轮子速度一样,现在你发现需要左转,这个时候PID控制器会降低左轮速度(假设PWM-n),同时增加右轮速度(假设PWM+n)。这样就可以实现左转,但是同时小车还需要前进,因此在保证小车的前进速度需要给PWM M,因此左轮的PWM占空比为M-n,右轮为M+n这样就能保证小车在前进过程中,左转。而PID控制器控制的是n的大小。当然如果你需要同时控制前进速度的话,就需要增加一个PID控制器。

cemi 发表于 2012-7-28 22:10:05

我最近也在做这个,请问有没有相关例程可以参考一下?

lengmian 发表于 2012-7-29 09:32:16

tiancaigao7 发表于 2012-7-28 09:40 static/image/common/back.gif
恒定的速度就是你的前进速度,假设你的两个轮子速度一样,现在你发现需要左转,这个时候PID控制器会降低左 ...

其实,我还是不大懂,您看一下,我是这个意思,我想把做右轮速度偏差控制成0,所以在
void IncPIDInit(void)
{
        sptr->SumError=0;
        sptr->LastError=0;
        sptr->PrevError=0;
        sptr->Proportion=3;
        sptr->Integral=0;
        sptr->Derivative=0;
        sptr->SetPoint=0;
}

int IncPIDCalc(int NextPoint)
{
        int iError,iIncpid;
        iError=sptr->SetPoint-NextPoint;
        iIncpid=sptr->Proportion*iError        -sptr->Integral*sptr->LastError+sptr->Derivative*sptr->PrevError;
        sptr->PrevError=sptr->LastError;
        sptr->LastError=iError;
        return(iIncpid);
}
里面 SetPoint=0;
然后我随便用一个参数sptr->Proportion=3,这样我每次采样50ms,然后把数据送到上面的结构体里计算,得到iIncpid我要怎么处理,它对应的到底是什么,我是直接用这个参数当做pwm是用还是左轮的pwm+iIncpid当做pwm ,这上面输入的Nextpoint是当前的左轮减去右轮的差值

希望您帮一下,我不大懂怎么去控制这个

tianyuhui 发表于 2012-7-29 09:43:46

同求高人详解该问题...

tiancaigao7 发表于 2012-7-29 09:58:42

首先你的PID公式有问题,看你的公式,用的应该是位置式PID,但是这个PID的积分应该是历次的偏差的积分。如果你用的是相对PID,那么比例部分,应该是本次偏差和上一次偏差之差。另外,在你这里,PID的输出当成PWM占空比的变化量是可以的,不过P I D这三个参数需要自己调试,这个只能通过实验来看自己调整。

lengmian 发表于 2012-7-29 11:15:55

tiancaigao7 发表于 2012-7-29 09:58 static/image/common/back.gif
首先你的PID公式有问题,看你的公式,用的应该是位置式PID,但是这个PID的积分应该是历次的偏差的积分。如 ...

谢谢您,那错误我明白了,那您看我这个问题适合用增量式还是位置式?

werren 发表于 2012-8-11 16:51:46

tiancaigao7 发表于 2012-7-28 09:40 static/image/common/back.gif
恒定的速度就是你的前进速度,假设你的两个轮子速度一样,现在你发现需要左转,这个时候PID控制器会降低左 ...

控制转速差误差累积很快。我使用700线的编码。每2ms计数一次让转速稳定控制在6,但是这个不可能保证一定是6,还是会在6±1波动,1s计算500次,误差累积还是相当快,转一圈最大就可能有500个脉冲误差,一圈总共才700个脉冲。如何才能稳定地控制?

werren 发表于 2012-8-11 16:53:53

werren 发表于 2012-8-11 16:51 static/image/common/back.gif
控制转速差误差累积很快。我使用700线的编码。每2ms计数一次让转速稳定控制在6,但是这个不可能保证一定 ...

对了,我点击控制的pwm使用100hz,想起来好像跟这个关系很大。

ldh0504 发表于 2012-8-21 17:05:36

werren 发表于 2012-8-11 16:51 static/image/common/back.gif
控制转速差误差累积很快。我使用700线的编码。每2ms计数一次让转速稳定控制在6,但是这个不可能保证一定 ...

我想问您一下 编码器的数据 是怎么得到的呢?

werren 发表于 2012-8-24 10:25:43

ldh0504 发表于 2012-8-21 17:05 static/image/common/back.gif
我想问您一下 编码器的数据 是怎么得到的呢?

ETR 外部脉衝計數(紅外對射管+齒輪盤輸出)得到。每隔2ms就去讀取一次。

werren 发表于 2012-9-23 09:34:15

tiancaigao7 发表于 2012-7-28 08:25 static/image/common/back.gif
用PID专门控制左右两个轮子的转速差,这个转速差叠加在一个恒定的转速上就可以实现转向和直行控制。 ...

如果这样的话只有一个轮子性能好的。控制速度差只能一个轮子跟另外一个轮子。
/ ==============        carblance modulation       
// ==============   carblance modulation       
// =======================================================PID compute       
                        if(motion)
                        {
                                IRSensor_ON();                                                    //turn on the ir sensor
                    pwm = IncPIDCalc(&A,(LDelta+RDelta)/2);
                                dDpwm = LDelta-RDelta;         //两轮速度差
                                dtpwm = IncPIDCalc(&B,dDpwm);
                                Lpwm = pwm+dtpwm;
                                if(Lpwm>250)Lpwm = 250;
                                if(Lpwm<0)Lpwm = 0;

                                Rpwm = pwm-dtpwm;
                               if(Rpwm>250)Rpwm = 250;

                                if(Rpwm<0)Rpwm = 0;
                                HB = 1;
                        }       
// =======================================================PID compute
// ==========================================movement handle
                  Pre_motion = motion;      //记录上一次的运动状态,若有改变运动状态则根据相应的动作来协调计数
        if(motion==FORWARD)
        CarMove(250+Lpwm,250+Rpwm);//<<======用手抓左轮,这样结果是左轮pid马上起作用,控制速度差;用手抓右轮左轮却偏快了。原因是左轮明显右边轮子慢下来。有没有办法右轮也ok?

bsz84 发表于 2012-9-23 10:23:00

顶一下让更多的高手出来参加讨论。

tiancaigao7 发表于 2012-9-23 14:29:30

werren 发表于 2012-9-23 09:34 static/image/common/back.gif
如果这样的话只有一个轮子性能好的。控制速度差只能一个轮子跟另外一个轮子。
/ ==============        carbla ...

你的目的是要控制小车走直线,而不是控制两个轮子速度相同,我说的分别施加转速差,输入应该是你的小车的偏角,而不是轮子的速度差。

风烟雨风 发表于 2012-10-11 01:40:33

werren 发表于 2012-8-11 16:51 static/image/common/back.gif
控制转速差误差累积很快。我使用700线的编码。每2ms计数一次让转速稳定控制在6,但是这个不可能保证一定 ...

可以采用位置差(及两轮行走距离差)作为误差来进行PID运算,最近我也在做

ldh0504 发表于 2012-10-11 12:08:25

ldh0504 发表于 2012-8-21 17:05 static/image/common/back.gif
我想问您一下 编码器的数据 是怎么得到的呢?

我现在用的传感器是用角度传感器和 加速度传感器融合一体的~现在角度已经测出来了 加速度求出来了 之后PID部分 怎么样控制 PID 我用位置式的PID 电机是用12V的直流电机 没有用到编码器 请问一下电机输出的PID 应该怎么去调节呢 您用的PID 是什么式的呢

werren 发表于 2012-10-11 15:30:25

风烟雨风 发表于 2012-10-11 01:40 static/image/common/back.gif
可以采用位置差(及两轮行走距离差)作为误差来进行PID运算,最近我也在做 ...

是 的,我後來也是這樣處理,這樣就沒有累積誤差。

风烟雨风 发表于 2012-10-11 22:21:57

werren 发表于 2012-10-11 15:30 static/image/common/back.gif
是 的,我後來也是這樣處理,這樣就沒有累積誤差。

但是现在一直没有调出来,不知道怎么调试参数   急求啊   希望指教一下

werren 发表于 2012-10-16 08:53:45

风烟雨风 发表于 2012-10-11 22:21 static/image/common/back.gif
但是现在一直没有调出来,不知道怎么调试参数   急求啊   希望指教一下

調試時候可以將PID計算結果實時show出來(這樣就可以直觀看出數據變化,然後需要將參數加大還是減小),先調節P再調節I。
只用P的話已經能夠達到不錯的效果了。你可以試試先往大的調,能穩定轉起來后再將P調小,直到轉速穩定或者振盪,加入I參數。再湊一下基本上可以用了。

以上是我的調試經驗。。。。我也是第一次用PID

风烟雨风 发表于 2012-10-18 17:07:31

werren 发表于 2012-10-16 08:53 static/image/common/back.gif
調試時候可以將PID計算結果實時show出來(這樣就可以直觀看出數據變化,然後需要將參數加大還是減小), ...

你调的误差有多少
能仔细请教一下吗
我的QQ号是505800119

werren 发表于 2012-10-19 13:11:53

风烟雨风 发表于 2012-10-18 17:07 static/image/common/back.gif
你调的误差有多少
能仔细请教一下吗
我的QQ号是505800119

誤差跟你的轉速設定有關係,我的電機是經過變速箱的。但是我測試的是沒有經過變速箱的原始轉速。我使用外部中斷,上升沿和下降沿都能觸發中斷。車輪轉一圈可以計數約700個脉衝,中斷上升下降沿都計數可以計到1400次。我10ms 讀一次轉速,將讀出轉速做參數給pid計算,計算結果直接作為pwm控制電機。假設我設定速度是每10ms20個脉衝那麼基本上可以穩定在20±3   ,手去抓車輪 機會不會感到轉速慢下來,扭力很大,看串口輸出結果也是在短時間內看到比較大的轉速波動而已。

风烟雨风 发表于 2012-10-20 16:37:05

我的情况跟你差不多,车轮转一圈大约700个脉冲,然后我是记700次,采样周期是20ms.
现在主要情况是我使用PID调时,(不放在地上)左右轮差距最多为20左右,但是放在地上后偏差很大。
不知道你的在正常情况下左右轮计数的差值最大大概多大?

风烟雨风 发表于 2012-10-20 16:37:28

werren 发表于 2012-10-19 13:11 static/image/common/back.gif
誤差跟你的轉速設定有關係,我的電機是經過變速箱的。但是我測試的是沒有經過變速箱的原始轉速。我使用外 ...

我的情况跟你差不多,车轮转一圈大约700个脉冲,然后我是记700次,采样周期是20ms.
现在主要情况是我使用PID调时,(不放在地上)左右轮差距最多为20左右,但是放在地上后偏差很大。
不知道你的在正常情况下左右轮计数的差值最大大概多大?

werren 发表于 2012-10-22 09:05:26

风烟雨风 发表于 2012-10-20 16:37 static/image/common/back.gif
我的情况跟你差不多,车轮转一圈大约700个脉冲,然后我是记700次,采样周期是20ms.
现在主要情况是我使用 ...

可能我們的做法還是有差異。
PID我分為兩部份 一部份計算控制小車的前進速度的pwm ,一部份做左右輪子平衡的pwm,我記得大概前進的時候是一般是在±4內波動,因為我是用累積的,所以沒有誤差積分。
但是這個情況下不一定能走直,想了好久,加了一個平衡誤差的虛參數,終於走直線了。見一下部份代碼
                        if(motion)
                        {
                    pwm = IncPIDCalc(&SPEED,(LDelta+RDelta)/2);        //小车恒定速度计算
                               
                                switch(motion){
                                case FORWARD:dSPEED.SetPoint = 0x00;                                                        //DIF是纠正参数,在小车前进或后退,没有传感器的状况下为保证
                                       dTotal = TotalCntL*DIFF- TotalCntR;                                                //运动路径为直线,必须做平衡去掉机械误差       
                                       //dTotal = TotalCntL*Line- TotalCntR;
                                       dtpwm = dtIncPIDCalc(&dSPEED,dTotal/8);break;                                //切此处用的速度计算是使用当前计数总和减去上一次计数总和,避免误差的累积                                       
                                case REVERSE:dSPEED.SetPoint = 0x00;
                                       dTotal = TotalCntL*DIFR- TotalCntR;                                                //DIF是纠正参数
                                       dtpwm = dtIncPIDCalc(&dSPEED,dTotal/8);break;
                                default:
                                          dTotal = TotalCntL- TotalCntR;
                                          dSpd = LDelta-RDelta;                                                                                //左右转速差值
                                          dtpwm = dtIncPIDCalc(&dSPEED,dSpd);break;
                                }               
                                Lpwm = pwm+dtpwm;                                                        //恒定速度控制+差分速度控制
                                if(Lpwm>250)Lpwm = 250;                                                //小车PWM的控制范围为0-250 所以要做限制
                                if(Lpwm<0)Lpwm = 0;

                                Rpwm = pwm-dtpwm;
                               if(Rpwm>250)Rpwm = 250;
                                if(Rpwm<0)Rpwm = 0;                                                        //使能H桥
                                HB = 1;
                        }
                        if(!(motion&0x0f))
                                HB = 0;//如果不在运动状态就把H桥进入休眠,避免电机狂转




                                                                              ……

风烟雨风 发表于 2012-10-29 19:35:49

果然不太一样,
dtIncPIDCalc(&dSPEED,dTotal/8); 再问一句,能看一下你这个函数是怎么写的吗
多谢了

风烟雨风 发表于 2012-11-5 22:37:55

werren 发表于 2012-10-22 09:05 static/image/common/back.gif
可能我們的做法還是有差異。
PID我分為兩部份 一部份計算控制小車的前進速度的pwm ,一部份做左右輪子平 ...

果然不太一样,
dtIncPIDCalc(&dSPEED,dTotal/8); 再问一句,能看一下你这个函数是怎么写的吗
多谢了

werren 发表于 2012-11-6 08:46:10

风烟雨风 发表于 2012-11-5 22:37 static/image/common/back.gif
果然不太一样,
dtIncPIDCalc(&dSPEED,dTotal/8); 再问一句,能看一下你这个函数是怎么写的吗
多谢了 ...

標準的增量式PID 寫法
int dtIncPIDCalc(PID *sptr,int NextPoint)
{
register int iError, iIncpid;
   //当前误差
iError = sptr->SetPoint - NextPoint;
   //增量计算

iIncpid= sptr->Proportion * iError               //E 项
            - sptr->Integral   * sptr->LastError   //E项
            + sptr->Derivative * sptr->PrevError;   //E项
   //存储误差,用于下次计算
sptr->PrevError = sptr->LastError;
sptr->LastError = iError;
   //返回增量值
return(iIncpid);
}
//////////////////////////////////////////////////////////////////////////
        //数据结构
        typedef struct PID
        {
          intSetPoint;   // 设定目标 Desired Value
          longSumError;                //误差累计
       
          floatProportion;         // 比例常数 Proportional Const
          floatIntegral;         // 积分常数 IntegralConst
          floatDerivative;         // 微分常数 Derivative Const
       
          int LastError;               //Error[-1]
          int PrevError;               //Error[-2]
        } PID;

风烟雨风 发表于 2012-11-7 00:50:11

werren 发表于 2012-11-6 08:46 static/image/common/back.gif
標準的增量式PID 寫法
int dtIncPIDCalc(PID *sptr,int NextPoint)
{


恩多谢了
我的小车跟你的基本要求一样。就是让小车能沿直线行走固定的距离。
现在走直线问题不大,行走固定的步数又是新问题了,不知能否指教一下?

werren 发表于 2012-11-9 10:08:08

风烟雨风 发表于 2012-11-7 00:50 static/image/common/back.gif
恩多谢了
我的小车跟你的基本要求一样。就是让小车能沿直线行走固定的距离。
现在走直线问题不大,行走 ...

我的做法是設置計數比如兩萬次走直線,然後測量實際走的距離最後求平均每計數一次小車移動的距離,把這個當做參數來用咯。

dmjkun 发表于 2012-11-9 11:43:30

我也想知道,两电机如果其中一个电机在运动过程中遇到有障碍物,怎样做同步控制,就是一个慢了另外一个快的怎样慢下来

风烟雨风 发表于 2012-11-10 09:21:06

werren 发表于 2012-11-9 10:08 static/image/common/back.gif
我的做法是設置計數比如兩萬次走直線,然後測量實際走的距離最後求平均每計數一次小車移動的距離,把這個 ...

太谢谢了   麻烦你这么多

风烟雨风 发表于 2012-11-10 09:22:27

dmjkun 发表于 2012-11-9 11:43 static/image/common/back.gif
我也想知道,两电机如果其中一个电机在运动过程中遇到有障碍物,怎样做同步控制,就是一个慢了另外一个快的 ...

我是用 光电编码器检测,然后调整PWM参数

雨念 发表于 2013-10-4 22:24:17

werren 发表于 2012-10-22 09:05 static/image/common/back.gif
可能我們的做法還是有差異。
PID我分為兩部份 一部份計算控制小車的前進速度的pwm ,一部份做左右輪子平 ...

看了你们的讨论,我感觉收获很大啊!太感谢了!
但是我有个问题,IncPIDCalc(……)和dtIncPIDCalc(……)有什么区别吗,难道不是增量式PID调节?能看看这个函数的具体定义吗? 谢谢了!

sunismyself-la 发表于 2013-12-11 23:44:23

mark mark mark

yuesheng1991 发表于 2014-4-17 12:50:20

cool 收藏,正好需要用

杏仁酥 发表于 2016-7-4 16:32:52

mark下,以后慢慢琢磨,正在想这个问题,谢谢{:smile:}

jihongyuan 发表于 2016-7-6 09:17:50

好贴mark一下

xaviersw 发表于 2020-12-19 16:23:53

不错的贴,收起来
页: [1]
查看完整版本: 两轮小车走直线是要分别对左右两个电机进行PID控制吗