STM32使用串级PID对编码器电机进行控制

目录

1. PID的作用

   1.1 PID应用概述

1.2 PID参数调整

1.3  实物

2.代码部分

2.1 定时器采样周期计算

2.2 PID算法代码

3.实物接线


设计目标:使电机以目标速度达到目标位置

1. PID的作用

   1.1 PID应用概述

      PID控制器是一种广泛应用于工业控制系统的反馈控制器,其名称来源于其三种基本控制规律:比例(Proportional)、积分(Integral)和微分(Derivative)。其基本原理是通过反馈实现控制,反馈来源是电机上安装的编码器,编码器种类有很多,常见的是霍尔式还有光电式,本文中使用的电机使用的就是霍尔式编码器电机

       普通电机上电后即可进行旋转运动,运动方向可以通过调节控制器的高低电平翻转来实现,而调节输出的电压,则可实现对电机的速度调节。

       在一个周期内,反复调节输出电压,即可实现调速,这是目前最常见的调速方式,即调整同一周期内通电的时间,同一周期内通电时间越长,等效电压越大,而等效电压越大,电机速度越快,考虑到电机的机械特性,每个电机的机械特性都不尽相同,如果只是单纯改变占空比,输出PWM,电机难以实现较为准确的速度控制,且很多场景中,运行路径是固定的,这就需要电机拥有重复定位的精确性,这就需要使用到编码器。

     通过STM32单片机开启定时器读取编码器值,这个代码来自江协科技。通过读取的值可以获取到电机的运动状态。

     在获取到编码器值后,需要将其保留下来,这就需要使用定时器中断,代码中是用定时器2,每隔10ms进入一次中断,进行一次编码器值的获取。

1.2 PID参数调整

      本文使用的是速度位置串级PID,在调节时,理论上应当先调节速度环,再调节外环,速度环作为内环,其响应速度通常要求比位置环快,以确保系统能够快速响应速度变化,

      调整速度环的比例增益(Kp),使其具有足够的增益来快速响应速度偏差,同时避免系统过冲或振荡。

      调整微调积分增益(Ki)以消除稳态误差,但要防止积分饱和。

      调整微分增益(Kd)可以帮助减少超调和振荡,提高系统的稳定性和响应速度。

      实际上调试时,我并没调整速度环,我的速度环PID值没有调整,只调整位置环的PID,首先使位置环先超调,再使得位置环逼近目标值,最后调整这两个PID区间值,最后实现的效果还算不错。

p1_p=0.074,p1_i=0.5,p1_d=0.05;//位置环PID

s1_p=1,s1_i=0,s1_d=1;//速度环PID 

1.3  实物

实物效果,在输出PWM为50时,能准确的实现位置定位。基本的目标已经实现

2.代码部分

2.1 定时器采样周期计算

       STM32F103C8T6的主频T1是72Mhz,即72x10^6hz,定时器每隔10ms需要进行一次编码器值获取,定时器的中断周期为

                       计数周期T=主频/(目标中断周期的倒数)=72\times 10^6/(1/0.001)=72000

      后面计算预分频值Prescaler

Prescaler=(T1/T)-1=999

      这意味着预分频器应该设置为999,这样定时器的计数频率将变为:

       定时器频率=72,000,000/1000=72,000

       自动重载寄存器值设置为71(因为从0开始计数,所以实际计数值为72),以便在72,000个计数后溢出。

    TIM_TimeBaseInitStructure.TIM_Period = 72-1;
    TIM_TimeBaseInitStructure.TIM_Prescaler =1000-1; 

2.2 编码器测速原理

      选用的编码器为普通的霍尔编码器,减速比为30:1.当电机旋转一圈时,释放13个脉冲,STM32采用4倍频,因此,电机旋转一周,编码器读取的值为30x13x4=1560个脉冲数。

   在知道旋转圈数使用的脉冲数后,可结合使用的轮子直径计算运行路程。

2.3 PID算法代码

#include "stm32f10x.h"                  // Device header

int16_t myabs(int a)
{ 		   
	  int temp;
		if(a<0)  temp=-a;  
	  else temp=a;
	  return temp;
}


float pwm_control(float pwm) //pwm输出限幅
{
    if(pwm>99)
        pwm=99;
    else if(pwm<-99)
        pwm=-99;
    return pwm;
}

float position_xianfu(int16_t now_position,float tar_psoition)//位置式PID位置误差限幅
{
		if(tar_psoition-now_position<3)
		{
				now_position=tar_psoition;
		}
		return now_position;
}


