这个调速算法是用在搬运机器人上的,一方面之前没有用过PID算法,另一方面在Arduino上实现的资料也比较少,所以我想把自己的尝试过程记录下来,如果能帮到别人再好不过了。

1.硬件线路连接

这里我使用的是用到了两个减速比为30霍尔编码器减速电机,电机驱动为AQMH2407ND,主控采用Arduino Mega 2560.

这是程序中的端口设置,可以看出硬件线路连接情况。

//左电机端口定义
#define MotorLpin1   35 //控制位3  这是电机驱动板上的,用来控制正,反转和停止的。
#define MotorLpin2   37 //控制位4  这是电机驱动板上的
#define MotorLpwm    3  //使能调速 ENB   这是电机驱动板上的PWM调速接口
#define MotorLcountA 18 //编码器A 中断号:5
#define MotorLcountB 19 //编码器B 中断号:4//右电机端口定义
#define MotorRpin1   31 //控制位1  这是电机驱动板上的
#define MotorRpin2   33 //控制位2  这是电机驱动板上的
#define MotorRpwm    2  //使能调速 ENA    这是电机驱动板上的PWM调速接口
#define MotorRcountA 20 //编码器A 中断号:3
#define MotorRcountB 21 //编码器B 中断号:2

2.PI增量调速算法

PID算法有位置式和增量式两种,位置式:考虑从开机到现在所有的偏差,增量式:考虑最近偏差。如果对PID算法不了解,可以看一下这个老师的视频:https://www.bilibili.com/video/BV14E411L7GB/

因为这个小车是要多次启动停止的,再加上很多电机调速算法用的都是增量式,所以我采用的也是增量式。并且在实际的调参过程中,PI的效果是比PID要好的,所以综合下来采用的就是增量式PI调速。

3.增量式调速算法的C语言表达

    这个我参考的式平衡小车之家的代码,这里用的是-=,不是+=。因为用-=,调试出来的PI参数是负数:

