8.3 机器人平台设计之arduino与电机驱动

机器人平台设计8章:https://blog.csdn.net/qq_52537255/article/details/119350982
机器人平台设计8章 8-1 概述:https://blog.csdn.net/qq_52537255/article/details/119351229
机器人平台设计8章8.2 机器人平台设计之arduino基础:https://blog.csdn.net/qq_52537255/article/details/119351360?spm=1001.2014.3001.5501
机器人平台设计8章8.3 机器人平台设计之arduino与电机驱动:https://blog.csdn.net/qq_52537255/article/details/119352154?spm=1001.2014.3001.5501

8.3 机器人平台设计之arduino与电机驱动

对于构建轮式机器人而言,电机驱动是一重要实现环节。

场景:在机器人架构中,如果要实现机器人移动,其中一种实现策略是:控制系统会先发布预期的车辆速度信息,然后驱动系统订阅到该信息,控制电机转速至预期速度,调速过程中需要时时测速用于计算实际速度与预期速度的差值,作为调速算法的输入数据,获取的实际速度还要反馈给控制系统,控制系统会计算实际位移并生成里程计信息。

在上述流程中,控制系统(ROS端)其实就是典型的发布和订阅实现,不再赘述,具体到驱动系统(Arduino)层面,需要解决的问题有如下几点:

一个周期伊始,Arduino 如何订阅控制系统发布的速度信息?

一个周期结束,Arduino 如何发布实际速度信息到控制系统?

一个周期之中,Arduino 如何驱动电机(正传、反转)?

一个周期之中,Arduino 如何实现电机测速?

一个周期之中,Arduino 如何实现电机调速?

前两个问题涉及到驱动系统与控制系统的通信,在下一节中单独讲解,本节主要介绍电机基本控制、电机测速以及调速实现,主要内容如下:

硬件:主要介绍电机类型与结构,还会介绍常用电机驱动板;

电机转向控制与电机转速的控制;

电机测速实现;

电机调速实现。

8.3.1 硬件_电机与电机驱动板

如果要通过Arduino实现电机相关操作(比如:转向控制、转速控制、测速等),那么必须先要具备两点前提知识:

需要简单了解电机类型、机械结构以及各项参数,这些是和机器人的负载、极限速度、测速结果等休戚相关的;
还需要选配合适的电机驱动板,因为Arduino的输出电流不足以直接驱动电机,需要通过电机驱动板放大电机控制信号。

当前我们的机器人平台使用的电机为直流减速电机,电机驱动板为L298P电机驱动板。接下来就分别介绍这两个模块:
1.直流减速电机
在这里插入图片描述
在这里插入图片描述

如图所示,相当一部分ROS智能车中使用的直流减速电机与之类似,只要构成由三部分构成:

头部:减速箱
中间:电机主体
尾部:编码器

电机主体通过输入轴与减速箱相连接,通过减速箱的减速效果,最终外端的输出轴会按照比例(取决于减速箱减速比)降低电机输入轴的转速,当然速度降低之后,将提升电机的力矩。

尾部是AB相霍尔编码器,通过AB编码器输出的波形图,可以判断电机的转向以及计算电机转速

另外,即便电机外观相同,具体参数也可能存在差异,参数需要商家提供,需要了解的参数如下:
在这里插入图片描述

额定电压
额定电流
额定功率
额定扭矩
减速比
减速前转速
减速后转速
编码器精度

主要参数:

额定扭矩:额定扭矩和机器人质量以及有效负荷相关,二者正比例相关,额定扭矩越大,可支持的机器人质量以及有效负荷越高;

减速比:电机输入轴与输出轴的减速比例,比如: 减速比为60,意味着电机主体旋转60圈,输出轴旋转1圈。

减速后转速:与减速比相关,是电机减速箱输出轴的转速,单位是 rpm(转/分),减速后转速与减速前转速存在转换关系: 减速后转速 = 减速前转速 / 减速比。另外,可以根据官方给定的额定功率下的减速后转速结合车轮参数来确定小车最大速度。

编码器精度:是指编码器旋转一圈单相(当前编码器有AB两相)输出的脉冲数,注意:电机输入轴旋转一圈的同时,编码器旋转一圈,如果输出轴旋转一圈,那么编码器的旋转圈数和减速比一致(比如减速比是60,那么输出轴旋转一圈,编码器旋转60圈),而编码器输出的脉冲数计算公式则是: 输出轴旋转一圈产生的脉冲数 = 减速比 * 编码器旋转一圈发送的脉冲数(比如:减速比为60,编码器旋转一圈输出13个脉冲,那么输出轴旋转一圈总共产生 13 * 60 也即780个脉冲)。