float xianfu(float now,float tar)
{
    if(now>tar)
        now=tar;
    if(now<-tar)
        now=-tar;
    return now;
}
//位置式PID
float p1_Err=0,p1_last_err=0,Integral1=0,p1_pwm=0,p1_p=0.074,p1_i=0.5,p1_d=0.05;//位置环PID

float p1_pid(int16_t now_position1,float tar_position1)
{
    now_position1=myabs(now_position1);
    p1_Err=tar_position1-now_position1;
    p1_pwm=p1_p*p1_Err+p1_i*Integral1+p1_d*(p1_Err-p1_last_err);
    p1_pwm=pwm_control(p1_pwm);
    p1_last_err=p1_Err;
    return p1_pwm+50;
}
//增量式PID
float s1_pid(int16_t Speed,int16_t tar_speed1)
{
		float s1_Err,s1_p=1,s1_i=0,s1_d=1;//速度环PID
		static float s1_last_err,Integral_bias1;
		s1_Err=tar_speed1-Speed;
		Integral_bias1+=s1_Err;
		Speed=s1_p*s1_Err+s1_i*Integral_bias1+s1_d*(s1_Err-s1_last_err);
		s1_last_err=s1_Err;
		Speed=xianfu(Speed,tar_speed1);
    return Speed;		
}

3.实物接线

OLED SCL   PB8

OLED SDA   PB9

TB6612                                        

EN-12V电源正极           PWMA --- STM32--PA0

GND-12V电源负极        AIN1------ STM32--PB0

AO1-电机正极               AIN2------ STM32--PB1

AO2-电机负极               STBY-----STM32---VCC

                                      

TB6612     其他引脚悬空

 Motor

电机正极-TB6612--AO1

GND-STM32--GND

B-STM32--PA6

A-STM32--PA7

VCC-STM32--5V

电机负极-TB6612--AO2

4.运行代码:

