AE-DRV8830 と HC-05を連携させてモーターを制御する(ブレッドボード編)

昨晩、AE-DRV8830 を使ってモーターが動いたので、そのまま HC-05(Bluetooth)と連携させてテスト、そのまま、もうひとつ AE-DRV8830 をつなげて、2個のモーターを動かすことができました。

20150310_02

これで、先に作った RasPi 戦車を自作のモータードライバ版に置き換えられます。AE-DRV8830 は、秋月電子で買えば 170円なので、2個買っても 340円と非常に安いです。一般的な Raspberry Pi のモーターシールドが 3000円強するので、これを使えばかなりモーターが制御できるようになります。ただし、Arduino に限って言えば Amazon.co.jp: Arduino MEGA UNO Duemilanove 最高品質 用の L293D モーター シールド ボード: DIY・工具 なんてのが出ていて、なんかひどく安いです。IC に L293D というのを使っていて、一時期大量生産したのか中国でコピーものが広まったのかよくわかりませんが、えらく安く手に入ります。ただし、レビューを見ると品質的に問題があって、動いたり動かなかったりする外れもあるみたいなんですが。

実は、L293D の IC って、日本向けには売っていないんですよね。

L293D | ペリフェラル・ドライバ/アクチュエータ | 他のインターフェイス | 概要と機能一覧
http://www.tij.co.jp/product/jp/L293D?keyMatch=L293D&tisearch=Search-JP-Everything

まあ、eBuy 経由か、どこか適当なところから買えば安く手にはいるので問題はなさそうです。海外の作例を見ると L293D を使っている例があって、手元の Raspberry Pi のモーターシールドにも L293D を使っているので回路を組んではみたいと思ってます。1つのICで、2つのモーターが制御できるので、AE-DRV8830 を 2つ使わなくてもよい、という利点があります。他にも色々違いはあると思うのですが。

それはさておき、

  • Arudino で、DRV8830 に Wire 送信する。
  • Arduino で、HC-05/Bluetooth シリアル受信する。
  • Windows ストアアプリから HC-05 へシリアル送信する。

のプログラムを組んで、無事無線でモーター制御が完了。コードは後日まとめます。Arduino のチップを抜き出して小型すれば、そのままプラレールの電車に乗せられそうです(電池は2両目から供給ってことになりそうですが)。

実際に配線したところはこちら。えらいごちゃごちゃしているのは、ジャンパーピンでやっているからですね。LED がついているのは、Bluetooth でのシリアル通信の確認用です。

image

タイマ IC 555 を 2つ使ってモーターを制御できる

DRV8830 は I2C を使っているので、たくさんの IC を使っても一組の SDA/SCL で済みます。まあ、それでもチップが小さすぎるので本格的に小型化するとき(基板に乗せるとき?)はいいんでしょうが、1,2 個のモーター制御だけだとちょっと大げさな感じがします。

で、Frizing のページを Bluetooth で検索していたら、タイマ IC を 2個使ってモーターを制御している例がありました。

Fritzing Project – Arduino Android Bluetooth Panzer
http://fritzing.org/projects/arduino-android-bluetooth-panzer
New Project: Projects in Motion: Control Three Types of Motors with 555 Timers – Make: | Make:
http://makezine.com/projects/projects-in-motion-control-three-types-of-motors-with-555-timers/

555 のタイマー IC は、ひどく安くて 30円とか50円ぐらいのものからあります。Arduino からのピン制御の数は増えてしまいますが、モーターだけを制御したい場合にはこれで十分かもしれません。これはまた別途購入したら試してみましょう。

カテゴリー: Arduino | AE-DRV8830 と HC-05を連携させてモーターを制御する(ブレッドボード編) はコメントを受け付けていません

mbed LPC1114FN28 で Lチカする

mbed LPC1114FN28 – スイッチサイエンス
https://www.switch-science.com/catalog/1714/
mbed LPC1114FN28

勢い(調子に)乗って、mbed も買ってみました。評価キットになっているものはそれなりに値段が高いので、ほとんど素の状態の LPC1114FN28 を使います。ついでに、LPC1114FN28 本体も安い(200円ちょっと)ので 2個ほど手に入れました。これでマイコンを倍増できるぞと思っていたわけですが、手元に届くと結構でかいですね、これ。20x40mm 位あって小さなブレッドボードの半分を占有してしまいます。今あらためてみたんですが、LPC1114FN28 って 32ビットマイコンなんですね。

ブラウザ上でコーディングする

http://developer.mbed.org/ でサインアップして、ブラウザ上でコーディングします。このアドレスは、mbed を USB に接続したときに出てくる、mbed.htm に書いてあります。この中には、デバイスの ID が書いてあるので、サイトでの登録も自動的に行われます。

image

インテリセンスはあまり効きませんが、ダブルクリックをするとヘルプがでます。あまりマニュアルを見なくても、なんとなくコーディングができるのが便利です。あと、色々なサンプルとライブラリがあるそうなので、そのあたり使うと一気に楽になるかも。

コンパイルして mbed にインストールする

メニューにある「Compile」ボタンを押すと、コンパイルが始まって、成功すると出来上がったバイナリファイル(*.bin)をダウンロードできるようになります。このファイルを、mbed がつながっているドライブにドラッグ&ドロップすれば ok です。

あとは、mbed ボードのスイッチを押してリセットすれば完了です。非常に簡単ですね。ブレッドボードを使って Lチカするだけならば、あっという間です。センサーを読み込んだり、サーボを動かしたりするのはそれなりに組まないとだめなんでしょうが、そのあたりは cookbook にありそうです。

image

ひとまず、

  • Raspberry Pi
  • Arduino
  • Netduino
  • PIC
  • mebed

と開発環境を触ってきたので、これで一区切りです。それぞれ得手不得手があるので、Raspi 戦車とか meArm をベースにして書き換えていこうという心づもり。あと Bluetooth LE との組み合わせとか、かなり自分の手が広がった感じ。

そうそう、ターゲットは、Raspberry Pi 2  + Windows 10 + 戦車/ロボットアーム ですからッ!!! これが一気にできると、相当広がるはず、と思ってます。

