2024电赛H题可能用到的代码——自动行驶小车

news2024/11/28 16:31:18

目录

前言

一、MPU6050零漂处理

二、MPU6050的Yaw(±180)误差处理

三、PID算法(增量式+位置式)

四、灰度传感器(以8路为例)

1、获取黑线偏差

2、判断ABCD点(有无黑线交点)

五、总结



前言

        小编分享了2024电赛H题参考方案(+视频演示+核心控制代码)——自动行驶小车文章后,于是根据其中问题写了一些可能用到的参考代码,希望能帮助大家,有问题欢迎大家指出。


一、MPU6050零漂处理

        在进行角度、转向控制中,大多采用MPU6050来进行姿态检测,但由于MPU6050的特性,上电运行时三个角度(Pitch、roll、yaw)存在一定的零漂,尤其时yaw角,有时上电就漂了20多度。

        为此提出了一种解决方法就是:在进行MPU6050初始化之后,马上进行初始值确定,通过多次测量求平均值的算法求得新的yaw,后续就以这个值为yaw的初始值,然后再进行运动控制。此方法不一定有效,推荐尝试。

        参考代码如下:

int i = 0;
float pitch,roll,yaw;
float start_yaw[50];
float base_yaw = 0;
float process_data(float data[],uint8_t NUM_SAMPLES);
while ( mpu_dmp_init())
{
    delay_ms(20);
}//等待初始化完成
while(1)
{
    mpu_dmp_get_data(&pitch, &roll, &yaw);
    start_yaw[i++] = yaw;
    if(i == 50) //采样50次
    {
        base_yaw = process_data(start_yaw,50);
        break;
    }
    delay_ms(5);
}
float process_data(float data[],uint8_t NUM_SAMPLES) //均值滤波算法
{
    // 找到最大值和最小值的索引
    float max_index = 0;
    float min_index = 0;
    for (int i = 1; i < NUM_SAMPLES; i++) {
        if (data[i] > data[max_index]) {
            max_index = i;
        }
        if (data[i] < data[min_index]) {
            min_index = i;
        }
    }
    // 去除最大值和最小值
    float sum = 0;
    for (int i = 0; i < NUM_SAMPLES; i++) {
        if (i != max_index && i != min_index) {
            sum += data[i];
        }
    }
    // 计算剩余数据的平均值(除去最大值和最小值后剩余NUM_SAMPLES-2个)
    float average = sum / (NUM_SAMPLES - 2);
    return average;
}

二、MPU6050的Yaw(±180)误差处理

        用过MPU6050的朋友都知道,经过DMP处理得到的三个角度的范围(如下代码),他们并不是连续的,在控制转向环等时,需要进行特殊处理后才可得到准确的角度误差。

//得到dmp处理后的数据(注意,本函数需要比较多堆栈,局部变量有点多)
//pitch:俯仰角 精度:0.1°   范围:-90.0° <---> +90.0°
//roll:横滚角  精度:0.1°   范围:-180.0°<---> +180.0°
//yaw:航向角   精度:0.1°   范围:-180.0°<---> +180.0°
//返回值:0,正常
//    其他,失败
u8 mpu_dmp_get_data(float *pitch,float *roll,float *yaw);

         处理方案一:根据特定的角度进行加减360°,但是需要判断什么时候该减,什么时候该加,有点麻烦。比如,小车当前角度为150°,如果要转到180°,这个时候肯定需要有大于180的值,但他会变成负值,所以这是需要将得到的负角度加上360°。

#define limit_180_Z(n) ((n>0)?(n-360):n)
#define limit_180_F(n) ((n<0)?(n+360):n)

        处理方案二:通过算法处理,无论陀螺仪测得的数据为多少,直接将其转化为与目标角度的偏差,直接得到误差,加入闭环控制算法即可。

#define My_abs(n) (n>0?n:(-n))

