所有分类
主题 主题
平台 平台
我的工作台
userHead
注册时间 [[userInfo.create_time]]
创造力 [[userInfo.creativity]]
[[userInfo.remark]]
[[d.project_title]]
articleThumb
[[d.material_name]]
timelineThumb
进入工作台
折叠
所有分类 我的工作台
展开

玩转撸狗系列——麦昆巡线

DFHJM_IpFmV DFHJM_IpFmV 2020-06-07 18:27:14
0
1
简单

       大家好!我是李诩,我又来啦!今天,我决定玩个“绝的”——撸狗系列 之 麦昆巡线!成品出来后,我觉得非常好玩,所以,我想来给大家分享这个项目。如果大家喜欢,可以学习一下制作这个项目!

       那么本项目用到了一个PID算法。那么什么是PID算法呢?

       PID 算法,是控制理论中最常用、最经典的算法,在我们的生产和生活中应用的非常广泛。它并不是什么很神圣的东西,大家一定都见过 PID 的实际应用:比如四轴飞行器,再比如平衡小车,还有汽车的定速巡航、3D 打印机上的温度控制器、恒温热水器等。就是类似于这种:需要将某一个物理量“保持稳定”的场合(比如维持平衡,稳定温度、转速等),PID 都会派上大用场。 

 它的公式为:

projectImage

或者我们在编程时更常用的是数字式的 PID 公式:

projectImage

PID 控制系统是一种闭环控制系统,闭环控制是根据控制对象输出的反馈来进行校正的控制方式。它能够根据测量出的实际值与计划值之间的误差 Error,按一定的标准来进行纠正。

根据公式,可以看到 PID 分为 3 个部分:比例调节(P)、积分调节(I)、微分调节(D)。那么这三者之间是什么关系呢?每个部分的调节对巡线会产生什么样的影响呢?我们一个一个来看。

> 注意:如标题所说,本文是写给小学生看的 PID 调速算法,所以下文中描述的是已经简化的 PID 算法,默认没有去计算每个程序的循环时间,也就是没有去计算积分和微分时间。主要有几个原因:一、是因为程序功能比较单一,每个循环时间差不多,在调节 Kd、Ki 参数时,将时间参数 T 当成一个整体进行调试了;二、省略了时间参数后,程序编写会更加简单,容易看懂与理解。 

先来看看我的“小麦坤”吧!

projectImage

这么可爱的“昆昆”是不是看之就很想入手一个呢?那,我们开始制作吧!

步骤1 步骤1
准备材料
材料清单 材料清单
1x
麦昆: micro:bit教育机器人 V4.0 锂电池豪华套餐赠地图
1x
AI视觉传感器 加 硅胶套
1x
Husky Lens外壳
步骤2 步骤2
拼装(有视频教程)

       接下来是文字教程

1、先安装锂电池至麦昆主体上面。

projectImage

2、安装Husky Lens到支架上。 

projectImage

3、安装Husky底座。

projectImage

4、把安装好的Husky Lens安装到底座上。

projectImage

5、装好micro:bit板

projectImage

6、完成

projectImage
步骤3 步骤3
切割外形
步骤4 步骤4
编写程序
projectImage
代码 代码
	                    					/*!
 * MindPlus
 * maqueen
 *
 */
#include <Maqueen_Motor.h>
#include <DFRobot_HuskyLens.h>

// 动态变量
volatile float mind_n_x1, mind_n_offset, mind_n_error, mind_n_Kp, mind_n_V_turn,
               mind_n_V_straight, mind_n_V_left, mind_n_V_right, mind_n_Ki, mind_n_Kd,
               mind_n_lastError, mind_n_integral, mind_n_derivative;
// 函数声明
void DF_MaiKunYunDongKongZhi_ZuoLunSuDu(float mind_n_V_left, float mind_n_V_right);
void DF_PXunXian();
void DF_PuTongXunXian1();
void DF_PIDCanShuChuShiHua();
void DF_PuTongXunXian2();
void DF_PDCanShuChuShiHua();
void DF_PuTongXunXian3();
void DF_PCanShuChuShiHua();
void DF_PIDXunXian();
void DF_PDXunXian();
// 创建对象
DFRobot_HuskyLens huskylens;
Maqueen_Motor     motor;