/********************************************************** 函数功能:增量式PI控制器(左轮)* 入口参数:当前速度(编码器测量值),目标速度* 返回 值:电机PWM * 参考资料: *    增量式离散PID公式:*                Pwm-=Kp*[e(k)-e(k-1)]+Ki*e(k)+Kd*[e(k)-2e(k-1)+e(k-2)]*                e(k):本次偏差*                e(k-1):上一次偏差*                e(k-2):上上次偏差*                Pwm:代表增量输出*    在速度闭环控制系统里面我们只使用PI控制,因此对PID公式可简化为:*                Pwm-=Kp*[e(k)-e(k-1)]+Ki*e(k)*                e(k):本次偏差*                e(k-1):上一次偏差*                Pwm:代表增量输出*                *    注意增量式PID先调I,再调P,最后再调D*********************************************************/int Incremental_Pi_L(int current_speed,int target_speed){static float pwm,bias,last_bias,prev_bias;  //静态变量存在程序全周期:pwm:增量输出,bias:本次偏差,last_bias:上次偏差,prev_bais_:上上次偏差bias=current_speed-target_speed;    //计算本次偏差e(k)pwm-=(kp*(bias-last_bias)+ki*bias+kd*(bias-2*last_bias+prev_bias));   //增量式PID控制器prev_bias=last_bias;  //保存上上次偏差last_bias=bias;     //保存上一次偏差//PWM 限幅度  Arduino的PWM 最高为255  限制在250if(pwm<-250){pwm=250;     }if(pwm>250){pwm=250;  }//Serial.println(pwm);return pwm;         //增量输出}

4.霍尔编码器的脉冲检测

这里我只用到了每个轮子的A相,线数是13,电机减速比为30,那么输出轴转动一周,A相编码器会输出390脉冲。这里用来测轮子的速度完全够用了。用Arduino的外部中断读取编码器脉冲,

/************************************ 电机实际速度计算:* 公式:* 已知参数:*     车轮直径65mm,*     左边轮子一圈:360脉冲(RISING),*     右边轮子一圈:390脉冲(RISING),* 单位时间读两个轮子脉冲读取两个轮子脉冲* 已知道参数:*     车轮直径65mm,*     左边轮子一圈:360脉冲(RISING),*     右边轮子一圈:390脉冲(RISING),*  * 外部中断触发模式:**    LOW:低电平触发;*    CHANGE:电平变化触发;*    RISING :上升沿触发(由LOW变为HIGH);*    FALLING:下降沿触发(由HIGH变为LOW); *    HIGH:高电平触发(该中断模式仅适用于Arduino due);*   ************************************/void Read_Moto_V(){unsigned long nowtime=0;motorL=0;motorR=0;nowtime=millis()+50;//读50毫秒attachInterrupt(digitalPinToInterrupt(MotorLcountA),Read_Moto_L,RISING);//左轮脉冲开中断计数attachInterrupt(digitalPinToInterrupt(MotorRcountA),Read_Moto_R,RISING);//右轮脉冲开中断计数while(millis()<nowtime); //达到50毫秒关闭中断detachInterrupt(digitalPinToInterrupt(MotorLcountA));//左轮脉冲关中断计数detachInterrupt(digitalPinToInterrupt(MotorRcountA));//右轮脉冲关中断计数V_L=((motorL/390)*6.5*PI)/0.05;   //单位cm/sV_R=((motorR/390)*6.5*PI)/0.05;   //单位cm/sv1=V_L;v2=V_R;
}/**************************** 中断函数:读左轮脉冲***************************/
void Read_Moto_L(){motorL++;
}/*************************** 中断函数:读右轮脉冲* *************************/
void Read_Moto_R(){motorR++;
}

5.PID参数调试整体程序

 这个调试过程我参考的是这篇文章:https://blog.csdn.net/C1664510416/article/details/107229958,PID算法的代码是现成的,改改挪到自己的程序中就能用了,但是要考虑到怎样嵌入到自己的程序中,还有就是参数应该怎么调节,如果是第一次用PID,可能你在把PID代码挪到自己程序中的时候,还是一头雾水,但是一旦你调完了参数,就会豁然开朗了。

曲线绘制我直接用的Arduino自带的串口绘图器,主控将实时速度通过Serial.println(V_L),传到电脑,打开串口绘图器就可以直接看到曲线。

我这里比较麻烦,就是不断的修改PID参数,然后开启电源让主控控制电机转动,打印数据。

增量式PID的调试与位置式不同,要先调I,再调P,再调D,最后再统一微调。

//左电机端口定义
#define MotorLpin1   35 //控制位3
#define MotorLpin2   37 //控制位4
#define MotorLpwm    3  //使能调速 ENB
#define MotorLcountA 18 //编码器A 中断号:5
#define MotorLcountB 19 //编码器B 中断号:4//右电机端口定义
#define MotorRpin1   31 //控制位1
#define MotorRpin2   33 //控制位2
#define MotorRpwm    2  //使能调速 ENA
#define MotorRcountA 20 //编码器A 中断号:3
#define MotorRcountB 21 //编码器B 中断号:2volatile float motorL=0;//中断变量,左轮子脉冲计数
volatile float motorR=0;//中断变量,右轮子脉冲计数
float V_L=0; //左轮速度 单位cm/s
float V_R=0; //右边轮速 单位cm/s
int v1=0;  //单位cm/s
int v2=0;  //单位cm/s
float Target_V_L=20,Target_V_R=20;   //单位cm/s
int Pwm_L=0,Pwm_R=0;  //左右轮PWM//PID变量
float kp=0,ki=0,kd=0;  //PID参数/*************************************** Arduino初始化函数* *************************************/
void setup() {Motor_Init();//电机端口初始化Serial.begin(9600);//开启串口
}/********************************************************** 函数功能:增量式PI控制器(左轮)* 入口参数:当前速度(编码器测量值),目标速度* 返回 值:电机PWM * 参考资料: *    增量式离散PID公式:*                Pwm-=Kp*[e(k)-e(k-1)]+Ki*e(k)+Kd*[e(k)-2e(k-1)+e(k-2)]*                e(k):本次偏差*                e(k-1):上一次偏差*                e(k-2):上上次偏差*                Pwm:代表增量输出*    在速度闭环控制系统里面我们只使用PI控制,因此对PID公式可简化为:*                Pwm-=Kp*[e(k)-e(k-1)]+Ki*e(k)*                e(k):本次偏差*                e(k-1):上一次偏差*                Pwm:代表增量输出*                *    注意增量式PID先调I,再调P,最后再调D*********************************************************/int Incremental_Pi_L(int current_speed,int target_speed){static float pwm,bias,last_bias,prev_bias;  //静态变量存在程序全周期:pwm:增量输出,bias:本次偏差,last_bias:上次偏差,prev_bais_:上上次偏差bias=current_speed-target_speed;    //计算本次偏差e(k)pwm-=(kp*(bias-last_bias)+ki*bias+kd*(bias-2*last_bias+prev_bias));   //增量式PID控制器prev_bias=last_bias;  //保存上上次偏差last_bias=bias;     //保存上一次偏差//PWM 限幅度  Arduino的PWM 最高为255  限制在250if(pwm<-250){pwm=250;     }if(pwm>250){pwm=250;  }//Serial.println(pwm);return pwm;         //增量输出}//右轮速度增量式PID控制器
int Incremental_Pi_R(float current_speed,float target_speed){static float pwm,bias,last_bias,prev_bias;  //静态变量存在程序全周期:pwm:增量输出,bias:本次偏差,last_bias:上次偏差,prev_bais_:上上次偏差bias=current_speed-target_speed;    //计算本次偏差e(k)pwm-=(kp*(bias-last_bias)+ki*bias+kd*(bias-2*last_bias+prev_bias));   //增量式PID控制器prev_bias=last_bias;  //保存上上次偏差last_bias=bias;     //保存上一次偏差//PWM 限幅度  Arduino的PWM 最高为255限制在250if(pwm<-250){pwm=250;     }if(pwm>250){pwm=250;  }//Serial.println(pwm);return pwm;         //增量输出}/**************************************************************************(测试完成)函数功能:设置双轮工作模式和运动速度入口参数:工作模式,左右轮pwm返回  值:无
**************************************************************************/
void Set_Pwm(int mode,int speed_L,int speed_R){if(mode==1){//前进模式//左电机digitalWrite(MotorLpin1,LOW);digitalWrite(MotorLpin2,HIGH);analogWrite(MotorLpwm,speed_L);//右电机digitalWrite(MotorRpin1,HIGH);digitalWrite(MotorRpin2,LOW);analogWrite(MotorRpwm,speed_R);}else if(mode==2){//后退模式//左电机digitalWrite(MotorLpin1,HIGH);digitalWrite(MotorLpin2,LOW);analogWrite(MotorLpwm,speed_L);//右电机digitalWrite(MotorRpin1,LOW);digitalWrite(MotorRpin2,HIGH);analogWrite(MotorRpwm,speed_R);}else if(mode==3){//左转模式//左电机digitalWrite(MotorLpin1,HIGH);digitalWrite(MotorLpin2,LOW);analogWrite(MotorLpwm,speed_L);//右电机digitalWrite(MotorRpin1,HIGH);digitalWrite(MotorRpin2,LOW);analogWrite(MotorRpwm,speed_R);}else if(mode==4){//右转模式//左电机digitalWrite(MotorLpin1,LOW);digitalWrite(MotorLpin2,HIGH);analogWrite(MotorLpwm,speed_L);//右电机digitalWrite(MotorRpin1,LOW);digitalWrite(MotorRpin2,HIGH);analogWrite(MotorRpwm,speed_R);}
}/**************************************************************************(测试完成)函数功能:电机端口初始化,控制芯片引脚拉低入口参数:无返回  值:无
**************************************************************************/
void Motor_Init(){//左电机pinMode(MotorLpin1,OUTPUT);  //驱动芯片控制引脚pinMode(MotorLpin2,OUTPUT);  //驱动芯片控制引脚pinMode(MotorLpwm,OUTPUT);   //驱动芯片控制引脚,PWM调速pinMode(MotorLcountA,INPUT); //左轮编码器A引脚pinMode(MotorLcountB,INPUT); //左轮编码器B引脚//右电机pinMode(MotorRpin1,OUTPUT);  //驱动芯片控制引脚pinMode(MotorRpin2,OUTPUT);  //驱动芯片控制引脚pinMode(MotorRpwm,OUTPUT);   //驱动芯片控制引脚,PWM调速pinMode(MotorRcountA,INPUT); //右轮编码器A引脚pinMode(MotorRcountB,INPUT); //右轮编码器B引脚//驱动芯片控制引脚全部拉低digitalWrite(MotorLpin1,LOW); //左电机digitalWrite(MotorLpin2,LOW);digitalWrite(MotorLpwm,LOW);digitalWrite(MotorRpin1,LOW); //右电机digitalWrite(MotorRpin2,LOW);digitalWrite(MotorRpwm,LOW);
}/************************************ 电机实际速度计算:* 公式:* 已知参数:*     车轮直径65mm,*     左边轮子一圈:390脉冲(RISING),*     右边轮子一圈:390脉冲(RISING),* 单位时间读两个轮子脉冲读取两个轮子脉冲***********************************/void Read_Moto_V(){unsigned long nowtime=0;motorL=0;motorR=0;nowtime=millis()+50;//读50毫秒attachInterrupt(digitalPinToInterrupt(MotorLcountA),Read_Moto_L,RISING);//左轮脉冲开中断计数attachInterrupt(digitalPinToInterrupt(MotorRcountA),Read_Moto_R,RISING);//右轮脉冲开中断计数while(millis()<nowtime); //达到50毫秒关闭中断detachInterrupt(digitalPinToInterrupt(MotorLcountA));//左轮脉冲关中断计数detachInterrupt(digitalPinToInterrupt(MotorRcountA));//右轮脉冲关中断计数V_L=((motorL/390)*6.5*PI)/0.05;   //单位cm/sV_R=((motorR/390)*6.5*PI)/0.05;   //单位cm/sv1=V_L;v2=V_R;
}/**************************** 中断函数:读左轮脉冲***************************/
void Read_Moto_L(){motorL++;
}/*************************** 中断函数:读右轮脉冲* *************************/
void Read_Moto_R(){motorR++;
}/**************************************** Arduino主循环* ***************************************/
void loop() {Read_Moto_V();//读取脉冲计算速度Pwm_L=Incremental_Pi_L(V_L,Target_V_L);//左轮PI运算Pwm_R=Incremental_Pi_R(V_R,Target_V_R);//右轮PI运算Serial.println(V_L);  //直接用串口绘图画出速度曲线Set_Pwm(1,Pwm_L,Pwm_R);  //设置左右轮速度
}

6.调参过程

  参考:https://blog.csdn.net/C1664510416/article/details/107229958

7.最终结果

kp=1.6,ki=0.8,kd=0;

用Arduino实现霍尔编码减速电机PI调速(增量式)相关推荐

  1. 学习方波有霍尔传感的电机调速记录

    学习报告2020-9-30 学习报告: 第4期 时间周期: 9月1日-9月30日 姓名.专业:闫春幸- 电子信息 一.内容 1.首先继续对带霍尔传感器的BLDC方波调速的程序继续学习,对其中的原理进行 ...

  2. STM32——直流电机PI调速

    所需元件   STM32F103开发板.L298N一个.带编码器的直流电机一个(如下图所示,淘宝上有很多) 系统框图   通过系统框图,我们需要做两件事,一是要测速,二是要调节.测速目前流行的就是通过 ...

  3. 电机调速制动matlab,鼠笼式三相异步电机:起动、调速、制动(原理与Simulink仿真)...

    3种起动方式: Y→∆换接起动.自耦变压器减压起动.定子回路串电抗起步: 3种调速方式: 电阻调速.电压调速.变频调速: 3种制动方式: 能耗制动.反接制动.变频器回馈制动. 目录 0 电机参数与负载 ...

  4. 鼠笼式三相异步电机 | 起动、调速、制动原理与Simulink仿真

    博客搬家到自己搭建的 主页(wonghaotian.com) 啦q(≧▽≦q),大家快来逛逛鸭! 3种起动方式: Y→∆换接起动.自耦变压器减压起动.定子回路串电抗起步: 3种调速方式: 电阻调速.电 ...

  5. Arduino 让小车走直线的秘密 增量式PID 直流减速编码电机

    直流减速电机增量式PID 通俗易懂版 对于我一个双非学校没上过自控的电子专业本科生而言,这个东西真的是太难了,之前研究了一个A4950驱动,价格便宜,驱动能力高,安全性高,便捷性高,一句话就是比L29 ...

  6. 基于MSP430f5529 编码电机测速 接收脉冲数 PWM调速 CCS编译器 代码分析

    前言:2022年TI杯大学生电子设计竞赛,小车跟随行驶系统(C题)要求:设计一套小车跟随行驶系统,采用TI的MCU,由一辆领头小车和一辆跟随小车组成,要求小车具有循迹功能,且速度在0.3~1m/s可调 ...

  7. 基于STM32F103C6T6的AB相霍尔编码电机的PID转速调节(CubeMx-HAL库)(未完成-持续更新)

    基于STM32F103C6T6的AB相霍尔编码电机的PID转速调节(CubeMx-HAL库)(未完成-持续更新) 主要是记录一下,以后忘了再来看看,也记录记录自己做过的东西 首先是硬件电路图,一下是驱 ...

  8. 学习带霍尔传感器的BLDC方波调速

    带霍尔传感器的BLDC方波调速 基本原理 BLDC控制框图 三路霍尔信号图 120°Hall换相真值表 PID 调节控制电机转速 程序应用 按键读取 启动后调速 PWM换相调压 霍尔信号处理 基本原理 ...

  9. Arduino驱动L298N控制直流电机的正反转和调速

    Arduino驱动L298N控制直流电机的正反转和调速 一.前言 二.产品参数 三.驱动直流电机 三.接线图 四.程序 五.实验结果 总结 一.前言 本模块使用ST公司的L298N作为主驱动芯片,具有 ...

最新文章

  1. module ‘tensorrt‘ has no attribute ‘BuilderFlag‘
  2. PostgreSQL 11 100亿 tpcb 性能测试 on ECS
  3. Keras之DNN:基于Keras(sigmoid+binary_crossentropy+predict_proba)利用DNN实现分类预测概率——DIY二分类数据集预测新数据点
  4. linux 读取内存颗粒,linux查看主板内存槽与内存信息的命令dmidecode怎么用
  5. PHP笔记-文件上传例子
  6. activity启动流程_以AMS视角看Activity启动过程
  7. 【Go语言】集合与文件操作
  8. plsql学习笔记---plsql相关概念,以及基础结构
  9. windows 64位sed.exe_32位,64位,x86,x64到底是什么关系?差距居然这么大
  10. WINCC AUDIT审计组建教程
  11. 遗传算法matlab_当结构设计遇到遗传算法应用ANSYS和MATLAB联合仿真优化设计探索(前传)...
  12. 第二章 01 节 常用信号及其基本特征
  13. PS制作(LOGO)步骤流程
  14. c语言课程设计家谱管理系统,数据结构-家谱管理系统
  15. spring-ant-处理zip
  16. 企业遇到什么问题一定要用360评估?
  17. 多态的表现形式有哪些?
  18. java如何获取复选框选中的值
  19. nginx端口映射配置(Windows)
  20. 网站申请服务器,网站申请服务器空间

热门文章

  1. 开发板启动时,内核打印出can't access tty,job control turned off
  2. 阿里-消息推送java后端,设备方式推送
  3. Android 集成阿里云移动推送
  4. 服装加盟系统选对了,服装连锁店的管理问题少一半!
  5. 享受奇妙的景点莫斯科
  6. 国际时区 TimeZone ID列表
  7. 网上做什么最赚钱:适合你的才是最赚钱的,
  8. QT + VS2010 实现中英文切换
  9. 【LeetCode】74、75
  10. Android模拟器上的本机IP地址