六足虫虫机器人高级玩法
虫虫机器人模型(300px)
目录
1 简介
2 产品规格
3 配送清单
4 教程
4.1 必备工具
4.2 组装步骤
5 虫虫代码
5.1 自动模式
5.1.1 自动模式代码
5.1.2 函数说明
简介
如果有一只“虫”会让你爱不释手,那就是这款虫虫机器人六足版了!
新版虫虫用3个微型舵机的协调摆动来行走,通过红外测距来感知环境,还能够感知周围的光线亮度。另外,新版虫虫的中枢依旧是一颗强大的Beetle控制器和扩展板,而且是利用简单易用的Arduino来编程。所有这些功能让虫虫的行走更加复杂,互动更加丰富。可以实现前进、后退、避障拐弯、巡光等功能。 简单的组装让你了解最基本的机器人原理和智能控制。喜欢DIY的用户还可以在原有代码的基础上改造出自己的互动模式。所以,其实打造一款机器人并没有那么难啦。产品规格
工作电压:5-6.4V(4节7号干电池)
控制器:Bluno Beetle (Bootloader: Arduino UNO)
组装后尺寸:180x153X120mm
重量:240g
配送清单
主控模组 (Bluno Beetle+Bluno Beetle shield) X1
9g Micro Servo X3
GP2Y0A21 距离传感器 X1
传感器支架 X1
2节7号电池盒 X2
热缩管-黑色-直径6mm-100mm长 X1
T型胶塞-规格M4 X8
钢丝200mm x 1mm X3
舵机连接器 X1
白色泡沫双面胶(L/W/H:78x61x3mm) X1
数字传感器线 X2
扎线带1.8x100mm X3
高品质 micro USB数据线 X1
安装说明书 x1
教程
按照我们的步骤,您将会制作出属于您自己的虫虫机器人。
必备工具
螺丝刀
螺丝刀,是机器人制作非常必要的工具。不用多说,用来拧螺丝的。建议你可以买一套完整的螺丝刀套件。面对不同型号的螺丝,使用起来就得心应手了。
尖嘴钳
这里用于弯曲钢丝用的,尽量少用手去折铁丝。尖嘴钳还常用于剪掉一些多余的线。
剪刀
剪刀用来剪贴纸和材料的。
组装步骤
详细组装步骤
虫虫机器人教程.pdf
虫虫代码
自动模式
自动模式代码
#include <Servo.h>
// creating the servo objects for front, rear and mid servo
Servo frontLeg;
Servo rearLeg;
Servo midLeg;
// setting the servo angle to 90° for startup
byte frontAngle = 90;
byte rearAngle = 90;
byte midAngle = 90;
// setting the delay value
byte delayWalk = 2;
byte delayTurn = 3;
// Analog sensor pins
int distanceSensor = A1;
int lightSensorLeft = A2;
int lightSensorRight = A0;
// Analog sensor reading
int sensorValue = 0;
// Values
int sensorValueLeft = 0;
int sensorValueRight = 0;
int left = 0;
int right = 0;
// Change the following value to decrease or increase the sensitivity.
// Bigger value for lower sensitivity and smaller value for highter sensitivity
int lightDifference = 60;
// Decrease the danger value when you want to INCREASE the collision trigger distance.
// Increase the danger value when you want to DECREASE the collision trigger distance
int danger = 450; // Increase this value when you want to DECREASE the collision trigger distance
// Arrays for sensor reading average calculation
int leftReadings[11];
int rightReadings[11];
// Booleans for decision
boolean lightLeft = false;
boolean lightRight = false;
// Setup function
void setup(){
// serial connection for debugging
Serial.begin(9600);
// attaching the servos to their pins
frontLeg.attach(9);
rearLeg.attach(10);
midLeg.attach(11);
// move servos to center position -> 90°
frontLeg.write(frontAngle);
rearLeg.write(rearAngle);
midLeg.write(midAngle);
delay(2000);
}
// Light detection and filtering
void scan()
{
int i;
// Take 5 readings on each sensor
for (i = 0; i < 11; i = i + 1) {
// read the value from the left and right sensor:
sensorValueLeft = analogRead(lightSensorLeft);
sensorValueRight = analogRead(lightSensorRight);
// add sensor readings of both sides to their respective array
leftReadings[i] = sensorValueLeft;
rightReadings[i] = sensorValueRight;
}
// calculate an average value for left and right sensor readings
// Sorting the left light sensor values
sort(leftReadings,11);
left = leftReadings[5];
sort(rightReadings,11);
right = rightReadings[5];
}
// Sort the array ascending
void sort(int a[], int size) {
for(int i=0; i<(size-1); i++) {
for(int o=0; o<(size-(i+1)); o++) {
if(a[o] > a[o+1]) {
int t = a[o];
a[o] = a[o+1];
a[o+1] = t;
}
}
}
}
// Desision depending on the light values
void decision(){
// Call the scan function to provide the sensor values of the left and right light sensor
scan();
// Compare the values and make a decision according the difference value
if (left > right){
// subtract right from left value to get a value to work with
left = left-right;
// check if that previous calculated value is greater than 50
if (left > lightDifference) // I will call this "Inside IF 1" in further comments.
{
lightLeft = true;
lightRight = false;
}
// That happens when the left value in "Inside IF 1" is lower than 50
else{
/* Is the calculated value for left lower than 50 then go forward. Why? Is that value lower than 50 then the difference
between the light on the left and right sensor are not that great. In this case it should be save to go forward.
/
lightLeft = true;
lightRight = true;
}
}
// That happens when left is lower than right
else if (left < right){
// subtract left from right value to get a value to work with
right = right-left;
// check if that previous calculated value is greater than 50
if (right > lightDifference){ // I will call this "Inside IF 2" in further comments.
lightLeft = false;
lightRight = true;
}
else{
lightLeft = true;
lightRight = true;
}
}
/ That "else" happens when none of the above conditions occur and the left and right sensor shows the same readings.
This condition will probably never occur but we need it anyway.
*/
else{
// Go forward without questions
lightLeft = true;
lightRight = true;
}
}
// Walk forward //////////////////////////////////////////////////////////
void forward(){
for (midAngle = 70; midAngle < 100; midAngle +=1){
midLeg.write(midAngle);
delay(delayWalk);
}
for (frontAngle = 120; frontAngle > 50; frontAngle -= 1){
frontLeg.write(frontAngle);
rearLeg.write(frontAngle);
delay(delayWalk);
}
for (midAngle = 100; midAngle > 70; midAngle -=1){
midLeg.write(midAngle);
delay(delayWalk);
}
for (frontAngle = 50; frontAngle < 120; frontAngle += 1){
frontLeg.write(frontAngle);
rearLeg.write(frontAngle);
delay(delayWalk);
}
}
// Walk reverse //////////////////////////////////////////////////////////
void reverse(){
for (midAngle = 70; midAngle < 100; midAngle +=1){
midLeg.write(midAngle);
delay(delayWalk);
}
for (frontAngle = 50; frontAngle < 120; frontAngle += 1){
frontLeg.write(frontAngle);
rearLeg.write(frontAngle);
delay(delayWalk);
}
for (midAngle = 100; midAngle > 70; midAngle -=1){
midLeg.write(midAngle);
delay(delayWalk);
}
for (frontAngle = 120; frontAngle > 50; frontAngle -= 1){
frontLeg.write(frontAngle);
rearLeg.write(frontAngle);
delay(delayWalk);
}
}
// Left Turn //////////////////////////////////////////////////////////
void leftTurn(){
rearLeg.write(90);
for (midAngle = 70; midAngle < 110; midAngle += 1){
midLeg.write(midAngle);
delay(delayTurn);
}
for (frontAngle = 70; frontAngle < 110; frontAngle +=1){
frontLeg.write(frontAngle);
delay(delayTurn);
}
for (rearAngle = 110; rearAngle > 70; rearAngle -=1){
rearLeg.write(rearAngle);
delay(delayTurn);
}
for (midAngle = 110; midAngle > 70; midAngle -= 1){
midLeg.write(midAngle);
delay(delayTurn);
}
for (frontAngle = 110; frontAngle > 70; frontAngle -=1){
frontLeg.write(frontAngle);
delay(delayTurn);
}
for (rearAngle = 70; rearAngle < 110; rearAngle +=1){
rearLeg.write(rearAngle);
delay(delayTurn);
}
}
// Right Turn //////////////////////////////////////////////////////////
void rightTurn(){
frontLeg.write(90);
for (midAngle = 70; midAngle < 110; midAngle += 1){
midLeg.write(midAngle);
delay(delayTurn);
}
for (rearAngle = 70; rearAngle < 110; rearAngle +=1){
rearLeg.write(rearAngle);
delay(delayTurn);
}
for (frontAngle = 110; frontAngle > 70; frontAngle -=1){
frontLeg.write(frontAngle);
delay(delayTurn);
}
for (midAngle = 110; midAngle > 70; midAngle -= 1){
midLeg.write(midAngle);
delay(delayTurn);
}
for (rearAngle = 110; rearAngle > 70; rearAngle -=1){
rearLeg.write(rearAngle);
delay(delayTurn);
}
for (frontAngle = 70; frontAngle < 110; frontAngle +=1){
frontLeg.write(frontAngle);
delay(delayTurn);
}
}
// Stop walking
void stay(){
frontLeg.write(90);
midLeg.write(90);
rearLeg.write(90);
}
//////////////////////////////////////////////////////////////
void loop(){
// First scan for the light
scan();
// read the IR distance sensor value
sensorValue = analogRead(distanceSensor);
if (sensorValue < danger){
decision();
}
else {
frontLeg.write(90);
rearLeg.write(90);
midLeg.write(90);
delay(1000);
for (byte x=0; x<5; x+=1){
reverse();
}
delay(300);
for (byte x=1; x<5; x+=1){
leftTurn();
}
delay(300);
}
decision();
if (lightLeft == true && lightRight == true){
forward();
// Serial.println("left = right");
delay(5);
}
else if (lightLeft == false && lightRight == true){
rightTurn();
// Serial.println("left < right");
delay(5);
}
else if (lightLeft == true && lightRight == false){
leftTurn();
// Serial.println("left > right");
delay(5);
}
else {
stay();
// Serial.println ("Nothing to complain");
}
}
函数说明
Servo.h库:
#include<Servo.h>,就是调用舵机的使用库,这个库已经在Arduino IDE 中了,可以打开Arduino-1.0.5/libraries/ Servo/Servo.h进行查看。
创建舵机对象:frontLeg;Servo rearLeg;Servo midLeg;这三句创建三个舵机对象,分别对应前腿后退和中腿。frontAngle rearAngle midAngle 这三个值作为之后舵机的角度值,在这里呢我们先给他赋90°让舵机们一开始在中间的位置停着,不偏不倚。
各个定义:
int distanceSensor = A1;int lightSensorLeft = A2;int lightSensorRight = A0;这三句定义了我们虫虫机器人身上的距离传感器、左右光线传感器(光敏电阻),他们分别于模拟口的A1,A2,A0相连接。而int sensorValue = 0;int sensorValueLeft = 0;int sensorValueRight = 0;分别是红外距离传感器接收的模拟值、左右光敏电阻接收的模拟值存放数据的变量。
可是既然已经有了左传感器接受到的值和右眼传感器接收到的值的存放变量,为何还要有int left = 0;int right = 0;这两个left和right的定义呢?我们往下看。
左右传感器取值问题:
harp GP2Y0A21 传感器的输出很不稳定,在相同情况下读取传感器,我们不可能取得全部相同的值,因此必须多次读取传感器,然后选择使用它们的中间值,因为这样就不会过或者不及的情况 。所以,这里定义的left和right是用来放置左右光敏电阻所传递回来模拟值的中间值的。int leftReadings[11];int rightReadings[11];我们定义了这两个数组来存放接收到的传感器模拟值,而void scan()所定义的scan函数就是用来存放数组的。
接着的两句函数sort(leftReadings,11);left = leftReadings[5];和sort(rightReadings,11);right = rightReadings[5];先用了两个分类函数,然后取数组中第6个值作为真正的left或者right的值。这两个值就是我们想要的居于中间的值。可是,这个sort函数又是怎么工作的呢?怎么会一使用这个函数之后取数组中的第六个也就是数组排序中位置居于中间的值就能够使得取值为所有12个数据中的中间数呢?那么下面,我们就再仔细观察一下sort函数。
传感器数据排序—冒泡法:
void sort(int a[], int size) {
for(int i=0; i<(size-1); i++) {
for(int o=0; o<(size-(i+1)); o++) {
if(a[o] > a[o+1]) {
int t = a[o];
a[o] = a[o+1];
a[o+1] = t;
}
}
}
}
虫虫行动判断:
虫虫行动的判断标志主要来自两个布尔型参数lightLeft和lightRight,布尔数据类型又称为逻辑数据类型,是一种只有两种取值的原始类型:真和假。如果lightLeft=true, lightRight=false,虫虫就启动左转程序,如果lightLeft= false, lightRight=true;虫虫就启动右转程序;如果lightLeft=true, lightRight= true,虫虫就直行。int lightDifference = 60;这个60就是我们所定义的灵敏度,int danger = 450;危险值为450指的的当传感器返回的值小于等于这个值得时候,我们的虫虫机器人就要转弯啦。当然如果想要增加碰撞的触发距离我们可以增加这个参数。
而对于左右的判断就要使用decision函数,来判断虫虫机器人左右光线传感器传回来的值。如果左边的光强度大于右边的光强度,就把两者的差量赋给左边;如果差量大于我们之前设置的灵敏度lightdifference时就给lightLeft赋“真”,lightRight赋“假”。如果差量不大于我们设置的灵敏度lightdifference就给lightLeft和lightRight都赋真。如果右边的值大于左边则将差值赋给right,如果此时right的值大于lightdifference则lightLeft赋“假”,lightRight赋“真”,如果right的值不大于lightdifference,则lightLeft和lightRight都赋真也就是要让虫虫保持直行。
虫虫如何行动:
这取决于定义的四个函数:forward()、reverse()、rightTurn()、leftTurn(),当然还有一个stay()停留函数起到让虫虫停留不动的作用。前进跟后退的代码参数相反,左转和右转的代码参数完全想法,下面我们分别看一下前行和左转函数。
void forward(){
for (midAngle = 70; midAngle < 100; midAngle +=1){
midLeg.write(midAngle);
delay(delayWalk);
}
for (frontAngle = 120; frontAngle > 50; frontAngle -= 1){
frontLeg.write(frontAngle);
rearLeg.write(frontAngle);
delay(delayWalk);
}
for (midAngle = 100; midAngle > 70; midAngle -=1){
midLeg.write(midAngle);
delay(delayWalk);
}
for (frontAngle = 50; frontAngle < 120; frontAngle += 1){
frontLeg.write(frontAngle);
rearLeg.write(frontAngle);
delay(delayWalk);
}
}
for (midAngle = 70; midAngle < 110; midAngle += 1){
midLeg.write(midAngle);
delay(delayTurn);
}
rearLeg.write(90);
for (midAngle = 70; midAngle < 110; midAngle += 1){
midLeg.write(midAngle);
delay(delayTurn);
}
for (frontAngle = 70; frontAngle < 110; frontAngle +=1){
frontLeg.write(frontAngle);
delay(delayTurn);
}
for (rearAngle = 110; rearAngle > 70; rearAngle -=1){
rearLeg.write(rearAngle);
delay(delayTurn);
}
for (midAngle = 110; midAngle > 70; midAngle -= 1){
midLeg.write(midAngle);
delay(delayTurn);
}
for (frontAngle = 110; frontAngle > 70; frontAngle -=1){
frontLeg.write(frontAngle);
delay(delayTurn);
}
for (rearAngle = 70; rearAngle < 110; rearAngle +=1){
rearLeg.write(rearAngle);
delay(delayTurn);
}
函数的一开始就调用scan函数,通过红外传感器得到距离模拟值。然后将此值与危险值作比较,如果是小于危险值(也就是说不用开始避障)则调用判断函数来判断虫虫应该直走还是左转。如果已经大于危险值了,则停留1秒接着调用后退函数和左转函数。这个if和else函数之后无论虫虫是否做出了行动都再调用一次判断函数,然后开始进行各种行为的判断。如果lightLeft=true, lightRight=false,虫虫就调用左转函数,如果lightLeft= false, lightRight=true;虫虫就调用右转函数;如果lightLeft=true, lightRight= true,虫虫就调用直行函数,如果都不满足,则虫虫调用停留函数。
[[名称]]