上一篇,我们为6足虫的制作提前准备研究了下 舵机的使用 ,这次,我们开始动手,实现我们的机械6脚虫虫。
准备的材料如下:
3个舵机(用于控制虫子的6条腿)、1个有一定硬度的铁丝(我用的铁质衣撑,用于制作6条腿)、1个核桃露瓶子(用于做虫身)、1个红外线发射和接收器(用于遥控)、1个led灯(用于遥控按下提示灯)、1个220的电阻、1块arduino uno板子及若干连接线。
思路:
由于上一篇 舵机的使用 已经为虫虫的制做做的准备,所以不再赘述,这次相当于在上一次的基础上,改进控制代码,增加遥控器c键初始化虫子脚;play键让虫子向前爬5步。
为了搞清楚虫子的腿应该怎么爬,我跟儿子一起趴床上假装老虎爬了一会儿,得出一个4腿动物的移动方法:左前腿->右后腿->右前腿->左后腿。
按这个思路实现了控制腿的代码逻辑后,用硬纸把舵机粘一起反复测试调角度参数,让它能向前爬动。测试发现4条腿遇到障碍物时容易侧翻,所以又在中间加了两条腿,变成的6脚虫。
之后儿子又提出能不能让虫子自己去外边爬,就一起顺便给虫子用核桃露瓶做了个外壳,把舵机用强力胶粘上去固定好(因为要背电池和板子,比较重),然后用两节18650 锂离子电池串联起来代替电脑usb供电(正极接到VIN端口、负极接到GND端口),再让虫子自己背着电路板和电池。由于负重后压力太大,舵机和腿掉了好几次,后来干脆把腿用502粘到舵机齿轮上了,再根据爬行情况调一下腿和角度参数,反复测试后终于成功,儿子很开心,还用他的超轻彩泥给虫子做了几个脚,哈哈。
v1.0硬纸版效果:
v1.1独自负重版:
(4个腿和6个腿在平地上爬行效果差不多,区别在一侧遇到障碍物时,6脚不容易侧翻)
代码如下:
#include <IRremote.h>//包含红外库
int infraredPin = 3;//红外线接收器端口
long INFRARED_PLAY = 0x00FFA857;//红外遥控器上的PLAY键指令
long INFRARED_LEFT = 0x00FFE01F;//红外遥控器上的左键指令
long INFRARED_RIGHT = 0x00FF906F;//红外遥控器上的右键指令
long INFRARED_UP = 0x00FF02FD;//红外遥控器上的上键指令
long INFRARED_DOWN = 0x00FF9867;//红外遥控器上的下键指令
long INFRARED_C = 0x00FFB04F;//红外遥控器上的C指令
int servo1Pin = 7;//舵机端口(前腿)
int servo2Pin = 8;//舵机端口(后腿)
int servo3Pin = 9;//舵机端口(中腿)
int ledPin = 4; //led端口
int servo1Angle = 0;//当前舵机角度(0-180)
int servo2Angle = 0;//当前舵机角度(0-180)
int servo3Angle = 0;//当前舵机角度(0-180)
int initAngle = 90;//默认舵机角度
IRrecv irrecv(infraredPin);//初始化红外接收器对象
decode_results results;//定义results变量为红外结果存放位置
void setup() {
//红外接收器端口初始化
pinMode(infraredPin, INPUT);
//舵机端口初始化
pinMode(servo1Pin, OUTPUT);
pinMode(servo2Pin, OUTPUT);
pinMode(servo3Pin, OUTPUT);
//led端口初始化
pinMode(ledPin, OUTPUT);
//波特率9600
Serial.begin(9600);
//启动红外解码
irrecv.enableIRIn();
//初始化6条腿的位置
led(ledPin, HIGH);
servopulse(servo1Pin, initAngle, 30);
servopulse(servo2Pin, initAngle, 30);
servopulse(servo3Pin, initAngle, 30);
led(ledPin, LOW);
}
void loop() {
//检测红外信号
int domove = false;
int stepval = 1;
int delayval = 0;
if (irrecv.decode(&results)) {//是否接收到解码数据,把接收到的数据存储在变量results中
Serial.println(results.value, HEX);//接收到的数据以16进制的方式在串口输出//接收到的数据以16进制的方式在串口输出
if (results.value == INFRARED_C ) {//遥控器按下了c键,重置虫子的前后舵机
stepval = 30;
led(ledPin, HIGH);
servopulse(servo1Pin, initAngle, stepval);
servopulse(servo2Pin, initAngle, stepval);
servopulse(servo3Pin, initAngle, stepval);
} else if (results.value == INFRARED_PLAY ) {//遥控器按下了PLAY键,虫子向前爬
//7舵机:前腿;8舵机:后腿
stepval = 10;
delayval = 10;
led(ledPin, HIGH);
for (int i = 0; i < 5; i++) {//连爬5次
Serial.print("moving play ");
Serial.print(i);
servo1Angle = constrain(initAngle - 15, 0, 180);
servo2Angle = constrain(initAngle + 15, 0, 180);
servo3Angle = constrain(initAngle - 10, 0, 180);
servopulse(servo1Pin, servo1Angle, stepval, delayval);
servopulse(servo2Pin, servo2Angle, stepval, delayval);
servopulse(servo3Pin, servo3Angle, stepval, delayval);
servo1Angle = constrain(initAngle + 15, 0, 180);
servo2Angle = constrain(initAngle - 15, 0, 180);
servo3Angle = constrain(initAngle + 10, 0, 180);
servopulse(servo1Pin, servo1Angle, stepval, delayval);
servopulse(servo2Pin, servo2Angle, stepval, delayval);
servopulse(servo3Pin, servo3Angle, stepval, delayval);
}
}
/* else if (results.value == INFRARED_LEFT ) {//遥控器按下了左键,转到最左边
domove = true;
servo1Angle = 180;
servo2Angle = 180;
servo3Angle = 180;
stepval = 30;
} else if (results.value == INFRARED_RIGHT ) {//遥控器按下了右键,转到最右边
domove = true;
servo1Angle = 0;
servo2Angle = 0;
servo3Angle = 0;
stepval = 30;
} else if (results.value == INFRARED_UP ) {//遥控器按下了上键,左转20度
domove = true;
servo1Angle = constrain(servo1Angle + 20, 0, 180);
servo2Angle = constrain(servo2Angle + 20, 0, 180);
servo3Angle = constrain(servo3Angle + 20, 0, 180);
stepval = 10;
} else if (results.value == INFRARED_DOWN ) {//遥控器按下了下键,右转20度
domove = true;
servo1Angle = constrain(servo1Angle - 20, 0, 180);
servo2Angle = constrain(servo2Angle - 20, 0, 180);
servo3Angle = constrain(servo3Angle - 20, 0, 180);
stepval = 10;
}*/
}
/*//舵机移动
if (domove == true) {
led(ledPin, HIGH);
servopulse(servo1Pin, servo1Angle, stepval);
servopulse(servo2Pin, servo2Angle, stepval);
servopulse(servo3Pin, servo3Angle, stepval);
}*/
//继续等待接收下一组信号
irrecv.resume();
//led熄灭
delay(200);
led(ledPin, LOW);
}
/* 向舵机发送移动角度指令 */
void servopulse(int pin, int angle, int stepval){
servopulse( pin, angle, stepval, 0);
}
void servopulse(int pin, int angle, int stepval, int delayval){
angle = constrain(angle, 0, 180);
Serial.print("moving servo to ");
Serial.print(angle, DEC);
Serial.print(" ");
int pulsewidth = angle * 8 + 400 ; //将角度转化为400-1900 的脉宽值
Serial.println(pulsewidth);
for (int i = 0; i < stepval; i++) {
digitalWrite(pin, HIGH); //将舵机接口电平置高
delayMicroseconds(pulsewidth);//延时脉宽值的微秒数
digitalWrite(pin, LOW); //将舵机接口电平置低
delay(20 - pulsewidth / 1000); //延时周期内剩余时间
}
delay(delayval);
}
/* 控制led灯亮起或熄灭 */
void led(int pin, int output) {
digitalWrite(pin, output);
//delay(500);
}
下一步,计划增加超声障碍物探测及自动转向功能。先休息一下,帮儿子把他的螺旋桨弄好。。。
yan 2016.9.25 14:38