小智 发表于 2014-8-24 00:19:08

kinect+processing+arduino体感小车

本帖最后由 小智 于 2014-9-2 21:40 编辑

      从上年的十月份开始接触arduino到现在快有一年的时间了,当第一次看见用程序控制的LED一闪一闪的兴奋的不得了,经过一年时间的不断的摸索与学习,觉得自己的进步还是很明显。极客工坊是我常逛的论坛,从这里学到了很多东西,先感谢各位!这是我第一次发帖,如有写的不好的地方希望各位见谅!
      我这次diy的作品是体感小车,这种小车用到的最重要的三个工具是arduino、kinect、processing。Arduino不说估计都比我明白。Kinect就是xbox360体感游戏机的一个传感器。另一个就是processing,说到prosessing它与arduino的关系那是非常的紧密,arduino的编译器貌似就是根据processing的编译器制作出来的,而且两个项目都是开源的,processing也和arduino一样包含大量的库,这次我们用到控制kinect传感器的库是SimpleOpenNI。
       先说说这个项目的基本原理吧。首先kinect传感器识别人体在空间的信息,接着将数据传到processing,processing可以识别人体的骨架即可以特定的识别人的手掌或胳膊的位置,当手掌摆动到设定的位置,processing就可以通过无线串口传输数据给arduino单片机。这样我们就可一站在kinect传感器面前,挥一挥手就可以轻松的控制我们的无线小车了。
由于这个diy电脑端要配置的内容较多,短时间内也出不了完整的教程,所以这次主要向各位展示下我的diy作品。(未改完,过一段时间将视屏、配置文件的压缩包链接附上)这是视屏网址:http://v.youku.com/v_show/id_XNzcxMTg4MzI4.html

import java.util.Map;
import java.util.Iterator;
import SimpleOpenNI.*;//begin the library of kinect
import processing.serial.*;//begin the library of serial port
Serial myPort;// Create object from Serial class
SimpleOpenNI context;
int handVecListSize = 20;
float value_x;//X坐标map值
float value_y;//Y坐标map值
int value_x_;//整型X坐标map值
int value_y_;//整型Y坐标map值
Map<Integer,ArrayList<PVector>>handPathList = new HashMap<Integer,ArrayList<PVector>>();
color[]       userClr = new color[]{ color(226,51,237),//用户的界面,横线、竖线
                                     color(126,81,232),
                                     color(107,145,224),
                                     color(134,216,219),
                                     color(156,211,177),
                                     color(249,23,126)
                                 };
void setup()
{
size(640*2,480);//显示界面的大小
context = new SimpleOpenNI(this);
if(context.isInit() == false)
{
   println("Can't init SimpleOpenNI, maybe the camera is not connected!");
   exit();
   return;
}   
context.enableDepth();// enable depthMap generation
context.setMirror(true); // 启用镜像,这是干嘛的
context.enableRGB();//使能RGB图像
context.enableHand();//使能手势识别
context.startGesture(SimpleOpenNI.GESTURE_WAVE);//摆手启动手势控制
String portName = Serial.list();//建立串口
myPort = new Serial(this, portName,9600);//设置波特率
}

