がたぶーのブログ

筆者の開発記録です。

Raspberry Pi3でラジコン製作(10)

本日はAndroid側プログラムについて書きます。

 

プログラムソースについて

Android側のプログラムについてはBluetooth周りのコードは「Androidプログラミングバイブル 布留川英一著」に書かれているものを丸写ししました。

Androidプログラミングバイブル SDK 7/6/5/4対応(布留川英一) | 書籍 本 | ソシム

 

いろいろと自分で試し、BluetoothChatを書き変えて作ろうとしていましたが、Androidのプログラムの書き方自体も理解が甘く、うまくいきませんでした。

 

最近Androidを学びなおしているところなので、細かい解説はしばらく先になるかもしれません。

 

アプリのふるまい


f:id:gataburo:20190213234136j:image

↑アプリ画面のスクリーンショット

 

 

ラズベリーパイの電源を入れた状態で、connectを押して接続すると左右のバーで操作できる状態になります。

それぞれ右タイヤ、左タイヤに対応し、真ん中が停止、上が正回転、下が逆回転です。

disconnectを押すと切断され、ラジコンは停止します。

reset valueを押すと0の位置にバーが移動します。

shutdownを押すとラズパイをシャットダウンできます。

 

アプリの解説

解説と言っても、今回はラズパイ側のプログラムを見て分かる程度しか書きません。

接続された状態でSeekBarが動いたとき、Bluetooth通信で、r20やr-30、l20などの値を送るようになっています。

disconnectではe、shutdownではe0が送られるようになっています。

 

次回

「ラズパイの電源を入れたとき、ラジコン用プログラムが実行されるようにする設定」の解説をします。

Raspberry Pi3でラジコン製作(9)

本日はRaspberryPi側のプログラムの内、Bluetooth通信に関する部分について書きます。

 

ライブラリのインポート

4. import bluetooth

 

接続まわり

 9. PORT = 22

13. bl_socket=bluetooth.BluetoothSocket(bluetooth.RFCOMM)

40. bl_socket.bind*1

42. bl_socket.listen(1)

45. client_socket,address = bl_socket.accept()

82. client_socket.close()

83. bl_socket.close()

なぜ一行だけ13行目に書いているのか...(しかも、定数定義の間...)

分かりにくいのでよくないですね。これはミスです。

 

プログラムの詳細はこちらのサイトで解説されています。Python and Bluetooth

注:筆者は説明できるほどはっきりと理解できていません。

PORTは

Raspberry Pi3でラジコン製作(7)>SDPサーバの準備>2.シリアルポートの...

で設定したchannel番号と一致させる必要があるみたいです。

 

データの受け取り

52. data = client_socket.recv(1024)

54. character = data[0]

55. digit = data[1:]

52行目でデータを受け取っています。

データは文字列で、次のものを想定しています。

"r[数値]"、"l[数値]"、"e" (例えば、"r25"や"l-22")

rはrightを意味し、lはleftを、eはexitを意味しています。

例えば、r24を受け取ると

右タイヤの逆回転用のPINの出力を切り、

右タイヤの正解転用のPINのPWMを(24/50に)セットします。

 

参考にしたサイト

Python and Bluetooth

RaspberryPi同士でbluetooth通信 - Qiita

 

