软件
- 核心类库
hexapod_bionic_robot.h
该头文件定义了
HexapodBionicRobot
类,里面声明了机器人避障、处理红外编码信息、处理超声波距离、获取红外编码信息、获取超声波距离和移动机器人躯体等核心函数。
#ifndef HEXAPOD_BIONIC_ROBOT_H #define HEXAPOD_BIONIC_ROBOT_H #include
#include
#define PIN_IR 2 #define PIN_TX 3 #define PIN_RX 4 #define PIN_TRIG 5 #define PIN_ECHO 6 #define PIN_LED 13 #define DIR_INIT 1 #define DIR_STOP 1 #define DIR_FRONT 2 #define DIR_BACK 3 #define DIR_LEFT 4 #define DIR_RIGHT 5 #define MODE_REMOTE 25 #define MODE_AUTO 26 #define RADIX 10 #define RUNTIME 2400 #define TIMEOUT 30000 class HexapodBionicRobot { public: HexapodBionicRobot(IRrecv *ir_receiver, decode_results *ir_results); void avoidFrontObstacle(void); void handleInfraredInformation(void); void handleUltrasonicDistance(void); void moveRobotBody(uint8_t direction, uint8_t times); uint32_t getInfraredInformation(void); float getUltrasonicDistance(void); private: int mode_flag_; float duration_; float distance_; IRrecv *ir_receiver_; decode_results *ir_results_; }; #endif // HEXAPOD_BIONIC_ROBOT_H
hexapod_bionic_robot.cpp
该源文件实现了
HexapodBionicRobot
类里面所有已经声明的函数,其中
getInfraredInformation()
函数调用了官方的
IRremote
库,可以实时获取红外遥控器所发送的红外编码,而
handleInfraredInformation()
函数则会将获取到的红外编码与已经定义好的进行比对,若符合则跳转入相应的代码块进行处理(机器人前后左右的移动,以及遥控模式或自动模式切换等),当然程序也会通过调用
avoidFrontObstacle()
函数来判断是否在遥控六足机器人移动的过程中,机器人前方的障碍物距离躯体较近,若距离小于事先设定的阈值,机器人便会自动后退或停止以进行避让。
#include "hexapod_bionic_robot.h" #define DEBUG 1 HexapodBionicRobot::HexapodBionicRobot(IRrecv *ir_recviver, decode_results *ir_results) : ir_receiver_(ir_recviver), ir_results_(ir_results) { pinMode(PIN_LED, OUTPUT); pinMode(PIN_TRIG, OUTPUT); pinMode(PIN_ECHO, INPUT); mode_flag_ = MODE_REMOTE; duration_ = 0.0; distance_ = 0.0; } void HexapodBionicRobot::avoidFrontObstacle(void) { float distance = getUltrasonicDistance(); Serial.println(distance); if (distance == false) { return ; } else if (distance
<=2 .5) { moveRobotBody(DIR_STOP, 2); } else if (distance <=5 .0) { moveRobotBody(DIR_BACK, 2); } } void HexapodBionicRobot::handleUltrasonicDistance(void) { float distance=g etUltrasonicDistance(); if (distance==f alse) { return ; } else if (distance <=5 .0) { digitalWrite(PIN_LED, HIGH); #if DEBUG Serial.println( "Warning! Distance is too close!!!"); #endif } else { digitalWrite(PIN_LED, LOW); } #if DEBUG Serial.print( "Distance: "); Serial.print(distance); Serial.println( "cm"); #endif delay(100); } void HexapodBionicRobot::handleInfraredInformation(void) { float distance=0 .0; uint32_t ir_results=g etInfraredInformation(); if (ir_results==f alse) { return ; } else { #if DEBUG Serial.print( "Infrared code: "); Serial.println(ir_results, HEX); #endif if (ir_results==0 XFF629D) { mode_flag_=M ODE_REMOTE; } else if (ir_results==0 XFFE21D) { mode_flag_=M ODE_AUTO; } if (mode_flag_==M ODE_REMOTE) { digitalWrite(PIN_LED, LOW); if (ir_results==0 xFF02FD) { moveRobotBody(DIR_FRONT, 2); delay(RUNTIME); } else if (ir_results==0 xFF9867) { moveRobotBody(DIR_BACK, 2); delay(RUNTIME); } else if (ir_results==0 xFFE01F) { moveRobotBody(DIR_LEFT, 2); delay(RUNTIME); } else if (ir_results==0 xFF906f) { moveRobotBody(DIR_RIGHT, 2); delay(RUNTIME); } else if (ir_results==0 xFFA857) { moveRobotBody(DIR_STOP, 2); delay(RUNTIME); } avoidFrontObstacle(); } else if (mode_flag_==M ODE_AUTO) { digitalWrite(PIN_LED, HIGH); while (ir_results !=0 XFF629D) { ir_results=g etInfraredInformation(); moveRobotBody(DIR_FRONT, 2); delay(RUNTIME); avoidFrontObstacle(); } mode_flag_=M ODE_REMOTE; } } } void HexapodBionicRobot::moveRobotBody(uint8_t direction, uint8_t times) { char string_direction[5]; char string_times[5]; itoa(direction, string_direction, RADIX); itoa(times, string_times, RADIX); Serial.print( "#"); Serial.print(string_direction); Serial.print( "G"); Serial.print(string_times); Serial.println( "C"); } uint32_t HexapodBionicRobot::getInfraredInformation(void) { if (ir_receiver_->decode(ir_results_)) { ir_receiver_->resume(); return ir_results_->value; } else { return false; } } float HexapodBionicRobot::getUltrasonicDistance(void) { duration_ = 0.0; distance_ = 0.0; digitalWrite(PIN_TRIG, LOW); delayMicroseconds(10); digitalWrite(PIN_TRIG, HIGH); delayMicroseconds(10); digitalWrite(PIN_TRIG, LOW); duration_ = pulseIn(PIN_ECHO, HIGH, TIMEOUT); if (duration_ == 0.0) { return false; } else { distance_ = duration_ * 0.017; return distance_; } }
- 测试代码
hexapod_bionic_robot_test.ino
该测试代码的原理非常简单,首先
setup()
函数会以115200的
波特率
初始化并打开串口,然后Arduino Nano会向串口发送
#1G2C
(1号动作组循环运行2次)让六足机器人站立起来,紧接着程序会使能红外接收管,让其可以接收遥控器发送的红外编码。等初始化结束后,主程序会跳转到
loop()
函数执行
HexapodBionicRobot
类对象的
handleInfraredInformation()
函数完成红外遥控以及超声波避障等功能。
#include
#include
IRrecv g_ir_receiver(PIN_IR); decode_results g_ir_results; void setup() { Serial.begin(115200); Serial.println("#1G2C"); g_ir_receiver.enableIRIn(); } void loop() { HexapodBionicRobot hexapod_bionic_robot(&g_ir_receiver, &g_ir_results); hexapod_bionic_robot.handleInfraredInformation(); }
成果
以下是制作完成后的成果图和测试视频:
总结
回想起当初,自己就是看了 六足机器昆虫-你的下一个足式移动机器人这篇教程才开始迷上六足机器人的,没想到大四快毕业的时候自己能有机会完成这个属于自己的六足仿生机器人,说实话当看到六足机器人第一次从团身状态下依靠自己的力量站立起来时,我的内心是无比激动的,尽管由于舵机的力矩偏小导致机器人的足体在支撑地面时会有轻微吱吱的抖动,但是得益于十八个关节自由度,六足机器人可以做出很多机器人都无法做出的复杂动作,我想这也许就是多足机器人的魅力所在吧!
不过话说回来,对于机器人初学者来说,制作一个六足机器人的难度相较于轮式机器人还是非常大的,而且投入的时间和资金成本也比较多。如果你的动手能力和技术水平足够强,且跟我一样认为六足机器人非常酷的话,你也可以尝试去做一台属于自己的六足机器人并为它扩展更多有意思的功能(比如我加入了MPU6050和HMC5883L模块来做机器人运动感知与矫正,可惜因时间有限没能实现)。最后我总结一下能成功自制六足机器人所需要的三个关键因素:1、从始至终发自内心的热爱;2、拥有机械、电子和软件方面的专业知识;3、为实现最终目标而坚持不懈的努力!
作者:机器小子myyerrol,首发:知乎