void draw()
{
context.update();//更新相机传来的数据
background(0,255,0);//设置背景颜色
image(context.depthImage(),0,0);//设置显示深度图在背景上的位置,
image(context.rgbImage(), context.depthWidth()+5,0); //设置RGB图在背景上显示的位置
if(handPathList.size() > 0)// draw the tracked hands
{   
    Iterator itr = handPathList.entrySet().iterator();   
    while(itr.hasNext())
    {
      Map.Entry mapEntry = (Map.Entry)itr.next();
      int handId =(Integer)mapEntry.getKey();
      ArrayList<PVector> vecList = (ArrayList<PVector>)mapEntry.getValue();
      PVector p;
      PVector p2d = new PVector();   
      stroke(userClr[ (handId - 1) % userClr.length ]);
      noFill();
      strokeWeight(1);      
      Iterator itrVec = vecList.iterator();
      beginShape();
          while( itrVec.hasNext() )
          {
            p = (PVector) itrVec.next();            
            context.convertRealWorldToProjective(p,p2d);
         // vertex(p2d.x,p2d.y);//显示移动点后面的尾巴
          }
      endShape();   
      stroke(userClr[ (handId - 1) % userClr.length ]);
      strokeWeight(4);
      p = vecList.get(0);
      context.convertRealWorldToProjective(p,p2d);
      line_display();//当追踪到手时,显示按键坐标
      //stroke(255,0,0);
      //strokeWeight(2);
      //ellipse(p2d.x,p2d.y,10,10);//圆心
      //fill(110,90,10);
      //line(p2d.x-10,p2d.y,p2d.x+10,p2d.y);//圆心横
      //line(p2d.x,p2d.y-10,p2d.x,p2d.y+10);//圆心竖
      /************************************************************************/
      /***************************发送指令(以下部分)**************************/
      /************************************************************************/
      if((p2d.x>213)&&(p2d.x<426)&&(p2d.y>160)&&(p2d.y<320)==true)//停车got
          {
             fill(255,255,0);
             display_stop();
             myPort.write('S');//指令
             myPort.write(0);//X轴命令
             myPort.write(0);//Y轴命令
             println("STOP");
          }
         if((p2d.x>20)&&(p2d.x<213)&&(p2d.y>160)&&(p2d.y<320)==true)//原地左转got
             {
               fill(173,255,147);
               display_left();
               value_x=map(p2d.x,20.0,213.0,255.0,1.0);
               value_x_=int(value_x);
               myPort.write('L');//指令
               myPort.write(value_x_);//X轴命令
               myPort.write(0);//Y轴命令
               print("GO--LEFT");
               println(value_x_);
            }
         if((p2d.x>426)&&(p2d.x<620)&&(p2d.y>160)&&(p2d.y<320)==true)//原地右转got
             {
               fill(173,255,47);
               display_right();
               value_x=map(p2d.x,426.0,620.0,1.0,255.0);
               value_x_=int(value_x);
               myPort.write('R');//指令
               myPort.write(value_x_);//X轴命令
               myPort.write(0);//Y轴命令
               print("GO--RIGHT");
               println(value_x_);
             }
          if((p2d.x>213)&&(p2d.x<426)&&(p2d.y>20)&&(p2d.y<160)==true)//前进got
            {
               fill(50,205,50);
               display_forward();
               value_y=map(p2d.y,20.0,160.0,255.0,1.0);
               value_y_=int(value_y);
               myPort.write('F');//指令
               myPort.write(0);//X轴命令
               myPort.write(value_y_);//Y轴命令
               print("GO--FORWARD");
               println(value_y_);
            }
          if((p2d.x>213)&&(p2d.x<426)&&(p2d.y>320)&&(p2d.y<460)==true)//后退got
            {
               fill(50,205,50);
               display_back();
               value_y=map(p2d.y,320.0,460.0,1.0,255.0);
               value_y_=int(value_y);
               myPort.write('B');//指令
               myPort.write(0);//X轴命令
               myPort.write(value_y_);//Y轴命令
               print("GO--BACK");
               println(value_y_);
            }
          if((p2d.x>20)&&(p2d.x<213)&&(p2d.y>20)&&(p2d.y<160)==true)//左前转
            {   
             fill(0,225,225);
             display_forward_left();   
             value_x=map(p2d.x,20.0,213.0,255.0,1.0);
             value_y=map(p2d.y,20.0,160.0,255.0,1.0);
             value_x_=int(value_x);
             value_y_=int(value_y);
             myPort.write('C');
             myPort.write(value_x_);
             myPort.write(value_y_);
             print("GO--LEFT FORWARD");
             print(" X=");
             print(value_x_);
             print(" Y=");
             println(value_y_);
            }
          if((p2d.x>426)&&(p2d.x<620)&&(p2d.y>20)&&(p2d.y<160)==true)//右前转
            {
             fill(0,225,225);
             display_forward_right();
             value_x=map(p2d.x,426.0,620.0,1.0,255.0);
             value_y=map(p2d.y,20.0,160.0,225.0,1.0);
             value_x_=int(value_x);
             value_y_=int(value_y);
             myPort.write('D');
             myPort.write(value_x_);
             myPort.write(value_y_);
             print("GO--RIGHT FORWARD");
             print(" X=");
             print(value_x_);
             print(" Y=");
             println(value_y_);
            }
            if((p2d.x>20)&&(p2d.x<213)&&(p2d.y>320)&&(p2d.y<460)==true)//左后传
            {
            fill(0,225,225);
            display_back_left();
            value_x=map(p2d.x,20.0,213.0,255.0,1.0);
            value_y=map(p2d.y,320.0,460.0,1.0,255.0);
            value_x_=int(value_x);
            value_y_=int(value_y);
            myPort.write('E');
            myPort.write(value_x_);
            myPort.write(value_y_);
            print("GO--LEFT BACK");
            print(" X=");
            print(value_x_);
            print(" Y=");
            println(value_y_);
            }
            if((p2d.x>426)&&(p2d.x<620)&&(p2d.y>320)&&(p2d.y<460)==true)//右后转
            {
            fill(0,225,225);
            display_back_right();
            value_x=map(p2d.x,426.0,620.0,1.0,255.0);
            value_y=map(p2d.y,320.0,460.0,1.0,255.0);
            value_x_=int(value_x);
            value_y_=int(value_y);
            myPort.write('G');
            myPort.write(value_x_);
            myPort.write(value_y_);
            print("GO--RIGHT BACK");
            print(" X=");
            print(value_x_);
            print(" Y=");
            println(value_y_);
            }               
       else if(p2d.x<20||p2d.x>620||p2d.y<20||p2d.y>460)//边缘命令保护
         {
            myPort.write('S');
            myPort.write(0);
            myPort.write(0);
            println("STOP");
         }         
      stroke(255,0,0);
      strokeWeight(2);
      ellipse(p2d.x,p2d.y,10,10);//圆心
      fill(110,90,10);
      line(p2d.x-10,p2d.y,p2d.x+10,p2d.y);//圆心横
      line(p2d.x,p2d.y-10,p2d.x,p2d.y+10);//圆心竖   
         /************************************************************************/
      /***************************发送指令(以上部分)***************************/
      /************************************************************************/
    }      
}
}
// -----------------------------------------------------------------
// hand events