コードの再掲

  1. # -*- coding: utf-8 -*-
  2.  
  3. import os
  4. import bluetooth
  5. import pigpio
  6. from time import sleep
  7.  
  8. #SerialPortは22番に設定している。
  9. PORT = 22
  10. #パッケージbluetooth内のBluetoothSocketクラスのインスタンスの生成
  11. #引数はRFCOMM,L2CAP,HCI,SCOから使うプロトコルを選択する。(初期化メソッドを使用)
  12. #RFCOMMはbluetoothモジュールの中で宣言されているためbluetooth.が必要
  13. bl_socket=bluetooth.BluetoothSocket( bluetooth.RFCOMM )
  14. PIN_RF = 16 #右タイヤ前回転
  15. PIN_LF = 19 #左タイヤ前回転
  16. PIN_RR = 20 #右タイヤ後ろ回転
  17. PIN_LR = 26 #左タイヤ後ろ回転
  18. FREQ = 50
  19. RANGE = 50
  20.  
  21. pi = pigpio.pi()
  22.  
  23. def setPWM(pin, speed):
  24.         if 0 <= speed and speed <= RANGE:
  25.                 pi.set_PWM_frequency(pin, FREQ)
  26.                 pi.set_PWM_range(pin,RANGE)
  27.                 pi.set_PWM_dutycycle(pin, speed)
  28.  
  29. def stopCar():
  30.         setPWM(PIN_RF, 0)
  31.         setPWM(PIN_RR, 0)
  32.         setPWM(PIN_LF, 0)
  33.         setPWM(PIN_LR, 0)
  34.  
  35. stopCar()
  36. print "connect..."
  37.  
  38. #BluetoothSocketに定義されたbind関数を使用
  39. #bind(addrport)で使う。RFCOMMだと引数addrportは(host, channnel)
  40. bl_socket.bind( ("", PORT ))
  41. #受信可能状態にする。
  42. bl_socket.listen(1)
  43.  
  44. #接続がされるまで待ち、接続されたらそれを新しい通信として扱い、そのソケットとアドレスを返す。
  45. client_socket,adress = bl_socket.accept()
  46.  
  47. print "connection success"
  48.  
  49. while 1:
  50.               try:
  51.                 #1024バイトまでのデータを受け取る。
  52.                 data = client_socket.recv(1024)
  53.                 print "receive = %s" % data
  54.                 character = data[0]
  55.                 digit = data[1:]
  56.                 if digit.isdigit() or (digit[0] == '-' and digit[1:].isdigit()):
  57.                         speed = int(digit)
  58.                         #print "%d convert to number" % speed
  59.                         if character == 'r':
  60.                                 if speed >= 0:
  61.                                         setPWM(PIN_RR, 0)
  62.                                         setPWM(PIN_RF, speed)
  63.                                 else:
  64.                                         speed = -speed
  65.                                         setPWM(PIN_RF, 0)
  66.                                         setPWM(PIN_RR, speed)
  67.                         elif character == 'l':
  68.                                 if speed >= 0:
  69.                                         setPWM(PIN_LR, 0)
  70.                                         setPWM(PIN_LF, speed)
  71.                                 else:
  72.                                         speed = -speed
  73.                                         setPWM(PIN_LF, 0)
  74.                                         setPWM(PIN_LR, speed)
  75.                 if character == 'e':
  76.                         stopCar();
  77.                         if digit[0] == '0':
  78.                                 os.system("sudo shutdown -h now")
  79.                         break
  80.               except KeyboardInterrupt: #Ctrl+cでの中断時
  81.                 stopCar()
  82.                             client_socket.close()
  83.                             bl_socket.close()
  84.                             break
  85.               except: #何かしらのエラーが発生したとき
  86.                             print "error"
  87.                             print '\n'
  88.                 stopCar()
  89.                             client_socket.close()
  90.                             bl_socket.close()
  91.                             break

 

*1:"", PORT

Raspberry Pi3でラジコン製作(8)

さぼりで投稿が遅れてます(;・∀・)

本日はAndroidのBluetoothChatについて書きます。

 

BluetoothChatとは

Android SDKのサンプルコードの一つ。

Bluetoothを利用して双方向テキストチャットができる。

BluetoothChat - Bluetooth Chat | Android Developers

 

インストール

サンプルコードのダウンロードは次のページを参考にしました。

Java - bluetooth chat (android sdk サンプルコード内のもの)について|teratail

 

※BluetoothChatの中身はまだ理解していません。またの機会に中身について書こうと思います。

 

次回、Raspberry Pi3側プログラムの内、Bluetooth通信に関する部分について書きます。

Raspberry Pi3でラジコン製作(7)

本日はBluetoothでデータを送るテストをコマンドライン上でした話を書きます。

 

ペアリング

下記サイトを参考に、bluetoothctlでペアリングしました。

Linux PCにBluetooth機器を接続する - Qiita

 

SDPサーバの準備

下記サイトを参考に行いました。

ラズパイとBlueToothで通信してみるまでの話 - Qiita

  1. SDPサーバが使えることの確認。
    コマンドラインでsdptool browse localを実行。すると、今有効なサービスが確認できる。
  2. シリアルポートのサービスを追加
    コマンドラインでsdptool add --channel=22 SPを実行。
    channel22番でシリアルポートのサービスを追加。

 

通信のテスト

再びこちらのサイトを参考にしました。

ラズパイとBlueToothで通信してみるまでの話 - Qiita

  • rfcommをリッスン状態にする。
    コマンドライン上でsudo rfcomm listen /dev/rfcomm0 22を実行。
    (22はchannel番号、/dev/rfcomm0は通信相手とやり取りする窓口的な場所。sudo rfcomm listen 0 22とやっても同様の動作が得られる。)
  • PCからTeraTermを使用して接続。(AndroidからBluetoothChatを用いて接続※)
  • TeraTermのwindowで文字列を入力すると、Raspberry Pi側の/dev/rfcomm0に書き込まれる。
  • catコマンドやlessコマンドで/dev/rfcomm0を確認。※

 

