で、温泉で(仕事の心の)疲れを癒して、今日は、久々に新しいキワモノをいじることにしました。今回のターゲットはセンチュリーの「USBスカッとミサイルランチャー」です。といってもセンチュリーがこういうものを開発しているわけはなく、ものとしてはDREAM CHEEKYのSTORM O.I.C というものです。以前にちょっと流行ったUSBミサイルランチャーですが、このモデルにはカメラもついています。となると、やっぱり、こいつを移動ロボットに載せて遠隔あるいは自立によって操作・制御したくなります。もちろんWindows用にはDREAM CHEEKYのサイトから制御アプリをダウンロードして利用することができます。このソフトもカメラに写った画面が表示され、砲台の制御・ミサイル発射ができるようになっていますが、独自に自作プログラムから操作しようとすると調査が必要です。また、ここはせっかくなので将来のロボット搭載も意識して Raspberry Pi での制御を実現したいと思います。
まずは、Raspberry Pi のUSBにミサイルランチャーを接続して、接続情報を調べます。lsusb でUSBデバイスの認識情報を確認すると
2123:1010 (空欄)
0ac8:3450 Z-Star Microelectronics Corp.
というふうに表示されます。上の名前が空欄になっている方がミサイルランチャーでHIDデバイスとして認識されているようです。ミサイルランチャーをUSBに挿すと自分の環境ではそれぞれ "/dev/hidraw2"と"/dev/usb/hiddev0"が追加されました。HIDデバイスとして認識されているならもしかするとファイルデバイスとしてコマンドを書き込んでやれば動いてくれるかもしれません。また、下のZ-Star ・・・がカメラのようです。"/dev/video0"として認識され、"ls /dev/v4l/by-id"では
usb-Vimicro_Corp._Altair_USB2.0_Camera-video-index0
と表示されます。OpenCVで画像取得してみたところ、
とりあえず、内蔵カメラでの画像取得は
sudo apt-get install libusb-dev
で。
Raspberry Pi のUSB端子に直接接続した状態だと砲台の駆動時に USB通信エラーになってしまい、途中で動かなくなってしまいました。これは、Raspberry PiのUSB駆動能力が140mA程度にポリスイッチで制限されているからだと思います。そこで、セルフパワー(ACアダプタ付き)のUSBハブを間に入れることで、ミサイル発射まで動かすことができるようになりました。ただし、数回に一度、ミサイル発射時にRaspberry Piのシステムが落ちます。発射時に突入電流やノイズのようなものがあるんでしょうか?でも、間にハブを入れているので、影響するんだろうか?この部分は今のところ原因不明です。
以下、ソースです。
#include <stdio.h>
#include <unistd.h>
#include <usb.h>
#define HID_REPORT_SET (0x09)
#define BULK_OUT (0x02)
#define MISSILE_VENDOR_ID (0x2123)
#define MISSILE_PRODUCT_ID (0x1010)
#define MISSILE_CMD_HEADER (0x02)
#define MISSILE_CMD_DOWN (0x01)
#define MISSILE_CMD_UP (0x02)
#define MISSILE_CMD_LEFT (0x04)
#define MISSILE_CMD_RIGHT (0x08);
#define MISSILE_CMD_FIRE (0x10);
#define MISSILE_CMD_STOP (0x20);
const int USB_TIMEOUT = 3000;
const int BUF_SIZE = 8;
int main(int argc, char **argv)
{
struct usb_bus *bus;
struct usb_device *dev;
usb_dev_handle *udh;
struct usb_config_descriptor *config;
struct usb_interface *interface;
struct usb_interface_descriptor *altsetting;
unsigned char buf[BUF_SIZE];
int result = -1;
int i = 0, j = 0;
// 初期化。
usb_init();
usb_find_busses();
usb_find_devices();
// デバイスチェック。
for(bus = usb_get_busses(); bus; bus = bus->next)
{
for(dev = bus->devices; dev; dev = dev->next)
{
if(dev->descriptor.idVendor == MISSILE_VENDOR_ID &&
dev->descriptor.idProduct == MISSILE_PRODUCT_ID)
{
// デバイスオープン。
if((udh = usb_open(dev)) == NULL)
{
// オープンに失敗。
printf("usb_open Error.(%s)\n", usb_strerror());
exit(-1);
}
printf("found usb missile launcher\n");
config = &dev->config[0];
interface = &config->interface[0];
altsetting = &interface->altsetting[0];
if (usb_set_configuration(udh, config->bConfigurationValue) < 0)
{
if (usb_detach_kernel_driver_np(udh,
altsetting->bInterfaceNumber) < 0)
{
printf("usb_set_configration() error.\n");
usb_close(udh);
return -1;
}
}
// インタフェースの使用をシステムに通知。
if (usb_claim_interface(udh, altsetting->bInterfaceNumber) < 0)
{
// インタフェース使用要求でエラー。
printf("claiming interface error\n");
}
else
{
for (j = 0; j < 6; j++)
{
// 送信データ構成。
buf[0] = MISSILE_CMD_HEADER;
switch (j)
{
case 0:
buf[1] = MISSILE_CMD_RIGHT;
break;
case 1:
buf[1] = MISSILE_CMD_LEFT;
break;
case 2:
buf[1] = MISSILE_CMD_UP;
break;
case 3:
buf[1] = MISSILE_CMD_DOWN;
break;
case 4:
buf[1] = MISSILE_CMD_STOP;
break;
case 5:
buf[1] = MISSILE_CMD_FIRE;
break;
default:
break;
}
for (i = 2; i < 8; i++)
{
buf[i] = 0x00;
}
// 送信。
result = usb_control_msg(
udh,
USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
HID_REPORT_SET,
0,
0,
(char*)buf,
sizeof(buf),
USB_TIMEOUT);
if (result < 0)
{
// 送信エラー。
printf("usb write error.\n");
}
else
{
printf("send data.\n");
}
sleep(1);
}
// インタフェースの解放。
usb_release_interface(udh, 0);
}
// デバイスクローズ。
usb_close(udh);
return 0;
}
}
}
return -1;
}

0 件のコメント:
コメントを投稿