ロボットを遠隔操作する
前回まででロボットを前後左右に動かす python の命令ができたと思います。 今回はキーボード、スマホを使って動かすようにしてみましょう。
キーボードを使って操作する
python では,ユーザー入力に input
を使うことが多いですが,この関数では文字を打った後必ずリターンキーを押す必要があります.ゲーム等で操作する時には,キーを押されたらキャラクターがすぐに動きますが,そのような操作を可能にするために,kbhit を使います.通常 Terminal でキーボードの入力を制御したい場合には termio という制御ライブラリを使いますが,今回は,その制御を簡単に使えるようにしたライブラリkbhit.pyを使います.
まずは
python kbhit.py
で kbhit の使い方を確認してください.(このプログラムの動作の確認は mac でもラズパイでもどちらで行っても構いません) キーボードを打つと,そのキーボードに対応した文字と,その文字に対応した番号が表示されます.ESCキーを押すと終了します.
kbhit を外部から使うには import kbhit
とします。以下は kbhit のサンプルプログラムです。
import kbhit
kb = kbhit.KBHIT()
while True:
if kb.kbhit():
c = kb.getch()
if c == 'a':
print("a is pushed!")
if ord(c) == 27:
break
print("owari")
例えば,上記のプログラムを "kb_test.py" とすると,kbhit.py のあるディレクトリで
python kb_test.py
と実行すると、a のキーを押すと、"a is pushed" というメッセージが現れ、esc キーを押すとプログラムが終了します。
__main__
とは?
"kbhit.py" のプログラムの最後を見ると,
if __name__ == "__main__":
なる記述があります.これはどういう意味でしょう?
Pythonの__name__は、モジュールが直接実行されているか、他のモジュールからインポートされているかを識別するために使用される特別な変数です。
具体的には、__name__には2つの可能な値があります。
1. モジュールが直接実行されている場合:
スクリプトが直接実行されると、name__の値は"__main"になります。
if __name__ == "__main__":
print("このスクリプトは直接実行されています")
2. モジュールが他のモジュールからインポートされた場合:
他のモジュールがインポートされると、そのモジュールの__name__は、モジュールのファイル名(拡張子を除いた部分)になります。
# モジュールが script.py という名前の場合
import script
print(script.__name__) # "script" と表示される
この仕組みにより、Pythonのコードを再利用可能にし、直接実行する場合と他のプログラムからインポートして使用する場合で、異なる動作をさせることができます。(以上,ChatGPTの説明)
通常ライブラリの使い方のサンプルが if __name__ == "__main__":
を使って書かれていることが多いです.
課題2
前回作成した Wheel クラスと kbhit を使い,
- 's' が押されたら止まる
- 'f' が押されたら前進
- 'b' が押されたら後退
- 'r' が押されたらその場で右回転
- 'l' が押されたらその場で左回転
となるプログラムを作成してください。
動作が確認できたら、遠隔操作ができるようにラズパイはロボットの上に乗せ、モバイルバッテリーを電源にして動作させます。(ディスプレイも外します)
そして、ssh を使って macbook からラズパイに接続し、プログラムを実行して、キーボードで動作ができることを確認してみてください。
Flask
次に、スマホからロボットを操作できるようにしてみましょう。そのために python の Webアプリケーションフレームワークである Flask を使います。
まずは Flask を pip でインストールします.
pip install flask
そして,最初のプログラムとして,以下のプログラム hello.py を作成してください.
from flask import Flask
app = Flask(__name__)
@app.route("/test")
def hello_world():
return "<p>Hello world!</p>"
if __name__ == "__main__":
app.run(host="127.0.0.1", port=5001, debug=True)
実行は,このプログラムのあるディレクトリで
python hello.py
とします.すると,
$ python hello.py
* Serving Flask app "hello" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: on
* Running on http://127.0.0.1:5001/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 220-515-480
のようにメッセージが出ます。 http://127.0.0.1:5001/test に動作させているコンピュータのブラウザ(Macの場合はMacのブラウザ、ラズパイの場合はラズパイのブラウザ)でアクセスすると,Hello world! と書かれたページが確認できると思います.(Ctl-c でプログラムは終了します)
このように,関数で web ページにアクセスされた時の振る舞いを記述していくのが flask のプログラミングとなります.
課題
上の hello.py を改変して http://127.0.0.1:5001/bye
にアクセスしたら,さようなら
と出るプログラムを書いてください.
Flask でリモコンを作る
次に flask でボタンを作ってみます. 以下のサンプルプログラムをダウンロードしてください.
まず,webapp.py を実行します.
python webapp.py
このプログラムでは,ボタンが押されると Car クラスの go
関数が実行されます.
よくみると,このボタンを押すたびに画面が遷移していることがわかります. 画面遷移がおこると,それだけ時間がかかりますので,画面遷移をしないように ajax を使います.
ajax とは「JavaScriptとXMLを使って非同期にサーバとの間の通信を行うこと。」です.google map などは画面遷移をせずに,ユーザーからの操作に応じて新しいデータを読み込み,画面を更新していますが,その仕組みに使われています.
- 参考: 初心者目線でAjaxの説明
これを使ったプログラムが webapp2.py に実行されていますので,これを実行してください.
python webapp2.py
スマホからの接続
"127.0.0.1" の IPアドレスは自分自身のコンピュータを指す特別なIPアドレスです.flask 内の
app.run(host="127.0.0.1", port=5001, debug=True)
を
app.run(host="0.0.0.0", port=5001, debug=True)
とすることで、作成した flask プログラムは同じ LAN 内であれば他のコンピュータからも接続可能となります.
まず、TC306 の無線環境である tc-room に接続してください。 次に、ラズパイのアドレスを確認してみてください.
ifconfig
さまざまに表示される情報のうち,wlan0 に相当するのが,無線LANになります.
ifconfig -l | xargs -n1 ipconfig getifaddr
のコマンドではIPアドレスだけを取り出すことができます.
ここで得られたアドレスを 172.19.193.xxx
とすると,スマホのブラウザで
http://172.19.193.xxx:5001/
のURLを開けることで,flask に接続することができます.
課題
- 別のコンピュータ,あるいはスマホからflask プログラムに接続できることを確認してください.
- "car.py", "webapp2.py" を編集して,ブラウザからロボットが前進,後退,左右回転,停止ができるようにしてください.
- スマホからリモコンで操作できるようにしてください.
- ボタンを十字に配置して、リモコンっぽくなるようにインタフェースを工夫してみてください。
- ChatGPT などを使うと簡単にコードを生成してくれます。