|
【S107】蓝牙遥控抓取小车
作品说明 |
作者:金晓峰 李赛明 凌路华 陈亦鑫
单位:杭州师范大学钱江学院
指导老师:马宝丽、孙红梅
现代的无线遥控小车技术,起源于美国,其实是第二次世界大战的产物。由于战事的需求尤其是需要各种不同与人类直接操作的机器,用于排雷、布雷、收集情报等,在此基础上需要智能遥控机器,随着技术的发展,出现了各种功能的小型遥控车。利用遥控小车排雷布雷执行危险的任务,随着技术的沉淀,现代遥控技术到达了相当的高度。
本作品以蓝牙遥控抓取小车为对象,具有遥控避障并且机械臂能定点抓取放置物料的蓝牙遥控小车。本作品全部材料均来自探索者,通过蓝牙遥控来实现小车的自主行走,抓取,通过机械臂上的关节舵机角度调节来实现抓取物品的功能,该作品主要分为两大机构:轮动装置和机械臂抓取装置,利用Arduino控制器使整个机构协同化运作,按照设计要求遥控小车运作,前轮使用转向机构,控制小车前进、后退、转向及停止,使用机械臂依次抓取物品,完成这一整套动作。
本作品几个突出的特点:本作品采用手机蓝牙控制小车,且机械臂较长,采用舵机联动控制,抓取范围广,抓取速度快,响应较快。
1.2 方案提出随着人类知识的不断深入和科学技术的进步,机器人已经被广泛应用于各类工业生产生活中,并取得了很好的效益。在工业生产中,机器人能够帮助人们从事点焊、码垛、喷漆、包装、装配等工作;在汽车工业、电子工业、核电工业等许多行业,以及在深海、太空等人类极限能力以外的应用领域,机器人正在发挥着巨大的、不可替代的作用。遥控机器人就是机器人在工业生产中应用的典型实例。
2. 设计方案
2.1 设计思路本设计是以单片机为核心,通过蓝牙模块和手机蓝牙的串口通讯来实现数据指令的传递,单片机对数据处理最后给电机驱动模块输出高低电平,从而来控制电机驱动模块的输出端。智能小车使用四轮驱动,以提高整车运动的平稳性。手机蓝牙遥控小车通过蓝牙接受模块手机客户端、单片机芯片,在驱动电机的拖动下,使小车实现各个功能。
2.2 设计构思结构图作品说明
电子线路连接流程图
平行四边形机构,直流电机驱动。
转向装置
动力装置由底板、电机、电机支架、车轮、联轴器等组成,电机支架固定到底板上,再把电机固定到电机支架上,通过联轴器将电机输出轴链接在一起,使小车具备行走功能。
轮子
直流电机
机械臂通过舵机和夹持器来拾取物品,机械臂的结构主要由舵机、小支架、大支架、夹持器等零件组成。机械手是主要的抓取部件,通过4个舵机来控制机械手的活动,实现多自由度的全方位抓取功能;其次该连接方式可以使手臂更加灵活,有利于调整关节间的相对角度,从而使机械手具有准确性;最后机械臂的夹持器是由舵机和夹爪组成。夹爪是通过一对不完全齿轮啮合产生相对转动,转动方向取决于舵机输出轴方向,进而实现抓放功能,有利于保证抓取物件及运输过程中的准确性和稳定性。
舵机
U型支架
4. 控制系统
4.1 Basra控制板Basra是一款基于Arduino开源方案设计的一款开发板,通过各种各样的传感器来感知环境,通过控制灯光、马达和其他的装置来反馈、影响环境。板子上的微控制器可以在Arduino、eclipse、Visual Studio等IDE中通过c/c++语言来编写程序,编译成二进制文件,烧录进微控制器。Basra的处理器核心是ATmega328,同时具有14路数字输入/输出口(其中6路可作为PWM输出),6路模拟输入,一个16MHz晶体振荡器,一个USB口,一个电源插座,一个ICSP header和一个复位按钮。
主CPU采用AVR ATMEGA328型控制芯片,支持C语言编程方式;该系统的硬件电路包括:电源电路、串口通信电路、MCU基本电路、烧写接口、显示模块、AD/DA转换模块、输入模块、IIC存储模块等其他电路模块电路。控制板尺寸不超过60*60mm,便于安装。CPU硬件软件全部开放,除能完成对小车控制外,还能使用本实验板完成单片机所有基础实验。供电范围宽泛,支持5v~9v的电压,干电池或锂电池都适用。编程器集成在控制板上,通过USB大小口的方式与电脑连接。下载程序。开放全部底层源代码。控制板含3A6V的稳压芯片,可为舵机提供6v额定电压。板载8*8led模块采用MAX7219驱动芯片。板载一片直流电机驱动芯片FAN8100MTC,可同时驱动两个直流电机。板载USB驱动芯片及自动复位电路,烧录程序时无需手动复位。2个2*5的杜邦座扩展坞,方便无线模块、OLED、蓝牙等扩展模块直插连接,无需额外接线。
主板
控制功能、精确自由度智能小车和机械手一体化协同工作的智能遥控小车工作流程图如下所示:
程序流程图
蓝牙( Bluetooth® ):是一种无线技术标准,可实现固定设备、移动设备和楼宇个人域网之间的短距离数据交换(使用2.4—2.485GHz的ISM波段的UHF无线电波)。
如下图所示,我们在此使用的蓝牙模块(HC-05)已经在内部实现了蓝牙协议,不用我们再去自己开发调试协议。这类模块一般都是借助于串口协议通信,因此我们只需借助串口将我们需要发送的数据发送给蓝牙模块,蓝牙模块会自动将数据通过蓝牙协议发送给配对好的蓝牙设备。
蓝牙模块
想实现蓝牙遥控小车,上位机是必不可少,采用蓝牙app手机作为上位机,对蓝牙串口模块发送数据指令,目前网上有很多蓝牙串口助手,省去了我们自己写APP的时间。
本次采用蓝牙串口助手,如下图所示,APP主界面,分别提供了三个滑条和六个自定义按键。
如上图所示,进入地面站控件设置,可以设置填写发送的数据,但需要注意的是
① 必须是十六进制,如 A5
② 两个字节间不要带空格
③ 每个字节要写完整,如 05 不可以写成 5
滑条[发送]
触发:当滑条的位置改变时,将触发程序发送数据帧(7个字节)
帧格式说明:
>例 A5 5A 05 F1 80 76 AA
Byte 0 A5 帧起始字节1
Byte 1 5A 帧起始字节2
Byte 2 05 本帧包含的字节数,除了起始字节外
Byte 3 F1 帧功能标示,F1表示滑条1状态
Byte 4 80 滑条的当前值
Byte 5 76 除了起始字节外的数据累加合
Byte 6 AA 帧结束
--------------------------------------
Byte 3 帧功能标志可以是:
F1 滑条1
F2 滑条2
F3 滑条3
Byte 4 滑条的当前值取决于android上的滑条位置,最大值可以自定义,最大不超过255。
Byte 5 是(Byte 2+Byte 3+Byte 4)累加合,取低字节。
Byte 0 Byte 1 Byte 6 是固定不变的字节。
按键[发送]
触发:当按键被按下并释放后,将触发程序发送数据帧(默认6个字节)
帧格式说明:
>例 A5 5A 04 B1 B5 AA
Byte 0 A5 帧起始字节1
Byte 1 5A 帧起始字节2
Byte 2 04 本帧包含的字节数,除了起始字节外
Byte 3 B1 帧功能标示,F1表示滑条1状态
Byte 4 B5 除了起始字节外的数据累加合
Byte 5 AA 帧结束
--------------------------------------
Byte 3 帧功能标志可以是:
B1 按键1
B2 按键2
B3 按键3
B4 按键4
B5 按键5
B6 按键6
Byte 4 是(Byte 2+Byte 3)累加合,取低字节。
Byte 0 Byte 1 Byte 5 是固定不变的字节。
注意:以上关于按键的说明只是以默认设置进行说明。如果用户对点击发送的数据已设置,则以设置的数据进行发送。
4.3 示例程序
#include<Servo.h> int data = 0; // 接收到的 data byte String inputString = ""; // 用来储存接收到的内容 boolean newLineReceived = false; // 前一次数据结束标志 #define STOP 177 //停止识别信号 #define FORWARD 178 //前进识别信号 #define TURNLEFT 180 //左转识别信号 #define BACKWARD 181 //后退识别信号 #define TURNRIGHT 182 //右转识别信号 #define SERVO1 241 //舵机1识别信号 #define SERVO2 242 //舵机2识别信号 #define SERVO3 243 //舵机3识别信号 #define SERVO4 179 //舵机4识别信号 int a=1; //爪子开合 Servo servo_[4]; //创建4个舵机 int servo_port[4]={3,4,7,8}; //4个舵机引脚端口 Servo servo_D; //方向舵机 int leftMotor1 = 5; //电机 int leftMotor2 = 6;//电机 int rightMotor1 = 9;//电机 int rightMotor2 = 10;//电机 void setup() { Serial.begin(9600); //波特率9600 for(int i =0;i<4;i++){servo_[i].attach(servo_port[i]);}//舵机关联引脚 servo_D.attach(11); //舵机关联引脚 pinMode(leftMotor1, OUTPUT); //定义电机引脚模式为输出 pinMode(leftMotor2, OUTPUT); pinMode(rightMotor1, OUTPUT); pinMode(rightMotor2, OUTPUT); }
void loop() {if (newLineReceived) { //主程序 /*motorRun((byte)inputString[5]);*/ motorRun((byte)inputString[3]); //调用swittch 选择判断 inputString = ""; // clear the string //清空字符串 防止累计叠加下次读值 newLineReceived = false; // 字符串完整标志 }}
void motorRun(int cmd) { switch(cmd){ case FORWARD:Serial.println("FORWARD");Forwards();break; case BACKWARD:Serial.println("BACKWARD");Back();break; case TURNLEFT:Serial.println("TURN LEFT");Left();break; case TURNRIGHT:Serial.println("TURN RIGHT");Right();break; case STOP:Serial.println("STOP");Stop();break; case SERVO1:servo_[0].write((byte)inputString[4]);break; case SERVO2:servo_[1].write((byte)inputString[4]);break; case SERVO3:servo_[2].write((byte)inputString[4]);break; case SERVO4:if(a==1){servo_[3].write(90);a=0;}else{servo_[3].write(140);a=1;} default:Stop(); } } void Forwards() //前进 { servo_D.write(90); digitalWrite(leftMotor1,1 ); digitalWrite(leftMotor2, 0); digitalWrite(rightMotor1, 1); digitalWrite(rightMotor2, 0); } void Back() //后退 { digitalWrite(leftMotor1,0); digitalWrite(leftMotor2, 1); digitalWrite(rightMotor1, 0); digitalWrite(rightMotor2, 1); } void Left() //左转 { servo_D.write(130); digitalWrite(leftMotor1,1 ); digitalWrite(leftMotor2, 0); digitalWrite(rightMotor1, 1); digitalWrite(rightMotor2, 0);/* analogWrite(leftMotor1, 100); analogWrite(leftMotor2, LOW); analogWrite(rightMotor1, 255); analogWrite(rightMotor2, LOW);*/
} void Right() //右转 { servo_D.write(50); digitalWrite(leftMotor1,1 ); digitalWrite(leftMotor2, 0); digitalWrite(rightMotor1, 1); digitalWrite(rightMotor2, 0); /*analogWrite(leftMotor1, 255); analogWrite(leftMotor2, LOW); analogWrite(rightMotor1, 100); analogWrite(rightMotor2, LOW);*/ } void Stop() //停止 { digitalWrite(leftMotor1, LOW); digitalWrite(leftMotor2, LOW); digitalWrite(rightMotor1, LOW); digitalWrite(rightMotor2, LOW); }
void serialEvent() //串口事件 对串口传输的信息进行处理 {while (Serial.available()) { //判断缓冲器状态。回传有多少位元组(bytes)的资料尚未被read()函式读取,如果回传值是0代表所有序列埠上资料都已经被read()函式读取。 data = Serial.read(); //一个字节一个字节地读,下一句是读到的放入字符串数组中组成一个完成的数据包 inputString += (char) data; // 全双工串口可以不用在下面加延时,半双工则要加的// if (data ==170) { newLineReceived = true; } } } |
* 本项目未获得作者开源授权,无法提供资料下载。