カテゴリー: mbed | mbed LPC1114FN28 で Lチカする はコメントを受け付けていません

PICでLチカするための環境を整える

やっとこさ PIC までたどり着いた…と思ったら、LPC という ARM のチップがあることを知ったので(mbed って ARM ですね、確かに)、小さくするのならば LPC でもいいかなと思い始めてはいるのですが…ともあれ、どちらもやったことがないので、まずは PIC から。

image

秋月電子で、PICkit3PIC18F14K50使用USB対応超小型マイコンボード を一緒に買いました。PIC のチップだけを買えば、100円もしないのですが、書き込み方がよくわからないのと、USB 書き込み(たぶんシリアル経由ですよね)と ICSP直結(こっちが PICKit3 で書き込む方)自体がよくわからなかったので、まあひとまず、初期投資ということで。それでも RPi を買うよりも随分安いわけですが。

開発環境をインストールする

MPLAB®X IDE | Microchip Technology Inc.
http://www.microchip.com/pagehandler/en-us/family/mplabx/home.html

上記から MPLAB X IDE をダウンロードします。現時点で、v3 のベータ版が出ているのですが、Available Downloads のほうの v2.35 を入れました。

これをインストールすると、コンパイラが自動でダウンロードして…となるハズなのですが、なんか、どうやってもコンパイラは自動ではインストールされていないみたいなので(アセンブラのほうは入った模様なんですが)、自前でダウンロードしてインストールします。これをやらないと、ビルドするときに「対応するコンパイラーがない」というエラーがでます。

| Microchip Technology Inc.
http://www.microchip.com/pagehandler/en-us/devtools/mplabxc/home.html

この中の MPLABR XC8 Compiler v1.34 をダウンロードすれば ok です。Free 版は最適化が弱いのですが、どうせ実験なのでこれで十分です。ビルドサイズに制限があるのかどうかは分かりません。32kb の制限がありそうな気がします。いくつかのブログでは HI-TECH PICC Lite の手順が書いてあったりしますが、Hi-TECH という会社が、Microchip社に買収されて、名前が、XC8 みたいになったようです。MPLAB X IDE の対象のコンパイラに Hi-TECH の名前が残っていますが、それは無視していいようです。

プロジェクトを作る

Visual Studio のようにいくつかのテンプレートが用意されています。PIC18F14K50 の場合は、Samples > Microchip Embedded > PIC18 C Template を選択すればよいでしょう。

image

そうすると、こんな風にいくつかのファイルを自動的に作ってくれます。使うところは main.c だけなんですが、

image

プログラミングする

Arduino とか Netduino のように、なんとなく勘で(苦笑)と思ったのですが、あえなく挫折しました。LED を光らせるにしてもポートの指定の仕方が分からないし、ポートの指定にしても PIC の種類によって違うらしく、目的のものを見つけないと難しい。

PIC18F14K80 の特徴 入門と応用
http://sky.geocities.jp/home_iwamoto/page/P14K50/P14_00.htm

そんな訳で、PIC18F14K80 でひたすら検索して、ずばりそのものを引き当ててコードを丸写しして動かしました。こりゃ大変だわ、と思って先人の感謝です。どうやら USB 内蔵の高性能 PIC らしいんですが、そこまで使い込めるかどうか自信がありませんw。まあ、練習用なので。

以下のコードでLチカができています。たぶん、#pragma のあたりはいらないのでしょうが…と思ったけど無いと動きません。そのままコピペです。

/******************************************************************************/
/* Files to Include                                                           */
/******************************************************************************/

#if defined(__XC)
    #include <xc.h>        /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>       /* HiTech General Include File */
#elif defined(__18CXX)
    #include <p18cxxx.h>   /* C18 General Include File */
#endif

#if defined(__XC) || defined(HI_TECH_C)

#include <stdint.h>        /* For uint8_t definition */
#include <stdbool.h>       /* For true/false definition */

#endif

#include &quot;system.h&quot;        /* System funct/params, like osc/peripheral config */
#include &quot;user.h&quot;          /* User funct/params, such as InitApp */

/******************************************************************************/
/* User Global Variable Declaration                                           */
/******************************************************************************/

/* i.e. uint8_t <variable_name>; */
#define LED LATCbits.LATC0

#pragma config FOSC = IRC    
#pragma config USBDIV = OFF, CPUDIV = NOCLKDIV
#pragma config IESO  = OFF, FCMEN = OFF, PLLEN  = ON
#pragma config BORV  = 30,  BOREN = OFF, PWRTEN = OFF
#pragma config WDTPS = 32768, WDTEN = OFF
#pragma config MCLRE = OFF, HFOFST = OFF, XINST  = OFF
#pragma config BBSIZ = OFF, LVP    = OFF, STVREN = ON
#pragma config CP1  = OFF, CP0  = OFF, CPD  = OFF, CPB  = OFF
#pragma config WRT1 = OFF, WRT0 = OFF, WRTB = OFF, WRTC = OFF
#pragma config EBTR1 = OFF, EBTR0 = OFF, EBTRB  = OFF

#define _XTAL_FREQ 12000000

/******************************************************************************/
/* Main Program                                                               */
/******************************************************************************/

void main(void)
{
    /* Configure the oscillator for the device */
    ConfigureOscillator();

    /* Initialize I/O and Peripherals for application */
    InitApp();

    /* TODO <INSERT USER APPLICATION CODE HERE> */
    OSCCON = 0x40; // 4MHz
    TRISC  = 0x00; // Degital mode

    while(1) {
        Delay1KTCYx(500);
        LED = 1;
        Delay1KTCYx(500);
        LED = 0;
    }
}

トラブルシューティング

最初はなかなか動かなくて苦労しました。で、もう一度動かそうと思って苦労してたりするので、ハマりどころが多いのかもしれません。

コンパイルができない

最初に嵌った穴で、MPLAB X IDE をインストールしただけではダメです。コンパイラ MPLABR XC8 Compiler v1.34  も手動でダウンロードしてインストールします。たぶん、以前から使っている場合は、HI-TECH PICC Lite が入っているので大丈夫っぽいのですが、新規にインストールするときはコンパイラを忘れずに