2.电机驱动板

电机驱动板可选型号较多,比如:TB6612、L298N、L298P…

TB6612:
在这里插入图片描述

L298N:
在这里插入图片描述

L298P:
在这里插入图片描述

在此我们选用 L298P,可以在Arduino上直接插拔,使用更为方便,另外请注意:为了保护电路板,使用之前,请先剔除L298P电机驱动板Vin引脚背后的锡焊或者也可以将对应的排针直接折断。至于更详细使用方式,后续有详细介绍。

8.3.2 电机基本控制实现

在ROS智能车中,控制车辆的前进、后退以及速度调节,那么就涉及到电机的转向与转速控制,本节主要就是介绍相关知识点。

需求:控制电机转动,先控制电机以某个速率正向转动N秒,再让电机停止N秒,再控制电机以某个速率逆向转动N秒,最后让电机停止N秒,如此循环。

实现流程:

接线,需要先集成电池、Arduino、电机驱动板与电机(可以使用杜邦线接线);
编写Arduino程序,setup中设置引脚模式,loop中控制电机运动;
上传并查看运行结果。

1.接线

先将电机驱动板与Arduino集成(注意:请先剔除L298P电机驱动板Vin引脚背后的锡焊或者也可以将对应的排针直接折断);

然后将电池的正负极使用杜邦线(公对公)分别接入L298P电机驱动模块的VIN与GND(注意:正负极不可接反,正=VIN,负=GND);

最后将电机编码器的电机线+和电机线-使用杜邦线(公对母)分别接入L298P电机驱动模块的A+与A-(无强制对应关系)。

接线效果图如下:
在这里插入图片描述
在这里插入图片描述

不同的编码器排针顺序可能有差异,请注意区分,当前的编码器电机线+与电机线-是最外围两个排针。
2.编码

前提知识点:

L298P电机驱动板的 A+ 与 A- 输出对应的是引脚4(DIRA)和引脚5(PWMA),引脚4控制转向,引脚5输出PWM。B+ 与 B- 输出对应的是引脚6(PWMB)和引脚7(DIRB),引脚7控制转向,引脚6输出PWM。
可以通过PWM控制电机转速。

代码:

 * 电机转动控制
 * 1.定义接线中电机对应的引脚
 * 2.setup 中设置引脚为输出模式
 * 3.loop中控制电机转动
 

int DIRA = 4;
int PWMA = 5;

void setup() {
  //两个引脚都设置为 OUTPUT
  pinMode(DIRA,OUTPUT);
  pinMode(PWMA,OUTPUT);
}