AndroidのBluetoothChatについては次の機会に書きます。

※/dev/rfcomm0を見るときは別のコマンドプロンプトを開く。
 rfcommコマンドをバックグラウンドで実行させるのもありです。

ちなみに筆者はrfcommコマンドを終了させ、ファイルを開こうとしてました。rfcommコマンドで/dev/rfcomm0を一時的に作っているので、コマンドを終了させるとファイルがなくなり開けません。

 

※バックグラウンドでの実行について(忘れていたのでメモしておきます。)

バックグラウンドプロセス(ジョブ)の管理 - satake7’s memo

最後に&をつければ、バックグラウンドで起動。
jobsでプロセスを表示して、killで終了させる。

Raspberry Pi3でラジコン製作(6)

本日はBlueZについて書きます。

 

BlueZとは

BluZはLinuxおよびAndroidで動作するオープンソースBluetoothプロトコルスタックです。

Bluetoothのはなし(4)|Wireless・のおと|サイレックス・テクノロジー株式会社

筆者はBlueZとはなにか、まだつかめていません。。bluetoothをシリアルポートとして扱い、データをやり取りするために必要なのだと筆者は認識しています。
次回以降登場するbluetooth周りのコマンドなどは、ほぼ全てBlueZに含まれています。

公式サイトのABOUTもご参照ください。BlueZ

 

BlueZのインストール

こちらのサイトを参考に作業しました。

Raspberry Pi 3でBluetoothデバイス接続 - Tech Blog by Akanuma Hiroaki

ざっくりとしたことを書きます。

  1. bluez-5.45.tar.xzをインストール
  2. 解凍(2重に圧縮されているので2回)
  3. makefileを作る。
    (bluez-5.45/configureを実行するとmakeファイルが作られる。)
    ※足りないライブラリがあるとインストールするように指示されるのでインストールする。
  4. 生成されたmakeファイルを実行する。
  5. インストール(make install)

ちなみに...

makeファイルについて

makeファイルはコンパイルを行ってくれるものです。こちらのサイトに詳しく書かれています。第5章 Makeの基本 

 

make installについて

make install を実行するとmakeで生成されたバイナリファイルが既定のディレクトリにコピーされます。
make uninstallでアンインストールでき、make -n install でインストール先のディレクトリが知れる。(このときインストールはされない)

 

 

 

Raspberry Pi3でラジコン製作(5)

だいぶ投稿が面倒になっていますが書きます。

本日はpigpioについて書きます。

 

pigpioとは

Raspberry PiのGPIO(General Purpose Input Outputs)を制御するためのライブラリです。

今回はGPIOをpwm制御するために使用しました。

pigpioの公式ページ

 

pigpioの導入

pigpioの導入については筆者は記述しません。

以下の記事を参考に導入しました。

 

pwmの使い方

こちらの記事を参考にしました。

[Raspbian] pigpioライブラリでPWMを使ってLEDの明るさを変えてみる - Life with IT

 

プログラムについて

プログラムについて少しだけ解説します。(公式サイトのドキュメントを見ればわかりますが)

21. pi = pigpio.pi()
22.
23. def setPWM(pin, speed):
24.        if 0 <= speed and speed <= RANGE:
25.                pi.set_PWM_frequency(pin, FREQ)
26.                pi.set_PWM_range(pin,RANGE)
27.                pi.set_PWM_dutycycle(pin, speed)

  • 21行目  pi = pigpio.pi()
    gpioを使うために必要。引数には(host, port, show_errors)を設定できるが、今回は特に指定はしていない。
  • 25行目 pi.set_PWM_freaquency(pin, FREQ)
    指定したGPIOピンにPWMの周波数をセットする。
  • 26行目 pi.set_PWM_range(pin, RANGE)
    指定したGPIOピンにデューティー比1(常にON)のときの値をセットする。
    ex. RANGE=100なら25はデューティー比 1/4
  • 27行目 pi.set_PWM_dutycycle(pin, speed)
    指定したGPIOピンにPWM出力をセットする。
    今回のプログラムではRANGE=50にセットしてあるため、speed=50で常にON、speed=0でOFFとなる。

※25,26行目について

