STM32机器人.docx
- 文档编号:2395202
- 上传时间:2023-05-03
- 格式:DOCX
- 页数:35
- 大小:2.48MB
STM32机器人.docx
《STM32机器人.docx》由会员分享,可在线阅读,更多相关《STM32机器人.docx(35页珍藏版)》请在冰点文库上搜索。
STM32机器人
上海第二工业大学
实训报告
课程名称:
一级项目(机器人)_
*******
学号:
***********
学院名称:
电子与电气工程学院
专业班级:
12自动化C1
第1章绪论
1.1研究背景和意义
机器人是一个很好的科研平台,非常适合以它作为工程对象,来学习和掌握软件编程、嵌入式技术、传感器技术、无线数据通信、机电一体化、图像处理与模式识别及人工智能等专业知识。
机器人已经广泛地应用于工业、医学、农业、建筑业、以及军事等领域,本项目通过用STM32单片机制作一个简单机器人,实现一些机器人必备的基本动作来进一步学习STM32单片机,提高我的实践操作能力,以弥补课堂上单纯的理论知识所造成的欠缺。
此外,参与机器人的制作会将理论知识与实践完美地结合在一起,制作的产品会给我们带来一种喜悦与自豪之感,这将进一步激发我们的学习热情,引领我们走向更远的专业之路。
1.2国内外机器人发展方向
随着机器人在社会中的不断普及和应用,人们对机器人实用化、市场化的呼声也越来越高。
未来机器人的发展将有一个非常大的发展空间。
未来机器人可能会朝着一下几个方面发展:
(1)外形结构的拟人化和微型化
机器人发展的初级阶段是以机械手的形式呈现的。
当时由于技术、资金、性价比等方面的原因,并没有注重发展拟人机器人。
随着技术的不断进步,还有机械手式机器人呈现的不足,拟人化的机器人正在得到快速的发展。
微型化也是机器人发展的一个目标,研制纳米级的机器人可以进入人体内部,帮助人体清理垃圾,治疗疾病等。
(2)功能的多样化
机器人以后的发展方向必然是向着多功能、多扩展性的方向发展,听、视、触、嗅、味觉将会是机器人必备的功能。
在现今的机器人中,听、视觉发展相对较快,在触、嗅、味觉方面的由于技术上的限制,现在还没有研制出在这些方面比较成熟的感应装置。
(3)具有自我学习和思考的能力
机器人相对于人最大的不足就是不具有思考和再学习的能力,这也是由于多方面原因造成的。
首先人类对自身的这种能力的认识也不是很彻底。
其次机器人的大脑(CPU)的运算能力还是不如人脑。
不过相信在不远的将来,人类对于这种能力的认识足够清楚之后,并且更加强大的CPU将能被研制出来。
机器人也将很快就具有这种思考和自我学习的能力了。
第2章系统总体设计思路
2.1项目设计要求
基于STM32开发板的基础上,通过以I/O口控制伺服电机的转动为起点逐步增加操作的复杂程度,最终使得小车可以实现复杂运动、智能探索和避开障碍物、距离检测并显示在液晶屏上以及进行小车尾随等功能。
2.2硬件系统设计方案
本项目所使用的智能小车为欧鹏科技有限公司生产的,采用STM32F103系类微控制器。
小车由两个舵机和一个前方的万向轮来控制其运动。
在小车的前方有一块面包板,便于我们自己搭建一些额外的外围电路模块,以增强小车的实用性和智能型。
小车使用的是两节3.7V的直流电源给电机供电,另外通过三端电源稳压芯片7805以及C1117芯片将7.4V的直流电源转化为3.3V的直流电源供STM32芯片使用。
小车的底面和正面分别见图1-1和1-2以及下载程序时的连接线路图如图1-3所示。
图1-1小车底面图
图1-2小车正面图
第3章系统模块软硬件设计
3.1机器人伺服电机控制信号
本项目中所用的机器人伺服电机型号为PARALLAX。
电机实物图见图2-1.控制伺服电机转动速度的信号如图2-2、2-3和2-4所示的脉冲信号。
图2-2所示是高电平持续1.5ms低电平持续20ms,然后不断重复地控制脉冲序列。
该脉冲序列发给经过零点标定后的伺服电机,伺服电机不会旋转。
如果此时你的电机旋转,表明电机需要标定。
此时,我们需要参考参考《基础机器人制作》教材中有关伺服电机标定的部分。
从图2-2、2-3和2-4可知,控制电机运动转速的是高电平持续的时间,当高电平持续时间为1.3ms时,电机顺时针全速旋转,当高电平持续时间1.7ms时,电机逆时针速旋转。
下面我们将看到如何给单片机微控制器编程使P1端口的第一脚(P1_0)来发出伺服电机的控制信号。
图2-1项目中所使用的舵机实物图
图2-2电机转速为零的控制信号时序图
图2-31.3ms的控制脉冲序列使电机顺时针全速旋转
图2-41.7ms的连续脉冲序列使电机逆时针全速旋转
3.1.1舵机控制
通过P1端口的第一脚(P1_0)来发出伺服电机的控制信号驱动一个舵机。
下面的程序代码1、代码2、代码3可以分别让一个舵机(舵机的标准状态下)静止不动、沿顺时针方向以最大速度转动、沿逆时针方向以最大速度转动。
代码1
while
(1)
{
GPIO_SetBits(GPIOC,GPIO_Pin_10);//PD10输出高电平
delay_nus(1500);//延时1500微秒
GPIO_ResetBits(GPIOC,GPIO_Pin_110);//PD10输出高电平
delay_nms(20000);//延时20毫秒
}
代码2
while
(1)
{
GPIO_SetBits(GPIOD,GPIO_Pin_10);//PD10输出高电平
delay_nus(1300);//延时1300微秒
GPIO_ResetBits(GPIOD,GPIO_Pin_10);//PD10输出高电平
delay_nms(20);//延时20毫秒
}
代码3
while
(1)
{
GPIO_SetBits(GPIOD,GPIO_Pin_10);//PD10输出高电平
delay_nus(1700);//延时1700微秒
GPIO_ResetBits(GPIOD,GPIO_Pin_10);//PD10输出高电平
delay_nms(20);//延时20毫秒
}
3.1.2驱动小车
以上的三段程序代码可以让我们来控制一个舵机的正反转以及停止这三种状态。
下面这段代码4是控制两个鸵机同时沿顺时针方向全速转动的程序,这样我们便可以让个小车向前跑起来。
代码4
#include"stm32f10x_heads.h"
#include"HelloRobot.h"
intmain(void)
{
BSP_Init();
USART_Configuration();
printf("ProgramRunning!
\n");
while
(1)
{
GPIO_SetBits(GPIOD,GPIO_Pin_10);//PD10输出高电平
delay_nus(1300);//延时1300微秒
GPIO_ResetBits(GPIOD,GPIO_Pin_10);//PD10输出高电平
GPIO_SetBits(GPIOD,GPIO_Pin_9);//PD10输出高电平
delay_nus(1700);//延时1700微秒
GPIO_ResetBits(GPIOD,GPIO_Pin_9);//PD10输出高电平
delay_nms(20);//延时20毫秒
}
}
3.2循环语句控制小车的运行时间长短
到目前为止,已经明白了脉冲宽度控制连续旋转电机速度和方向的原理。
控制电机速度和方向的方法是非常简单的。
控制电机运行的时间也非常简单,那就是用for循环。
下面代码5是for循环的例子,它会使小车向前运动大约3秒钟。
代码5
#include"stm32f10x_heads.h"
#include"HelloRobot.h"
intmain(void)
{
intcounter;
BSP_Init();
USART_Configuration();
printf("ProgramRunning!
\n");
for(counter=0;counter<130;counter++)//ÔËÐÐ3Ãë
{
GPIO_SetBits(GPIOD,GPIO_Pin_10);
delay_nus(1700);
GPIO_ResetBits(GPIOD,GPIO_Pin_10);
GPIO_SetBits(GPIOD,GPIO_Pin_9);
delay_nus(1300);
GPIO_ResetBits(GPIOD,GPIO_Pin_9);
delay_nms(20);
}
while
(1);
}让我们来计算一下这个代码能使电机转动的确切的时间长度。
每通过循环一次delay_nus(1700)持续1.7ms,delay_nms(20)持续20ms,再delay_nus(1300),其他语句的执行时间很少,可忽略。
那么for循环整体执行一次的时间是:
1.7ms+20ms+1.3ms=23ms,本循环执行130次,即就是23ms乘以130,时间=130*23ms=130*0.023秒=3秒。
这样我们的这个电机就可以沿逆时针方向转动大约3秒的时间了。
这样就可以有效控制小车运动时间的长短。
3.3用C语言函数进行机器人巡航控制
前面我们已经知道控制电机前进、后退以及左右转等简单操作,下面我们通过建立数组来让小车进行复杂的连续性的运动。
要点:
建立一个数组,通过switch、case语句来让小车执行相应的命令,最终完成小车的复杂运动。
相应的程序如下代码6所示:
代码6
#include"stm32f10x_heads.h"
#include"HelloRobot.h"
voidForward(void)//建立一个小车前进的子函数
{
inti;
for(i=1;i<=65;i++)//延时大约1.5秒
{
GPIO_SetBits(GPIOD,GPIO_Pin_10);
delay_nus(1700);
GPIO_ResetBits(GPIOD,GPIO_Pin_10);
GPIO_SetBits(GPIOD,GPIO_Pin_9);
delay_nus(1300);
GPIO_ResetBits(GPIOD,GPIO_Pin_9);
delay_nms(20);
}
}
voidLeft_Turn(void)//建立一个小车左转的子函数
{
inti;
for(i=1;i<=26;i++)//延时大约0.65秒
{
GPIO_SetBits(GPIOD,GPIO_Pin_10);
delay_nus(1300);
GPIO_ResetBits(GPIOD,GPIO_Pin_10);
GPIO_SetBits(GPIOD,GPIO_Pin_9);
delay_nus(1300);
GPIO_ResetBits(GPIOD,GPIO_Pin_9);
delay_nms(20);
}
}
voidRight_Turn(void)//建立一个小车右转的子函数
{
inti;
for(i=1;i<=26;i++)//延时大约0.65秒
{
GPIO_SetBits(GPIOD,GPIO_Pin_10);
delay_nus(1700);
GPIO_ResetBits(GPIOD,GPIO_Pin_10);
GPIO_SetBits(GPIOD,GPIO_Pin_9);
delay_nus(1700);
GPIO_ResetBits(GPIOD,GPIO_Pin_9);
delay_nms(20);
}
}
voidBackward(void)//建立一个小车后退的子函数
{
inti;
for(i=1;i<=65;i++)//延时大约1.5秒
{
GPIO_SetBits(GPIOD,GPIO_Pin_10);
delay_nus(1300);
GPIO_ResetBits(GPIOD,GPIO_Pin_10);
GPIO_SetBits(GPIOD,GPIO_Pin_9);
delay_nus(1700);
GPIO_ResetBits(GPIOD,GPIO_Pin_9);
delay_nms(20);
}
}
intmain(void)
{
charNavigation[10]={'F','L','F','F','R','B','L','B','B','Q'};
intaddress=0;
BSP_Init();
USART_Configuration();
printf("ProgramRunning!
\n");
while(Navigation[address]!
='Q')
{
switch(Navigation[address])
{
case'F':
Forward();break;
case'L':
Left_Turn();break;
case'R':
Right_Turn();break;
case'B':
Backward();break;
}
address++;
}
while
(1);
}
3.3.1代码分析
在程序主函数中定义了一个字符数组如下所示:
charNavigation[10]={'F','L','F','F','R','B','L','B','B','Q'};
这个数组中存储的是一些命令:
F表示向前运动,L表示向左转,R表示向右转,B表示向后退,Q表示程序结束。
之后,定义了一个int型变量address,用来作为访问数组的索引。
接着是一个while循环,注意到这个循环的条件表达式与前面的不同:
只有当前访问的数组值不为Q时,才执行循环体内的语句。
在循环内,每次执行switch语句后,都要更新address,以使下次循环时执行新的运动。
switch语句
switch语句是一种多分支选择语句,其一般形式如下:
switch(表达式){
case常量表达式1:
语句1;break;
case常量表达式2:
语句2;break;
…
case常量表达式n:
语句n;break;
default:
语句n+1;break;
}
其语义是:
计算表达式的值,逐个与其后的常量表达式值相比较,当表达式的值与某个常量表达式的值相等时,即执行其后的语句。
如表达式的值与所有case后的常量表达式均不相同时,则执行default后的语句。
在本例程中,当Navigation[address]为’F’时,执行向前运动的函数Forward();当
Navigation[address]为’L’时,执行向左转的函数Left_Turn();当Navigation[address]为’R’时,执行向右转的函数Right_Turn();当Navigation[address]为’B’时,执行向后运动的函数Backward()。
3.4单片机输入接口与机器人触觉导航
许多自动化机械都依赖于各种触觉型开关,例如当机器人碰到障碍物时,接触开关就会
察觉,通过编程让机器人躲开障碍物;旅客登机桥在靠近飞机时为了保护昂贵的飞机,在登
机桥接口安装触须,当登机桥离飞机很近后触须就会碰到飞机,立即通知控制器提醒离飞机
已经很近了,需要降低靠近速度;工厂利用触觉开关来计量生产线上的工件数量;在工业加
工过程中,也被用来排列物体。
在所有这些实例中,触觉开关提供的输入通过计算机或者单
片机处理后生成其它形式的程序化的输出。
3.4.1触觉导航与单片机输入接口
STM32单片机的5组GPIO端口既可以作为输入,也可以作为输出,既可按16位处理,也可按位方式使用。
实际上,当单片机启动或复位时,复用功能未开启,IO端口被配制成浮空输入模式。
所有端口都有外部中断能力。
为了使用外部中断线,必须将端口配置成输入模式。
作为输入,如果I/O脚上的电压为3.3V,则其相对应的I/O口寄存器中的相应位存储1;如果电压为0V,则存储0。
布置恰当的电路,可以让胡须达到上述效果:
当胡须没有被碰到时,使I/O脚上的电压
为3.3V;当胡须被碰到时,则使I/O脚上电压为0。
然后,单片机就可以读入相应数据,进行分析、处理,控制机器人的运动。
3.4.2安装并测试机器人胡须
机器人的胡须安装实物图如图2-5所示。
图2-6是其电路简化图,图2-7是小车触须的完整实物图。
图2-5机器人胡须
图2-6机器人胡须电路示意图
图2-7机器人的触须实物图
通过编程让单片机探测什么时候胡须被触动。
由图2-6可知,连接到每个胡须电路的I/O
引脚监视着10K上拉电阻上的电压变化。
当胡须没有被触动,连接胡须的I/O管脚的电压是3.3V;当胡须被触动时,I/O短接到地,所以I/O管脚的电压是0V。
3.4.3基于胡须的机器人触觉导航
在机器人行走过程中,如果有胡须被触动,那就意味着碰到了什么。
导航程序需要接受这些输入信息,判断它的意义,调用一系列使机器人倒退、旋转朝不同方向行走的动作子函数以避开障碍物。
下面的程序让机器人向前走直到碰到障碍物。
在这种情况下,机器人用它的一根或者两
根胡须探测障碍物。
一旦胡须探测到障碍物,调用C语言函数控制机器人巡航导航中的导航程序和子程序使小车倒退或者旋转,然后再重新向前行走,直到遇到另一个障碍物。
为了实现这些功能,需要编程机器人来做出选择,此时要用到if语句的另一种形式,if-else-if形式,它可以进行多分支选择。
它的一般形式为:
if(表达式1)
语句1;
elseif(表达式2)
语句2;
elseif(表达式3)
语句3;
……
elseif(表达式n-1)
语句n-1;
Else
语句n;
其语义为:
依次判断表达式的值,当出现某个值为真时,则执行其对应的语句。
然后跳到整个if语句之外继续执行程序;如果所有的表达式均为假,则执行语句n。
然后继续执行后续程序。
3.4.4机器人进入死区后人工智能决策程序代码7如下:
代码7
#include"stm32f10x_heads.h"
#include"HelloRobot.h"
intPE2state(void)//获取PE2胡须的状态
{
returnGPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2);
}
intPE3state(void)//获取PE3胡须的状态
{
returnGPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3);
}
voidForward(void)
{
GPIO_SetBits(GPIOD,GPIO_Pin_10);
delay_nus(1700);
GPIO_ResetBits(GPIOD,GPIO_Pin_10);
GPIO_SetBits(GPIOD,GPIO_Pin_9);
delay_nus(1300);
GPIO_ResetBits(GPIOD,GPIO_Pin_9);
delay_nms(20);
}
voidLeft_Turn(void)
{
inti;
for(i=1;i<=26;i++)
{
GPIO_SetBits(GPIOD,GPIO_Pin_10);
delay_nus(1300);
GPIO_ResetBits(GPIOD,GPIO_Pin_10);
GPIO_SetBits(GPIOD,GPIO_Pin_9);
delay_nus(1300);
GPIO_ResetBits(GPIOD,GPIO_Pin_9);
delay_nms(20);
}
}
voidRight_Turn(void)
{
inti;
for(i=1;i<=26;i++)
{
GPIO_SetBits(GPIOD,GPIO_Pin_10);
delay_nus(1700);
GPIO_ResetBits(GPIOD,GPIO_Pin_10);
GPIO_SetBits(GPIOD,GPIO_Pin_9);
delay_nus(1700);
GPIO_ResetBits(GPIOD,GPIO_Pin_9);
delay_nms(20);
}
}
voidBackward(void)
{
inti;
for(i=1;i<=65;i++)
{
GPIO_SetBits(GPIOD,GPIO_Pin_10);
delay_nus(1300);
GPIO_ResetBits(GPIOD,GPIO_Pin_10);
GPIO_SetBits(GPIOD,GPIO_Pin_9);
delay_nus(1700);
GPIO_ResetBits(GPIOD,GPIO_Pin_9);
delay_nms(20);
}
}
intmain(void)
{
BSP_Init();
USART_Configuration();
printf("ProgramRunning!
\n");
while
(1)
{
if((PE2state()==0)&&(PE3state()==0))//两胡须同时碰到
{
Backward();//向后退
Left_Turn();//向左转
Left_Turn();//向左转
}
elseif(PE2state()==0)//右边胡须碰到
{
Backward();//向后退
Left_Turn();//向左转
}
elseif(PE3state()==0)//左边胡须碰到
{
Backward();//后退
Right_Turn();//向右转
}
else//胡须没有碰到
Forward();//前进
}
}
3.5接口综合应用与红外导航
红外线二极管发射红外光,如果机器人前面有障碍物,红外线从物体反射回来,相当于机器人眼睛的红外检测(接收)器,检测到反射回的红外光线,并发出信号来表明检测到从物体反射回红外线。
机器人的大脑——STM32基于这个传感器的输入控制伺服电机。
红外线(IR)接收/检测器有内置的光滤波器,除了需要检测的980nm波长的红外线外,它几乎不允许其它光通过。
红外检测器还有一个电子滤波器,它只允许大约38.5kHz的电信号通过。
换句话说,检测器只寻找每秒闪烁38,500次的红外光。
这就防止了普通光源象太阳光和室内光对IR的干涉。
太阳光是直流干涉(0Hz)源,而室内光依赖于所在区域的主电源,闪烁频率接近100或120Hz。
由于120Hz在电子滤波器的38.5kHz通带频率之外,它完全被IR探测器忽略。
3.5.1搭建电路并测试红外发射和接收.电路如图-所示。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- STM32 机器人