作者:孙宇晗、刘子昊、单正扬、李悦、张紫琦
单位:山东大学(威海)
指导老师:庞豹
1. 场景调研
1.1 宏观背景
体育作为社会经济、政治、文化的重要组成部分,越来越受政府、社会、学校等各阶层的关注。近年来,国家为推进“健康中国”建设、提高人民健康水平,印发并实施《“健康中国2030”规划纲要》和《体育强国纲要》。各大高校为响应国家号召也加强对学生的身体素质的培养,重视体育建设,增加对体育建设的资金投入。
同时,在机器人成为热门话题的今天,机器人被期待应用于更多领域。其中,体育行业就是机器人可以发挥作用的一片沃土。老牌体育用品公司彪马研发“BeatBot”陪跑机器人,2016年四川省暨成都市科技活动周上成都电子科大的羽毛球机器人产品引起轰动,越来越多机器人将应用于体育行业。目前体育机器人大多作为辅助训练装置,然而体育运动中能运用机器人的场景远不止于此,对于喜爱体育运动的普通消费者,更加渴望一些能更好地服务于日常体育锻炼的机器人的出现。
1.2 应用需求
目前高校的体育设施配置普遍提升,一般高校都配置有标准网球场,并且开设网球课程。一片标准网球场地的占地面积不小于670平方米,长36.60米,宽18.30米。在这个面积内,有效双打场地的标准尺寸达到23.77米(长)×10.97米(宽),有效单打场地的标准尺寸达到23.77米(长)×8.23米(宽),并且实际上高校的网球场往往是多个连接在一起的一大片空旷场地。而一个标准网球大小在6.541~6.858 cm之间,在训练网球时通常需要使用大量网球,作为网球训练的发球机器人一次可以发出几十个球。由于网球弹性大,每次训练之后,几十个网球散落在场地各个地方,捡球是一件非常麻烦的事。为了给高校网球训练者提供一个更方便、更流畅、更轻松的训练或娱乐体验,我们设计了这一款体育器械智能收纳机器人。
1.3 应用场景
由于高校消费能力相较于个人更强,网球场广阔,几乎每天使用,并且对于新兴产品的接受度较高。所以,该网球收纳机器人前期主要应用于高校网球场的收纳。机器人轻便小巧,工作能力强,一个机器可以适应与完成不同大小,环境场地网球的收纳,所以机器人在高校的应用趋于稳定后,后期可将其应用于其它网球场区域总体较大、较为平旷、使用率高、具有较高的网球收纳需求的场景,如网球俱乐部、私人网球馆等。
2. 网球收纳机器人介绍
2.1 关于此网球收纳机器人
该机器人是一款基于“探索者”平台搭建的能够自主识别并收纳体育器械的小型机器人。目前我们主要设想将它运用于高校网球场地上网球的捡拾与收纳。
2.2 与市面上已有网球收集机器对比
市面上一般的网球机器人体型较大,主要依赖于人将装置带至网球散落处,然后装置将网球收集,整个过程并非全自动,仅仅是简化了人弯腰捡拾起网球这一动作,并没有解放使用者双手。并且由于装置一般体型较大,占地大,机器的收纳与转移较为不便,这使得使用者在装置的保存与转移上需要耗费空间与精力,增加了使用负担。
而在自动模式下使用机器人时,只需要使用者启动机器人,机器人便可自动完成网球的收纳,几乎完全解放用户双手。即使是手动模式,也只需要使用者操控遥控器,不需要使用者在网球场上来回走动。并且该网球收纳机器人机身小巧,重量较小,可以轻易拿起,无论是收纳或者是将其转移都十分方便,大大利于普通消费者的收纳与使用,不会给用户造成额外的收纳困难与使用烦恼。
3. 机器人技术说明
3.1 主要技术参数
(1)采用Basra主控板,堆叠BigFish扩展板
(2)电机转速最高可达70r/min
(3)前方装有二自由度机械臂,伸长可达30cm,单一维度活动范围0~180°
(4)底盘距地面6cm
(5)一个颜色模块,一个超声波测距模块,两个触须模块
3.2 机械结构
体育器械收纳智能机器人的整体结构及各部分功能如下图所示:
3.2.1 底盘结构
该网球收集机器人主要零件均采用标准件进行装配,车身整体尺寸较小,可灵活穿梭于各类球场中。机器人底盘采用一块7*11孔平板,电机悬挂在外侧的四个3*5双折面板上,既缩小了车身宽度和长度,使其通过弯道时不容易被卡住,又增加了底盘的高度,使机器人通过草地和上台阶和窄桥时越野能力增强。
机器人采用轮形结构,四驱动力设计,使其能够在复杂地形上获得足够的驱动力。当机器人需要转向或掉头时,左右两侧电机提供不同的转速,利用转速差的原理对小车进行转向或掉头动作,从而实现以极小的转弯半径完成转向及掉头动作。
3.2.2 机械臂
查阅相关资料可知,一般网球直径分布区间为6.541~6.858cm,重量分布区间为56.7~58.5g,按照误差正态分布,在设计时选用直径6.7cm,重量57g作为设计的标准尺寸。为了确保抓取的成功率和可靠性,与网球接触的弧形抓手设计为弦长为80mm,弦高为20mm的圆弧,可以将网球完全包裹。
为了抓取和放置平地上距车身较远的工件,机器人机械臂模仿人类手臂和手指的构造,使用了三个M04舵机:一个控制机械爪,采用齿轮咬合结构,实现对工件的抓取;中间关节的舵机用于伸展机械臂;根部的M04舵机控制整体机械臂的抬升和降落。
3.3 控制方案
该网球收纳机器人有自动和手动两种控制模式,两种模式下的控制方案如下图所示:
3.3.1 自动模式
机器人采取全局遍历算法巡回扫场,如下图所示:
实现方式如下:
1)变量设置:首先,设置一个变量a1作为标记以确定机器人旋转方 向,a1初始值为1。a1值为1为向右旋转,标志为0表示向左旋转。
其次,设置三个距离常量,D1,D2,D3。D3>D2。
用变量d1记录机器人每次旋转后直行距离。
2)具体过程:
①当机器人识别到障碍物时,后退距离D1;
②a1==1?为真向右旋转否则向左旋转,d1=0;
③前进D2
④a1==1?向右旋转否则向左旋转,d1=0;
⑤前进
⑥d1>D3?为真a1取反
这样设计当机器人前进至防护网或者障碍物处会自动变换方向继续搜索,重复这一过程,可以实现对网球场的遍历并且能够排除行至墙角被困住的情况。
该算法的优点是复杂性较低、可靠性高,能显著提高网球的收纳率,缺点是机器人可能会在无球区域耗费很多时间。
机器人通过超声波测距检测有无物体靠近,并确定物体的相对位置,相对位置允许存在6%~10%的误差。若测距结果小于6.5cm,说明有物体靠近,此时读取颜色传感器数据,采用色域识别法对网球进行识别。(色域识别法依靠其简易性在网球识别任务中有很大的优势。)若识别结果为网球,为顺利抓取网球,小车需要缓慢后退,当与网球相距10.3cm时,停止运动并进行抓取。抓取成功后,机械臂伸向车后,机械爪松开将网球抛入框。
机器人的主体搭建基于一个全方位移动平台,检测系统位于平台前端,用于对网球的识别定位,网球信号确认后,系统控制机械手进行抓取动作,抓取确认成功后机械手松开,网球斜抛入框。
3.3.2 手动模式
当自动模式失灵或者网球位于机器人扫场盲区时,操作人员可以通过手动模式遥控机器人。手动模式下,机器人和2.4G手柄通过NRF24L01无线通信模块,实现手柄对机器人移动和机械臂抓取的遥控。
3.4 模块功能
3.4.1 颜色传感器模块
TCS3200是一种全彩的颜色检测器,包括了一块RGB感应芯片TAOSTCS3200和4个白色LED灯,能在一定的范围内检测和测量几乎所有的可见光。
本机器人采用的图像识别分析模型为HSI颜色空间模型,但由于TCS3200颜色传感器采集的图像是RGB格式,所以需要把RGB模型转换为HSI颜色模型。网球的颜色接近绿色,颜色分量Hue范围在45°到90°之间即有可能为网球。
Hue:
3.4.2 超声波模块
HC-SR04超声波模块感应角度不大于15°,探测距离2cm-450cm,精度可达0.2cm。当颜色传感器检测到网球,小车缓慢后退,同时超声波模块对网球进行测距,当与网球相距10.3cm时,机器人停止移动并抓取网球。
3.4.3 触碰模块
触碰模块安装在小车前方,上面有一个按键,可以切换自动模式和手动模式。机器人默认采用自动模式,当自动模式失灵或者网球位于机器人扫场盲区时,操作人员可以通过触碰模块将机器人切换为手动模式。
3.4.4 NRF24L01无线通信模块
nRF24L01是由NORDIC生产的工作在2.4GHz~2.5GHz的ISM频段的单片无线收发器芯片。首先将机器人和手柄上的无线模块调节到相同的通道,依次打开机器人、手柄,即可实现通过2.4G手柄的按键、摇杆对机器人的移动和机械臂的抓取进行遥控。
3.5 调试与测试结果
模拟场景大小为1.2m×1.2m。将机器人切换为自动模式,在测试场地内随机放置20个网球,捡球机器人从网球场一角开始搜索测试场地内的网球。在进行了约3min的自动捡球之后,机器人成功将16个网球捡起,自动捡球模式下的捡球效率达到80%;此时,将机器人切换为手动模式,将另外4个网球捡起,自动模式与手动模式搭配使用可使捡球效率达到100%。共约进行200组相同的测试,总的捡球效率均为100%。随机选取其中10次的数据统计,结果如表1所示。
4. 示例程序
4.1 自动模式
int _ABVAR_1_yuzhi1 = 30 ;
int _ABVAR_2_yuzhi2 = 0 ;
int _ABVAR_3_yuzhi3 = 120 ;
bool _ABVAR_4_stop= false ;
int _ABVAR_5_state = 0 ;
void stop();
void xunzhixian();
void test();
void autocar();
void back();
void hengxian_right();
void push();
void forward();
void turn_right();
void left();
void hengxian_left();
void right();
void turn_left();
void youzhuan();
void setup()
{
pinMode( 10, OUTPUT);
pinMode( 6, OUTPUT);
pinMode( 5, OUTPUT);
pinMode( 9, OUTPUT);
Serial.begin(9600);
_ABVAR_1_yuzhi1 = 150 ;
_ABVAR_2_yuzhi2 = 200 ;
_ABVAR_3_yuzhi3 = 100 ;
_ABVAR_4_stop = HIGH ;
forward();
}
void loop()
{
autocar();
}
void hengxian_right()
{
if (( ( ( analogRead(14) ) >= ( _ABVAR_1_yuzhi1 ) ) && ( ( analogRead(18) ) >= ( _ABVAR_3_yuzhi3 ) ) ))
{
turn_right();
_ABVAR_5_state = ( _ABVAR_5_state + 1 ) ;
}
else
{
xunzhixian();
}
}
void xunzhixian()
{
if (( ( analogRead(18) ) >= ( _ABVAR_3_yuzhi3 ) ))
{
right();
}
else
{
if (( ( analogRead(14) ) >= ( _ABVAR_1_yuzhi1 ) ))
{
left();
}
else
{
forward();
}
}
}
void hengxian_left()
{
if (( ( ( analogRead(14) ) >= ( _ABVAR_1_yuzhi1 ) ) && ( ( analogRead(18) ) >= ( _ABVAR_3_yuzhi3 ) ) ))
{
turn_left();
_ABVAR_5_state = ( _ABVAR_5_state + 1 ) ;
}
else
{
xunzhixian();
}
}
void left()
{
analogWrite(10 , 0);
analogWrite(9 , 160);
analogWrite(6 , 160);
analogWrite(5 , 0);
}
void right()
{
analogWrite(10 , 160);
analogWrite(9 , 0);
analogWrite(6 , 0);
analogWrite(5 , 160);
}
void turn_left()
{
analogWrite(10 , 255);
analogWrite(9 , 0);
analogWrite(6 , 0);
analogWrite(5 , 255);
delay( 800 );
forward();
delay( 1000 );
}
void autocar()
{
forward();
delay( 6000 );
while ( true )
{
if (( ( _ABVAR_5_state ) == ( 0 ) ))
{
hengxian_left();
}
if (( ( _ABVAR_5_state ) == ( 1 ) ))
{
push();
}
if (( ( _ABVAR_5_state ) == ( 2 ) ))
{
hengxian_left();
}
if (( ( _ABVAR_5_state ) == ( 3 ) ))
{
youzhuan();
}
if (( ( _ABVAR_5_state ) == ( 4 ) ))
{
youzhuan();
}
if (( ( _ABVAR_5_state ) == ( 5 ) ))
{
push();
}
if (( ( _ABVAR_5_state ) == ( 7 ) ))
{
hengxian_left();
}
if (( ( _ABVAR_5_state ) == ( 8 ) ))
{
youzhuan();
}
if (( ( _ABVAR_5_state ) == ( 10 ) ))
{
hengxian_right();
}
if (( ( _ABVAR_5_state ) == ( 11 ) ))
{
push();
}
if (( ( _ABVAR_5_state ) == ( 12 ) ))
{
hengxian_left();
}
if (( ( _ABVAR_5_state ) == ( 13 ) ))
{
youzhuan();
}
if (( ( _ABVAR_5_state ) == ( 14 ) ))
{
youzhuan();
}
if (( ( _ABVAR_5_state ) == ( 15 ) ))
{
push();
}
if (( ( _ABVAR_5_state ) == ( 16 ) ))
{
hengxian_left();
}
if (( ( _ABVAR_5_state ) == ( 17 ) ))
{
youzhuan();
}
if (( ( _ABVAR_5_state ) == ( 18 ) ))
{
hengxian_right();
_ABVAR_5_state = 1 ;
}
}
}
void push()
{
forward();
delay( 2000 );
back();
_ABVAR_5_state = ( _ABVAR_5_state + 1 ) ;
}
void stop()
{
analogWrite(10 , 0);
analogWrite(9 , 0);
analogWrite(6 , 0);
analogWrite(5 , 0);
}
void turn_right()
{
analogWrite(10 , 0);
analogWrite(9 , 255);
analogWrite(6 , 255);
analogWrite(5 , 0);
delay( 800 );
forward();
delay( 1000 );
}
void test()
{
Serial.print(analogRead(14));
Serial.println();
Serial.print(analogRead(16));
Serial.println();
Serial.print(analogRead(18));
Serial.println();
delay( 3000 );
}
void back()
{
analogWrite(10 , 0);
analogWrite(9 , 105);
analogWrite(6 , 0);
analogWrite(5 , 105);
}
void youzhuan()
{
if (( ( ( ( analogRead(14) ) < ( _ABVAR_1_yuzhi1 ) ) && ( ( analogRead(18) ) >= ( _ABVAR_3_yuzhi3 ) ) ) && ( ( analogRead(16) ) >= ( _ABVAR_2_yuzhi2 ) ) ))
{
turn_right();
_ABVAR_5_state = ( _ABVAR_5_state + 1 ) ;
}
else
{
xunzhixian();
}
}
void forward()
{
analogWrite(10 , 100);
analogWrite(9 , 0);
analogWrite(6 , 100);
analogWrite(5 , 0);
}
4.2手动模式
① control_mode_code_of_car.ino
#include <Servo.h>
int _ABVAR_1__data = 0 ;
int servo_pin_4 = 4;
int servo_pin_7 = 7;
int servo_pin_3 = 3;
int _ABVAR3 = 20;
int _ABVAR7 = 10;
int _ABVAR4 = 0;
int _ABVAR_2_i = 0 ;
int _ABVAR_3_i = 0 ;
int _ABVAR_4_i = 0 ;
//20 0
//130 100
void Right();
void Up_Close();
void Up_Open();
void Select();
void Down_Open();
void Down_Close();
void Mid_Open();
void Mid_Close();
void Left();
void Stop();
void Back();
void Forward();
void servo3();
void servo4();
void servo7();
void setup()
{
Serial.begin(9600);
pinMode( 5 , OUTPUT);
pinMode( 6 , OUTPUT);
pinMode( 9 , OUTPUT);
pinMode( 10 , OUTPUT);
// servo_pin_4.attach(4);
// servo_pin_7.attach(7);
//servo_pin_3.attach(3);
pinMode(servo_pin_3,OUTPUT);
pinMode(servo_pin_4,OUTPUT);
pinMode(servo_pin_7,OUTPUT);
servo3(_ABVAR3);
servo4(_ABVAR4);
servo7(_ABVAR7);
_ABVAR_1__data = 0 ;
}
void loop()
{
_ABVAR_1__data = Serial.parseInt() ;
Select();
delay( 1 );
}
void Select()
{
Stop();
if (( ( _ABVAR_1__data ) == ( 2 ) ))
{
Back();
}
else if (( ( _ABVAR_1__data ) == ( 1 ) ))
{
Forward();
}
else if (( ( _ABVAR_1__data ) == ( 0 ) ))
{
Stop();
}
else if (( ( _ABVAR_1__data ) == ( 4 ) ))
{
Left();
}
else if (( ( _ABVAR_1__data ) == ( 3 ) ))
{
Right();
}
else if (( ( _ABVAR_1__data ) == ( 5 ) ))
{
Down_Open();
}
else if (( ( _ABVAR_1__data ) == ( 6 ) ))
{
Down_Close();
}
else if (( ( _ABVAR_1__data ) == ( 7 ) ))
{
Mid_Open();
}
else if (( ( _ABVAR_1__data ) == ( 8 ) ))
{
Mid_Close();
}
else if (( ( _ABVAR_1__data ) == ( 9 ) ))
{
Up_Open();
}
else if (( ( _ABVAR_1__data ) == ( 10 ) ))
{
Up_Close();
}
else if (( ( _ABVAR_1__data ) == ( 11 ) ))
{
Down_Close();
}
else if (( ( _ABVAR_1__data ) == ( 12 ) ))
{
Down_Open();
}
else if (( ( _ABVAR_1__data ) == ( 13 ) ))
{
while(_ABVAR3<20)
{
Down_Open();
}
while(_ABVAR3>20)
{
Down_Close();
}
while(_ABVAR7<10)
{
Mid_Open();
}
while(_ABVAR7>10)
{
Mid_Close();
}
}
else if (( ( _ABVAR_1__data ) == ( 14 ) ))
{
while(_ABVAR3<130)
{
Down_Open();
}
while(_ABVAR3>130)
{
Down_Close();
}
while(_ABVAR7<100)
{
Mid_Open();
}
while(_ABVAR7>100)
{
Mid_Close();
}
}
}
void Right()
{
analogWrite(5 , 200);
analogWrite(6 , 0);
analogWrite(9 , 0);
analogWrite(10 , 200);
}
void Stop()
{
analogWrite(5 , 0);
analogWrite(6 , 0);
analogWrite(9 , 0);
analogWrite(10 , 0);
}
void Forward()
{
analogWrite(5 , 100);
analogWrite(6 , 0);
analogWrite(9 , 100);
analogWrite(10 , 0);
}
void Back()
{
analogWrite(5 , 0);
analogWrite(6 , 100);
analogWrite(9 , 0);
analogWrite(10 , 100);
}
void Left()
{
analogWrite(5 , 0);
analogWrite(6 , 200);
analogWrite(9 , 200);
analogWrite(10 , 0);
}
void Down_Open()
{
if(_ABVAR3<180)
{
_ABVAR3 ++;
servo3(_ABVAR3);
delay( 6 );
}
}
void Down_Close()
{
if(_ABVAR3>0)
{
_ABVAR3 --;
servo3(_ABVAR3);
delay( 6 );
}
}
void Mid_Open()
{
if(_ABVAR7<180)
{
_ABVAR7 ++;
servo7(_ABVAR7);
delay( 6 );
}
}
void Mid_Close()
{
if(_ABVAR7>0)
{
_ABVAR7 --;
servo7(_ABVAR7);
delay( 6 );
}
}
void Up_Open()
{
if(_ABVAR4<150)
{
_ABVAR4 ++;
servo4(_ABVAR4);
delay( 6 );
}
}
void Up_Close()
{
if(_ABVAR4>0)
{
_ABVAR4 --;
servo4(_ABVAR4);
delay( 6 );
}
}
void servo7(int angle)
{
for(int i=0;i<6;i++)
{
int pulsewidth = (angle * 11) + 500;
digitalWrite(servo_pin_7, HIGH);
delayMicroseconds(pulsewidth);
digitalWrite(servo_pin_7, LOW);
delayMicroseconds(20000 - pulsewidth);
}
}
void servo4(int angle)
{
for(int i=0;i<6;i++)
{
int pulsewidth = (angle * 11) + 500;
digitalWrite(servo_pin_4, HIGH);
delayMicroseconds(pulsewidth);
digitalWrite(servo_pin_4, LOW);
delayMicroseconds(20000 - pulsewidth);
}
}
void servo3(int angle)
{
for(int i=0;i<6;i++)
{
int pulsewidth = (angle * 11) + 500;
digitalWrite(servo_pin_3, HIGH);
delayMicroseconds(pulsewidth);
digitalWrite(servo_pin_3, LOW);
delayMicroseconds(20000 - pulsewidth);
}
}
② control_mode_code_of_controller.ino
int _ABVAR_1_Ctrl_Val_1 = 0 ;
int _ABVAR_2_Ctrl_Val_2 = 0 ;
int _ABVAR_3_A0Value = 0 ;
int _ABVAR_4_A1Value = 0 ;
int _ABVAR_5_A2Value = 0 ;
int _ABVAR_6_A3Value = 0 ;
void VAL_caculate();
void ADGet();
void SerialPrint();
void setup()
{
Serial.begin(9600);
}
void loop()
{
ADGet();
VAL_caculate();
SerialPrint();
delay( 50 );
}
void SerialPrint()
{
if( ( _ABVAR_1_Ctrl_Val_1 ) == ( 9 ) )
{
if( ( _ABVAR_2_Ctrl_Val_2 ) == ( 3 ) )
{
Serial.print("0");
Serial.println();
}
else if( ( _ABVAR_2_Ctrl_Val_2 ) == ( 1 ) )
{
Serial.print("1");
Serial.println();
}
else if( ( _ABVAR_2_Ctrl_Val_2 ) == ( 2 ) )
{
Serial.print("2");
Serial.println();
}
else if( ( _ABVAR_2_Ctrl_Val_2 ) == ( 4 ) )
{
Serial.print("3");
Serial.println();
}
else if( ( _ABVAR_2_Ctrl_Val_2 ) == ( 5 ) )
{
Serial.print("4");
Serial.println();
}
}
if ( ( _ABVAR_1_Ctrl_Val_1 ) == ( 6 ) )
{
if ( ( _ABVAR_2_Ctrl_Val_2 ) == ( 2 ) )
{
Serial.print("5");
Serial.println();
}
else if ( ( _ABVAR_2_Ctrl_Val_2 ) == ( 1 ) )
{
Serial.print("6");
Serial.println();
}
}
if ( ( _ABVAR_1_Ctrl_Val_1 ) == ( 10 ) )
{
if( ( _ABVAR_2_Ctrl_Val_2 ) == ( 2 ) )
{
Serial.print("7");
Serial.println();
}
else if ( ( _ABVAR_2_Ctrl_Val_2 ) == ( 1 ) )
{
Serial.print("8");
Serial.println();
}
}
if ( ( _ABVAR_1_Ctrl_Val_1 ) == ( 7 ) )
{
if( ( _ABVAR_2_Ctrl_Val_2 ) == ( 1 ) )
{
Serial.print("9");
Serial.println();
}
else if( ( _ABVAR_2_Ctrl_Val_2 ) == ( 2 ) )
{
Serial.print("10");
Serial.println();
}
}
if ( ( _ABVAR_1_Ctrl_Val_1 ) == ( 10 ) )
{
if( ( _ABVAR_2_Ctrl_Val_2 ) == ( 4 ) )
{
Serial.print("11");
Serial.println();
}
else if( ( _ABVAR_2_Ctrl_Val_2 ) == ( 5 ) )
{
Serial.print("12");
Serial.println();
}
else if( ( _ABVAR_2_Ctrl_Val_2 ) == ( 3 ) )
{
Serial.print("0");
Serial.println();
}
}
if( (digitalRead(2)) == ( 0 ) )
{
Serial.print("13");
Serial.println();
}
if( (digitalRead(3)) == ( 0 ) )
{
Serial.print("14");
Serial.println();
}
}
void VAL_caculate()
{
if (( ( ( _ABVAR_3_A0Value ) == ( 0 ) ) && ( ( _ABVAR_4_A1Value ) == ( 1 ) ) ))
{
_ABVAR_1_Ctrl_Val_1 = 7 ;
}
if (( ( ( _ABVAR_3_A0Value ) == ( 1 ) ) && ( ( _ABVAR_4_A1Value ) == ( 0 ) ) ))
{
_ABVAR_1_Ctrl_Val_1 = 9 ;
}
if (( ( ( _ABVAR_3_A0Value ) == ( 1 ) ) && ( ( _ABVAR_4_A1Value ) == ( 1 ) ) ))
{
_ABVAR_1_Ctrl_Val_1 = 8 ;
}
if (( ( ( _ABVAR_3_A0Value ) == ( 1 ) ) && ( ( _ABVAR_4_A1Value ) == ( 2 ) ) ))
{
_ABVAR_1_Ctrl_Val_1 = 10 ;
}
if (( ( ( _ABVAR_3_A0Value ) == ( 2 ) ) && ( ( _ABVAR_4_A1Value ) == ( 1 ) ) ))
{
_ABVAR_1_Ctrl_Val_1 = 6 ;
}
if (( ( ( _ABVAR_5_A2Value ) == ( 4 ) ) && ( ( _ABVAR_6_A3Value ) == ( 5 ) ) ))
{
_ABVAR_2_Ctrl_Val_2 = 2 ;
}
if (( ( ( _ABVAR_5_A2Value ) == ( 5 ) ) && ( ( _ABVAR_6_A3Value ) == ( 4 ) ) ))
{
_ABVAR_2_Ctrl_Val_2 = 4 ;
}
if (( ( ( _ABVAR_5_A2Value ) == ( 5 ) ) && ( ( _ABVAR_6_A3Value ) == ( 5 ) ) ))
{
_ABVAR_2_Ctrl_Val_2 = 3 ;
}
if (( ( ( _ABVAR_5_A2Value ) == ( 5 ) ) && ( ( _ABVAR_6_A3Value ) == ( 6 ) ) ))
{
_ABVAR_2_Ctrl_Val_2 = 5 ;
}
if (( ( ( _ABVAR_5_A2Value ) == ( 6 ) ) && ( ( _ABVAR_6_A3Value ) == ( 5 ) ) ))
{
_ABVAR_2_Ctrl_Val_2 = 1 ;
}
}
void ADGet()
{
_ABVAR_3_A0Value = analogRead(14) ;
_ABVAR_4_A1Value = analogRead(15) ;
_ABVAR_5_A2Value = analogRead(16) ;
_ABVAR_6_A3Value = analogRead(17) ;
_ABVAR_3_A0Value = map ( _ABVAR_3_A0Value , 0 , 1024 , 0 , 3 ) ;
_ABVAR_4_A1Value = map ( _ABVAR_4_A1Value , 0 , 1024 , 0 , 3 ) ;
_ABVAR_5_A2Value = map ( _ABVAR_5_A2Value , 0 , 1024 , 4 , 7 ) ;
_ABVAR_6_A3Value = map ( _ABVAR_6_A3Value , 0 , 1024 , 4 , 7 ) ;
}
5. 作品创新点
5.1 技术创新点
5.1.1 防碰撞安全系统-超声波与颜色传感器的使用
机器人在使用过程中可能会与人员或障碍物发生碰撞,为了提高安全性,减少损伤,我们增加了超声波模块,在机器人运动时进行物体的检测。当机器人前方出现物体时,超声波模块检测出遮挡,颜色传感器进行识别,确认物体非网球,则机器人进行避障操作,有效防止因碰撞而造成的损失,更有利于机器人在实际场景进行工作,提高机器人应用的稳定性。
5.1.2 基于颜色传感器与超声波传感器的物体识别与测距
为了完成对目标物体的识别与抓取,我们在机器人前方安装了探索者套件中的颜色传感器。颜色传感器将物体颜色同前面已经示教过的参考颜色进行比较来检测颜色,当前方物体颜色与内设颜色(这里就是网球的颜色)在一定的误差范围内相吻合时,输出检测结果。如果前方物体颜色与内置颜色符合则进行抓取操作,不符合则进行避障操作。在识别到网球后,我们利用超声波传感器进行与目标物体距离的检测,从而能有效控制机器人与网球的距离,使对网球的抓取能够成功。
由于网球场的环境较为空旷,场景物品较少,场景颜色较为单一,所以在这一场景下利用颜色模块进行物体检测这一设计可以在尽可能降低成本并且保证准确率的情况下实现对物体的识别与检测。这一设计相较于其他如利用红外检测进行识别更具分辨性,更符合只识别收集网球的要求,并且相比于利用相机进行检测的方式成本更低。
5.1.3 自动+手动双模式
针对自动模式下可能遗漏部分角落处网球问题,我们加入了手动模式。在手动模式下,可以遥控机器人进行网球收纳,实现场地全识别,不遗漏任何网球。自动为主,手动为辅,两模式双辅双成,实现目标100%检测收纳。
5.2 设计创新点
目前机器人的研究已经十分深入,机器人技术与机器人产品已十分成熟,人们现在迫切需要的是如何将现有的机器人产品与技术应用于实际生活生产,将机器人产品产业化。我们基于此,细心观察生活细节,立足于大众日常生活,发现了将机器人运用于器械收纳这一方面的空白与应用价值。
基于高校的网球场地大且空旷,网球较小且弹力大,训练时使用量大,每次打完网球后会有大量网球散布场地各地不方便检拾,这一令网球爱好者与网球训练者头疼的问题提出了自动网球收纳机器人这一想法。区别于市面上需要人员推动找到网球所在地的“半自动化”网球收纳机器人,该网球收纳机器人可以在无人指挥情况下进行自主器械收纳,具有高度自主性,彻底解放用户。并且,机器人的手动与自动两挡模式可以针对自动模式下的未识别物体进行遥控抓取收纳,更好的实现网球收纳不遗漏,高质量完成场地网球收纳任务。
外观设计上,我们在机器人的前端安装了两个向斜外方向延伸的直杆,这样设计可以在机器人运动时将前方区域物体带至前方检测区。在方便机器人检测的同时,增大了机器人扫场检测的检测范围,能够更好的提高机器人工作效率。机器人整体材质坚硬,结构坚固,机身小巧,方便运输,不易损坏,可很好的适用于多种场地,多种环境,具有优秀的环境适用性与稳定性。立足于体育领域,将机器人应用于器械收纳的这种创新性想法可以大大方便人们的体育活动生活,提升体育运动幸福度。
6. 作品难点及解决方案
6.1 遇到的问题
6.1.1 机器人全局遍历问题
首先,由于场地相对于机器人来说较大,网球散落点多且不定,所以需要机器人具有良好的全局遍历能力才能对场地实现较好的搜索,识别到场地上全部散落网球。但是如何规划,才能让机器人在成本较低,没有安装摄像头,没有导航的情况下实现良好的全局遍历这是一个棘手的问题。
6.1.2 目标物体识别问题
在不依赖摄像头的情况下,实现对目标物体也就是网球的识别,这同样是一个难题。由于目标物体体积较小,且运动自由度高,对目标物体的识别难度较高。
6.1.3 物体抓取问题
在目标物体成功识别之后,如何使机械臂抓取到目标物体也是一大难题。
6.1.4 自动模式下,部分网球未识别问题
在自动模式下,小车进行遍历,检测场地内所有目标物体,但是有时仍可能出现场地部分角落位置网球遗落问题。
6.2 解决方案
6.2.1 对于机器人遍历问题的解决
在基于网球场地的环境调研与思考以后,我们想到了利用好环境特点。由于网球弹力较大,所以网球场几乎全部在四周安装防护网,以防止球被打击至网球场外部区域,对于高校,网球场区域的防护措施做得更为完善。我们实地考察了几所高校,山东大学(威海)、哈工大(威海)、重庆大学,在校园网球场四周都设置有防护网。
所以,基于这种环境特点,我们决定在机器人身上安装超声波传感器,当机器人检测到前方有遮挡时,颜色传感器进行检测,当颜色非绿色时,识别物体为障碍物,启动避障措施。机器人后退,旋转一定角度,前进一小段距离,向后旋转,再继续前进的动作。为了确定具体旋转方向,这里我们设置一个变量作为标记,初始小车行驶时标志为1,表示向右旋转。0表示向左旋转。当遇到障碍物时,后退,根据标志数值进行旋转,前进一小段距离D1,旋转,继续前进。当继续前进距离大于一定距离时(这段距离大于D1)将标志取反。这样设计当机器人前进至防护网或者障碍物处时会自动变换方向继续搜索,重复这一过程,可以实现对网球场的遍历。这样的设计也能防止机器人运动至墙角被困住。
6.2.2 对于目标识别问题的解决方案
由于网球场场地空旷,场地物体较少,场地颜色单一,所以我们提出了基于颜色传感器进行目标物体检测的想法。我们利用颜色传感器,内设目前物体网球的颜色信息,让机器人能够通过检测目标物体颜色来实现目标物体的检测。同时,针对网球体积小不利于检测这一问题,我们将颜色传感器安装于机器人前端较低位置处,由于机器人本身体积小巧,这样的安排可以使得机器人能够更为灵敏地识别到地上物体颜色,完成对于地上网球的识别。
6.2.3 对物体抓取问题的解决方案
我们在机器人前端放置了超声波传感器,由于超声波传感器可以检测与物体距离,所以利用超声波传感器检测机械臂与目标物体的距离,超声波传感器将距离信息实时传输,算法调整机械臂位置姿态,直至触碰目标物体,进行抓取。
6.2.4 对部分网球遗漏问题的解决方案
针对自动识别模式下可能出现的部分网球遗落问题,我们加入了手动模式。追加遥控功能辅助,在部分网球未识别成功时,进行手动识别。利用遥控器操控机器人到达遗漏网球处,进行抓取。
7. 机器人目前不足与后续改良
目前机器人的主要不足在于避障与物体识别功能基于一些传感器,虽然可以完成规定任务但是智能性可以进一步提高。后续可以加上摄像模块,通过摄像头记录场景信息,并且通过模式识别算法识别筛选出网球位置,计算出目标距离,向机器人发送运动与后续指令。
8. 后续应用发展
前期,该网球收纳机器人主要设想在对新智能技术包容与接受度较高的高校进行使用,但如果前期发展良好,一段时间后可以将目光投向其他网球使用环境,如网球俱乐部,网球训练基地等。由于机器人本身轻便、方便转移的特点,可以实现在多个场地的切换,大大地提高其利用率。
将机器人应用于体育行业,将智能技术融入体育生活这一想法是未来体育行业的一大期待趋势,其发展潜力无限。并且,只需要稍微的改动,机器人也可应用于对羽毛球与乒乓球等其他小型球类的收纳,但由于羽毛球与乒乓球等收纳困难度相较于网球较小,所以这一领域可以在后续机器人的应用已初具规模,成本进一步下降的时候涉及。
最后,我们的机器人不止可以收纳网球,只需要作进一步的算法与设备调整(如加装摄像头,加入模式识别算法),机器人可以检测并收集人们希望收集的小型物品,如地面上被丢弃的垃圾,有害物品等,实现向更多领域的突破。
*更多资料请见:【S036】网球收纳机器人