PICKit3 から書き込めない

Connect できないパターンは、私の場合は3つの落とし穴でした。

  • PICkit3 は USB 2.0 に差すこと(USB 3.0のコネクタでは動かない)
  • PICkit3 の電源のため、USB ハブではなくて、PC の元に差すこと(これはマニュアルにも書いてありました。電力が結構必要なようです)
  • PIC 自身に電源供給をしないと駄目。PICkit3 から PIC のチップへ給電するモードもあるのですが、安定せずに何回か失敗します。

PIC への書き込みも、種類によって 3V から 9V まで必要な電圧が違うそうなので、USB の 5V だけでは足りない場合もあります。そのときは、外部電源として電池を使うのがいいんでしょう。

何かを壊して、書き込めないときがある

よくわからないのですが、The programmer could not be started: Could not acquire hardware tool communications resources: PICkit3PlatformTool SN# のようになって、何度やっても書き込めないときがあります。どうやら、ブートローダーか何かを壊したらしく、そのままでは書き込みができません。同じようなプロジェクトを作って、焼き込みをすると直るという不思議な現象なのですが、そういうものみたいです。ドライバーを再書き込みすればいいみたいです。

そんな訳でやっとこさ Lチカまで。

image

この後、mbed を試したのですが、これはすんなりといきました。ああ、セッティングをしなくていいいってのは mbed の素晴らしところですね。

カテゴリー: PIC | PICでLチカするための環境を整える はコメントを受け付けていません

Raspberry Pi で Wii コントローラを認識させる準備

Wiimote という python スクリプトがあって、これを使うとさっくりと Wii コントローラーを試せます。となるハズです。「ハズです」というのは、どうやら Wii コントローラ自体の個体差があって、すんなり繋がったり繋がらなかったりするらしいんですね。ちなみに、私の手元の Wii コントローラは「Wii MotionPlus INSIDE」というやつなのですが、すんなり繋がらないほうです。

Raspberry Pi – How to use a Wiimote! – YouTube
https://www.youtube.com/watch?v=bO5-FjLe5xE&list=UUfY8sl5Q6VKndz0nLaGygPw

にある通り、

– Bluetooth ドングルを RasPi に差しておく
– git clone https://github.com/the-raspberry-pi-guy/Wiimote でサンプルコードを取得
– sh setup.sh で bluetooth 関連を apt-get する
– python wiimote.py を起動したら、Wii コントローラの 1,2 ボタンを同時押ししてペアリングを行う。

そうすると、うまく接続できればペアリングが実行されて、各種のボタンを認識します。

ペアリングできない

しかし、私の手元にあるもので試すと、何度やってもペアリングができません。lsusb で確認したりしたのですが、No wiimotes found となって、認識しません。

Wii コントローラ自体が壊れているのかと思ったのですが、hcitool scan をすると MAC ID が取得できます。

ちなみに、実は Wii MotionPlus の場合は 1+2 ボタンの同時押しではペアリングできなくて、後ろの Sync ボタンを押さないとペアリングできないそうです。youtube の画像は 1+2 ボタンの同時押しでうまくいっているので、北米版と日本版との違いとか販売時期で違いがあるのかもしれません。手元にあるのは去年の夏に買ったものです。

CWiiDを直接調べる

最終的に使うのは、python ではなくて、C# から使いたいので、先の setup.sh でインストールしたライブラリを直接使う必要があります。

sudo apt-get update
sudo apt-get install --no-install-recommends bluetooth -y
sudo apt-get install python-cwiid

wiimote は、ライブラリに python-cwiid を使っていて、これが cwiid を使っています。

CWiiD – Community Help Wiki
https://help.ubuntu.com/community/CWiiD
abstrakraft/cwiid
https://github.com/abstrakraft/cwiid

github にコードが公開されているので、ビルドし直すかデバッグを入れればなんとかわかるだろうと思ったわけです。
cwiid 自体のビルドにちょっと苦労しましたが、以下のようにパッケージをインストールしておけば ok です。現在の RasPi は Gtk3 が入っているのですが、cwiid は Gtk2 を要求するので、パッケージを改めていれておきます。

apt-get install flex bison libgtk2.0-dev

で、結論から言えば、libcwiid/process.c にある process_write 関数での wiimote->rw_status の判別をコメントアウトしてしまいます。

cwiid/process.c at master ・ abstrakraft/cwiid
https://github.com/abstrakraft/cwiid/blob/master/libcwiid/process.c#L284-L287

int process_write(struct wiimote *wiimote, unsigned char *data)
{
        struct rw_mesg rw_mesg;
/*
        if (wiimote->rw_status != RW_WRITE) {
                cwiid_err(wiimote, &quot;XXX Received unexpected write report&quot;);
                return -1;
        }
*/
        rw_mesg.type = RW_WRITE;
        rw_mesg.error = data[0];

        if (write(wiimote->rw_pipe[1], &rw_mesg, sizeof rw_mesg) !=
          sizeof rw_mesg) {
                cwiid_err(wiimote, &quot;RW pipe write error&quot;);
                return -1;
        }

        return 0;
}

どうやら、手元にある wii コントローラだと wiimote->rw_status の値が RW_WRITE にならないみたいなのです。すんなり動くパターンもあるので、どこかのコードの判別だと思うのですが、ひとまず、ここをコメントアウトしてしまうと普通に通るようになります。

wmdemo で試してみる

これも 1+2 同時押しが効かない関連なのかもしれませんが、手元のものだと自動検索が効かないらしく Wii コントローラーの MAC アドレスを直接指定します。先に hcitool scan で探し出しておいた MAC ID を引数にして起動します。

wmdemo 8C:CD:E8:6B:B4:3A

そして、Wii コントローラの裏にある Sync ボタンを押すと、無事ペアリングが行われます。LED が常にちかちかした状態になってしまうのは、このあたりの不具合のせいなのかもしれませんが、一応ボタンなどのデータが取れます。

受信データは、以下のコメントアウトを戻せば表示されます。