//输入角度目标值,和当前读出yaw角度即可,自动算出最小偏差。
float Yaw_error(float Target, float Now)
 {
    float error;
    if (Target >= 0) 
	{
        if (Now <= 0) 
		{
            if (My_abs(Now) < (180 - Target)) 
			{
                error = My_abs(Now) + Target;
            } 
			else 
			{
                error = -(180 - Target) - (180 - My_abs(Now));
            }
        } 
		else 
		{
            if (Now > 0) 
			{
                error = Target - Now;
            }
        }
    } 
	else if (Target < 0)
	 {
        if (Now > 0) 
		{
            if (Now > Target + 180)
			{
                error = (180 - Now) + (180 - My_abs(Target));
            }
			 else if (Now < Target + 180) 
			{
                error = -(My_abs(Target) + Now);
            }
        } 
		else if (Now < 0) 
		{
            error = -(My_abs(Target) - My_abs(Now));
        }
    }    
     return error;
}

三、PID算法(增量式+位置式)

        但凡涉及到控制,一般选用PID控制算法来实现,其通过模拟PID离散化处理而来。在进行小车的速度环、转向环、巡线等控制中普遍使用。

        下面就以C语言来实现其控制代码:

/**
 * @brief      增量式 PID and 位置式 PID
 * 
 */
typedef enum
{
    POSITION_PID = 0,
    DELTA_PID    = 1,
}PID_mode;
#define XIAN_FU 7000               //积分限幅
#define LIMIT(x,min,max) (x)=(((x)<=(min))?(min):(((x)>=(max))?(max):(x)))  //限幅定义


int pid_control(PID_mode mode,float get_speed, float set_Target,float P,float I,float D)
{
	static int Integral,Last_error,LLast_Error;
    int Error,pid_out;      
    Error = set_Target - get_speed;      
  if (mode == POSITION_PID) // position PID
  {
    Integral +=  Error; 
    LIMIT(Integral,-XIAN_FU,XIAN_FU);//积分限幅
    pid_out = P*Error + I*Integral + D*(Error - Last_error);    
    Last_error = Error;   
  }
  else if (mode == DELTA_PID) // delta PID
  {
    pid_out += P* (Error - Last_error) + I * Error + D * (Error - 2*Last_error + LLast_Error);      
    Last_error = Error;
    LLast_Error = Last_error;     
  }
    return pid_out;
}

        如果这两种控制算法还不达标的话,可以对其进行控制算法改进:

1、积分分离;

2、变速积分;

3、微分先行;

4、。。。。。。 

四、灰度传感器(以8路为例)

1、获取黑线偏差

        在进行循迹或巡线的控制过程中,若我们需要采用闭环控制(PID控制),则需要获得黑线和小车中心线的偏差,然后以减小此偏差为目的去控制小车,从而实现稳定的循迹或巡线功能。而如果采取摄像头如(CCD、OpenMV等)获取次偏差的话,其获取的偏差数值相对灰度传感器而言,要连续得多,相同控制参数下,用摄像头要平稳得多,但是只要参数调得好,算法使用得精,用灰度传感器效果也是很不错得。

        用灰度传感器获取偏差,就需要我们自行处理数据,相当于对不同得情况进行人为赋值,以此来规定误差,类似于模糊控制。这里以8路灰度传感器为例,以其中间的4、5路为中心,即当4、5路同时识别到,而其他路没有识别到时,就认为其偏差为零。设向右偏为正的偏差,则向左偏为负偏差。当然,需要考虑黑线宽度,传感器各路间隔等因素,情况分得越细越好。

        以下代码只做参考(写得有点垃):

