ラズパイを無線ロボットカーにする

ラズパイ(ラズベリーPi)に車輪をつけ、Android端末のアプリ操作で動かします。
これを実現するために、以下のことをおこないます。
また、回路はブレットボードを使用して制作します。

ラズパイに車輪をつけ動かす

■ 全景

まずロボットカーにするため、ボディを作成します。
この図では、以下の物を使用しました。

・ラズパイ本体
・ボディ
・電池ボックス(モーター用)
・モバイルバッテリー
・ブレットボード
・ギアボックス
・タイヤ
・Wifi子機
・電子回路パーツ

ラズパイ本体を乗せる筐体を工作し、
モーター付きのギアボックスにタイヤをつけて、
電池ボックス、モバイルバッテリ、ブレットボードを
取り付けます。
Android端末の通信する為に、Wifi子機もUSBに接続します。

■ ブロック図(制御回路のみ)

ギアボックスにはモーターが2個ついていて、
駆動させるために、モータードライブ用ICを使用します。
使用する目的は、ラズパイ本体の電流では容量が足らない為
電流量を増やすためです。
また、電子回路の悪影響を避けるために、モーター用の電源を別に設けます。
モータードライブ用ICは、DRV8835を使用します。

■ pin配線図

GPIOの、10,7,27,22の4本を使用します。
また、GPIO5のSW4は、ラズパイをシャットダウンさせる為のスイッチです。
ラズパイにログインしなくてもシャットダウンさせる為です。

■ DRV8835のpin配線図

GPIOの、10,7,27,22の4本を使用します。
GPIO5のSW4は、ラズパイをシャットダウンさせる為のスイッチです。
ラズパイにログインしなくてもシャットダウンさせる為です。

■ ブレットボード配線の様子

モータードライブ用IC、DRV8835をブレットボードに配置し、
ジャンパーで配線した様子です。
DRV8835の左となりには、SW4を配置しています。
また、左のLEDは赤外線LED送信用ですが、今回は使用しません

■ モーター用電源配線の様子

モーター用電源は単3型電池2個です。
充電池を使用するため、1.2V x 2 = 2.4v になります。

■ ギアボックス設置の様子

モーター駆動のギアボックスは、タミヤのツインギアボックスを使用しました。

■ シャットダウンSWの回路図

ラズパイには、LinxOSが稼働していますので、電源を切るときは
OSのシャットダウンをする必要があります。
(※シャットダウンの必要性はネットで検索)

その時に、シャットダウンSWがあると便利です。
(ラズパイにログインして、シャットダウン操作をしなくていい)

■ シャットダウンのコードの抜粋(C言語)


           if ( digitalRead(SW4) == HIGH ) { /* SW4が押下*/
               system("/sbin/shutdown -h now"); /*シャットダウンコマンド*/
               break;
            }
        

シャットダウンさせるには、 シャットダウンSWが押下されたのを判断し、 OSのシャットダウンコンンドを発行します。

【シャットダウンSWの押下】 -->【シャットダウンコマンド実行】

■ モーター駆動のコードの抜粋(C言語)


#define     MOT_LEFT1   10      //左モータ AIN1
#define     MOT_LEFT2   17      //左モータ AIN2
#define     MOT_REGHT1  27      //右モータ BIN1
#define     MOT_REGHT2  22      //右モータ BIN2

//前進
void mt_Forward(void)
{
    digitalWrite(MOT_LEFT1, HIGH );     //左モータ AIN1
    digitalWrite(MOT_LEFT2, LOW );      //左モータ AIN2
    digitalWrite(MOT_REGHT1, HIGH );    //右モータ BIN1
    digitalWrite(MOT_REGHT2, LOW );     //右モータ BIN2
}

//後退
void mt_Reverse(void)
{
    digitalWrite(MOT_LEFT1, HIGH );     //左モータ AIN1
    digitalWrite(MOT_LEFT2, HIGH );     //左モータ AIN2
    digitalWrite(MOT_REGHT1, HIGH );    //右モータ BIN1
    digitalWrite(MOT_REGHT2, HIGH );    //右モータ BIN2
}

モータードライブ用IC DRV8835は動作モードがあり、
今回はPHASE/ENABLEモードで使用します。
以下、DRV8835の動作表ですが、AOUT1およびAOUT2がHの時
モーターに電流が流れて回転します。

