一、智能车舵机控制

一、智能车舵机控制前言:本文章主要是近期有关舵机知识的总结,将分别从舵机的控制原理,控制流程和代码实现流程几个方面作简要介绍,由于时间紧急,难免有疏漏错误之处,欢迎留言指正,QQ:2046890259一、多级的控制原理:我们本次智能车使用的舵机是通过PWM进行控制。而PWM几个重要的参数就是最大值,最小值和占空比。其中占空比决定了舵机的旋转角度,如下图所示:不同的占空比控制不同的角度。而我们的目的就是通过…

大家好,又见面了,我是你们的朋友全栈君。

前言:
本文章主要是近期有关舵机知识的总结,将分别从舵机的控制原理,控制流程和代码实现流程几个方面作简要介绍,由于时间紧急,难免有疏漏错误之处,欢迎留言指正
一、舵机的控制原理:
我们本次智能车使用的舵机是通过PWM进行控制。而PWM几个重要的参数就是最大值,最小值和占空比。其中占空比决定了舵机的旋转角度,如下图所示:在这里插入图片描述
不同的占空比控制不同的角度。而我们的目的就是通过摄像头和电感采集上来的数据(MiddleLine)通过算法来控制占空比(脉冲宽度),进而控制舵机的旋转角度。简单介绍了原理之后下面就开始介绍舵机的使用和控制。
二、舵机左右极值和中值参数设置:
使用舵机的第一步就是先对舵机进行调中,目的是使舵机左右自由度相同,从而是控制更加准确和方便,如果不调中,很容易出现舵机打死现象,轻则是车子无法正常转弯,重则烧坏舵机。调中方法:
1、调左极值:
使以下单个参数相同,观察舵机旋转角度,当左轮即将接触车子为最佳。
2、调中值:
方法同上。
3、调右极值:
方法同上。

位置:macro.h

//-------舵机pwm-------------------
#define STEER_MIN 9580 //左值9455
#define STEER_MID 9580 //中值9500
#define STEER_MAX 9580 //又值9580

注意:在调中的过程中,应尽量做到左右对称,如果左右不对称,可以采取以下几种方法:
(1)、调节舵机中值角度位置,尽量做到左右自由度对称
(2)、调节连接杆位置(推荐)
(3)、有的时候由于工艺的限制,会有部分偏差,只能通过其他硬件结构和软件设计进行弥补
二、哪里用到这些值:
1、角度控制
位置:control.c

void AngleControl(PID *pid_steer)
{ 
   
	float middle_line = getMiddleLine();
	if(middle_line > IMAGE_WIDTH)//中线偏差限幅
		middle_line = IMAGE_WIDTH;
	else if(middle_line < 0)
		middle_line = 0;
#if DIR == 0//左小右大
	steer_u = STEER_MID - PositionalPD(pid_steer, middle_line);
#elif DIR == 1
	steer_u = STEER_MID + PositionalPD(pid_steer, middle_line);
#endif
	
	//舵机脉宽平滑变化
	if(steer_u > STEER_MAX)
		steer_u = STEER_MAX;
	else if(steer_u < STEER_MIN)
		steer_u = STEER_MIN;
	setPWMWidth(steer_u);
}

uint8 cnt = 0;
uint8 flag = 0;

从这段代码可以看出,程序先通过函数getMiddleLine()获得中线,然后对中线进行了限幅,防止数值过大或过小损坏硬件。然后传递到 PositionalPD()函数,该函数通过中线和PID结构体中的数值进行计算,最终得出一个误差数值(PD运算得出)output,然后与舵机中值做差,数值传给steer_u ,然后再函数setPWMWidth()函数中对steer_u做一次限幅,然后传递给函数cmt_pwm_duty()就可以进行PWM的设置了,下面将对相关函数作简要介绍:
(1)、脉冲宽度设置:

void setPWMWidth(uint16 steer_u)
{ 
   
	if(steer_u > STEER_MAX) { 
   
		steer_u = STEER_MAX;
	} else if(steer_u < STEER_MIN) { 
   
		steer_u = STEER_MIN;
	}
        cmt_pwm_duty(steer_u/10); 
}

该函数看似是进行脉冲宽度设置,实质时进行限幅作用,真正进行脉宽设置的是cmt_pwm_duty()函数。
(2)、cmt_pwm_duty()函数:

void cmt_pwm_duty(uint16 duty)
{ 
   
    
    uint32 temp_high_num, temp_low_num;

    //计算高低电平的计数次数
    temp_low_num = (cmt_period*(CMT_PRECISON-duty)/CMT_PRECISON);
    temp_high_num = (cmt_period*(duty)/CMT_PRECISON);
    
    //设置低电平时间
    temp_low_num--;
    CMT->CMD1 = temp_low_num >> 8;
    CMT->CMD2 = (uint8)temp_low_num;
    
    //设置高电平时间
    CMT->CMD3 = temp_high_num >> 8;
    CMT->CMD4 = (uint8)temp_high_num;

}```
这里面有几个参数需要大家了解一下:
1、cmt_period :一个周期计数的次数
		表达式:cmt_period = temp_clk/(temp_div+1)/freq;
		注意:这里用到了预分频的方法,就不多做介绍
		
2、CMT_PRECISON:占空比精度
3、duty:占空比

该函数的作用是进行占空比设置,用到了CMT模块,这里不做详细介绍。

(3)、PositionalPD()函数:


//积分饱和,输出限幅
int16 PositionalPD(PID *pid, float sensor_val)//位置式pd
{ 
   
	float output = 0.0f;
	float error = 0.0f;
	
	float p_error = 0.0f;//当前误差项
	float d_error = 0.0f;//微分误差项
	
	error = pid->set_point - sensor_val;
	
	p_error	= error;
	d_error = error - pid->last_error;
	
	if(fabs(error) < 0.1f)
		output = 0.0f;
	else
		output = pid->K_p * p_error + pid->K_d * d_error;

	pid->last_error = error;
	return (int)output;
}

该函数的功能主要是根据摄像头和电感传回来的数据进行误差计算,用到了PID控制,算法不是很难,不做详细介绍。
4、 getMiddleLine()函数:

float getMiddleLine(void)
{ 
   
	float inductor = getInductorMiddleLine();
	float camera = getCameraMiddleLine();
#if CAMERA==1
	float result = inductor * car_info.K_g + camera * (1 - car_info.K_g);
#else
        float result = inductor;
#endif
	car_info.mid_line_ = result;
	return result;
}

该函数的作用是获得中线,当有摄像头时取摄像头和电感的加权值,否则使用电感的数值,这也是为什么不用摄像头也能进行循迹的原因。
三、总结:
由次可以看出,舵机控制大致分以下几个步骤:
1、调中,就是调那三个数值
2、获得中线:getMiddleLine(),分两种情况,有摄像头和无摄像头
3、将获得的中线值和调中设置的值通过函数PositionalPD()PID运算得出差值,并将结果传给steer_u
4、根据steer_u的数值,通过函数setPWMWidth()进行限幅
5、限幅后将数值steer_u/10传给函数cmt_pwm_duty()进行脉宽设置
以上就是舵机的大致控制流程,由于能力有限,难免有疏漏错误之处,欢迎留言指正,进行交流。由于本次主要是介绍舵机的有关控制,里面有很多细节没有做详细介绍,大家可以自己上网查阅相关资料进行了解。比赛是一个学习的过程,只有多动手,勤思考,才能有所收获,失败的经验比成功地经验更重要。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/151730.html原文链接:https://javaforall.net

(0)
上一篇 2022年6月20日 下午11:46
下一篇 2022年6月20日 下午11:46


相关推荐

  • 批处理当前文件夹下所有文件和子文件夹中的文件

    批处理当前文件夹下所有文件和子文件夹中的文件setnum 0 nbsp For r xin index mp4 do nbsp set anum 1 nbsp echo xecho 第 num 个文件处理成功 nbsp del x nbsp nbsp echo 共 num 个文件被处理成功 nbsp pausenul nbsp 在需要处理的文件夹中建立一个批处理文件 写入以上信息 保存直接运行 不要用管理

    2026年3月17日
    2
  • 录取为2021年同济大学秋季博士研究生(电子与信息工程学院计算机科学与技术)

    录取为2021年同济大学秋季博士研究生(电子与信息工程学院计算机科学与技术)本来不想回忆往事,读博路上有点坎坷!!遇人不淑,时运不济,还好也遇到一些特别好的老师!同学帮忙。非常感谢这些老师的帮忙。首先是2020年10月份,我硕士生博导朱老师,告诉我他没博士招生名额,但有资格,这个吉大计算机比较特殊,每年博导重新排名,一年一考核,按照分来分博士名额,我老师最后一名,院长副院长有要两个名额的!这里面不方便多说,最后就是我老师今年21招不了博士,到我这卡壳一年,也特别遗憾没能读朱老师的博士。接下来沉沦了两天,10月10号左右吧,开始疯狂联系吉大别的博导,还好联系了几位,其中一z姓老

    2022年7月25日
    36
  • OpenClaw 实战 72 小时:那些文档不会告诉你的坑

    OpenClaw 实战 72 小时:那些文档不会告诉你的坑

    2026年3月13日
    1
  • html+CSS让背景图片充满整个屏幕

    html+CSS让背景图片充满整个屏幕由于给网页设置背景图时,需要设置背景图不重复且充满整个浏览器屏幕。   给body标签指定背景图,这样背景图就可以填充整个浏览器viewport了。其实,该方案对所有的块级容器都可以生效。块级容器的宽高是动态的,那么背景图将自动伸缩,充满整个容器。可设置body标签的CSS样式如下:body{/*加载背景图*/backg

    2022年6月7日
    31
  • matlab层次聚类中birch,Birch层次聚类

    matlab层次聚类中birch,Birch层次聚类Birch 层次聚类算法标签 空格分隔 CF 树建立 BIRCH 算法比较适合于数据量大 类别数 K 也比较多的情况 它运行速度很快 只需要单遍扫描数据集就能进行聚类 当然需要用到一些技巧 下面我们就对 BIRCH 算法做一个总结 个人建议 如想要自己写 CF 树生成代码前 请先了解一下 B 树的构造与写法对之后的代码完成将会有帮助 1 聚类特征 CF 与聚类特征树 CFTree 在聚类特征树中 一个聚类特征 CF 是这

    2026年3月17日
    2
  • ebx文件

    ebx文件EBX 是一种电子书格式 打开方式 用 XReader ebx 阅读器 打开 xreader 免费版是一款专门针对 psp 而推出的一款大众软件 不仅能够在 psp 中看图片 还能够当成一个专业的 PSP 阅读器 支持任意大小点阵字体 支持 html 读取 编码转换 竖看 翻页保留行 书签及自动书签等 可以看 zip 和 chm 和 rar 内的文本文件 有自动降频节能 不播放 mp3 时 另外 xReader 支持看图的格式有 b

    2026年3月20日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号