void onNewHand(SimpleOpenNI curContext,int handId,PVector pos)
{
println("onNewHand - handId: " + handId + ", pos: " + pos);

ArrayList<PVector> vecList = new ArrayList<PVector>();
vecList.add(pos);

handPathList.put(handId,vecList);
}

void onTrackedHand(SimpleOpenNI curContext,int handId,PVector pos)
{
//println("onTrackedHand - handId: " + handId + ", pos: " + pos );
ArrayList<PVector> vecList = handPathList.get(handId);
if(vecList != null)
{
    vecList.add(0,pos);
    if(vecList.size() >= handVecListSize)
      // remove the last point
      vecList.remove(vecList.size()-1);
}
}
void onLostHand(SimpleOpenNI curContext,int handId)
{
println("onLostHand - handId: " + handId);
handPathList.remove(handId);
}
// -----------------------------------------------------------------
// gesture events
void onCompletedGesture(SimpleOpenNI curContext,int gestureType, PVector pos)
{
println("onCompletedGesture - gestureType: " + gestureType + ", pos: " + pos);

int handId = context.startTrackingHand(pos);
println("hand stracked: " + handId);
}
// -----------------------------------------------------------------
// Keyboard event
void keyPressed()
{
switch(key)
{
case ' ':
    context.setMirror(!context.mirror());
    break;
case '1':
    context.setMirror(true);
    break;
case '2':
    context.setMirror(false);
    break;
}
}
/*****************************************************************************/
/*******************************自定义界面************************************/
/*****************************************************************************/
void line_display()
{
      strokeWeight(3);
      line_();
      display_forward();
      display_back();//后退
      display_left();
      display_right();
      display_stop();
      display_forward_left();
      display_forward_right();
      display_back_left();
      display_back_right();
}
void display_forward()//前进箭头
{
      stroke(50,205,50);
      //fill(50,205,50);
      beginShape();
      vertex(320,30);
      vertex(280,150);
      vertex(360,150);
      vertex(320,30);
      endShape();
}
void display_back()//后退
{
    //后退箭头
      stroke(50,205,50);
      //fill(50,205,50);
      beginShape();
      vertex(320,450);
      vertex(280,330);
      vertex(360,330);
      vertex(320,450);
      endShape();
}
void display_left()
{
         //左转箭头
      stroke(173,255,47);
      //fill(255,20,147);
      beginShape();
      vertex(40,240);
      vertex(160,200);
      vertex(160,280);
      vertex(40,240);
      endShape();
}
void display_right()
{
         //右转箭头
      stroke(173,255,47);
      //fill(255,20,147);
      beginShape();
      vertex(600,240);
      vertex(480,200);
      vertex(480,280);
      vertex(600,240);
      endShape();
      
}
void display_stop()
{
            
      //停止
      stroke(255,255,0);
      //noFill();
      ellipse(320,240,80,80);
      //fill(255,255,0);
      beginShape();
      vertex(330,245);
      vertex(310,245);
      vertex(300,265);
      vertex(310,265);
      vertex(317,251);
      vertex(323,251);
      vertex(330,265);
      vertex(340,265);
      vertex(330,245);
      endShape();
      beginShape();
      vertex(300,239);
      vertex(340,239);
      vertex(346,227);
      vertex(340,227);
      vertex(337,233);
      vertex(303,233);
      vertex(300,227);
      vertex(294,227);
      vertex(300,239);
      endShape();
      beginShape();
      vertex(315,218);
      vertex(315,228);
      vertex(325,228);
      vertex(325,218);//第四个点
      vertex(315,218);
      endShape();
      line(315,218,325,228);
      line(315,228,325,218);      
}
void display_forward_left()
{
      //左前箭头got
      stroke(0,255,255);
      //fill(0,255,255);
      beginShape();
      vertex(56,38);
      vertex(180,84);
      vertex(128,150);
      vertex(56,38);
      endShape();
   
}
void display_forward_right()
{
         //右前箭头got
      stroke(0,255,255);
      //fill(0,255,255);
      beginShape();
      vertex(584,38);
      vertex(460,84);
      vertex(512,150);
      vertex(584,38);
      endShape();
   
}
void display_back_left()
{
         //左后箭头
      stroke(0,255,255);
      //fill(0,255,255);
      beginShape();
      vertex(56,442);
      vertex(180,396);
      vertex(128,330);
      vertex(56,442);
      endShape();
      
}
void display_back_right()
{
          //右后箭头
      stroke(0,255,255);
      //fill(0,255,255);
      beginShape();
      vertex(584,442);
      vertex(460,396);
      vertex(512,330);
      vertex(584,442);
      endShape();
}
void line_()
{
      line(213,20,213,460);//竖线1
      line(426,20,426,460);//竖线2
      line(20,160,620,160);//横线1
      line(20,320,620,320);//横线2
      beginShape();
      vertex(20,20);
      vertex(620,20);
      vertex(620,460);
      vertex(20,460);
      vertex(20,20);
      endShape();
}      