// 主程序开始
void setup() {
	huskylens.beginI2CUntilSuccess();
	DF_PIDCanShuChuShiHua();
}
void loop() {
	mind_n_x1 = huskylens.readArrowParameter(1).xOrigin;
	DF_PIDXunXian();
}


// 自定义函数
void DF_MaiKunYunDongKongZhi_ZuoLunSuDu(float mind_n_V_left, float mind_n_V_right) {
	if ((mind_n_V_left>=0)) {
		motor.motorRun(motor.LEFT,motor.CW,mind_n_V_left);
	}
	else {
		motor.motorRun(motor.LEFT,motor.CCW,(abs(mind_n_V_left)));
	}
	if ((mind_n_V_right>=0)) {
		motor.motorRun(motor.RIGHT,motor.CW,mind_n_V_right);
	}
	else {
		motor.motorRun(motor.RIGHT,motor.CCW,(abs(mind_n_V_right)));
	}
}
void DF_PXunXian() {
	mind_n_error = (mind_n_x1 - mind_n_offset);
	mind_n_V_turn = (mind_n_Kp * mind_n_error);
	mind_n_V_left = (mind_n_V_straight + mind_n_V_turn);
	mind_n_V_right = (mind_n_V_straight - mind_n_V_turn);
	DF_MaiKunYunDongKongZhi_ZuoLunSuDu(mind_n_V_left, mind_n_V_right);
}
void DF_PuTongXunXian1() {
	if ((mind_n_x1==160)) {
		// 直行
		DF_MaiKunYunDongKongZhi_ZuoLunSuDu(60, 60);
	}
	if ((mind_n_x1<160)) {
		// 左转
		DF_MaiKunYunDongKongZhi_ZuoLunSuDu(35, 85);
	}
	if ((mind_n_x1>160)) {
		// 右转
		DF_MaiKunYunDongKongZhi_ZuoLunSuDu(85, 35);
	}
}
void DF_PIDCanShuChuShiHua() {
	mind_n_V_straight = 120;
	mind_n_offset = 160;
	mind_n_Kp = 0.55;
	mind_n_Ki = 0.00025;
	mind_n_Kd = 3.5;
	mind_n_error = 0;
	mind_n_lastError = 0;
	mind_n_integral = 0;
	mind_n_derivative = 0;
}
void DF_PuTongXunXian2() {
	if (((mind_n_x1>=150) && (mind_n_x1<=170))) {
		// 直行
		DF_MaiKunYunDongKongZhi_ZuoLunSuDu(70, 70);
	}
	if ((mind_n_x1<150)) {
		// 左转
		DF_MaiKunYunDongKongZhi_ZuoLunSuDu(40, 100);
	}
	if ((mind_n_x1>170)) {
		// 右转
		DF_MaiKunYunDongKongZhi_ZuoLunSuDu(100, 40);
	}
}
void DF_PDCanShuChuShiHua() {
	mind_n_V_straight = 120;
	mind_n_offset = 160;
	mind_n_Kp = 0.55;
	mind_n_Kd = 3.5;
	mind_n_error = 0;
	mind_n_lastError = 0;
	mind_n_derivative = 0;
}
void DF_PuTongXunXian3() {
	if (((mind_n_x1>=150) && (mind_n_x1<=170))) {
		// 直行
		DF_MaiKunYunDongKongZhi_ZuoLunSuDu(80, 80);
	}
	if (((mind_n_x1>=130) && (mind_n_x1<150))) {
		// 左小转
		DF_MaiKunYunDongKongZhi_ZuoLunSuDu(70, 90);
	}
	if (((mind_n_x1>=110) && (mind_n_x1<130))) {
		// 左中转
		DF_MaiKunYunDongKongZhi_ZuoLunSuDu(60, 100);
	}
	if ((mind_n_x1<110)) {
		// 左大转
		DF_MaiKunYunDongKongZhi_ZuoLunSuDu(40, 120);
	}
	if (((mind_n_x1>170) && (mind_n_x1<=190))) {
		// 右小转
		DF_MaiKunYunDongKongZhi_ZuoLunSuDu(90, 70);
	}
	if (((mind_n_x1>190) && (mind_n_x1<=210))) {
		// 右中转
		DF_MaiKunYunDongKongZhi_ZuoLunSuDu(100, 60);
	}
	if ((mind_n_x1>210)) {
		// 右大转
		DF_MaiKunYunDongKongZhi_ZuoLunSuDu(120, 40);
	}
}
void DF_PCanShuChuShiHua() {
	mind_n_V_straight = 120;
	mind_n_offset = 160;
	mind_n_Kp = 0.55;
	mind_n_error = 0;
}
void DF_PIDXunXian() {
	mind_n_error = (mind_n_x1 - mind_n_offset);
	mind_n_integral = (mind_n_integral + mind_n_error);
	mind_n_derivative = (mind_n_error - mind_n_lastError);
	mind_n_V_turn = (((mind_n_Kp * mind_n_error) + (mind_n_Ki * mind_n_integral)) + (mind_n_Kd * mind_n_derivative));
	mind_n_V_left = (mind_n_V_straight + mind_n_V_turn);
	mind_n_V_right = (mind_n_V_straight - mind_n_V_turn);
	mind_n_lastError = mind_n_error;
	DF_MaiKunYunDongKongZhi_ZuoLunSuDu(mind_n_V_left, mind_n_V_right);
}
void DF_PDXunXian() {
	mind_n_error = (mind_n_x1 - mind_n_offset);
	mind_n_derivative = (mind_n_error - mind_n_lastError);
	mind_n_V_turn = ((mind_n_Kp * mind_n_error) + (mind_n_Kd * mind_n_derivative));
	mind_n_V_left = (mind_n_V_straight + mind_n_V_turn);
	mind_n_V_right = (mind_n_V_straight - mind_n_V_turn);
	mind_n_lastError = mind_n_error;
	DF_MaiKunYunDongKongZhi_ZuoLunSuDu(mind_n_V_left, mind_n_V_right);
}

	                    				
步骤5 步骤5
最后来看看效果吧!