void loop() {
  //先正向转动3秒
  digitalWrite(DIRA,HIGH);
  analogWrite(PWMA,100);
  delay(3000);
  //停止3秒
  digitalWrite(DIRA,HIGH);
  analogWrite(PWMA,0);
  delay(3000);
  //再反向转动3秒
  digitalWrite(DIRA,LOW);
  analogWrite(PWMA,100);
  delay(3000);
  //停止3秒
  digitalWrite(DIRA,LOW);
  analogWrite(PWMA,0);
  delay(3000);

  
  • 注意:
  • 1.可以通过将DIRA设置为HIGH或LOW来控制电机转向,但是哪个标志位正转或反转需要根据需求判断,转向是相对的。
  • 2.PWM的取值为 [0,255],该值可自己设置。

3.运行

程序上传到Arduino上,如无异常,电机开始转动,转动结果与需求描述类似。

8.3.3 电机测速01_理论

测速实现是调速实现的前提,8.3.3-8.3.N会循序渐进的介绍测速的完整实现,本节主要介绍AB相增量式编码器测速原理。
1.概念

百度百科关于编码器介绍如下:
编码器(encoder)是将信号(如比特流)或数据进行编制、转换为可用以通讯、传输和存储的信号形式的设备。编码器把角位移或直线位移转换成电信号,前者称为码盘,后者称为码尺。按照读出方式编码器可以分为接触式和非接触式两种;按照工作原理编码器可分为增量式和绝对式两类。增量式编码器是将位移转换成周期性的电信号,再把这个电信号转变成计数脉冲,用脉冲的个数表示位移的大小。绝对式编码器的每一个位置对应一个确定的数字码,因此它的示值只与测量的起始和终止位置有关,而与测量的中间过程无关。

2.测速原理

关于编码器相关概念简单了解即可,在此需要着重介绍的是 AB相增量式编码器测速原理:
在这里插入图片描述
AB相编码器主要构成为A相与B相,每一相每转过单位的角度就发出一个脉冲信号(一圈可以发出N个脉冲信号),A相、B相为相互延迟1/4周期的脉冲输出,根据延迟关系可以区别正反转,而且通过取A相、B相的上升和下降沿可以进行单频或2倍频或4倍频测速。
3.测速举例

假设编码器旋转1圈输出13个脉冲,减速比为 60。伪代码如下:

单频计数:

//设置一个计数器
int count = 0;
//当A为上升沿时
if(B为高电平){
    count++;
}else {
    count--;
}
//....
//速度=单位时间内统计的脉冲的个数 / (13*60) / 单位时间

2倍频计数:

//设置一个计数器
int count = 0;
//当A为上升沿时
if(B为高电平){
    count++;
}else {
    count--;
}
//当A为下降沿时
if(B为低电平){
    count++;
}else {
    count--;
}

//....
//速度=单位时间内统计的脉冲的个数 / (13*2*60) / 单位时间

4倍频计数:

//设置一个计数器
int count = 0;
//当A为上升沿时
if(B为高电平){
    count++;
}else {
    count--;
}
//当A为下降沿时
if(B为低电平){
    count++;
}else {
    count--;
}
//当B为上升沿时
if(A为低电平){
    count++;
} else {
    count--;
}
//当B为下降沿时
if(A为高电平){
    count++;
} else {
    count--;
}
//....
//速度=单位时间内统计的脉冲的个数 / (13*4*60) / 单位时间

8.3.4 电机测速02_实现

需求:统计并输出电机转速。
思路:先统计单位时间内以单频或2倍频或4倍频的方式统计脉冲数,再除以一圈对应的脉冲数,最后再除以时间所得即为电机转速。
核心:计数时,需要在A相或B相的上升沿或下降沿触发时,实现计数,在此需要使用中断引脚与中断函数。

Arduino Mega 2560 的中断引脚:2 (interrupt 0), 3 (interrupt 1),18 (interrupt 5), 19 (interrupt 4), 20 (interrupt 3), 21 (interrupt 2)

实现流程:

接线:将Arduino与电机驱动模块集成,使用杜邦线将电机编码器连接到Arduino的相关引脚;
编写Arduino程序先实现脉冲数统计;
编写Arduino程序再实现转速计算相关实现;
上传到Arduino并测试。

1.接线

先将Arduino与电机驱动模块集成(以实现);

然后使用杜邦线(公对母)将编码器5V与编码器GND分别连接到Arduino或电机驱动板的5V和GND;

最后使用杜邦线(公对母)将编码器A相和编码器B相分别连接中断引脚(比如:A相连接18,B相连接19)。

注意:当前只是测速案例,没必要必须连接电池以及为电机供电,精简期间,当前只连接编码器。

**接线效果图如下:
在这里插入图片描述在这里插入图片描述

2.编码实现脉冲统计**

核心知识点:attachInterrupt()函数

描述:当发生外部中断时,调用一个指定函数。当中断发生时,该函数会取代正在执行的程序。大多数的Arduino板有两个外部中断:0(数字引脚2)和1(数字引脚3)。

arduino Mege有四个外部中断:数字2(引脚21),3(引脚20),4(引脚19),5(引脚18)。

语法:attachInterrupt(interrupt, function, mode)

interrupt:中断引脚数

function:中断发生时调用的函数,此函数必须不带参数和不返回任何值。该函数有时被称为中断服务程序。

mode:定义何时发生中断以下四个contstants预定有效值:

    LOW 当引脚为低电平时,触发中断

    CHANGE 当引脚电平发生改变时,触发中断

    RISING 当引脚由低电平变为高电平时,触发中断

    FALLING 当引脚由高电平变为低电平时,触发中断.

返回:无

注意事项:当中断函数发生时,delay()和millis()的数值将不会继续变化。当中断发生时,串口收到的数据可能会丢失。你应该声明一个变量来在未发生中断时储存变量。

代码:

  • 测速实现:

  • 阶段1:脉冲数统计

  • 阶段2:速度计算

  • 阶段1:

  • 1.定义所使用的中断引脚,以及计数器(使用 volatile 修饰)

  • 2.setup 中设置波特率,将引脚设置为输入模式

  • 3.使用 attachInterupt() 函数为引脚添加中断出发时机以及中断函数

  • 4.中断函数编写计算算法,并打印

  • A.单频统计只需要统计单相上升沿或下降沿

  • B.2倍频统计需要统计单相的上升沿和下降沿

  • C.4倍频统计需要统计两相的上升沿和下降沿

  • 5.上传并查看结果

int motor_A = 18;//中端口是5
int motor_B = 19;//中断口是4
volatile int count = 0;//如果是正转,那么每计数一次自增1,如果是反转,那么每计数一次自减1 


void count_A(){
  //单频计数实现
  //手动旋转电机一圈,输出结果为 一圈脉冲数 * 减速比
  /*if(digitalRead(motor_A) == HIGH){

    if(digitalRead(motor_B) == LOW){//A 高 B 低
      count++;  
    } else {//A 高 B 高
      count--;  
    }


  }*/

  //2倍频计数实现
  //手动旋转电机一圈,输出结果为 一圈脉冲数 * 减速比 * 2
  if(digitalRead(motor_A) == HIGH){

    if(digitalRead(motor_B) == HIGH){//A 高 B 高
      count++;  
    } else {//A 高 B 低
      count--;  
    }


  } else {

    if(digitalRead(motor_B) == LOW){//A 低 B 低
      count++;  
    } else {//A 低 B 高
      count--;  
    }  

  }

}

//与A实现类似
//4倍频计数实现
//手动旋转电机一圈,输出结果为 一圈脉冲数 * 减速比 * 4
void count_B(){
  if(digitalRead(motor_B) == HIGH){

    if(digitalRead(motor_A) == LOW){//B 高 A 低
      count++;
    } else {//B 高 A 高
      count--;
    }


  } else {

    if(digitalRead(motor_A) == HIGH){//B 低 A 高
      count++;
    } else {//B 低 A 低
      count--;
    }

  }

}

void setup() {
  Serial.begin(57600);//设置波特率  
  pinMode(18,INPUT);
  pinMode(19,INPUT);
  attachInterrupt(5,count_A,CHANGE);//当电平发生改变时触发中断函数
  //四倍频统计需要为B相也添加中断
  attachInterrupt(4,count_B,CHANGE);
}


void loop() {
  //测试计数器输出
  delay(3000);
  Serial.println(count);

}

3.转速计算

思路:需要定义一个开始时间(用于记录每个测速周期的开始时刻),还需要定义一个时间区间(比如50毫秒),时时获取当前时刻,当当前时刻 - 上传结束时刻 >= 时间区间时,就获取当前计数并根据测速公式计算时时速度,计算完毕,计数器归零,重置开始时间

核心知识点:当使用中断函数中的变量时,需要先禁止中断noInterrupts(),调用完毕,再重启中断interrupts()

代码(核心):

2中代码除了 loop 实现,无需修改。

int reducation = 60;//减速比,根据电机参数设置,比如 15 | 30 | 60
int pulse = 13; //编码器旋转一圈产生的脉冲数该值需要参考商家电机参数
int per_round = pulse * reducation * 4;//车轮旋转一圈产生的脉冲数 
long start_time = millis();//一个计算周期的开始时刻,初始值为 millis();
long interval_time = 50;//一个计算周期 50ms
double current_vel;

//获取当前转速的函数
void get_current_vel(){
  long right_now = millis();  
  long past_time = right_now - start_time;//计算逝去的时间
  if(past_time >= interval_time){//如果逝去时间大于等于一个计算周期
    //1.禁止中断
    noInterrupts();
    //2.计算转速 转速单位可以是秒,也可以是分钟... 自定义即可
    current_vel = (double)count / per_round / past_time * 1000 * 60;
    //3.重置计数器
    count = 0;
    //4.重置开始时间
    start_time = right_now;
    //5.重启中断
    interrupts();

    Serial.println(current_vel);

  }
}

void loop() {
  //测试计数器输出
  //delay(3000);
  //Serial.println(count);

  delay(10);
  get_current_vel();

}

4.测试

将代码上传至Arduino,打开出口监视器,手动旋转电机,可以查看到转速信息。

8.3.5 电机调速01_PID控制理论

场景:

速度信息可以以m/s为单位,或者也可以转换成转速 r/s,而电机的转速是由PWM脉冲宽度来控制的,如何根据速度信息量化成合适的PWM至呢?
比如:现有一辆行驶中的无人车,要求将车速调整至100KM/h,那么应该如何向电机输出PWM值?或换言之,如何控制油门?

调速实现策略由多种,PID其中较为常用。
PID简介

PID算法是一种经典、简单、高效的动态速度调节方式,P代表比例,I代表积分,D代表微分。

PID公式如下:

在这里插入图片描述

  e(t)作为 PID 控制的输入;

   u(t)作为 PID 控制器的输出和被控对象的输入;

   Kp 控制器的比例系数;

   Ki控制器的积分时间,也称积分系数;

   Kd控制器的微分时间,也称微分系数。

上述公式稍显晦涩,PID控制原理框架图更有助于理解:
在这里插入图片描述

1.P

如果实现上述场景中的车速控制,一种简单的实现方式是: 确定目标速度,获取当前速度,使用(目标速度-当前速度)*某一系数 计算结果为输出的PWM,再获取当前速度,使用(目标速度-当前速度)*某一系数 计算结果累加上次的PWM并输出…如此循环

比如:

目标速度为100KM/h,系数为0.5
初始状态为静止0KM/h,差值为100,差值*系数计算输出结果为50,当前速度可达 60KM/h
初始速度为60KM/h,差值为40,差值*系数计算结果为20,累加之后为70,当前速度可达84KM/h
初始速度为84KM/h,差值为16,差值*系数计算结果为8,累加之后为78,当前速度可达93.6KM/h
.... 以此类推,最终达成目标速度。

在上述模型中,调速实现是一个闭环,每一次循环都会根据当前时速与目标时速的差值,再乘以以固定系数,计算出需要增长的PWM值,这其中的系数,称之为比例,也是PID中的P。
2.I

上述模型是理想状态实现,当PWM按照比例增长时,时速也是等比例增长的,但是实际状态下,可能由于内部外部因素的影响(摩擦力、风阻等),时速不能等比例增长,每次循环中实际速度与预期速度存在稳态误差,这意味着最终结果可能永远无法达成预期,解决的方法就是使用积分I。

每次调速时,输出除了要累加计算的PWM之外,还要累加根据积分I计算的结果,以消除静态误差。
3.D

仍然以模型1为例,当比例设置的过大时,可能会出先"超速"的情况,超速之后可能需要多次调整,产生系统震荡,具体到电机上表现,可能会出现抖动,解决这种情况可以使用D微分,当速度越是接近目标速度时,D就会越施加反方向力,减弱P的控制,起到类似”阻尼“的作用。通过D的使用可以减小系统震荡。

综上,PID闭环控制实现是结合了比例、积分和微分的一种控制机制,通过P可以以增量的方式计算输出,通过I可以消除稳态误差,通过D可以减小系统震荡,三者相结合,最终是要快速、精准且稳定的达成预期结果,而要实现该结果,还需要对这三个数值反复测试、调整…下一节将介绍在 Arduino 中PID控制的具体实现,其中就包括PID库的调用,以及PID调试的具体方式。

8.3.6 电机调速02_PID控制实现

了解了PID原理以及计算公式之后,我们可以在程序中自实现PID相关算法实现,不过,在Arduino中该算法已经被封装了,直接整合调用即可,从而提高程序的安全性与开发效率。该库是:Arduino-PID-Library,接下来通过一个案例演示该库的使用。

需求:通过PID控制电机转速,预期转速为 120r/m。

实现流程:

添加Arduino-PID-Library;
接线——Arduino集成电机驱动模块、电池、电机;
编写Arduino程序直接调用相关实现;
使用串口绘图器调试PID值。

1.添加Arduino-PID-Library

首先在 GitHub 下载 PID 库: git clone https://github.com/br3ttb/Arduino-PID-Library

然后将该文件夹移动到 arduino 的安装目录的 libraries下: sudo cp -r Arduino-PID-Library /usr/share/arduino/libraries

还要重命名文件夹: sudo mv Arduino-PID-Library ArduinoPIDLibrary

最后重启 ArduinoIDE
2.接线

需要按照8.3.2中的接线模式集成电机驱动模块、电池与电机线;

需要按照8.3.4中的接线模式集成Arduino与电机编码器。

接线效果图如下:
在这里插入图片描述

3.编码

PID调速中,测速是实现闭环的关键实现,所以需要复制之前的电机控制代码以及测速代码。

完整代码实现:

  • PID 调速实现:
  • 1.代码准备,复制并修改电机控制以及测速代码
  • 2.包含PID头文件
  • 3.创建PID对象
  • 4.在setup中启用自动调试
  • 5.调试并更新PWM
#include <PID_v1.h> 

int DIRA = 4;
int PWMA = 5;

int motor_A = 18;//中端口是5
int motor_B = 19;//中断口是4
volatile int count = 0;//如果是正转,那么每计数一次自增1,如果是反转,那么每计数一次自减1 


void count_A(){
  //单频计数实现
  //手动旋转电机一圈,输出结果为 一圈脉冲数 * 减速比
  /*if(digitalRead(motor_A) == HIGH){

    if(digitalRead(motor_B) == LOW){//A 高 B 低
      count++;  
    } else {//A 高 B 高
      count--;  
    }


  }*/

  //2倍频计数实现
  //手动旋转电机一圈,输出结果为 一圈脉冲数 * 减速比 * 2
  if(digitalRead(motor_A) == HIGH){

    if(digitalRead(motor_B) == HIGH){//A 高 B 高
      count++;  
    } else {//A 高 B 低
      count--;  
    }


  } else {

    if(digitalRead(motor_B) == LOW){//A 低 B 低
      count++;  
    } else {//A 低 B 高
      count--;  
    }  

  }

}

//与A实现类似
//4倍频计数实现
//手动旋转电机一圈,输出结果为 一圈脉冲数 * 减速比 * 4
void count_B(){
  if(digitalRead(motor_B) == HIGH){

    if(digitalRead(motor_A) == LOW){//B 高 A 低
      count++;
    } else {//B 高 A 高
      count--;
    }


  } else {

    if(digitalRead(motor_A) == HIGH){//B 低 A 高
      count++;
    } else {//B 低 A 低
      count--;
    }

  }

}


int reducation = 60;//减速比,根据电机参数设置,比如 15 | 30 | 60
int pulse = 13; //编码器旋转一圈产生的脉冲数该值需要参考商家电机参数
int per_round = pulse * reducation * 4;//车轮旋转一圈产生的脉冲数 
long start_time = millis();//一个计算周期的开始时刻,初始值为 millis();
long interval_time = 50;//一个计算周期 50ms
double current_vel;

//获取当前转速的函数
void get_current_vel(){
  long right_now = millis();  
  long past_time = right_now - start_time;//计算逝去的时间
  if(past_time >= interval_time){//如果逝去时间大于等于一个计算周期
    //1.禁止中断
    noInterrupts();
    //2.计算转速 转速单位可以是秒,也可以是分钟... 自定义即可
    current_vel = (double)count / per_round / past_time * 1000 * 60;
    //3.重置计数器
    count = 0;
    //4.重置开始时间
    start_time = right_now;
    //5.重启中断
    interrupts();

    Serial.println(current_vel);

  }
}

//-------------------------------------PID-------------------------------------------
//创建 PID 对象
//1.当前转速 2.计算输出的pwm 3.目标转速 4.kp 5.ki 6.kd 7.当输入与目标值出现偏差时,向哪个方向控制
double pwm;//电机驱动的PWM值
double target = 120;
double kp=1.5, ki=3.0, kd=0.1;
PID pid(&current_vel,&pwm,&target,kp,ki,kd,DIRECT);

//速度更新函数
void update_vel(){
  //获取当前速度
  get_current_vel();
  pid.Compute();//计算需要输出的PWM
  digitalWrite(DIRA,HIGH);
  analogWrite(PWMA,pwm);

}

void setup() {
  Serial.begin(57600);//设置波特率  
  pinMode(18,INPUT);
  pinMode(19,INPUT);
  //两个电机驱动引脚都设置为 OUTPUT
  pinMode(DIRA,OUTPUT);
  pinMode(PWMA,OUTPUT);

  attachInterrupt(5,count_A,CHANGE);//当电平发生改变时触发中断函数
  //四倍频统计需要为B相也添加中断
  attachInterrupt(4,count_B,CHANGE);

  pid.SetMode(AUTOMATIC);
}



void loop() {
  delay(10);
  //digitalWrite(DIRA,HIGH);
  //analogWrite(PWMA,150);
  //get_current_vel();
  update_vel();

}

核心代码解释:

1.包含PID头文件

#include <PID_v1.h>

2.创建PID对象

//创建 PID 对象
//1.当前转速 2.计算输出的pwm 3.目标转速 4.kp 5.ki 6.kd 7.当输入与目标值出现偏差时,向哪个方向控制

double pwm;//电机驱动的PWM值
double target = 120;
double kp=1.5, ki=3.0, kd=0.1;
PID pid(&current_vel,&pwm,&target,kp,ki,kd,DIRECT);

3.setup中启用PID自动控制

pid.SetMode(AUTOMATIC);

4.计算输出值

pid.Compute();

4.调试

PID控制的最终预期结果,是要快速、精准、稳定的达成预期结果,P主要用于控制响应速度,I主要用于控制精度,D主要用于减小震荡增强系统稳定性,三者的取值是需要反复调试的,调试过程中需要查看系统的响应曲线,根据响应曲线以确定合适的PID值。

在 Arduino 中响应曲线的查看可以借助于 Serial.println() 将结果输出,然后再选择菜单栏的工具下串口绘图器以图形化的方式显示响应结果:
在这里插入图片描述
PID调试技巧:

参数整定找最佳,从小到大顺序查
先是比例后积分,最后再专把微分加
曲线振属荡很频繁,比例度盘要放大
曲线漂浮绕大湾,比例度盘往小扳
曲线偏离回复慢,积分时间往下降
曲线波动周期长,积分时间再加长
曲线振荡频率快,先把微分降下来
动差大来波动慢。微分时间应加长
理想曲线两个波,前高后低4比1
一看二调多分析,调节质量不会低

后面发现了一个骚操作: 呜呜呜,没有之前那么麻烦的Ծ‸Ծ,链接惊喜:http://www.autolabor.com.cn/book/ROSTutorials/di-9-zhang-ji-qi-ren-dao-822a28-shi-4f5329.html

有帮助的小伙伴给个赞呗,大家进交流群一起学习。

  • 21
    点赞
  • 105
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
您可以通过以下步骤来实现Arduino电机驱动: 1. 首先,您需要添加Arduino-PID-Library库到您的Arduino开发环境中。这个库将帮助您实现PID控制算法。 2. 接下来,您需要将Arduino电机驱动模块和电池进行接线。使用适当的杜邦线将它们连接在一起,并确保连接正确。 3. 然后,您需要编写Arduino程序来调用相关实现。您可以使用Arduino IDE来编写程序,实现您的电机驱动逻辑。 4. 最后,您可以使用串口绘图器来调试PID值。通过监视串口数据输出,您可以调整和优化PID参数,以实现更好的电机驱动效果。 另外,您也可以通过以下步骤来实现Arduino电机驱动: 1. 首先,进行接线。将Arduino电机驱动模块集成,并使用杜邦线将电机编码器连接到Arduino的相关引脚。确保连接正确。 2. 然后,您需要编写Arduino程序来实现脉冲数统计。通过读取编码器的脉冲数,您可以确定电机的转速。 3. 接着,编写Arduino程序来计算电机的转速。根据脉冲数和时间,您可以计算出电机的转速,并进行相应的控制。 4. 最后,将程序上传到Arduino并进行测试。通过观察电机的运行情况,您可以验证您的电机驱动实现是否正确。 此外,您还可以通过以下步骤来实现Arduino电机驱动: 1. 首先,进行接线。集成电池、Arduino电机驱动板和电机,您可以使用杜邦线来完成接线。确保连接正确。 2. 接着,编写Arduino程序。在程序的setup部分,您需要设置引脚模式,确保Arduino正确识别电机驱动板和电机。在loop部分,您可以编写控制电机运动的代码逻辑。 3. 最后,将程序上传到Arduino,并查看运行结果。通过观察电机的运动情况,您可以验证您的电机驱动是否成功实现。 请根据您的具体需求和实际情况选择适合您的实现流程。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [8.3 机器人平台设计arduino电机驱动](https://blog.csdn.net/qq_52537255/article/details/119352154)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值