char value;//接收命令字符变量
int carspeed_x;//接收速度字符变量
int carspeed_y;
int leftA=3;//左电机A
int leftB=4;//左电机B
int rightA=7;//右电机A
int rightB=2;//右电机B
int pwm_A=5;
int pwm_B=6;
void setup()
{
pinMode(leftA,OUTPUT);
pinMode(leftB,OUTPUT);
pinMode(rightA,OUTPUT);
pinMode(rightB,OUTPUT);
pinMode(pwm_A,OUTPUT);
pinMode(pwm_B,OUTPUT);
Serial.begin(9600);
}
void loop()
{
   if (Serial.available())
   {
       value = Serial.read();//接收指令
       while(!Serial.available());
       carspeed_x=Serial.read();//接收数据
       while(!Serial.available());
       carspeed_y=Serial.read();
       switch(value)
       {
         case'F': Forward(carspeed_y);break;
         case'B': Back(carspeed_y);break;
         case'L': Left_Here(carspeed_x);break;
         case'R': Right_Here(carspeed_x);break;
         case'C': Left_Forward(carspeed_x,carspeed_y);break;
         case'D': Right_Forward(carspeed_x,carspeed_y);break;
         case'E': Left_Back(carspeed_x,carspeed_y);break;
         case'G': Right_Back(carspeed_x,carspeed_y);break;
         case'S': Stop();
         default: break;
       }
   }
}
void Forward(int _speed_1)//前进got
{
    digitalWrite(leftA,HIGH);
    digitalWrite(leftB,LOW);
    analogWrite(pwm_A,_speed_1);
    digitalWrite(rightA,HIGH);
    digitalWrite(rightB,LOW);
    analogWrite(pwm_B,_speed_1);
}
void Back(int _speed_2)//后退got
{
    digitalWrite(leftA,LOW);
    digitalWrite(leftB,HIGH);
    analogWrite(pwm_A,_speed_2);
    digitalWrite(rightA,LOW);
    digitalWrite(rightB,HIGH);
    analogWrite(pwm_B,_speed_2);
}
void Left_Here(int _speed_3)//原地左转got
{
    digitalWrite(leftA,HIGH);
    digitalWrite(leftB,LOW);
    analogWrite(pwm_A,_speed_3);
    digitalWrite(rightA,LOW);
    digitalWrite(rightB,HIGH);
    analogWrite(pwm_B,_speed_3);
}
void Right_Here(int _speed_4)//原地右转got
{
    digitalWrite(leftA,LOW);
    digitalWrite(leftB,HIGH);
    analogWrite(pwm_A,_speed_4);
    digitalWrite(rightA,HIGH);
    digitalWrite(rightB,LOW);
    analogWrite(pwm_B,_speed_4);
}
void Left_Forward(int _speed_5_1,int _speed_5_2)//左前转got
{
    digitalWrite(leftA,HIGH);
    digitalWrite(leftB,LOW);
    analogWrite(pwm_A,255-_speed_5_1);
    digitalWrite(rightA,HIGH);
    digitalWrite(rightB,LOW);
    analogWrite(pwm_B,_speed_5_2);
}
void Right_Forward(int _speed_6_1,int _speed_6_2 )//右前转got
{
    digitalWrite(leftA,HIGH);
    digitalWrite(leftB,LOW);
    analogWrite(pwm_A,_speed_6_2);
    digitalWrite(rightA,HIGH);
    digitalWrite(rightB,LOW);
    analogWrite(pwm_B,255-_speed_6_1);
}
void Left_Back(int _speed_7_1,int _speed_7_2)//左后转got
{
    digitalWrite(leftA,LOW);
    digitalWrite(leftB,HIGH);
    analogWrite(pwm_A,255-_speed_7_1);
    digitalWrite(rightA,LOW);
    digitalWrite(rightB,HIGH);
    analogWrite(pwm_B,_speed_7_2);
}
void Right_Back(int _speed_8_1,int _speed_8_2)//右后转got
{
    digitalWrite(leftA,LOW);
    digitalWrite(leftB,HIGH);
    analogWrite(pwm_A,_speed_8_2);
    digitalWrite(rightA,LOW);
    digitalWrite(rightB,HIGH);
    analogWrite(pwm_B,255-_speed_8_1);
}
void Stop()//停车got
{
    digitalWrite(leftA,LOW);
    digitalWrite(leftB,LOW);
    analogWrite(pwm_A,0);
    digitalWrite(rightA,LOW);
    digitalWrite(rightB,LOW);
    analogWrite(pwm_B,0);
}