今回のプログラムでは、pwmのデューティー比を変えるたびに呼び出していますが毎回呼び出す必要はないです。自分の理解が浅いために無駄ができてます

 

今回のプログラムで使っているpigpioライブラリは以上です。

 

ちなみに

dutycycleで0より小さい、またはRANGEより大きい値がセットされるとエラーをはいて止まります。そのため、異常値の除外を行うsetPWM関数を通してdutycycleを呼び出すようにしてあります。

 

Raspberry Pi3でラジコン製作(4)

本日はraspberry Pi側のプログラムを掲載します。

だいぶ忘れているので、次回以降のんびり解説をしていきます。

 

Pythonプログラム

  1. # -*- coding: utf-8 -*-
  2.  
  3. import os
  4. import bluetooth
  5. import pigpio
  6. from time import sleep
  7.  
  8. #SerialPortは22番に設定している。
  9. PORT = 22
  10. #パッケージbluetooth内のBluetoothSocketクラスのインスタンスの生成
  11. #引数はRFCOMM,L2CAP,HCI,SCOから使うプロトコルを選択する。(初期化メソッドを使用)
  12. #RFCOMMはbluetoothモジュールの中で宣言されているためbluetooth.が必要
  13. bl_socket=bluetooth.BluetoothSocket( bluetooth.RFCOMM )
  14. PIN_RF = 16 #右タイヤ前回転
  15. PIN_LF = 19 #左タイヤ前回転
  16. PIN_RR = 20 #右タイヤ後ろ回転
  17. PIN_LR = 26 #左タイヤ後ろ回転
  18. FREQ = 50
  19. RANGE = 50
  20.  
  21. pi = pigpio.pi()
  22.  
  23. def setPWM(pin, speed):
  24.         if 0 <= speed and speed <= RANGE:
  25.                 pi.set_PWM_frequency(pin, FREQ)
  26.                 pi.set_PWM_range(pin,RANGE)
  27.                 pi.set_PWM_dutycycle(pin, speed)
  28.  
  29. def stopCar():
  30.         setPWM(PIN_RF, 0)
  31.         setPWM(PIN_RR, 0)
  32.         setPWM(PIN_LF, 0)
  33.         setPWM(PIN_LR, 0)
  34.  
  35. stopCar()
  36. print "connect..."
  37.  
  38. #BluetoothSocketに定義されたbind関数を使用
  39. #bind(addrport)で使う。RFCOMMだと引数addrportは(host, channnel)
  40. bl_socket.bind( ("", PORT ))
  41. #受信可能状態にする。
  42. bl_socket.listen(1)
  43.  
  44. #接続がされるまで待ち、接続されたらそれを新しい通信として扱い、そのソケットとアドレスを返す。
  45. client_socket,adress = bl_socket.accept()
  46.  
  47. print "connection success"
  48.  
  49. while 1:
  50.               try:
  51.                 #1024バイトまでのデータを受け取る。
  52.                 data = client_socket.recv(1024)
  53.                 print "receive = %s" % data
  54.                 character = data[0]
  55.                 digit = data[1:]
  56.                 if digit.isdigit() or (digit[0] == '-' and digit[1:].isdigit()):
  57.                         speed = int(digit)
  58.                         #print "%d convert to number" % speed
  59.                         if character == 'r':
  60.                                 if speed >= 0:
  61.                                         setPWM(PIN_RR, 0)
  62.                                         setPWM(PIN_RF, speed)
  63.                                 else:
  64.                                         speed = -speed
  65.                                         setPWM(PIN_RF, 0)
  66.                                         setPWM(PIN_RR, speed)
  67.                         elif character == 'l':
  68.                                 if speed >= 0:
  69.                                         setPWM(PIN_LR, 0)
  70.                                         setPWM(PIN_LF, speed)
  71.                                 else:
  72.                                         speed = -speed
  73.                                         setPWM(PIN_LF, 0)
  74.                                         setPWM(PIN_LR, speed)
  75.                 if character == 'e':
  76.                         stopCar();
  77.                         if digit[0] == '0':
  78.                                 os.system("sudo shutdown -h now")
  79.                         break
  80.               except KeyboardInterrupt: #Ctrl+cでの中断時
  81.                 stopCar()
  82.                             client_socket.close()
  83.                             bl_socket.close()
  84.                             break
  85.               except: #何かしらのエラーが発生したとき
  86.                             print "error"
  87.                             print '\n'
  88.                 stopCar()
  89.                             client_socket.close()
  90.                             bl_socket.close()
  91.                             break