cwiid/thread.c at master ・ abstrakraft/cwiid
https://github.com/abstrakraft/cwiid/blob/master/libcwiid/thread.c#L59-L62

データ長さは、4バイトか6バイトのようです。-/+ ボタンや方向ボタンを押すとビットが変わるので、これを取れば他のプログラムと連携することができます。

Windows で動く wiimote がある

あれこれと探していたら、以下に C# での実装がありました。

Managed Library for Nintendo’s Wiimote | Coding4Fun Articles | Channel 9
http://channel9.msdn.com/coding4fun/articles/Managed-Library-for-Nintendos-Wiimote
Managed Library for Nintendo’s Wiimote – Home
http://wiimotelib.codeplex.com/

試してみると、私の wii コントローラでは動かない(コード自体は wii remote 対応らしく微妙に違うみたい)のですが、コードがあるのでなんとかなりそうです。

ちなみに、Windows 8.1 では wii コントローラは認識されます。

Bluetooth でのペアリングで、PIN コードは何のか?と悩んだのですが、「何もいれない」まま次へボタンを押せば ok です。PIN コードが設定されていないので、そのままペアリングが成功します(むしろ、入れるとエラーになります)。

Bluetooth での認識では、Nintendo RVL-CNT-01-TR となっていて、サービスは、HID になっていますね。いくつか調べていくと、HID と SPP と両方が対応しているようなので、RasPi の cwiid では SPP を使っているような感じがします。このあたりは、PS3 の Dualshock3 のコードと後から見比べてみます。

デバイス – Windows app development
https://msdn.microsoft.com/ja-jp/library/windows/apps/bg182882.aspx#one

にストアアプリから HID を扱う方法があるのですが、これがそのまま wii コントローラで使えるかどうかは謎です。

Dolphinで実機のWiiリモコン(周辺機器)を使う – GC+Wiiエミュレータ Wiki*
http://wikiwiki.jp/gcwiiemu/?Tips_Connect_RealWiimote

Wii エミュレータをインストールして、ドライバー部分だけ使うっていう方法もあるみたいなんですが、動作確認はしていません。
Windows 10 だと Bluetooth 周りが楽になっているハズなので、そっちのほうは後で確認。

追記 Wii リモートで接続

気になったので、中古で Wii Remote を買ってきました。そうすると、あっさりつながりますね。managed 版の wiimote もあっさり認識するので、使うならばこっちのほうが良さそうです。これの話は後日。

カテゴリー: RaspberryPi | 5件のコメント

Raspberry Pi で戦車を作る(拡張編)

ひと通り、Raspberry Pi で動く戦車ができたのでおしまい…という訳ではなくて、これを拡張/派生させていきます。RasPi 戦車の最大の目的は、

  • リモコンで動くこと
  • モーターが制御できること

の2点なので、有線ケーブル(USBケーブル接続など)は対象外です。あと、戦車自体を「動かす」ことが私の目的なので、Raspberry Pi に外部電源を乗せています。これは、拡張先である Arduino なども同じです。メインチップに供給する電源とは違うところから取ってくるってのが必須。

image

以前、LEGO Mindstorms EV3 で作った時のノウハウを使っているので、PS3 Dualshock3 のコントローラーで Bluetooth 接続させています。モータードライバは手早く済まそうと思って購入してしまいました(本当は自作する予定だった)。制御フローでいえば、5つのブロックに分かれているわけで、これを切り替えることで、拡張できますよね。というか、もともとそのつもりでプログラムの作っています。

ざっと、今考えているところを書き出すとこれだけあります。

image

Bluetooth 付きのコントローラーとして Wii コントローラーを使う方法があります。また、Android のスマートフォンを使って RFCOMM で繋ぐ方法もありますよね。通信方法も、Bluetooth よりも WiFi のほうが手軽です。更に、赤外線を使うと非常に安くできます。Dualshock3 が 4,000円を超えますが、赤外線だと500円ぐらいでできそうです。

また、本体は、Raspberry Pi で動かしてますが、Arduino を使ってもできるハズです。これもシリアル通信にすれば結構いろんなことができるし、赤外線通信も可能です。ライントレーサーのような自動で動く仕組みでもいいんですが、ここはコントローラーで動かしていきたいですね。

モータ制御のところも、現在の ON/OFF だけではなくて、PWM 制御にすれば高速/低速で動かせます。このあたりはラジコンカーの制御も合わせると色々種類があります。また、コントローラ自体が多様(スマートフォンからの動かせるし)なので、従来のラジコンよりも色々な操作をひとつのコントローラに詰め込めます。動力のモーターと、サーボを同時に動かすこともできるだろうし、LEDや音を鳴らすこともできるでしょう。そのあたりのギミックが無線でもやりやすくなっています。

Raspberry Pi 2 自体は 5,000円近くするので、数台用意して実験するのは大変ですが、Arduino のボードを使って半額ぐらいで済ますことも可能です。更に言えば、Arduino で使っているチップを取り出して、必要な部分だけ基板で組めばもっと安くできそうです。このあたりはもうちょっと探っていきたいところです。

Arduinoブートローダ書き込み済みATMega328P-PU(内蔵CR発振8MHz版) – スイッチサイエンス
https://www.switch-science.com/catalog/1414/
Arduinoブートローダ書き込み済みATMega328P-PU(内蔵CR発振8MHz版)

こんな感じで、ブートローダーが書き込んだものが 400円弱で手に入るのだから、モーター制御だけの専用基板に組み込めば、かなり小さく&安くできそうな感じです。そうすると、1台だけじゃなくて、5,6台は一気に作れそうですよね。5台ぐらいあると、個々に赤外線センサーや距離センサーを乗せて、相互に自動で動かしたりかなりおもしろいことができそうです。まあ、1万円/台で作ってもいいんでしょうが、そこは創意工夫と頭を使って製作費を下げる努力をするということで。

カテゴリー: RaspberryPi | Raspberry Pi で戦車を作る(拡張編) はコメントを受け付けていません

Raspberry Pi で戦車を作る(リモコン編)

ゲームコントローラーで戦車のモーターを制御するということで、以下の2つをくっつけます。