jikecyatmcn 发表于 2014-8-24 01:02:59

……………………

潇洒哥 发表于 2014-8-24 09:21:56

这个的确不错,比我的手机控制的wifirobot要精密的多,
手动指挥小车给女友送个花,碉堡了

潇洒哥 发表于 2014-8-24 09:22:57

搂着的车体也是用了,arduino +L298N的架构,实现四驱动

小智 发表于 2014-8-24 09:30:47

潇洒哥 发表于 2014-8-24 09:21 static/image/common/back.gif
这个的确不错,比我的手机控制的wifirobot要精密的多,
手动指挥小车给女友送个花,碉堡了

这个车还没成型,暑假后加上机械臂,打算重力传感器控制臂弯,弯曲传感器控制抓取

小智 发表于 2014-8-24 09:33:37

潇洒哥 发表于 2014-8-24 09:21 static/image/common/back.gif
这个的确不错,比我的手机控制的wifirobot要精密的多,
手动指挥小车给女友送个花,碉堡了

手机控制方便多了,用kinect炫一点,就是预算大

软件-蹄飞 发表于 2014-8-24 16:49:14

这年头玩4轴的真多,我看见了是NAZA飞控~~
期待楼主的视频

SnowMath 发表于 2014-8-24 21:41:53

不错不错呵呵

万马奔腾 发表于 2014-8-24 22:23:51

kinect这个要几千吧?

ceo 发表于 2014-8-24 23:20:17

万马奔腾 发表于 2014-8-24 22:23 static/image/common/back.gif
kinect这个要几千吧?

用不着,才600左右。

vigiles 发表于 2014-8-25 11:44:16

期待做得更牛逼,直接使用普通的webcam

小智 发表于 2014-9-2 21:33:23

本帖最后由 小智 于 2014-9-2 21:41 编辑

软件-蹄飞 发表于 2014-8-24 16:49 static/image/common/back.gif
这年头玩4轴的真多,我看见了是NAZA飞控~~
期待楼主的视频

http://v.youku.com/v_show/id_XNzcxMTg4MzI4.html这是视屏的链接,做的有些粗糙

软件-蹄飞 发表于 2014-9-4 14:05:56

小智 发表于 2014-9-2 21:33 static/image/common/back.gif
http://v.youku.com/v_show/id_XNzcxMTg4MzI4.html这是视屏的链接,做的有些粗糙

听小车的声音,好像好暴力的样子

ggg781959574 发表于 2014-9-28 07:55:43

我也好想做kinect啊,怎样实现与Arduino的交互啊? 有kinect的代码可以共享吗?

小智 发表于 2014-9-28 22:22:35

ggg781959574 发表于 2014-9-28 07:55 static/image/common/back.gif
我也好想做kinect啊,怎样实现与Arduino的交互啊? 有kinect的代码可以共享吗?

kinect交互是通过processing与arduino交互的,arduino的代码都在帖子里
页: [1] 2
查看完整版本: kinect+processing+arduino体感小车