//以STM32为例,默认扫到黑线为高电平
#define Get_Value1 GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_7)
#define Get_Value2 GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_6)
#define Get_Value3 GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_5)
#define Get_Value4 GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_4)
#define Get_Value5 GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_3)
#define Get_Value6 GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_2)
#define Get_Value7 GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_1)
#define Get_Value8 GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_0)
int Get_Err(void)
{
    int err = 0;
    //中间
    if(!Get_Value1 && !Get_Value2 && !Get_Value3 && Get_Value4 && Get_Value5 && !Get_Value6 && !Get_Value7 && !Get_Value8) err = 0;
    //右边
    else if(!Get_Value1 && !Get_Value2 && !Get_Value3 && !Get_Value4 && Get_Value5 && !Get_Value6 && !Get_Value7 && !Get_Value8) err = 1;
    else if(!Get_Value1 && !Get_Value2 && !Get_Value3 && !Get_Value4 && Get_Value5 && Get_Value6 && !Get_Value7 && !Get_Value8) err = 2;
    else if(!Get_Value1 && !Get_Value2 && !Get_Value3 && !Get_Value4 && !Get_Value5 && Get_Value6 && !Get_Value7 && !Get_Value8) err = 3;
    else if(!Get_Value1 && !Get_Value2 && !Get_Value3 && !Get_Value4 && !Get_Value5 && Get_Value6 && Get_Value7 && !Get_Value8) err = 4;
    else if(!Get_Value1 && !Get_Value2 && !Get_Value3 && !Get_Value4 && !Get_Value5 && !Get_Value6 && Get_Value7 && !Get_Value8) err = 5;
    else if(!Get_Value1 && !Get_Value2 && !Get_Value3 && !Get_Value4 && !Get_Value5 && !Get_Value6 && Get_Value7 && Get_Value8) err = 6;
    else if(!Get_Value1 && !Get_Value2 && !Get_Value3 && !Get_Value4 && !Get_Value5 && !Get_Value6 && !Get_Value7 && Get_Value8) err = 7;
    //左边
    else if(!Get_Value1 && !Get_Value2 && !Get_Value3 && Get_Value4 && !Get_Value5 && !Get_Value6 && !Get_Value7 && !Get_Value8) err = -1;
    else if(!Get_Value1 && !Get_Value2 && Get_Value3 && Get_Value4 && !Get_Value5 && !Get_Value6 && !Get_Value7 && !Get_Value8) err = -2;
    else if(!Get_Value1 && !Get_Value2 && Get_Value3 && !Get_Value4 && !Get_Value5 && !Get_Value6 && !Get_Value7 && !Get_Value8) err = -3;
    else if(!Get_Value1 && Get_Value2 && Get_Value3 && !Get_Value4 && !Get_Value5 && !Get_Value6 && !Get_Value7 && !Get_Value8) err = -4;
    else if(!Get_Value1 && Get_Value2 && !Get_Value3 && !Get_Value4 && !Get_Value5 && !Get_Value6 && !Get_Value7 && !Get_Value8) err = -5;
    else if(Get_Value1 && Get_Value2 && !Get_Value3 && !Get_Value4 && !Get_Value5 && !Get_Value6 && !Get_Value7 && !Get_Value8) err = -6;
    else if(Get_Value1 && !Get_Value2 && !Get_Value3 && !Get_Value4 && !Get_Value5 && !Get_Value6 && !Get_Value7 && !Get_Value8) err = -7;  
   
    return err;  
}

2、判断ABCD点(有无黑线处)

        本次黑线宽度为1.5cm,其宽度较大,所以可以只用灰度传感器便可以判断是否到达该点。

        只要在一定时间内(不能只判断一次,与按键消抖差不多一个理),一次都没有检测到黑线,便可认为丢失黑线了,到了ABCD点处。

//N 自定
#define N  3
int i,j;//参数类型尽量大一些,防止溢出
uint8_t line_flag = 0;//判断是否在线上 0不在,1在
void get_ABCD(void) //每隔一定时间调用一次函数,进行判断是否在线上,需要结合N考虑
{
    if(!Get_Value1 && !Get_Value2 && !Get_Value3 && !Get_Value4 && !Get_Value5 && !Get_Value6 && !Get_Value7 && !Get_Value8)
    {
        j = 0;
        if(++i >= N)
        {
            line_flag = 0;
        }
    }
    else
    {
        i = 0;
        if(++j >= N)
        {
            line_flag = 1;
        }        
    }   
}

        根据以上代码,可以判断小车经过ABCD这样的点几次了,从而可以判断小车到达ABCD的具体点位。

uint8_t last_line_flag = 0;
uint8_t ABCD_count = 0

if(last_line_flag != line_flag ) ABCD_count++;
last_line_flag = line_flag;
//每换一题,ABCD_count需要清零


五、总结

        代码仅作参考,有误之处多担待。有些代码可能写得累赘多余,如果有更好的方法还请不吝赐教!!!

        控制参考方案请查看:2024电赛H题参考方案(+视频演示+核心控制代码)——自动行驶小车-CSDN博客文章浏览阅读5k次,点赞37次,收藏125次。此次电赛的H题属于控制类题目,相较于往年较为简单,功能也算单一,四个题目的时间要求都不是很高,容易得分,其中主要难点可能是TI芯片了,但是资源丰富,那也就不是问题了。控制的难点就在与ABCD四点之间的丝滑连接,如何让小车又快又稳的运行,最后比拼的就是时间了,可能也是比赛现场的重点评判标准,毕竟选择该题的人多。https://blog.csdn.net/qq_67319052/article/details/140763678

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1961508.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

