基于Arduino的捡乒乓球小车
本帖最后由 MT不吃鷄 于 2019-5-2 17:11 编辑基于Arduino的捡乒乓球小车
先上演示视频:
https://v.youku.com/v_show/id_XNDE2MzE3Mzg3Mg==.html?spm=a2h3j.8428770.3416059.1
这个小车是基于pixy视觉识别的模块来完成动作的;根据反馈的物体面积判断距离物体的远近,反馈的横纵坐标来判断物体的方向。
拾取流程:小车自转(寻找物体)------识别到物体,根据反馈的横纵坐标走到小球跟前------下爪抓球-----自转(寻找储存区)-----根据反馈的横纵坐标去到储存区-----放球-----again
/*****************************************组成部分*********************************************/pixy视觉识别+全向底盘+Arduino+手爪
小车外型
pixy模块 此处附上pixy模块使用方法的连接和个人用的固件: pixy模块使用方法:http://www.makerlab.me/guides/6/articles/34 最新固件:https://pan.baidu.com/s/1dfDxQtDd0mzxSvZYWn7AfQ 提取码:3247/*****************************************组成部分*********************************************/
/****************************************各个模块测试视频************************************************/ pixy模块: 优点:比较方便,圈选你要识别的物体后它会自动进行跟踪,并反馈回物体坐标,面积信息 缺点:受光线干扰较大,选中物体的方框有点不稳定,会时常跳动
pixy模块测试视频: https://v.youku.com/v_show/id_XNDE2MzIzNjY1Ng==.html?spm=a2h3j.8428770.3416059.1
全向底盘: 用的是步进电机和cnc的步进电机驱动,跑的是开环 优点:走的非常平稳,同样是开环,步进电机会比直流电机稳很多 缺点:速度太慢了。。。TAT 用的还是雕刻机CNC的驱动,楼主太菜了,莫得办法
舵机:这个要求不大,因为乒乓球不是很重 /****************************************各个模块测试视频************************************************/
/*******************************************遇到的问题****************************************************/ 小车走到小球的面前停不下来,会出现小幅度的抖动 原因上面也说了,因为pixy这个模块受光线影响较大 所以当车到了小球的面前时,我直接跑个for循环,让手爪下去,此举可以避免底盘的抖动。 https://v.youku.com/v_show/id_XNDE2MzI2NTI3Ng==.html?spm=a2h3j.8428770.3416059.1
/*******************************************遇到的问题****************************************************/
代码: 有两个UNO一个用于控制舵机和接收pixy反馈的信息 (在这称之上位机)一个是用于控制底盘(接受到pixy反馈的信息后走至小球跟前,在这称之下位机)
上位机:#include <SPI.h>
#include <Pixy2.h>
#include<Servo.h>
#include<Wire.h>
Pixy2 pixy;
Servo taiservo;
Servo catchservo;
int signature = 0;
int x = 0; //positon x axis
int y = 0; //position y axis
unsigned int width = 0; //object's width
unsigned int height = 0; //object's height
unsigned int area = 0;
unsigned int newarea = 0;
int Xmin =130; //min x position
int Xmax =180; //max x position
int maxArea = 0;
int minArea = 0;
int Cmin=115;
int Cmax=195;
//volatile int count=0;
int c;
int n=0;
int jet=1;
int i = 0;
static boolean zhua=false;
static boolean chucun=false;
static boolean zhaoqiu=true;
int STEP=1;
void setup()
{
taiservo.attach(9);
catchservo.attach(10);
taiservo.write(65);
catchservo.write(25);
Serial.begin(9600);
pixy.init();
Wire.begin(4);
Wire.onRequest(requestEvent);
//c=6;
//requestEvent();
//delay(5);
}
void loop()
{
//scan(); // rescan();
/*********************************步骤1:找到目标球*******************************************************************/
if(STEP==1)
{
scan();
if(signature ==1&&0.85*width<height)
{
//delay(1000);
//volatile int count=0;
if(n<3){n++;}
if(n==3){
newarea = width * height;
if (x < Xmin&&0.85*width<height) //左平移
{
c=1;
requestEvent();
delay(5);
}
else if (x > Xmax&&0.85*width<height) //右平移
{
c=2;
requestEvent();
delay(5);
}
else if(Xmin<x<Xmax&&newarea <2450&&0.85*width<height) //前进
{
c=3;
requestEvent();
delay(5);
}
else if(Xmin<x<Xmax&&newarea >2650&&0.85*width<height) //后退
{
c=4;
requestEvent();
delay(5);
}
//else stop
else if(Xmin<x<Xmax&&2450<newarea<2650&&0.85*width<height) // if(Xmin<x<Xmax&&8400<newarea<9000) //最佳抓球位置
{
c=5;
requestEvent();
delay(5);
zhuaqiu();
//触发找球条件
STEP=2;
n=0;
taiservo.write(55);
delay(15);
}
}
}
else
{
c=6;
requestEvent();
delay(5);
}
}
/**********************************步骤2:行走至储存区******************************************************************/
// if(signature==2&&chucun==true)
// {
// c=3;
// requestEvent();
// delay(5);
// }
// if(signature==2)
// {
// if(chucun==true)
// {
// c=3; requestEvent();
// }
// }
if(STEP==2)
{
scan(); //另作说明
if(signature==2) //{c=3; requestEvent();}
{
newarea = width * height;
if (x < Cmin) //左平移
{
c=1;
requestEvent();
delay(5);
}
else if (x > Cmax) //右平移
{
c=2;
requestEvent();
delay(5);
}
else if(Cmin<x<Cmax&&newarea <58000) //前进 Xmin<x<Xmax&&newarea <58000
{
c=3;
requestEvent();
delay(5);
}
else if(Cmin<x<Cmax&&newarea >61500) //后退 Xmin<x<Xmax&&newarea >61500
{
c=4;
requestEvent();
delay(5);
}
else if(Cmin<x<Cmax&&58000<newarea<61500)
{
c=5;
requestEvent();
delay(5);
fangqiu();
STEP=1;
catchservo.write(25);
delay(15);
}
}
else
{
c=6;
requestEvent();
delay(5);
}
}
}
/*********************************************扫描目标球*****************************************************/
void scan()
{
uint16_t blocks;
blocks = pixy.ccc.getBlocks(); //receive data from pixy
signature = pixy.ccc.blocks.m_signature; //get object's signature
x = pixy.ccc.blocks.m_x; //get x position
y = pixy.ccc.blocks.m_y; //get y position
width = pixy.ccc.blocks.m_width; //get width
height = pixy.ccc.blocks.m_height; //get height
}
/**********************************************抓球子函数*************************************************/
void zhuaqiu()
{
int i,j;
for(i=65;i>=10;i-=1)
{
taiservo.write(i);
delay(20);
}
delay(100);
for(j=25;j<=80;j+=1)
{
catchservo.write(j);
delay(15);
}
// taiservo.write(55);
// delay(10000);
}
void fangqiu()
{
int k;
for(k=80;k>=25;k-=1)
{
catchservo.write(k);
delay(15);
}
}
void xunzhao()
{
c=6;
requestEvent();
}
void requestEvent()
{
Wire.write(c);
}
下位机:
#include<Wire.h>
#include<TimerOne.h>
int X=0;
#define EN 8 //步进电机使能端,低电平有效
#define X_DIR 5 //X轴 步进电机方向控制
#define Y_DIR 6 //y轴
#define Z_DIR 7 //z轴
#define A_DIR 13 //A轴
#define X_STP 2 //x轴脉冲控制
#define Y_STP 3 //y轴
#define Z_STP 4 //z轴
#define A_STP 12 //A轴
void flash()
{
static boolean output=LOW; //低电平有 HIGH
digitalWrite(X_STP,output);
digitalWrite(Y_STP,output);
digitalWrite(Z_STP,output);
digitalWrite(A_STP,output);
output=!output;
}
void setup()
{ //将步进电机用到的IO管脚设置成输出
Serial.begin(115200);
Wire.begin();
pinMode(X_DIR, OUTPUT); pinMode(X_STP, OUTPUT);
pinMode(Y_DIR, OUTPUT); pinMode(Y_STP, OUTPUT);
pinMode(Z_DIR, OUTPUT); pinMode(Z_STP, OUTPUT);
pinMode(A_DIR, OUTPUT); pinMode(A_STP, OUTPUT);
pinMode(EN, OUTPUT);
digitalWrite(EN, LOW); //低電平有效
//stepper.setSpeed(360);
//Timer1.initialize(1000);
Timer1.attachInterrupt(flash);
//MsTimer2::stop();
}
void(* resetFunc) (void) = 0;
const int A=1800;
void loop()
{
//MsTimer2::set(3,flash);
Wire.requestFrom(4,1);
while(Wire.available()>0)
{
volatile byte c=Wire.read(); // volatile储存动态易变常量
switch(c)
{
case 1: //目标球太靠右,右走
Timer1.initialize(A); //100000 micro=100ms
Timer1.attachInterrupt(flash);
zuozou();
Serial.println("1");
break;
delay(5);
case 2: //目标球靠左,左走
Timer1.initialize(A);
Timer1.attachInterrupt(flash);
youzou();
Serial.println("2");
break;
delay(5);
case 3: //无目标球,停止
Timer1.initialize(A); //100000 micro=100ms
Timer1.attachInterrupt(flash);
forward();
Serial.println("3");
break;
delay(5);
case 4:
Timer1.initialize(A); //100000 micro=100ms
Timer1.attachInterrupt(flash);
backward();
Serial.println("4");
break;
delay(5);
case 5:
Timer1.detachInterrupt();
Serial.println("5");
break;
delay(5);
case 6:
Timer1.initialize(A); //100000 micro=100ms
Timer1.attachInterrupt(flash);
ni();
Serial.println("4");
break;
delay(5);
}
}
}
void ni()
{
digitalWrite(X_DIR,LOW);
digitalWrite(Y_DIR,LOW);
digitalWrite(Z_DIR,LOW);
digitalWrite(A_DIR,LOW);
}
void forward()
{
digitalWrite(X_DIR,LOW);
digitalWrite(Y_DIR,HIGH);
digitalWrite(Z_DIR,HIGH);
digitalWrite(A_DIR,LOW);
}
void backward()
{
digitalWrite(X_DIR,HIGH);
digitalWrite(Y_DIR,LOW);
digitalWrite(Z_DIR,LOW);
digitalWrite(A_DIR,HIGH);
}
void zuozou()
{
digitalWrite(X_DIR,HIGH);
digitalWrite(Y_DIR,HIGH);
digitalWrite(Z_DIR,LOW);
digitalWrite(A_DIR,LOW);
}
void youzou()
{
digitalWrite(X_DIR,LOW);
digitalWrite(Y_DIR,LOW);
digitalWrite(Z_DIR,HIGH);
digitalWrite(A_DIR,HIGH);
}
void tingzhi()
{
digitalWrite(X_STP,HIGH);
digitalWrite(Y_STP,HIGH);
digitalWrite(Z_STP,HIGH);
digitalWrite(A_STP,HIGH);
}
void Reset()
{
resetFunc();
}
心得: 以一个门外汉的身份去看别人做的东西,觉得很容易,但是当自己开始动手去做的时候才知道“知之不难,行之不易”这个道理。这个小作品也当是用来入门单片机吧,后面有什么不足的地方看评论区继续补充。
欢迎大家一起交流QQ:292780142微信:18476202021
你这背景好像我们实验室,桌子底板都好像;P;P 啃番薯 发表于 2019-5-3 11:04
你这背景好像我们实验室,桌子底板都好像
朋友你是哪个实验室的 新人学习报道! MT不吃鷄 发表于 2019-5-3 14:03
朋友你是哪个实验室的
学校的 我也觉得好像呀这实验室 您好 我想向您请教几个问题 就是小车怎样找到篮筐的 至于你的程序及各种调整啥的我看不明白外,我能提出的建议就是,你文本的背景设置的花,太花了看代码眼睛不好使的,就完蛋了/ xu13596489881 发表于 2019-5-19 15:28
至于你的程序及各种调整啥的我看不明白外,我能提出的建议就是,你文本的背景设置的花,太花了看代码眼睛不 ...
以后改进,谢谢! cl1902345841 发表于 2019-5-16 19:37
您好 我想向您请教几个问题 就是小车怎样找到篮筐的
通过视觉的模块选中绿色区域,然后判断篮筐的面积大小走至篮筐前
页:
[1]
2