Raspberry Pi で戦車を作る(Bluetooth/PS3 Dualshock3編)
http://www.moonmile.net/blog/archives/6898
Raspberry Pi で戦車を作る(モーターシールド編)
http://www.moonmile.net/blog/archives/6910

ジョイスティックをイベント化する

https://github.com/moonmile/RaspiTank/blob/master/RaspiRobot/BPiJoystick.cs

– ジョイスティックの変更イベント OnChangedJoystick
– ボタン状態の変更イベント OnChangedButton

を作成します。ジョイスティックの場合は、XY軸がちょっとずれただけでイベントが発生するので、ボタンのON/OFFとは別にイベントを発生させます。

protected void OnLoop()
{
    while (this.IsLoop)
    {
        js_event js;
        js.time = _br.ReadUInt32();
        js.value = _br.ReadInt16();
        js.type = _br.ReadByte();
        js.number = _br.ReadByte();
        // Console.WriteLine(js.ToString());

		bool changedJoystick = false;
		bool changedButton = false;
        if (BPiJoystickData.IsAxis(js.type))
        {
            if (this.Joystick.GetAxisValue(js.number) != js.value)
            {
                Joystick.SetValue(js.type, js.number, js.value);
				changedJoystick = true;
            }
        }
        else if (BPiJoystickData.IsButton(js.type))
        {
            if (Joystick.GetButtonValue(js.number) != (js.value != 0))
            {
                Joystick.SetValue(js.type, js.number, js.value);
				changedButton = true;
            }
        }
        // filter
        if (BPiJoystickData.IsAxis(js.type) && js.number >= 6) changedJoystick = false;
        if (BPiJoystickData.IsButton(js.type) && js.number >= 16) changedButton = false;

        // raise value change event
		if (changedJoystick)
        {
            if (OnChangedJoystick != null)
            {
				OnChangedJoystick(this, new JoystickEventArgs()
                {
                    Joystick = this.Joystick,
                    Raw = js
                });
            }
            // Console.Write(&quot;{0} {1} {2} &quot;, js.type, js.number, js.value );
            // Console.WriteLine(j.ToString());
        }
		if (changedButton)
		{
			if (OnChangedButton != null)
			{
				OnChangedButton(this, new JoystickEventArgs()
				{
					Joystick = this.Joystick,
					Raw = js
				});
			}
			// Console.Write(&quot;{0} {1} {2} &quot;, js.type, js.number, js.value );
			// Console.WriteLine(j.ToString());
		}
    }
    this._br.Close();
}

コントローラーの動きでモーターを制御する

アナログジョイスティックやボタンを押したときのモーター制御やLED点灯を行います。

https://github.com/moonmile/RaspiTank/blob/master/RaspiRobot/Program.cs

class Program
{
	static void Main(string[] args)
	{
		new Program().main();
	}

	BPiJoystick js;
	RaspiRobotNet.RaspiRobot robot;
		
	public void main()
	{
		robot = new RaspiRobotNet.RaspiRobot();

		js = new BPiJoystick();
		js.OnChangedJoystick += js_OnChangedJoystick;
		js.OnChangedButton += js_OnChangedButton;
		js.Setup();
		Console.WriteLine(&quot;any key is stop.&quot;);
		var key = Console.ReadKey();
	}

	/// <summary>
	/// ボタンが変更された
	/// </summary>
	/// <param name=&quot;arg1&quot;></param>
	/// <param name=&quot;arg2&quot;></param>
	void js_OnChangedButton(object sender, JoystickEventArgs e)
	{
		if (e.Joystick.Up == true) robot.Forward();
		else if (e.Joystick.Down == true) robot.Back();
		else if (e.Joystick.Left == true) robot.Left();
		else if (e.Joystick.Right == true) robot.Right();
		else
		{
			if (e.Joystick.Up == false && e.Joystick.Down == false &&
				e.Joystick.Left == false && e.Joystick.Right == false)
				robot.Stop();
		}

		/// LED1,2 を点灯する
		robot.SetLED1( e.Joystick.Circle );
		robot.SetLED2( e.Joystick.Cross );
	}
	/// <summary>
	/// ジョイスティックを変更
	/// </summary>
	/// <param name=&quot;sender&quot;></param>
	/// <param name=&quot;e&quot;></param>
	void js_OnChangedJoystick(object sender, JoystickEventArgs e)
	{
		int ly = e.Joystick.LeftAxisY;
		int ry = e.Joystick.RightAxisY;
		Console.WriteLine(&quot;joystick {0} {1}&quot;, ly, ry);
		int sp1 = ly / (32767 / 200);
		int sp2 = ry / (32767 / 200);
		if (e.Joystick.Up == false && e.Joystick.Down == false &&
			e.Joystick.Left == false && e.Joystick.Right == false)
		{
			move_bot(sp1, sp2);
		}
	}
	void move_bot(int sp1, int sp2)
	{
		if (sp1 > 0 && sp2 > 0) { robot.Forward(); }
		if (sp1 < 0 && sp2 > 0) { robot.Right(); }
		if (sp1 > 0 && sp2 < 0) { robot.Left(); }
		if (sp1 < 0 && sp2 < 0) { robot.Reverse(); }
		// 停止
		if (sp1 == 0 && sp2 == 0) { 
			robot.Stop(); 
		}
		// 右だけ動かす
		if (sp1 == 0)
		{
			if ( sp2 > 0 )
				robot.SetMotors(false, false, true, false);
			if (sp2 < 0)
				robot.SetMotors(false, false, true, true);
		}
		// 左だけ動かす
		if (sp2 == 0)
		{
			if (sp1 > 0)
				robot.SetMotors(true, false, false, false);
			if (sp1 < 0)
				robot.SetMotors(true, true, false, false);
		}
	}
}

このプログラム自体はターミナルで起動することを想定しているので、最終的には /etc/ini.d を利用して初期起動させます。WiFi のドングルが結構な電力を食っているので、これを外すだけでもかなり RasPi の動作が安定します。ただし、外側から RasPi の状態が見えなくなってしまうので、何らかのモニタリングが必要ですよね。あとで、RasPi にミニ液晶を付けて状態を監視できるようにします。

