小猪学arduino—机械6足虫的制作

上一篇,我们为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硬纸版效果:

111

v1.1独自负重版:

(4个腿和6个腿在平地上爬行效果差不多,区别在一侧遇到障碍物时,6脚不容易侧翻)img_3861 img_3864

代码如下:

#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

发表评论

电子邮件地址不会被公开。