内存原生CRAM技术将会颠覆计算存储的未来?

近期&#xff0c;一项刚刚发布的最新研究表明&#xff0c;一种名为计算随机存取存储器&#xff08;Computational Random-Access Memory, CRAM&#xff09;的新技术能够极大地减少人工智能&#xff08;AI&#xff09;处理所需的能量消耗。这项技术由明尼苏达大学双城分校的一组…

SmartInitializingSingleton和InitializingBean的区别

SmartInitializingSingleton&#xff1a;接口里面就一个方法afterSingletonsInstantiated&#xff0c;它是spring容器将所有bean都初始化完成之后&#xff0c;才会去调用&#xff0c;要求实现它接口的bean必须是单例的。 应用场景&#xff1a;可以在服务启动之后去处理一些逻辑…

红酒与电影:银幕上的醉人瞬间

在光影交织的银幕世界里&#xff0c;红酒不仅是品味生活的象征&#xff0c;更是情感交流的媒介。当定制红酒与电影相遇&#xff0c;它们共同编织出一个个醉人的瞬间&#xff0c;让观众在品味红酒的同时&#xff0c;也沉醉于电影的魅力之中。今天&#xff0c;就让我们一起走进红…

JS小应用:从图床获取的html代码中提取IMG标签并提取图片复制到剪贴板

JS小应用&#xff1a;从图床获取的html代码中提取IMG标签并提取图片复制到剪贴板 问题产生 自己做站长&#xff0c;为了节省银子&#xff0c;难免要用到图床。有的图床可以直接给你URL&#xff0c;这当然是最好的情况&#xff1a; 而有的图床&#xff0c;却禁用了鼠标右键&am…

“论数据分片技术及其应用”写作框架软考高级论文系统架构设计师论文

论文真题 数据分片就是按照一定的规则&#xff0c;将数据集划分成相互独立、正交的数据子集&#xff0c;然后将数据子集分布到不同的节点上。通过设计合理的数据分片规则&#xff0c;可将系统中的数据分布在不同的物理数据库中&#xff0c;达到提升应用系统数据处理速度的目的…

FP分数规划在无线通信中的应用(II)

3. 具体例子 3.1-3.3都只需要用第一章concave-convex方法求解&#xff0c;3.4-3.6需要用到第二章的拉格朗日对偶变换&#xff0c;而且具体解 x \mathbf{x} x时需要对离散变量单独开发算法。 3.1 多小区SISO能量分配 第一个例子是具有一组单天线基站&#xff08;BSs&#xff…

Python面向对象浅析

目录 面向对象基本概念 一、类和对象 类和对象是面向对象骗程的两个核心概念。 在程序开发中&#xff0c;要设计一个类&#xff0c;通常需要满足一下三个要素: self详解&#xff1a; 对象&#xff08;Object&#xff09; 魔法方法&#xff1a; 类里的一些特殊方法 __in…

RK3568笔记四十八:ADC驱动开发测试

若该文为原创文章&#xff0c;转载请注明原文出处。 一、ADC介绍 RK3568集成了一个逐次逼近模数转换器&#xff08;Successive Approximation ADC&#xff09;&#xff0c;通常简称为SAR ADC。 这种转换器能够将连续的模拟信号转换为离散的数字信号&#xff0c;其特点在于具有…

nginx转发netty长链接(nginx负载tcp长链接配置)

首先要清楚一点&#xff0c;netty是长链接是tcp连接不同于http中负载在http中配置server监听。长连接需要开启nginx的stream模块(和http是并列关系) 安装nginx时注意开启stream&#xff0c;编译时加上参数 --with-stream &#xff08;其他参数根据自己所需来加&#xff09; …

rem实现屏幕适配(jQuery)

一、rem换算 1.根据视口宽度动态计算字体大小&#xff0c;如果宽度大于750px&#xff0c;则将字体大小设置为100px&#xff0c;否则按比例缩小。 tips:使用时记得引入jQuery.js // 在文档加载完成后执行函数&#xff0c;确保DOM已经准备就绪$(function () {// 定义一个自执行…

