0 前言
🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。
为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天要分享的是
🚩 毕业设计 STM32的轮足两用可变形环境感知探测机器人
🥇学长这里给一个题目综合评分(每项满分5分)
- 难度系数:3分
- 工作量:3分
- 创新点:4分
🧿 选题指导, 项目分享:
1 简介
基于STM32的轮足两用可变形环境感知探测机器人。该机器人具有轮式滚动、多足爬行两种形态,能够适应各种复杂地形的同时,具有较强的移动灵活性,可用于井矿、地穴、消防等危险领域的环境感知探测工作。
2 主要器件
- STM32F405主控芯片
- ZMOD4410气体传感器
- 无线图传模块
- 安卓手机APP
- 电机驱动模块
- 摄像头模块
- 霍尔传感器
- LED模块
- 蜂鸣器模块
- 蓝牙模块
- SD模块
3 实现效果
机器人具有轮式滚动、多足爬行两种形态,适应各种复杂地形的同时,具有较强的移动灵活性
可用于井矿、地穴、消防等危险领域的环境感知探测工作
4 设计原理
4.1 硬件设计
机器人硬件系统由机器人控制器、ZMOD4410 HiCom 模块、无线图传模块、电机驱动模块四个部分组成。
机器人控制器
机器人控制器由 PMW 模块、OLED 模块、LED 模块、蜂鸣器模块、蓝牙模块、SD 模块、MCU 模块共七个模块组成。
硬件原理框图
MCU 模块
本次设计选用 ST 公司的 STM32F405RET6 单片机作为机器人系统的控制单元。该控制器以 ARM Cortex-M4 为内核,CPU 主频为 168MHz,内存容量为 512KB,具有多个定时器、USART 接口、IIC 接口、SPI 接口、ADC 通道、DAC 通道、DMA 通道等外设资源。此外,该单片机具有的 FPU浮点型数据计算单元能够精确快速求解机器人步态行走时所需的运动数据,完全能够满足本文设计的需要。该芯片最小系统电路原理图如图所示。
PWM 模块
设计的机器人需 19 路 PWM 信号控制伺服电机的转角,同时需两路 PWM 信号控制两个直流无刷电机的转速和转向,故本文设计的机器人系统至少需要 21 路 PWM 脉冲信号。本文选用 NXP 公司的 PCA9685 芯片设计 PWM 模块,该芯片通过 IIC 通信,单颗芯片可同时产生 16 路频率相同的 PWM 脉冲信号。本文选用两颗 PCA9685 芯片产生 32 路PWM 信号。电路原理图如图所示。
蓝牙模块
蓝牙通信模块用于机器人系统向手机 APP 客户端发送机器人当前状态的数据,方便系统整机调试和人机交互。本文选用信驰达的 RF-BM-S02I 4.0BLE 作为机器人的蓝牙通信模块。该模块可外接增益天线,通信距离较远,可通过 UART 通信接口与 MCU 通信。模块实物图片和安卓 APP 上位机截图如图所示。
气体传感器模块
本文选用 ZMOD4410 HiCom 模块作为机器人的气体传感器模块,模块实物图片如图所示。
ZMOD4410 传感器的组成如图所示。
通过 IDT 关于 TVOC、eCO2 和 CO2的数据统计可知,如图 2.9 所示,三者之间存在极强的线性关系。
故可直接通过 TVOC 的数据计算出 eCO2的数据,进而估计出实际空气中 CO2的浓度大小。根据 IDT 官方提供的算法库文件,可直接通过调用 API 的方式计算出 TVOC、IAQ、eCO2 三个参数的大小,能够监控气体浓度是否在短时间内发生突变,极大地简化了气体浓度检测的硬件设计和软件设计,同时具有极强的稳定性和准确性。本文通过连接 HiCom 的 IIC 接口与 MCU 通信,未使用 USB 功能。
无线图传模块
为了保证机器人的远程无线图像传输,本文选用 FPV 摄像头、TS5828 图传发射机模块和RC832 图传接收机模块作为本文设计的机器人的无线图像传输模块。
4.2 软件设计
系统软件流程图
系统上电后,MCU 首先完成外设的初始化,其次开始初始化各个硬件模块,具体 LED 模块、蓝牙模块、气体传感器模块、蜂鸣器模块、PWM 模块、直流电机初始化、运动形态的初始化。之后进入系统的循环主流程。机器人系统首将先检测电池当前的电量,若电池电量较低,系统将停止运行,并通过蜂
鸣器播放充电提示音;若电池电量充足,系统开始接收遥控器的控制信号。若系统收到气体轮足两用可
测量控制指令,系统将开启 ZMOD4410 的气体检测功能,否则将停止气体检测功能。若系统收到形态切换指令,机器人将进行形态切换(系统默认的机器人形态为轮式滚动形态),否则系统将保持当前的运动形态。
气体检测软件流程图
气体检测的软件流程图如左图所示,当系统收到气体测量控制指令时,MCU 将首先通过 IIC 总线读取 ZMOD4410 MOX 电阻的数据,其次运行 IDT 的算法库依次读取 TVOC、IAQ、eCO2、ODOR state 的数据。若此时气体浓度超标(通过 eCO2 或 IAQ 等级与设定阈值进行比较),系统将发出报警信号;若气体浓度在极端的时间内发生突变,此时 ODOR state将置位,此时系统也将发出报警信号。气体浓度数据读取的软件代码如右图所示。
运动算法 D-H 算法
简介
仿生六足机器人的运动数学建模采用的是 Denavit 和 Hartenberg 提出来的标准方法,称为 D‐H 模型,D‐H 建模方法适用于任何复杂的机器人建模。通常机器人都是有旋转关节、滑动关节等组成的,而连杆的长度则是根据需求来制定的即是长度是可以任意的。在构建机器人的数学模型时,首先要做的就是固连一个参考的坐标系,然后就是选择昀简便的变换顺序,把坐标从第一个的关节变换到昀后的关节。若一个机器人的结构是由很多个的关节与连杆组成,且依次连接的三个关节能在坐标系中通过变换互相转换;可将第一个关节为关节 n,依次类推为关节 n+1、关节 n+2,同时称在n 与 n+1 之间的关节为连杆 n,依照顺序为连杆 n+1、连杆 n+2。如图所示。
5 部分核心代码
//RocRobotControl.c
/*********************************************************************************
* Description:
* Input cmd to let robot standing
*
* Parameter:
* None
*
* Return:
* None
*
* Author:
* ROC LiRen(2019.07.23)
**********************************************************************************/
static void RocRobotHexapodStanding(void)
{
g_RobotCtrl.RemoteCtrl.X = 0;
g_RobotCtrl.RemoteCtrl.Y = 0;
g_RobotCtrl.RemoteCtrl.Z = 0;
g_RobotCtrl.RemoteCtrl.A = 0;
g_RobotCtrl.RemoteCtrl.H = 0;
RocRobotMoveStatus_Set(ROC_ROBOT_MOVE_STATUS_STANDING);
if(ROC_FALSE == RocRobotCtrlFlagGet(0))
{
RocRobotCtrlFlagSet(0);
}
}
/*********************************************************************************
* Description:
* Input cmd to let robot forward
*
* Parameter:
* None
*
* Return:
* None
*
* Author:
* ROC LiRen(2019.07.23)
**********************************************************************************/
static void RocRobotHexapodForwardRun(void)
{
g_RobotCtrl.RemoteCtrl.X = 0;
g_RobotCtrl.RemoteCtrl.Y = ROC_ROBOT_DEFAULT_LEG_STEP;
g_RobotCtrl.RemoteCtrl.Z = 0;
g_RobotCtrl.RemoteCtrl.A = 0;
g_RobotCtrl.RemoteCtrl.H = ROC_ROBOT_DEFAULT_FEET_LIFT;
RocRobotMoveStatus_Set(ROC_ROBOT_MOVE_STATUS_FORWALKING);
if(ROC_FALSE == RocRobotCtrlFlagGet(1))
{
RocRobotCtrlFlagSet(1);
g_RobotCtrl.MoveCtrl->CurState.RefImuAngle = g_RobotCtrl.MoveCtrl->CurState.CurImuAngle;
/* Used for robot bady balance control */
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.X = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Pitch;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.Y = g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Roll;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.Z = g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Yaw;
}
}
/*********************************************************************************
* Description:
* Input cmd to let robot backward
*
* Parameter:
* None
*
* Return:
* None
*
* Author:
* ROC LiRen(2019.07.23)
**********************************************************************************/
static void RocRobotHexapodBackwardRun(void)
{
g_RobotCtrl.RemoteCtrl.X = 0;
g_RobotCtrl.RemoteCtrl.Y = -ROC_ROBOT_DEFAULT_LEG_STEP;
g_RobotCtrl.RemoteCtrl.Z = 0;
g_RobotCtrl.RemoteCtrl.A = 0;
g_RobotCtrl.RemoteCtrl.H = ROC_ROBOT_DEFAULT_FEET_LIFT;
RocRobotMoveStatus_Set(ROC_ROBOT_MOVE_STATUS_BAKWALKING);
if(ROC_FALSE == RocRobotCtrlFlagGet(2))
{
RocRobotCtrlFlagSet(2);
g_RobotCtrl.MoveCtrl->CurState.RefImuAngle = g_RobotCtrl.MoveCtrl->CurState.CurImuAngle;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.X = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Pitch;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.Y = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Roll;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.Z = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Yaw;
}
}
/*********************************************************************************
* Description:
* Input cmd to let robot left moving
*
* Parameter:
* None
*
* Return:
* None
*
* Author:
* ROC LiRen(2019.07.23)
**********************************************************************************/
static void RocRobotHexapodLeftMovingRun(void)
{
g_RobotCtrl.RemoteCtrl.X = -ROC_ROBOT_DEFAULT_LEG_STEP;
g_RobotCtrl.RemoteCtrl.Y = 0;
g_RobotCtrl.RemoteCtrl.Z = 0;
g_RobotCtrl.RemoteCtrl.A = 0;
g_RobotCtrl.RemoteCtrl.H = ROC_ROBOT_DEFAULT_FEET_LIFT;
RocRobotMoveStatus_Set(ROC_ROBOT_MOVE_STATUS_BAKWALKING);
if(ROC_FALSE == RocRobotCtrlFlagGet(7))
{
RocRobotCtrlFlagSet(7);
g_RobotCtrl.MoveCtrl->CurState.RefImuAngle = g_RobotCtrl.MoveCtrl->CurState.CurImuAngle;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.X = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Pitch;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.Y = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Roll;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.Z = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Yaw;
}
}
/*********************************************************************************
* Description:
* Input cmd to let robot right moving
*
* Parameter:
* None
*
* Return:
* None
*
* Author:
* ROC LiRen(2019.07.23)
**********************************************************************************/
static void RocRobotHexapodRightMovingRun(void)
{
g_RobotCtrl.RemoteCtrl.X = ROC_ROBOT_DEFAULT_LEG_STEP;
g_RobotCtrl.RemoteCtrl.Y = 0;
g_RobotCtrl.RemoteCtrl.Z = 0;
g_RobotCtrl.RemoteCtrl.A = 0;
g_RobotCtrl.RemoteCtrl.H = ROC_ROBOT_DEFAULT_FEET_LIFT;
RocRobotMoveStatus_Set(ROC_ROBOT_MOVE_STATUS_BAKWALKING);
if(ROC_FALSE == RocRobotCtrlFlagGet(8))
{
RocRobotCtrlFlagSet(8);
g_RobotCtrl.MoveCtrl->CurState.RefImuAngle = g_RobotCtrl.MoveCtrl->CurState.CurImuAngle;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.X = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Pitch;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.Y = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Roll;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.Z = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Yaw;
}
}
/*********************************************************************************
* Description:
* Input cmd to let robot left forward
*
* Parameter:
* None
*
* Return:
* None
*
* Author:
* ROC LiRen(2019.07.23)
**********************************************************************************/
static void RocRobotHexapodLeftForwardRun(void)
{
g_RobotCtrl.RemoteCtrl.X = -ROC_ROBOT_DEFAULT_LEG_STEP * 0.5;
g_RobotCtrl.RemoteCtrl.Y = ROC_ROBOT_DEFAULT_LEG_STEP * 0.5;
g_RobotCtrl.RemoteCtrl.Z = 0;
g_RobotCtrl.RemoteCtrl.A = 0;
g_RobotCtrl.RemoteCtrl.H = ROC_ROBOT_DEFAULT_FEET_LIFT;
RocRobotMoveStatus_Set(ROC_ROBOT_MOVE_STATUS_FORWALKING);
if(ROC_FALSE == RocRobotCtrlFlagGet(5))
{
RocRobotCtrlFlagSet(5);
g_RobotCtrl.MoveCtrl->CurState.RefImuAngle = g_RobotCtrl.MoveCtrl->CurState.CurImuAngle;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.X = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Pitch;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.Y = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Roll;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.Z = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Yaw;
}
}
/*********************************************************************************
* Description:
* Input cmd to let robot left backward
*
* Parameter:
* None
*
* Return:
* None
*
* Author:
* ROC LiRen(2019.07.23)
**********************************************************************************/
static void RocRobotHexapodLeftBackwardRun(void)
{
g_RobotCtrl.RemoteCtrl.X = ROC_ROBOT_DEFAULT_LEG_STEP * 0.5;
g_RobotCtrl.RemoteCtrl.Y = -ROC_ROBOT_DEFAULT_LEG_STEP * 0.5;
g_RobotCtrl.RemoteCtrl.Z = 0;
g_RobotCtrl.RemoteCtrl.A = 0;
g_RobotCtrl.RemoteCtrl.H = ROC_ROBOT_DEFAULT_FEET_LIFT;
RocRobotMoveStatus_Set(ROC_ROBOT_MOVE_STATUS_BAKWALKING);
if(ROC_FALSE == RocRobotCtrlFlagGet(7))
{
RocRobotCtrlFlagSet(7);
g_RobotCtrl.MoveCtrl->CurState.RefImuAngle = g_RobotCtrl.MoveCtrl->CurState.CurImuAngle;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.X = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Pitch;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.Y = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Roll;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.Z = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Yaw;
}
}
/*********************************************************************************
* Description:
* Input cmd to let robot right forward
*
* Parameter:
* None
*
* Return:
* None
*
* Author:
* ROC LiRen(2019.07.23)
**********************************************************************************/
static void RocRobotHexapodRightForwardRun(void)
{
g_RobotCtrl.RemoteCtrl.X = ROC_ROBOT_DEFAULT_LEG_STEP * 0.5;
g_RobotCtrl.RemoteCtrl.Y = ROC_ROBOT_DEFAULT_LEG_STEP * 0.5;
g_RobotCtrl.RemoteCtrl.Z = 0;
g_RobotCtrl.RemoteCtrl.A = 0;
g_RobotCtrl.RemoteCtrl.H = ROC_ROBOT_DEFAULT_FEET_LIFT;
RocRobotMoveStatus_Set(ROC_ROBOT_MOVE_STATUS_FORWALKING);
if(ROC_FALSE == RocRobotCtrlFlagGet(6))
{
RocRobotCtrlFlagSet(6);
g_RobotCtrl.MoveCtrl->CurState.RefImuAngle = g_RobotCtrl.MoveCtrl->CurState.CurImuAngle;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.X = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Pitch;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.Y = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Roll;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.Z = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Yaw;
}
}
/*********************************************************************************
* Description:
* Input cmd to let robot right backward
*
* Parameter:
* None
*
* Return:
* None
*
* Author:
* ROC LiRen(2019.07.23)
**********************************************************************************/
static void RocRobotHexapodRightBackwardRun(void)
{
g_RobotCtrl.RemoteCtrl.X = -ROC_ROBOT_DEFAULT_LEG_STEP * 0.5;
g_RobotCtrl.RemoteCtrl.Y = -ROC_ROBOT_DEFAULT_LEG_STEP * 0.5;
g_RobotCtrl.RemoteCtrl.Z = 0;
g_RobotCtrl.RemoteCtrl.A = 0;
g_RobotCtrl.RemoteCtrl.H = ROC_ROBOT_DEFAULT_FEET_LIFT;
RocRobotMoveStatus_Set(ROC_ROBOT_MOVE_STATUS_BAKWALKING);
if(ROC_FALSE == RocRobotCtrlFlagGet(8))
{
RocRobotCtrlFlagSet(8);
g_RobotCtrl.MoveCtrl->CurState.RefImuAngle = g_RobotCtrl.MoveCtrl->CurState.CurImuAngle;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.X = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Pitch;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.Y = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Roll;
//g_RobotCtrl.MoveCtrl->CurState.BodyRot.Z = -g_RobotCtrl.MoveCtrl->CurState.CurImuAngle.Yaw;
}
}