当然本文讲的是最基本的 PID 算法,这个算法在实际应用中还有很多可以进一步完善的地方。基于 PID 控制理论设计的新算法也很多,但是最基本的原理都是类似的。

最后用一张动图来总结一下本文讲的 PID 算法。从下图中,我们可以直观理解 PID 中三个参数 Kp、Ki、Kd 的作用。图中红色虚线为目标位置,蓝色实线为系统输出。


 - 当调节 Kp 参数时,可以让系统输出越来越接近目标位置,但是存在抖动、以及存在稳定误差调节力度不够的问题;

 - 调节 Ki 参数,可以弥补 Kp 参数调节力度不够的问题,但是也会增加抖动;

 - 调节 Kd 参数,会让抖动减小,变化曲线更加平滑。 

projectImage

# 补充思考# 

在本文中,我们利用哈士奇摄像头得到了黑线位置,这里我们只用了黑线的其中一个位置参数:起点坐标 x1。但是另外三个参数都没有用上(起点坐标 y1,终点坐标 x2、y2)。


 请你思考,是否将另外几个参数利用起来效果会更好呢?我们在巡线过程中,发现哈士奇屏幕中的黑线经常是斜着的,是否让黑线整体保持竖直,也就是让黑线与哈士奇屏幕的中轴线重合效果会更好呢?不仅去调节黑线与屏幕中间位置的偏差,还要去调节黑线的方向。

projectImage

 赶紧用本文讲的 PID 算法试试吧,你能挑战更快的速度么? 

点击链接可以查看相关文章:

我对『PID算法』的理解 —— 原理介绍:http://mc.dfrobot.com.cn/thread-14783-1-1.html

用于乐高机器人的PID控制器:https://bbs.cmnxt.com/thread-5688-1-1.html

撸狗初体验 | 手把手教你上手 HuskyLens 哈士奇人工智能摄像头:https://mc.dfrobot.com.cn/thread-299462-1-1.html

我的项目分享结束谢谢大家的收看!

喜欢我的文章可以在下方留言、点赞、和转发,谢谢!

projectImage
projectImage
Makelog作者原创文章,未经授权禁止转载。
0
1
评论
[[c.user_name]] [[c.create_time]]
[[c.parent_comment.count]]
|
[[c.comment_content]]