AIN1 AIN2 AOUT1 AOUT2 FUNCTION
0 X L L Breake ブレーキ
1 1 L H Reverse 逆転
1 0 H L Forward 正転

速度調節は出来ませんが、簡単に前後左右の動作が制御できました。
前進・後退は、モーター2個を正転・逆転で動かしますが、
左右の旋回は、2個のモーター正転・逆転を逆にします。
動作をまとめると以下のようにしました。
※正転・逆転はモーターの取り付け極性で変わります。

動作  左モータ 右モーター
---------------------------
前進   正転   逆転
後退   逆転   正転
左旋回  逆転   正転
右旋回  正転   逆転

■ Socket受信のコードの抜粋(C言語)


    /* 通信ポート・アドレスの設定 */
    memset((char *) &server_addr, '\0',sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(skv_port);
    server_addr.sin_addr.s_addr = inet_addr("192.168.xxx.xxx");
    
    /* ソケットの生成 */
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("server: socket");
        exit(2);
    }
    memset((char *) &ifr, '\0',sizeof(ifr));
    strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name)-1);
    ioctl(sockfd, SIOCGIFADDR, &ifr); //IPaddress get

    /* ソケットにアドレスを結びつける */
    if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("server: bind");
        exit(3);
    }
    /* socket 受信 */
    //メインループ
    for (;;) {
        // クライアントからのコネクト要求待ち
        sin_size = sizeof(from_addr);
        rdbuf_len = recvfrom( sockfd, rdbuf, sizeof(rdbuf), 0,
            (struct sockaddr *)&from_addr, &sin_size ) ;
        if(rdbuf_len  < 0 ) {
            perror( "recvfrom" );
            return(2);
        }
        // コマンド処理
        if ( strncmp(rdbuf,"1-fd", rdbuf_len)== 0) {
            mt_mv_Forward();  // 前進
            
            ~~~~~~~~以下、後退、左旋回、右旋回も同様
    }
    close(sockfd);  /* ソケットを閉鎖 */

ラズパイとAndroid端末は、Wifi通信で接続します。
Wifi通信はTCP/IPのSocket通信で行いますので、 Wifi接続された状態であれば、 通常のSocketプログラムコードで記述できます。

ここでは、Socketから受信したコード値により、 前進後退等の動作をプログラムしていきます。

動作  受信コード
---------------------------
前進   "1-fd"
後退   "2-bk"
左旋回  "3-lf"
右旋回  "4-rg"

Androidで操作アプリを作る

■ Androidアプリ

Androidアプリは、画面上のボタンを押下すると、 socket通信でラズパイにコードを送信するしくみに作成します。

■ Androidアプリの操作画面

アプリの画面構成は、以下のようにします。
※発射ボタンは今回は使用しません

ボタン動作 送信コード
---------------------------
前進   "1-fd"
後退   "2-bk"
左旋回  "3-lf"
右旋回  "4-rg"

■ Socket送信のコードの抜粋(Java言語)


public class MainActivity extends AppCompatActivity {
    Button fowardbtn, backbtn,leftbtn, rightbtn, stopbtn, sendbtn;

    class UdpSendClass implements Runnable {
        String cmd;

        public void setCmd(String cmd) {
            this.cmd = cmd;
        }

        @Override
        public void run() {
            int port = 8000;

            //Socket 生成
            try {
                InetAddress ip = InetAddress.getByName("192.168.xxx.xxx"); //IPアドレス
                DatagramSocket Udpsocket = new DatagramSocket();

                String strval = cmd;
                byte[] strByte = strval.getBytes("UTF-8");
                DatagramPacket sendPacket = new DatagramPacket(strByte, strByte.length, ip, port);
                Udpsocket.send(sendPacket);
                Udpsocket.close();

            } catch (Exception e) {
                e.printStackTrace();
                MainActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this, "接続に失敗しました。",Toast.LENGTH_LONG).show();
                    }
                });
                return;
            }
        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        fowardbtn = findViewById(R.id.fwdbtn_id);

        //前進ボタン
        fowardbtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                UdpSendClass f_run = new UdpSendClass();
                f_run.setCmd("1-fd");
                Thread f_run_td = new Thread(f_run);
                f_run_td.start();
            }
        });

上記のコードは、レスポンスの早い、 Socket通信のUDPプロトコルで記述しました。