增量学习中Task incremental、Domain incremental、Class incremental 三种学习模式的概念及代表性数据集?

1 概念 在持续学习领域&#xff0c;Task incremental、Domain incremental、Class incremental 是三种主要的学习模式&#xff0c;它们分别关注不同类型的任务序列和数据分布变化。 1.1 Task Incremental Learning (Task-incremental) 任务增量学习&#xff0c;也称为任务增…

盐分反演关键:批量计算常用的盐分指数反演变量

盐分反演关键&#xff1a;批量计算常用的盐分指数反演变量 一、引言 盐分指数反演是遥感应用中的一个重要方面&#xff0c;尤其在农业和环境监测中有着广泛的应用。通过遥感影像&#xff0c;研究人员可以高效地获取和分析地表盐分信息&#xff0c;为土地管理和作物生产提供重…

YOLOX+PyQt5交通路口智能监测平台设计与实现

1.概述 交通要道的路口上人车穿行&#xff0c;特别是上下班早高峰&#xff0c;且时常发生交通事故。因此对交通路口的车流量和人流量的监测必不可少。 2.检测模型 使用的检测模型为YOLOX模型&#xff0c;模型权重为训练VOC数据集得来&#xff0c;其中包括了二十个类别&#…

ONLYOFFICE 协作空间 2.6 已发布:表单填写房间、LDAP、优化房间和文件管理等

更新后的 ONLYOFFICE 协作空间带来了超过 20 项新功能和优化&#xff0c;让工作更加高效和舒适。阅读本文了解详情。 表单填写房间 这次更新增加了一种新的房间类型&#xff0c;可在 ONLYOFFICE 协作空间中组织简单的表单填写流程。 通过表单填写房间&#xff0c;目前可以完成…

仓库物品与装备物品位置更换

一、装备物品与选中的仓库物品位置交换 1、准备工作 2、Inventory Items 3、给Warehouse添加Grid Layout Group组件 4、复制Inventory Items&#xff0c;设置Grid Layout Group组件 5、创建文本ItemName和ItemDescription 6、设置物品数据 (1) 创建 ItemData.cs using Syst…

Spring boot tomcat 读写超时时间设置

yaml配置 connection-timeout: 20000 server:port: 9898servlet:context-path: /testtomcat:connection-timeout: 20000max-connections: 250accept-count: 300 spring源码设置自定义tomcat参数 customizeConnector(connector); Overridepublic WebServer getWebServer(Serv…

【MySQL】表的约束{ 常见约束 空属性 默认值 列描述comment zerofill 主键 复合主键 自增长 唯一键 外键 }

文章目录 常见约束空属性默认值列描述commentzerofill主键复合主键自增长唯一键外键 2.总结 真正约束字段的是数据类型&#xff0c;但是数据类型约束很单一&#xff0c;需要有一些额外的约束&#xff0c;更好的保证数据的合法性&#xff0c;从业务逻辑角度保证数据的正确性。比…

MySQL基础练习题12-使用唯一标识码替换员工ID

题目&#xff1a;展示每位用户的 唯一标识码&#xff08;unique ID &#xff09;&#xff1b;如果某位员工没有唯一标识码&#xff0c;使用 null 填充即可。 准备数据 分析数据 题目&#xff1a;展示每位用户的 唯一标识码&#xff08;unique ID &#xff09;&#xff1b;如果…

一, 创建工程,引入依赖

一&#xff0c; 创建工程&#xff0c;引入依赖 文章目录 一&#xff0c; 创建工程&#xff0c;引入依赖创建工程工程间的关系的建立配置各个工程当中的 pow 配置信息&#xff0c;相关的依赖父工程(也就是总项目工程)的 pow 配置demo-module06-generate 模块中pow 配置&#xff…

基于IEC61499标准的在线工业编程平台open61499

基于IEC61499标准的在线工业编程平台open61499是一个专为工业自动化领域设计的编程环境&#xff0c;它遵循IEC 61499标准&#xff0c;为开发者提供了一种高效、灵活的方式来创建、配置和管理分布式控制系统&#xff08;DCS&#xff09;的应用程序。以下是对open61499的详细解析…