上記ではジョイスティックといくつかの○×ボタンを単独で感知していますが、同時押しとかR/Lボタンも取得ができます。ちなみに、ジョイスティックの傾きも取れるので、スマートフォンを傾けたときのような動作も可能です。このあたりは、RasPi 戦車に限らず、RasPi 自体を媒介させることで、ゲームコントローラー -> RasPi -> Windows PC というパターンが組めます。Windows 自体はゲームコントローラを認識するのですが、なぜか 8.1 から PS3 Dualshock3 は認識しないんですよね。

カテゴリー: C#, RaspberryPi | Raspberry Pi で戦車を作る(リモコン編) はコメントを受け付けていません

Raspberry Pi で戦車を作る(モーターシールド編)

Raspberry Pi用モータードライバボード(キット) – スイッチサイエンス
https://www.switch-science.com/catalog/1239/

今度は、モータードライバーを使ってモーターを動かします。今回使っているのは Raspberry Pi 用のモータードライバーシールドで、4,000円弱という RasPi が買えるかもしれません、というお値段で結構します。慣れれば自作できるようなんですが、手始めにひとつ買ってためしています。ちなみに、このキットは v2 が出ていて adafrutit などから購入できます。

RasPi Robot Board v2 by MonkMakes ID: 1940 – $29.95 : Adafruit Industries, Unique & fun DIY electronics and kits
http://www.adafruit.com/product/1940

動作させるためのサンプルコードは以下にあります。

simonmonk/raspirobotboard2
https://github.com/simonmonk/raspirobotboard2

9V(乾電池6個)を給電すると、RasPi に 5V 給電してくれるので、RasPi 本体への USB 給電がいらなくなるみたいです。私の場合は、両方に 5V ずつ給電しているので、今度試してみましょう。

サンプルコードを追っていくと

– ボード上の LED1,2 を光らせる
– ボード上の SW1,2 を ON/OFF できる
– モーター1,2 を回転/逆回転できる

ことが分かります。残念ながらスピード制御はできないので、戦車のようなキャタピラ式のものとか、ギア比を変えてアームを動かすとかに使えますね。PWM制御(パルス制御)のほうは、別途回路を組んで実験していきます。

両輪のギアーボックスを使うと、右左の車輪を別々に制御できるので、車体を右左に曲げることができます。普通の車のようにハンドル+後輪駆動みたいにしたい場合は、別途サーボ制御が必要になるのですが、キャタピラ式はこれで十分だったりします。まあ、普通のラジコンカーを作るのも今後の課題ですね。

ピンを調べる

さて、ON/OFF のピンは、サンプルの python スクリプトを見ると以下のようになっています。

https://github.com/simonmonk/raspirobotboard/blob/master/raspirobotboard.py

LEFT_GO_PIN = 17
LEFT_DIR_PIN = 4
RIGHT_GO_PIN = 10
RIGHT_DIR_PIN = 25
SW1_PIN = 11
SW2_PIN = 9
LED1_PIN = 7
LED2_PIN = 8
OC1_PIN = 22
OC2_PIN = 21

RasPi 専用のシールドなので、GPIO のピンは RasPi に合わせてあるわけですが、この GPIO の番号と Arduino のそれとを合わせてやれば、Arduino でも使うことができると思います。まあ、Arduino 専用のものを買ったほうが早かったり、自作したほうがいい気もしますが。

C# で使えるように書き直す

後で整理して git にアップしますが、python のコードを C# に書き直したのが次のものです。
内部的に

AlexSartori/RaspberryGPIOManager
https://github.com/AlexSartori/RaspberryGPIOManager

をちょっと改変して使っています。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RaspberryGPIOManager;
using System.Threading;

namespace RaspiRobotNet
{
    public class RaspiRobot
    {
		const int LEFT_GO_PIN = 17;
		const int LEFT_DIR_PIN = 4;
		const int RIGHT_GO_PIN = 10;
		const int RIGHT_DIR_PIN = 25;
		const int SW1_PIN = 11;
		const int SW2_PIN = 9;
		const int LED1_PIN = 7;
		const int LED2_PIN = 8;
		const int OC1_PIN = 22;
		const int OC2_PIN = 21;

		public GPIOPinDriver LED1 { get; set; }
		public GPIOPinDriver LED2 { get; set; }
		public GPIOPinDriver OC1 { get; set; }
		public GPIOPinDriver OC2 { get; set; }
		public GPIOPinDriver LEFT_GO { get; set; }
		public GPIOPinDriver LEFT_DIR { get; set; }
		public GPIOPinDriver RIGHT_GO { get; set; }
		public GPIOPinDriver RIGHT_DIR { get; set; }

		public RaspiRobot()
		{
			this.LED1 = new GPIOPinDriver(GPIOPinDriver.Pin.GPIO7, GPIOPinDriver.GPIODirection.Out, GPIOPinDriver.GPIOState.Low);
			this.LED2 = new GPIOPinDriver(GPIOPinDriver.Pin.GPIO8, GPIOPinDriver.GPIODirection.Out, GPIOPinDriver.GPIOState.Low);
			this.OC1 = new GPIOPinDriver(GPIOPinDriver.Pin.GPIO22, GPIOPinDriver.GPIODirection.Out, GPIOPinDriver.GPIOState.Low);
			this.OC2 = new GPIOPinDriver(GPIOPinDriver.Pin.GPIO21, GPIOPinDriver.GPIODirection.Out, GPIOPinDriver.GPIOState.Low);
			this.LEFT_GO = new GPIOPinDriver(GPIOPinDriver.Pin.GPIO17, GPIOPinDriver.GPIODirection.Out, GPIOPinDriver.GPIOState.Low);
			this.LEFT_DIR = new GPIOPinDriver(GPIOPinDriver.Pin.GPIO4, GPIOPinDriver.GPIODirection.Out, GPIOPinDriver.GPIOState.Low);
			this.RIGHT_GO = new GPIOPinDriver(GPIOPinDriver.Pin.GPIO10, GPIOPinDriver.GPIODirection.Out, GPIOPinDriver.GPIOState.Low);
			this.RIGHT_DIR = new GPIOPinDriver(GPIOPinDriver.Pin.GPIO25, GPIOPinDriver.GPIODirection.Out, GPIOPinDriver.GPIOState.Low);
		}

