使用OpenNI 控制Kinect 的马达

来源:互联网 发布:手机淘宝怎么设置客服 编辑:程序博客网 时间:2024/04/28 07:57

虽然应该有很多人是用Microsoft Kinect for Xbox 360来进行OpenNI程式的开发,但是到目前为止,市面上OpenNI真正的相容装置,其实还是只有ASUS的Xtion Pro系列,要使用Kinect是需要特殊修改过的驱动程式的。而在驱动程式的部分,目前大部分的开发应该都还是使用avin2所提供SensorKinect吧~

而如果是要使用Kinect进行程式开发的话,使用跨平台、开放原始码的OpenNI和使用微软官方的Kinect for Windows SDK相比,一个很大的缺点,就是功能上的不完整;这包括了声音、以及Kinect上的马达。

声音的部分,OpenNI本身有提供API来做控制,目前的问题应该是SensorKinect还没有支援(有列在todo list);而马达的部分,OpenNI本来的API并没有支援,不过目前看来也已经是打算透过xn::GeneralIntCapability的形式来做支援了,只是现在还是无法使用就是了。

不过,后来才发现,在官方论坛上,已经有强者透过OpenNI比较低阶的USB控制介面(XnUSB.h),来做到马达的控制了!原文可以参考《Easy way to control Kinect motor through OpenNI》一文;而目前OpenNI也已经把他的程式码放到github上的Samples里(连结)了!

他基本上是把相关功能封包成一个KinectMotors的类别,把相关的控制写成它的成员函式、以方便操作;其内容如下:

class KinectMotors{public :   enum { MaxDevs = 16 };public :  KinectMotors()  {    m_isOpen = false ;  }  virtual ~KinectMotors()  {    Close();  }  bool Open()  {    const  XnUSBConnectionString *paths;     XnUInt32 count;     XnStatus res;    // Init OpenNI USB    res = xnUSBInit ();     if (res != XN_STATUS_OK )    {      xnPrintError(res, "xnUSBInit failed" );       return  false ;    }    // Open all "Kinect motor" USB devices    res = xnUSBEnumerateDevices (0x045E /* VendorID */ , 0x02B0 /*ProductID*/ , &paths, &count);     if (res != XN_STATUS_OK)    {      xnPrintError(res, "xnUSBEnumerateDevices failed" );       return  false ;    }    // Open devices    for (XnUInt32 index = 0; index < count; ++index)    {      res = xnUSBOpenDeviceByPath (paths[index], &m_devs[index]);       if (res != XN_STATUS_OK)      {        xnPrintError(res, "xnUSBOpenDeviceByPath failed" );         return  false ;      }    }    m_num = count;    XnUChar buf[1];   // output buffer    // Init motors    for (XnUInt32 index = 0; index < m_num; ++index)    {      res = xnUSBSendControl (m_devs[index], (XnUSBControlType) 0xc0, 0x10, 0x00, 0x00, buf, sizeof (buf), 0);       if (res != XN_STATUS_OK)      {        xnPrintError(res, "xnUSBSendControl failed" );        Close();        return  false ;      }      res = xnUSBSendControl (m_devs[index], XN_USB_CONTROL_TYPE_VENDOR, 0x06, 0x01, 0x00, NULL, 0, 0);       if (res != XN_STATUS_OK)      {        xnPrintError(res, "xnUSBSendControl failed" );        Close();        return  false ;      }    }    m_isOpen = true ;     return  true ;  }  void Close()  {    if (m_isOpen)    {      for (XnUInt32 index = 0; index < m_num; ++index)      {        xnUSBCloseDevice (m_devs[index]);      }      m_isOpen = false ;    }  }  bool Move( int angle)  {    XnStatus res;    // Send move control requests    for (XnUInt32 index = 0; index < m_num; ++index)    {      res = xnUSBSendControl (m_devs[index], XN_USB_CONTROL_TYPE_VENDOR, 0x31, angle, 0x00, NULL, 0, 0);       if (res != XN_STATUS_OK)      {        xnPrintError(res, "xnUSBSendControl failed" );         return  false ;      }    }    return  true ;  }private :   XN_USB_DEV_HANDLE m_devs[MaxDevs];  XnUInt32 m_num;  bool m_isOpen;};

而在程式里建立一个KinectMotors的物件后,就可以透过他的Move()这个函式,来进行Kinect仰角的调整了!简单的操作范例,大致上如下:

KinectMotors motors; if (!motors.Open())   return 1;motors.Move(31);

不过基本上,这个方法应该只算是一个雏形,和OpenNI提供的一般操作介面不完全一致;而且在这个类别里,他基本上会根据Vender ID和Product ID把系统里的Kinect马达装置都找出来(透过xnUSBEnumerateDevices()),然后都开启来控制;所以如果有使用多台Kinect的话,他会同时对所有的Kinect来进行操作如果要个别控制的话,则是需要改写这个类别,并针对得到的XnUSBConnectionString来和xn::Device的资讯(应该是「Create Info」、参考)做比对、以找出要控制的是哪一个Kinect 。

另外要注意的是,由于Kinect内部其实还有一个加速度感应器,可以判断自身的倾角,所以实际上这边透过Move()设定的角度,会是空间中绝对的角度也就是说,0度的时候,Kinect会是水平的,正值会往上抬、负值则会往下倾,直到到达目标角度为止;这是在使用时可能要注意的地方。

总之,如果有必要的话,透过这个方法应该是可以用来操作Kinect 的马达了~不过,还是希望OpenNI 能赶快把Kinect 纳入正式支援吧~ ^^”


http://kheresy.wordpress.com/2012/02/03/control_kinect_motor_via_openni/


原创粉丝点击