<think>好的,我现在需要解释用户提出的问题:“docker ps -a|grep registry &> /dev/null 这里的 &>的作用”。用户之前询问过如何在Shell中使用if判断命令是否执行成功,现在这个问题是关于重定向符号&>的用途。 首先,我应该回忆Shell中的重定向相关知识。用户给出的命令是docker ps -a通过管道传给grep registry,然后使用&>将输出重定向到/dev/null。用户想知道&>在这里的作用。 我记得在Shell中,>用于标准输出重定向,而2>用于标准错误。而&>可能是一个合并重定向的语法,将标准输出和标准错误都重定向到同一个文件。但需要确认不同Shell的兼容性,比如Bash是否支持这种写法,而其他Shell如sh可能不支持。同时,用户示例中的&> /dev/null可能就是将命令的所有输出(包括标准输出和标准错误)丢弃。 接下来,我需要检查是否正确。比如,对比使用>和2>&1的组合,是否与&>等效。例如,command > file 2>&1和command &> file是否效果相同。是的,在Bash中这两种写法是等价的,都是将stdout和stderr都重定向到file。 但需要注意的是,&>是Bash的特性,可能在其他的Shell中不被支持,比如POSIX标准的sh可能不支持,所以在编写可移植脚本时需要注意。不过用户给出的命令可能是在Bash环境中使用,所以这点可能需要提及但不需要深入,除非用户特别关心可移植性。 然后,用户的具体例子中,docker ps -a的输出通过管道传给grep,而grep的结果又被&>重定向到/dev/null。这里需要分析整个命令的结构。实际上,管道|连接的两个命令,docker ps -a的输出作为grep的输入,而grep的stdout和stderr都被重定向到/dev/null。因此,&>在这里作用于grep命令,而不是整个管道。这一点可能需要澄清,因为有时候用户可能会误解重定向的作用范围。 需要指出的是,&> /dev/null是附加在grep registry后面的,所以它只会影响grep命令的输出,而docker ps -a的输出已经通过管道传递给了grep,所以docker命令的stdout会被grep处理,而stderr可能仍然会输出到终端,除非docker命令的stderr也被重定向。但在这个命令中,docker的stderr并没有被重定向,所以如果有错误信息,比如docker命令执行出错,错误信息会显示在终端上,而不会被重定向到/dev/null。因此,整个命令的结构可能需要更仔细的分析。 或者,是否整个管道的输出都被重定向?不,因为重定向符号的优先高于管道。所以,命令的结构是docker ps -a的输出传给grep,然后grep的stdout和stderr被重定向到/dev/null。因此,docker的stderr仍然会显示在终端,而grep的结果(包括stdout和stderr)被丢弃。 用户可能需要知道的是,这个命令的目的是检查是否存在包含"registry"的容器,但将grep的输出(匹配的行和可能的错误)都丢弃,只通过退出状态来判断是否存在。即,如果grep找到匹配行,返回0,否则非0。而使用&> /dev/null是为了不显示任何grep的输出或错误,只根据退出状态进行判断,可能在脚本中用于条件判断。 总结来说,&>的作用是将命令的标准输出和标准错误都重定向到指定文件,这里是/dev/null,即丢弃所有输出。用户可能在之前的if判断中使用类似的结构,通过命令的退出状态来执行后续操作,而不关心输出内容。 需要确保解释清楚&>的含义,与其他重定向方式的区别,以及在具体例子中的应用。同时,提醒用户注意Shell的兼容性问题,如果脚本需要跨Shell运行的话。此外,可能还需要说明为什么在这个例子中使用&>而不是单独重定向stdout或stderr,比如用户希望同时隐藏grep的可能错误信息(例如,如果grep参数错误)或者正常输出。 最后,用简洁明了的中文分步骤解释,确保用户能够理解。</think>在Shell中,`&>` 是一个**合并输出重定向操作符**,用于同时将命令的**标准输出(stdout)**和**标准错误(stderr)**重定向到指定位置。以下是对其作用的详细解析: --- ### 一、`&>` 的核心作用 - **功能**:将命令的**所有输出(正常输出和错误信息)**重定向到指定文件或设备(如 `/dev/null`)。 - **等价写法**:`command > file 2>&1`(将stdout和stderr合并后重定向到文件) - **常见场景**:隐藏命令的所有输出(包括报错信息),仅通过**退出状态码**判断命令是否成功。 --- ### 二、命令示例解析 ```bash docker ps -a | grep registry &> /dev/null ``` 1. **命令分解**: - `docker ps -a`:列出所有容器(包括已停止的) - `| grep registry`:通过管道筛选包含关键词 `registry` 的行 - `&> /dev/null`:将 `grep` 命令的**所有输出(stdout + stderr)**丢弃 2. **实际效果**: - 若存在含 `registry` 的容器 → `grep` 匹配成功,退出码为 `0` - 若未匹配到内容或命令出错 → 退出码为 `1`(或其他非零值) - **无论结果如何**,屏幕不会显示任何输出(包括可能的`grep`报错) --- ### 三、与其他重定向方式的对比 | 操作符 | 作用 | 示例 | |----------------|-------------------------------|--------------------------| | `>` | 仅重定向**stdout**到文件 | `command > output.txt` | | `2>` | 仅重定向**stderr**到文件 | `command 2> errors.log` | | `&>` 或 `>&` | 同时重定向**stdout和stderr** | `command &> /dev/null` | | `>>` | 追加stdout到文件(不覆盖) | `command >> output.txt` | --- ### 四、典型使用场景 #### 场景1:静默执行命令,仅关注结果 ```bash # 检查容器是否存在,不显示任何输出 if docker ps -a | grep registry &> /dev/null; then echo "存在registry容器" else echo "未找到容器" fi ``` #### 场景2:调试时临时屏蔽输出 ```bash # 执行敏感操作时隐藏输出 rm -rf /tmp/cache/* &> /dev/null ``` --- ### 五、注意事项 1. **Shell兼容性** - `&>` 是 **Bash的扩展语法**,在部分Shell(如`sh`)中可能不支持,需改用 `command > file 2>&1`。 2. **管道与重定向的优先** 重定向符(如 `&>`)的优先**高于管道符**(`|`),因此: ```bash cmd1 | cmd2 &> file # 仅对cmd2重定向,cmd1的输出仍通过管道传递 ``` 若需重定向整个管道的输出,需用括号明确作用域: ```bash (cmd1 | cmd2) &> file # cmd1和cmd2的输出均被重定向 ``` --- ### 六、扩展知识 若需要**分离保存stdout和stderr**,可使用: ```bash # stdout保存到log.txt,stderr保存到error.log command > log.txt 2> error.log ``` 通过理解 `&>` 的作用,您可以更灵活地控制命令输出的显示与隐藏,尤其在编写自动化脚本时非常实用!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值