		public void SetMotors( int left_go, int left_dir, int right_go, int right_dir )
		{
			this.SetMotors(left_go != 0, left_dir != 0, right_go != 0, right_dir != 0);
		}
		public void SetMotors( bool left_go, bool left_dir, bool right_go, bool right_dir )
		{
			this.LEFT_GO.State = left_go  ? GPIOPinDriver.GPIOState.High : GPIOPinDriver.GPIOState.Low;
			this.LEFT_DIR.State = left_dir ? GPIOPinDriver.GPIOState.High : GPIOPinDriver.GPIOState.Low;
			this.RIGHT_GO.State = right_go ? GPIOPinDriver.GPIOState.High : GPIOPinDriver.GPIOState.Low;
			this.RIGHT_DIR.State = right_dir ? GPIOPinDriver.GPIOState.High : GPIOPinDriver.GPIOState.Low;
		}

		public void Stop()
		{
			this.SetMotors(false, false, false, false);
		}
		public void Forward(float sec = 0.0f)
		{
			this.SetMotors(true, false, true, false);
			if (sec > 0.0f)
			{
				Thread.Sleep((int)(sec * 1000.0));
				this.Stop();
			}
		}
		public void Left(float sec = 0.0f)
		{
			this.SetMotors(true, false, true, true);
			if (sec > 0.0f)
			{
				Thread.Sleep((int)(sec * 1000.0));
				this.Stop();
			}
		}
		public void Right(float sec = 0.0f)
		{
			this.SetMotors(true, true, true, false);
			if (sec > 0.0f)
			{
				Thread.Sleep((int)(sec * 1000.0));
				this.Stop();
			}
		}
		public void Reverse(float sec = 0.0f)
		{
			this.SetMotors(true, true, true, true);
			if (sec > 0.0f)
			{
				Thread.Sleep((int)(sec * 1000.0));
				this.Stop();
			}
		}
		public void Back(float sec = 0.0f)
		{
			this.Reverse(sec);
		}

		public void SetLED1( bool sw ) {
			this.LED1.State = sw ? GPIOPinDriver.GPIOState.High : GPIOPinDriver.GPIOState.Low;
		}
		public void SetLED2(bool sw)
		{
			this.LED2.State = sw ? GPIOPinDriver.GPIOState.High : GPIOPinDriver.GPIOState.Low;
		}
		public void SetOC1(bool sw)
		{
			this.OC1.State = sw ? GPIOPinDriver.GPIOState.High : GPIOPinDriver.GPIOState.Low;
		}
		public void SetOC2(bool sw)
		{
			this.OC2.State = sw ? GPIOPinDriver.GPIOState.High : GPIOPinDriver.GPIOState.Low;
		}
	}
}

でもって、F# でテストコードを書いてみます。

open System
open RaspiRobotNet
open RaspberryGPIOManager

[<EntryPoint>]
let main argv = 
    printfn &quot;Hello RaspiRobotNet&quot;

    let robot = new RaspiRobot()
    let mutable loop = true
    while loop do
      let key = Console.ReadKey()
      match key.KeyChar with
      | 'e' | 'q' -> loop <- false
      | 'f' -> robot.Forward(1.0f)
      | 'b' -> robot.Back(1.0f)
      | 'r' -> robot.Right(1.0f)
      | 'l' -> robot.Left(1.0f)
      | 's' -> robot.Stop()
      | '1' -> robot.SetLED1( robot.LED1.State = GPIOPinDriver.GPIOState.Low )
      | '2' -> robot.SetLED2( robot.LED2.State = GPIOPinDriver.GPIOState.Low )
      | '3' -> robot.SetOC1( robot.OC1.State = GPIOPinDriver.GPIOState.Low )
      | '4' -> robot.SetOC2( robot.OC2.State = GPIOPinDriver.GPIOState.Low )
      | _ -> ()
    0 // 整数の終了コードを返します

Tera Term で接続して、WiFi 経由で制御ができます。
F# のインストールは、以下を参考にしてください。

Raspberry Pi 2 に F# をインストールする | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6870

これで、モータードライバーの制御は作れたので、これをゲームコントローラーで制御できるようにしていきます。

カテゴリー: C#, F#, RaspberryPi | Raspberry Pi で戦車を作る(モーターシールド編) はコメントを受け付けていません

MySQL の謎なアップデータを止める方法

正月あたりから、真夜中に謎の黒い画像が出てきて、なんかやって止まるという現象が起きていました。謎な黒い画面ってのは cmd の画面で、なんか流れて1秒経たずに消えてしまうのでなんだか分からなかったんですよね。

それを昨晩、やっとこさ捕まえました。

image

どのプロセスか分からなかったのですが、

C:Program Files (x86)MySQLMySQL Installer for WindowsMySQLInstallerConsole.exe

です。MySQL の何かのアップデートのようで、検索していくと

MySQL :: MySQL Installer Guide :: 2.1 MySQL Product Catalog
http://dev.mysql.com/doc/mysql-installer/en/mysql-installer-catalog.html

なところでカタログのスケジューラが動いているとのことです。左上のアイコンを押して、MySQL Installer Options でスケジュールのチェックを外せば ok ですね。どうやら、MySQL 関連のバージョンアップデートしたかどうか毎日チェックするツールなようです。ええ、毎日チェックしたって、そうそうバージョンアップするものではないし、止めておいてもよいでしょう。

以前はなかったものなので、たぶん最新の MySQL Workbench を入れたときのような気がします。サーバー系ではチェックが必要なんでしょうが、開発用 PC で一瞬だけでるのはやめて欲しいところですね。

ちなみにコマンドプロンプトで schtasks と打っても出てきます。at コマンドってなくなったんですね、ってに今更気づきました。

image

そんな訳で MySQL のカタログスケジューラを止めると、真夜中の謎な黒い画面(cmd)が消えます。カタログ自体は手動でアップデートすればよいので、これで十分です。

