基于Arduino的捡乒乓球小车-Arduino中文社区 - Powered by Discuz! Archiver

MT不吃鷄 发表于 2019-5-2 15:04

基于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






啃番薯 发表于 2019-5-3 11:04

你这背景好像我们实验室,桌子底板都好像;P;P

MT不吃鷄 发表于 2019-5-3 14:03

啃番薯 发表于 2019-5-3 11:04
你这背景好像我们实验室,桌子底板都好像

朋友你是哪个实验室的

自寻烦恼 发表于 2019-5-3 20:39

新人学习报道!

啃番薯 发表于 2019-5-4 16:12

MT不吃鷄 发表于 2019-5-3 14:03
朋友你是哪个实验室的

学校的               

JIMJIM 发表于 2019-5-15 16:48

我也觉得好像呀这实验室

cl1902345841 发表于 2019-5-16 19:37

您好 我想向您请教几个问题 就是小车怎样找到篮筐的

xu13596489881 发表于 2019-5-19 15:28

至于你的程序及各种调整啥的我看不明白外,我能提出的建议就是,你文本的背景设置的花,太花了看代码眼睛不好使的,就完蛋了/

MT不吃鷄 发表于 2019-5-21 11:31

xu13596489881 发表于 2019-5-19 15:28
至于你的程序及各种调整啥的我看不明白外,我能提出的建议就是,你文本的背景设置的花,太花了看代码眼睛不 ...

以后改进,谢谢!

MT不吃鷄 发表于 2019-5-21 11:33

cl1902345841 发表于 2019-5-16 19:37
您好 我想向您请教几个问题 就是小车怎样找到篮筐的

通过视觉的模块选中绿色区域,然后判断篮筐的面积大小走至篮筐前
页: [1] 2
查看完整版本: 基于Arduino的捡乒乓球小车