查看: 1308|回复: 10

基于Arduino的捡乒乓球小车

[复制链接]
  • TA的每日心情
    开心
    2019-7-13 17:06
  • 签到天数: 49 天

    [LV.5]常住居民I

    发表于 2019-5-2 15:04 | 显示全部楼层 |阅读模式
    本帖最后由 MT不吃鷄 于 2019-5-2 17:11 编辑
    基于Arduino的捡乒乓球小车
    先上演示视频:



    这个小车是基于pixy视觉识别的模块来完成动作的;
    根据反馈的物体面积判断距离物体的远近,反馈的横纵坐标来判断物体的方向。

    拾取流程:
    小车自转(寻找物体)------识别到物体,根据反馈的横纵坐标走到小球跟前------下爪抓球-----自转(寻找储存区)-----根据反馈的横纵坐标去到储存区-----放球-----again

    /*****************************************组成部分*********************************************/
    pixy视觉识别+全向底盘+Arduino+手爪


    [size=10.5000pt]               
                   

    小车外型

    小车外型
                                                   小车外型

                         

    pixy模块

    pixy模块
                                             pixy模块
                      此处附上pixy模块使用方法的连接和个人用的固件:
                      pixy模块使用方法:http://www.makerlab.me/guides/6/articles/34
                      最新固件:https://pan.baidu.com/s/1dfDxQtDd0mzxSvZYWn7AfQ
                                        提取码:3247
    /*****************************************组成部分*********************************************/
















                    /****************************************各个模块测试视频************************************************/
                    pixy模块:
                    优点:比较方便,圈选你要识别的物体后它会自动进行跟踪,并反馈回物体坐标,面积信息
                    缺点:受光线干扰较大,选中物体的方框有点不稳定,会时常跳动

                    pixy模块测试视频:
                   



                   全向底盘:
                   用的是步进电机和cnc的步进电机驱动,跑的是开环
                    优点:走的非常平稳,同样是开环,步进电机会比直流电机稳很多
                    缺点:速度太慢了。。。TAT 用的还是雕刻机CNC的驱动,楼主太菜了,莫得办法

                

    cnc 驱动

    cnc 驱动


                   

    步进电机

    步进电机

                     舵机:
    这个要求不大,因为乒乓球不是很重
              /****************************************各个模块测试视频************************************************/












           /*******************************************遇到的问题****************************************************/
           小车走到小球的面前停不下来,会出现小幅度的抖动
           原因上面也说了,因为pixy这个模块受光线影响较大
           所以当车到了小球的面前时,我直接跑个for循环,让手爪下去,此举可以避免底盘的抖动。
          

           /*******************************************遇到的问题****************************************************/


                
        代码:
       有两个UNO
      一个用于控制舵机和接收pixy反馈的信息 (在这称之上位机)
      一个是用于控制底盘(接受到pixy反馈的信息后走至小球跟前,在这称之下位机)

    上位机:

    kittenblock中小学创客名师推荐的图形化编程软件

    #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);
        
        }




    下位机:

    kittenblock中小学创客名师推荐的图形化编程软件

    #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







    打赏作者鼓励一下!
  • TA的每日心情
    奋斗
    2019-7-19 10:06
  • 签到天数: 165 天

    [LV.7]常住居民III

    发表于 2019-5-3 11:04 | 显示全部楼层
    你这背景好像我们实验室,桌子底板都好像
  • TA的每日心情
    开心
    2019-7-13 17:06
  • 签到天数: 49 天

    [LV.5]常住居民I

     楼主| 发表于 2019-5-3 14:03 | 显示全部楼层
    啃番薯 发表于 2019-5-3 11:04
    你这背景好像我们实验室,桌子底板都好像

    朋友你是哪个实验室的
    打赏作者鼓励一下!
  • TA的每日心情
    难过
    2019-7-8 21:22
  • 签到天数: 13 天

    [LV.3]偶尔看看II

    发表于 2019-5-3 20:39 | 显示全部楼层
    新人学习报道!
  • TA的每日心情
    奋斗
    2019-7-19 10:06
  • 签到天数: 165 天

    [LV.7]常住居民III

    发表于 2019-5-4 16:12 | 显示全部楼层
    MT不吃鷄 发表于 2019-5-3 14:03
    朋友你是哪个实验室的

    学校的                 
  • TA的每日心情
    开心
    2018-5-29 13:32
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2019-5-15 16:48 | 显示全部楼层
    我也觉得好像呀这实验室

    该用户从未签到

    发表于 2019-5-16 19:37 | 显示全部楼层
    您好 我想向您请教几个问题 就是小车怎样找到篮筐的
  • TA的每日心情

    2019-5-19 12:33
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2019-5-19 15:28 | 显示全部楼层
    至于你的程序及各种调整啥的我看不明白外,我能提出的建议就是,你文本的背景设置的花,太花了看代码眼睛不好使的,就完蛋了/
  • TA的每日心情
    开心
    2019-7-13 17:06
  • 签到天数: 49 天

    [LV.5]常住居民I

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

    以后改进,谢谢!
    打赏作者鼓励一下!
  • TA的每日心情
    开心
    2019-7-13 17:06
  • 签到天数: 49 天

    [LV.5]常住居民I

     楼主| 发表于 2019-5-21 11:33 | 显示全部楼层
    cl1902345841 发表于 2019-5-16 19:37
    您好 我想向您请教几个问题 就是小车怎样找到篮筐的

    通过视觉的模块选中绿色区域,然后判断篮筐的面积大小走至篮筐前
    打赏作者鼓励一下!
    您需要登录后才可以回帖 登录 | 立即注册  

    本版积分规则

    Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   ( 蜀ICP备14017632号-3 )
    快速回复 返回顶部 返回列表