カテゴリー: MySQL | MySQL の謎なアップデータを止める方法 はコメントを受け付けていません

Raspberry Pi で戦車を作る(Bluetooth/PS3 Dualshock3編)

RasPi 戦車は、PS3 Dualshock3 コントローラーで操作できるようにしてあります。スマートフォンで WiFi 経由とか Bluetooth 経由が多い中で、コントローラーを使っているのは、まあ、ラジコンと同じ風に扱いたかったからです。これだと5歳児でも動かせますからね。PS3 Dualshock3 には、アナログスティックが2つと、上下ボタンと○×ボタン4個と…色々ついているので、車輪だけじゃない制御がしやすいそうってのもあります。サーボを制御してロボットアームを動かす予定もあって、これを使っています。

が、去年買ってみてあまり汎用的ではないので、どうせならば Bluetooth 対応のコントローラーを自作したほうがいいのですが…まあ、手元にあるということで。ちなみ、PS3 のコントローラは持っているけど、PS3 本体は持っていません。PS4 も持ってません。PS4 用の DualShock4 の場合はどうなるのか?は分からないので、持っている方は試してみてください。

Bluetooth の準備

基本は、

BrickPi + LOGO Mindstorms EV3 をゲームコントローラーでコントロールする(前編) | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/5997

に書いてある手順の通りなのですが、おさらいも兼ねて、もう一度書き連ねておきます。RasPi のレポジトリも新しくなっているので。

apt-get で bluetooth 関連をインストール

sudo apt-get install bluetooth bluez-utils bluez-compat bluez-hcidump
sudo apt-get install libusb-dev libbluetooth-dev

基本は bluetooth だけでいいはずですが、後の QtSixA のために libusb-dev あたりが必要です。

/etc/init.d/bluetooth status

で、きちんと bluetooth デーモンが動いているか確認します。

lsusb

で、Bluetooth ドングルが認識できることを確認。ここでは、Bus 001 Device 004 がそれです。

QtSixA のインストール

PS3 Dualshock3 用のドライバーを入れます。

QtSixA – Browse /QtSixA 1.5.1 at SourceForge.net
http://sourceforge.net/projects/qtsixa/files/QtSixA%201.5.1/

tar -xvf QtSixA-1.5.1-src.tar.gz
cd QtSixA-1.5.1/sixad
make
sudo make install 

今の環境ではきちんとビルドできて、sixpair まで出来上がります。
中身は、bluetooth SPP を解析しているだけだから、C# で書き直すのはそんなに難しくはないと思うんですよね。これは、RasPi で直接 Bluetooth を扱うときに試してみます。

PS3 Dualshock3 とペアリングする

ゲームコントローラーを USB で RasPi につなげて

sudo sixpair

を動かします。

Bluetooth ドングルの MAC ID が表示されます。MAC ID 自体は Windows 8.1 の PC に繋いでデバイスマネージャから確認できます。

動作させる。

ペアリング自体は、最初だけなので、その後はゲームコントローラーの USB を外しても大丈夫です。確か、つなげないで直接 MAC ID を書き込む方法もあります。

sudo sixad -start &

させます。うまく起動したら、ゲームコントローラーの PS ボタンを押せば接続できます。Dualshock3 の MAC ID が表示されます。

通信情報は、/dev/input/js0 に流れてくるので、

sudo cat /dev/input/js0

接続を止める場合は、

sixad -stop

すれば大丈夫です。

コントローラーの通信を解析する

データ自体は以下の構造体で流れてきます。これをうまく読み取ってやれば、各種のボタンの判別がつきます。

public struct js_event
{
	public UInt32 time; /* event timestamp in milliseconds */
	public Int16 value; /* value */
	public byte type; /* event type */
	public byte number; /* axis/button number */
	public override string ToString()
	{
		return string.Format("time:{0} val:{1} type:{2} num:{3}", time, value, type, number);
	}
}

テストコード
https://gist.github.com/moonmile/7c44e5130617c7a76a87

ボタンの割り当てをしたのが上記になります。
このコードは以前書いたもので、ジョイスティックのチェックしかやっていませんが、今回の RasPi 戦車では上下左右ボタンにも対応させています。これは後述します。
同じものが飛んできたら捨てるような処理を入れればいいのです。

カテゴリー: RaspberryPi | Raspberry Pi で戦車を作る(Bluetooth/PS3 Dualshock3編) はコメントを受け付けていません

Raspberry Pi で戦車を作る(材料編)

モーターの制御…というか、モーターってどうやって駆動させるの?の理解に苦労しましたが、ひとまず、コントローラを使って戦車を動かすところまでが完成しました。

https://www.youtube.com/watch?v=LTFYI98lF3c

image

例のごとく Raspberry Pi が固定されていませんが、これはいずれ。土台を LEGO で組んだのですが、ギア部分ががたつくのと RasPi と電源が落ちそうになるので、これも固定式に変えないと駄目です。予定では、この上にアームを乗っけるので。

meArm を使ってサーボモーターの制御はできていたので、今度は足回りの制御です。前に進むだけならば GPIO の ON/OFF でいけるのですが、反転させないといけないので以前に買ったモーターシールドを使っています。RaspiRobot Board 自体は新しいバージョン v2 が出ていることと、もうちょっと頑張れば独自にモータードライバー DRV8830  を買って回路を組めば、もっと安く済みます。

ともあれ、戦車をリモートコントロールで動かす場合は、本体に Arudino/Netduino を使うこともできるし、通信に赤外線/Bluetooth/BLE/WiFi を選ぶことができます。これらの組み合わせは、いずれやっていく予定ですが、ひとまず手元にある/以前やったことがある Bluetooth で試しています。

材料

あとは、土台に LEGO を使っていますが、Amazon.co.jp | 楽しい工作シリーズ No.157 ユニバーサルプレート 2枚セット (70157) | ホビー 通販 を使って組み立てたほうがしっかり作れるでしょう。私ももう一台作るつもりなので、これを買う予定。

という訳で、材料が整ったのでお次は、Bluetooth のセッティングから。

カテゴリー: RaspberryPi | Raspberry Pi で戦車を作る(材料編) はコメントを受け付けていません