0 前言
🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。
为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天要分享的是
🚩 毕业设计 基于单片机的双足机器人
🥇学长这里给一个题目综合评分(每项满分5分)
- 难度系数:3分
- 工作量:3分
- 创新点:4分
🧿 选题指导, 项目分享:
1 简介
相信变形金刚、钢铁侠是很多少年时候不可或缺的梦,都希望有一台属于自己的“大黄蜂”。虽然现在离能达到与电影中一样的机器人这个梦还很遥远,但机器人的制造、应用也必将在未来由人类所掌握。机器人学集成了力学、机械工程学、电子学、计算机等等很多前言学科。说实话我也不懂,不懂这些高深的理论是不是就与机器人无缘了呢。并不是! 我觉得机器人应该具备的第一功能应该是步行(好像日本一个机器人专家也说过),但是真正的做一个很强大的机器人,所花费的成本远超普通人业余爱好的承受。本项目就是从 低成本、零基础制作一个可以行走的双足机器人。由于步行是基础,那我们就先完成步态的行走就行。只有完成了初步行走功能,建立了对于机器人的初步认识,才能明白自己的机器人之路后续往什么方向发展。 废话不多说。
2 主要器件
- 中科蓝讯的AB32VG1单片机
- RT-Thread物联网操作系统
- 各关节舵机
- PCA9685模块
- 与手机上位机通信
3 实现效果
4 硬件设计
总体框架
AB32VG1主控MCU
简介
开发板采用中科蓝讯的32位RISC-V指令集的AB32VG1型号MCU,主频120M。MCU有8M的Flash,和192K SRAM。支持3.0V-5.0V供电。
与一般MCU不同的是,这款MCU具有MPU模块,就是电源管理模块,支持Charge电路、BUCK电路、LDO电路等等,手册第十页给出了MPU模块的详细参数。
开发环境搭建
根据官方的指导,使用的是RT-thread官方stduio平台,先更新软件源代码至最新版,下载中科蓝讯软件包,下载RISC-V-GCC工具链,编译程序会用到。
软件包配置
接下来选择我们本次实验用到的软件包,wavplayer软件包、optparse软件包和multibutton软件包,实现通过板载按键控制声音的播放语音量的增减。
然后对软件包进行简单配置,按键的示例代码可以勾选也可以不勾选,后面要对此进行修改,改为评测板上的用户按键,optparse软件包默认即可。
PCA9685PWM模块
简介
PCA9685是一个基于IIC通信的16路PWM输出模块,可以在单片机资源不足的情况下进行扩展使用。
在使用PCA9685的时候需要注意以下几点:
1.PCA9685的分辨率是12位,即占空比控制时,0-4096对应的占空比为0-100,在控制舵机的时候,控制信号是0.5ms-2.5ms,周期20ms,所以控制舵机角度不会有太高的分辨率,对舵机控制精度较高的地方不建议使用。
2.PCA9685地址位和很多描述的不一样,根据芯片手册,地址位的寄存器一共8位,其中最高位固定是1,A0-A5这六位是用户可更改的,而其中最关键的一位是R/W位,这一位主要是决定了读还是写,置1时为读,置0时为写,所以我们在写程序的时候,PCA9685的地址应把R/W位加上,是0x80,而不是0x40,在写的时候,发送地址位是0x80,在读的时候,发送的地址位是0x81。
硬件连接
Arduino和PCA9685主要以IIC方式连接,接线顺序如下:
Arduino PCA9685
5V —–> VCC
SDA —–> SDA
SCL —–> SCL
GND —–> GND
根据模块的电路原理图,可以看到模块上芯片的供电VCC和舵机驱动引脚的供电5V是分开的,我们开发板的5V功率较小,无法带动多个舵机,我们可以通过5V接口外接供电电路。在试验的时候为了方便接线,我就直接把VCC和5V引脚用接线帽短接了。
Arduino本身自带IIC接口,但不同的板子接口不一样,Arduino UNO的是A4和A5两个引脚,不过一般板子上都会明确标出来。
5 软件说明
RT-Thread物联网操作系统
RT-Thread 概述
RT-Thread,全称是 Real Time-Thread,顾名思义,它是一个嵌入式实时多线程操作系统,基本属性之一是支持多任务,允许多个任务同时运行并不意味着处理器在同一时刻真地执行了多个任务。事实上,一个处理器核心在某一时刻只能运行一个任务,由于每次对一个任务的执行时间很短、任务与任务之间通过任务调度器进行非常快速地切换(调度器根据优先级决定此刻该执行的任务),给人造成多个任务在一个时刻同时运行的错觉。在 RT-Thread 系统中,任务通过线程实现的,RT-Thread 中的线程调度器也就是以上提到的任务调度器。
RT-Thread 主要采用 C 语言编写,浅显易懂,方便移植。它把面向对象的设计方法应用到实时系统设计中,使得代码风格优雅、架构清晰、系统模块化并且可裁剪性非常好。针对资源受限的微控制器(MCU)系统,可通过方便易用的工具,裁剪出仅需要 3KB Flash、1.2KB RAM 内存资源的 NANO 版本(NANO 是 RT-Thread 官方于 2017 年 7 月份发布的一个极简版内核);而对于资源丰富的物联网设备,RT-Thread 又能使用在线的软件包管理工具,配合系统配置工具实现直观快速的模块化裁剪,无缝地导入丰富的软件功能包,实现类似 Android 的图形界面及触摸滑动效果、智能语音交互效果等复杂功能。
相较于 Linux 操作系统,RT-Thread 体积小,成本低,功耗低、启动快速,除此以外 RT-Thread 还具有实时性高、占用资源小等特点,非常适用于各种资源受限(如成本、功耗限制等)的场合。虽然 32 位 MCU 是它的主要运行平台,实际上很多带有 MMU、基于 ARM9、ARM11 甚至 Cortex-A 系列级别 CPU 的应用处理器在特定应用场合也适合使用 RT-Thread。
RT-Thread 的架构
具体包括以下部分:
- 内核层:RT-Thread 内核,是 RT-Thread 的核心部分,包括了内核系统中对象的实现,例如多线程及其调度、信号量、邮箱、消息队列、内存管理、定时器等;libcpu/BSP(芯片移植相关文件 / 板级支持包)与硬件密切相关,由外设驱动和 CPU 移植构成。
- 组件与服务层:组件是基于 RT-Thread 内核之上的上层软件,例如虚拟文件系统、FinSH 命令行界面、网络框架、设备框架等。采用模块化设计,做到组件内部高内聚,组件之间低耦合。
- RT-Thread 软件包:运行于 RT-Thread 物联网操作系统平台上,面向不同应用领域的通用软件组件,由描述信息、源代码或库文件组成。RT-Thread 提供了开放的软件包平台,这里存放了官方提供或开发者提供的软件包,该平台为开发者提供了众多可重用软件包的选择,这也是 RT-Thread 生态的重要组成部分。软件包生态对于一个操作系统的选择至关重要,因为这些软件包具有很强的可重用性,模块化程度很高,极大的方便应用开发者在最短时间内,打造出自己想要的系统。RT-Thread 已经支持的软件包数量已经达到 400+,如下举例:
- 物联网相关的软件包:Paho MQTT、WebClient、mongoose、WebTerminal 等等。
- 脚本语言相关的软件包:目前支持 Lua、JerryScript、MicroPython、PikaScript。
- 多媒体相关的软件包:Openmv、mupdf。
- 工具类软件包:CmBacktrace、EasyFlash、EasyLogger、SystemView。
- 系统相关的软件包:RTGUI、Persimmon UI、lwext4、partition、SQLite 等等。
- 外设库与驱动类软件包:RealTek RTL8710BN SDK。
- 其他。
功能函数介绍
1、是红外接收处理线程。接收调试、动作的命令,发送命令到运行控制线程。
2、是舵机运动控制线程,根据命令进行运动控制。
其他新建的函数主要是进行步态控制。下面简单的描述一下的函数功能;
void robot_left_tilt(rt_uint8_t left_angle,rt_uint8_t range,rt_uint16_t speed)
//功能:向左倾斜
//形参:left_angle倾斜的角度(本项目中简化成了PWM的高电平)
//形参:range舵机单次转动的角度(换算后)
//形参:speed是单次转动后的稳定时间
void robot_left_tilt_attention(rt_uint8_t range,rt_uint16_t speed)
//功能:左倾斜恢复直立
//形参:range舵机单次转动的角度(换算后)
//形参:speed是单次转动后的稳定时间
void robot_right_tilt(rt_uint8_t right_angle,rt_uint8_t range,rt_uint16_t speed)
//功能:向右倾斜
void robot_right_tilt_attention(rt_uint8_t range,rt_uint16_t speed)
//功能:右倾斜恢复直立
void robot_right_forward(rt_uint8_t forward_angle,rt_uint8_t range,rt_uint16_t speed)
//功能:右脚向前一步
void robot_right_forward_attention(rt_uint8_t range,rt_uint16_t speed)
//功能:右脚向前一步后恢复直立
void robot_left_forward(rt_uint8_t forward_angle,rt_uint8_t range,rt_uint16_t speed)
//功能:左脚向前一步
void robot_left_forward_attention(rt_uint8_t range,rt_uint16_t speed)
//功能:左脚向前一步后恢复直立
void go_right_step(rt_uint8_t angle,rt_uint8_t range,rt_uint16_t speed)
//功能:向右脚迈一步
void go_left_step(rt_uint8_t angle,rt_uint8_t range,rt_uint16_t speed)
//功能:向左脚迈一步
void go_left(rt_uint8_t angle,rt_uint8_t range,rt_uint16_t speed)
//功能:向左转
void go_right(rt_uint8_t angle,rt_uint8_t range,rt_uint16_t speed)
//功能:向右转
部分代码
void set_robot_left(rt_uint16_t left_up,rt_uint16_t left_mid,rt_uint16_t left_down)
{
left_up_num=constrain_num(left_up,left_up_max_num,left_up_mini_num);
pca9685_set_pwm(Servo_dev1, 13, 0, left_up_num);// 左上
left_mid_num=constrain_num(left_mid,left_mid_max_num,left_mid_mini_num);
pca9685_set_pwm(Servo_dev1, 14, 0, left_mid_num);// 左中
left_down_num=constrain_num(left_down,left_down_max_num,left_down_mini_num);
pca9685_set_pwm(Servo_dev1, 15, 0, left_down_num);// 左下
}
void set_robot_right(rt_uint16_t right_up,rt_uint16_t right_mid,rt_uint16_t right_down)
{
right_down_num=constrain_num(right_down,right_down_max_num,right_down_mini_num);
pca9685_set_pwm(Servo_dev1, 0, 0, right_down_num);// 右下
right_mid_num=constrain_num(right_mid,right_mid_max_num,right_mid_mini_num);
pca9685_set_pwm(Servo_dev1, 1, 0, right_mid_num);// 右中
right_up_num=constrain_num(right_up,right_up_max_num,right_up_mini_num);
pca9685_set_pwm(Servo_dev1, 2, 0, right_up_num);// 右上
/* */
}/* /* * left_angle 左倾角度 * range 为单次角度的 * speed 为两个幅度之间的时间 单位ms * 右脚刚刚离地的left_angle 值为35 */
void robot_left_tilt(rt_uint8_t left_angle,rt_uint8_t range,rt_uint16_t speed)
{
rt_uint8_t multiple=2; //左脚和右脚的角度倍数
rt_uint8_t now_angle=0;
//双脚左倾斜
while(now_angle!=left_angle)
{
if(now_angle<(left_angle-range)){
now_angle=now_angle+range;}
else{
range=left_angle-now_angle;now_angle=left_angle;}
left_down_num = left_down_num + range;right_down_num = right_down_num - (range * multiple);
set_robot_left(left_up_num,left_mid_num,left_down_num);
set_robot_right(right_up_num,right_mid_num,right_down_num);
rt_thread_mdelay(speed);
}
}
void robot_left_tilt_attention(rt_uint8_t range,rt_uint16_t speed)
{
rt_uint8_t multiple=2; //左脚和右脚的角度倍数
rt_uint8_t now_angle=left_down_num-left_down_int_num;
rt_uint8_t left_angle=0;
//双脚恢复直立
while(now_angle)
{
if(now_angle>range){
now_angle=now_angle-range;left_down_num = left_down_num - range;right_down_num = right_down_num + (range * multiple);}
else{
now_angle=0;left_down_num=left_down_int_num;right_down_num=right_down_int_num;}
set_robot_left(left_up_num,left_mid_num,left_down_num);
set_robot_right(right_up_num,right_mid_num,right_down_num);
rt_thread_mdelay(speed);
}
}
/* * right_angle 右倾角度 * range 为单次角度的 * speed 为两个幅度之间的时间 单位ms * 左脚刚刚离地的right_angle 值为 */
void robot_right_tilt(rt_uint8_t right_angle,rt_uint8_t range,rt_uint16_t speed)
{
rt_uint8_t multiple=2; //左脚和右脚的角度倍数
rt_uint8_t now_angle=0;
//双脚右倾斜
while(now_angle!=right_angle)
{
if(now_angle<(right_angle-range)){
now_angle=now_angle+range;}
else{
range=right_angle-now_angle;now_angle=right_angle;}
right_down_num = right_down_num + range;left_down_num = left_down_num - (range * multiple);
set_robot_left(left_up_num,left_mid_num,left_down_num);
set_robot_right(right_up_num,right_mid_num,right_down_num);
rt_thread_mdelay(speed);
}
}
void robot_right_tilt_attention(rt_uint8_t range,rt_uint16_t speed)
{
rt_uint8_t multiple=2; //左脚和右脚的角度倍数
rt_uint8_t now_angle=right_down_num-right_down_int_num;
// rt_kprintf("now_angle =%d\r\n",now_angle);
rt_uint8_t right_angle=0;
//双脚恢复直立
//以下存在倍数超过中间值得bug
while(now_angle)
{
if(now_angle>range){
now_angle=now_angle-range;right_down_num = right_down_num - range;left_down_num = left_down_num + (range * multiple);}
else{
now_angle=0;range=0;left_down_num=left_down_int_num;right_down_num=right_down_int_num;}
set_robot_left(left_up_num,left_mid_num,left_down_num);
set_robot_right(right_up_num,right_mid_num,right_down_num);
rt_thread_mdelay(speed);
}
}
void robot_right_forward(rt_uint8_t forward_angle,rt_uint8_t range,rt_uint16_t speed)
{
while(forward_angle)
{
if(forward_angle>range){
forward_angle=forward_angle-range;
left_mid_num=left_mid_num-range;
left_up_num=left_up_num-range;
right_mid_num=right_mid_num-range;
right_up_num=right_up_num-range;
}
else{
range=forward_angle;
forward_angle=0;
left_mid_num=left_mid_num-range;
left_up_num=left_up_num-range;
right_mid_num=right_mid_num-range;
right_up_num=right_up_num-range;
}
set_robot_left(left_up_num,left_mid_num,left_down_num);
set_robot_right(right_up_num,right_mid_num,right_down_num);
rt_thread_mdelay(speed);
}
}
void robot_right_forward_attention(rt_uint8_t range,rt_uint16_t speed)
{
rt_uint8_t forward_angle=0;
if(left_mid_int_num>left_mid_num){
forward_angle=left_mid_int_num-left_mid_num;}//说明有位移
else{
forward_angle=0;}
while(forward_angle)
{
if(forward_angle>range){
forward_angle=forward_angle-range;
left_mid_num=left_mid_num+range;
left_up_num=left_up_num+range;
right_mid_num=right_mid_num+range;
right_up_num=right_up_num+range;
}
else{
range=forward_angle;
forward_angle=0;
left_mid_num=left_mid_int_num;
left_up_num=left_up_int_num;
right_mid_num=right_mid_int_num;
right_up_num=right_up_int_num;
}
set_robot_left(left_up_num,left_mid_num,left_down_num);
set_robot_right(right_up_num,right_mid_num,right_down_num);
rt_thread_mdelay(speed);
}
}
void robot_left_forward(rt_uint8_t forward_angle,rt_uint8_t range,rt_uint16_t speed)
{
while(forward_angle)
{
if(forward_angle>range){
forward_angle=forward_angle-range;
left_mid_num=left_mid_num+range;
left_up_num=left_up_num+range;
right_mid_num=right_mid_num+range;
right_up_num=right_up_num+range;
}
else{
range=forward_angle;
forward_angle=0;
left_mid_num=left_mid_num+range;
left_up_num=left_up_num+range;
right_mid_num=right_mid_num+range;
right_up_num=right_up_num+range;
}
set_robot_left(left_up_num,left_mid_num,left_down_num);
set_robot_right(right_up_num,right_mid_num,right_down_num);
// rt_kprintf("left_down_=%d",left_down_num);
// rt_kprintf("right_down_=%d\r\n",right_down_num);
rt_thread_mdelay(speed);
}
}
void robot_left_forward_attention(rt_uint8_t range,rt_uint16_t speed)
{
rt_uint8_t forward_angle=0;
if(left_mid_num>left_mid_int_num){
forward_angle=left_mid_num-left_mid_int_num;}//说明有位移
else{
forward_angle=0;}
while(forward_angle)
{
if(forward_angle>range){
forward_angle=forward_angle-range;
left_mid_num=left_mid_num-range;
left_up_num=left_up_num-range;
right_mid_num=right_mid_num-range;
right_up_num=right_up_num-range;
}
else{
range=forward_angle;
forward_angle=0;
left_mid_num=left_mid_int_num;
left_up_num=left_up_int_num;
right_mid_num=right_mid_int_num;
right_up_num=right_up_int_num;
}
set_robot_left(left_up_num,left_mid_num,left_down_num);
set_robot_right(right_up_num,right_mid_num,right_down_num);
// rt_kprintf("left_down_=%d",left_down_num);
// rt_kprintf("right_down_=%d\r\n",right_down_num);
rt_thread_mdelay(speed);
}
}
void go_right_step(rt_uint8_t angle,rt_uint8_t range,rt_uint16_t speed)
{
//右脚迈一步
robot_left_tilt(angle,range,speed);//左倾
robot_right_forward(angle,range,speed);//右脚向前走
robot_left_tilt_attention(range,speed);//左倾回正
robot_right_tilt(angle,range,speed);//右倾
robot_right_forward_attention(range,speed);//右脚回正
robot_right_tilt_attention(range,speed);//右倾回正
}
void go_left_step(rt_uint8_t angle,rt_uint8_t range,rt_uint16_t speed)
{
//左脚迈一步
robot_right_tilt(angle,range,speed);//右倾
robot_left_forward(angle,range,speed);//左脚向前走
robot_right_tilt_attention(range,speed);//右倾回正
robot_left_tilt(angle,range,speed);//左倾
robot_left_forward_attention(range,speed);//左脚回正
robot_left_tilt_attention(range,speed);//左倾回正
}
最后
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/37692.html