はじめに
ラズベリーパイにて、自作のラジコンカーをつくったので紹介します。
今回は、ネットワーク越しのラジコン制御になります。
ラジコンカー関連の記事
- ラズパイにて、ラジコンカーを自作する-その1
- ラズパイにて、ラジコンカーを自作する-その2
- ラズパイにて、ラジコンカーを自作する-その3 ← 本記事
紹介する内容
- ラズパイ側のwebサーバ側の作成
- 外部PCからの制御
- iPhone(Pythonista)からの制御
作るものの全体
ラズパイ側のサーバーおよび外部制御プログラムです。
作業環境
- ラズベリーパイ3
- Raspbian Buster with desktop and recommended software
- Version:February 2020
- Release date:2020-02-13
- Kernel version:4.19
- Python3.7.3
- Raspbian Buster with desktop and recommended software
- ホストPC
- windows10 64bit
- Python3.7.4
- windows10 64bit
- iPhone
- Pythonista
作業手順
今回も、すべてPythonで実装します。
まずは、ラズパイ側のサーバを作ります。
※動く程度のものなので、書き方として間違っている場合があります
ラズパイ側のサーバ - responder
Python WebFrameworkである[responder]を使用します。
responder自体の記事は、
人間のためのイケてるPython WebFramework「responder」、そして作者のKenneth Reitzについて
がすごくわかりやすいです。
注意点として、responderは、python3.6.1以上でないと動作しません。
Raspbianの古いものは、python3.5がインストールされていたかと思います。
必要に応じて、アップデートしてください。
responderのインストール
$ pip install responder
以上。
サーバー側の仕様
以下のような動作にします。
- 送信側
- GETリクエスト : http://[ラズパイIPアドレス]:5042/pi_car/[動作コマンド]
- 受信側
- レスポンス : "ok [動作コマンド]!"
具体例は、以下の通りです。
- 送信側
- GETリクエスト : http://192.168.11.29:5042/pi_car/forward
- 受信側
- レスポンス : "ok forward"
- =>ラジコンカーが前進する
サーバー側のコード
前回記事のコードはそのまま使用します。
ファイル構成は、下記のとおりです。
$ ls
picar.py rc_server.py ta7291p.py
コードは以下となります。
ファイル名:rc_server.py
import responder
import picar
api = responder.API()
pi_car = picar.PiCar()
@api.route("/picar/{prm}")
def control_picar(req, resp, *, prm):
if "turn_left" in prm:
pi_car.turn_left()
if "turn_right" in prm:
pi_car.turn_right()
if "forward" in prm:
pi_car.forward()
if "back" in prm:
pi_car.back()
if "brake" in prm:
pi_car.brake()
if "acceloff" in prm:
pi_car.acceloff()
if "debug_proc" in prm:
pi_car.debug_proc()
resp.text = f"ok, {prm}!"
@api.route("/picar/speed/{prm}")
def control_picar_speed(req, resp, *, prm):
pi_car.speed(int(prm))
resp.text = f"ok_speed, {prm}!"
if __name__ == '__main__':
api.run(address='0.0.0.0', port=5042)
※address='0.0.0.0'は、外部アクセス可とするため
実行と動作確認
実行は下記のとおりです。
$ python rc_server.py
INFO: Started server process [3392]
INFO: Uvicorn running on http://0.0.0.0:5042 (Press CTRL+C to quit)
INFO: Waiting for application startup.
INFO: Application startup complete.
外部PCより、GETリクエストをなげて確認します。
※本環境では、chromeを使用しました。
INFO: 192.168.11.17:63850 - "GET /picar/forward HTTP/1.1" 200 OK
forward : run
forward : over
- →ラジコンカーが前進する
以上でサーバ側の動作は完了です。
クライアント側(ホストPC)
GETのリクエストを投げるだけなので、さらっと。
コード
以下がコードとなります。
※IPアドレスは必要に応じて変更してください。
ファイル名:car_test.py
import requests
import time
url = 'http://192.168.11.29:5042/picar/'
cmds = ["forward", "back", "brake", "turn_left", "turn_right", "acceloff"]
def main():
for cmd in cmds:
curl = url + cmd
print(cmd)
response = requests.get(curl)
time.sleep(3)
if __name__ == '__main__':
main()
実行
> python .\car_test.py
forward
back
brake
turn_left
turn_right
acceloff
前進→バック→ブレーキ→左旋回→右旋回→→停止
の順に動作したかと思います。
クライアント側(iPhone)
せっかくラジコンをつくったので、やっぱり手元で手軽に動かしたいです。
今回は、iPhoneからPython経由で制御します。
Pythonistaについて
Pythonista は、iOS上で動作するPythonの統合開発環境です。
有料アプリではありますが、とても気に入っています。
Pythonistaの詳細は、下記の記事が参考になります。
AppStoreでのアイコンは以下です。
UIと動作仕様
- [forward]のボタンをタップ -> ラジコン前進
- [back]のボタンをタップ -> ラジコンバック
- [turn_left]のボタンをタップ -> ラジコン左旋回
- [turn_right]のボタンをタップ -> ラジコン右旋回
- [acceloff]のボタンをタップ -> ラジコン停止
早速コードに移ります。
コード
以下がコードとなります。
ファイル名:car_remo.py
from objc_util import *
import ui
import console
import requests
import time
url = 'http://192.168.11.29:5042/picar/'
def btn_turn_left_tapped(sender):
curl = url + "turn_left"
response = requests.get(curl)
def btn_turn_right_tapped(sender):
curl = url + "turn_right"
response = requests.get(curl)
def btn_forward_tapped(sender):
curl = url + "forward"
response = requests.get(curl)
def btn_brake_tapped(sender):
curl = url + "brake"
response = requests.get(curl)
def btn_back_tapped(sender):
curl = url + "back"
response = requests.get(curl)
def btn_acceloff_tapped(sender):
curl = url + "acceloff"
response = requests.get(curl)
def main():
# メイン画面の作成
main_view = ui.View(frame=(0, 0, 375, 667))
main_view.name = 'test view'
main_view.background_color = ('white')
width_unit = main_view.width // 4
height_unit = main_view.width // 4
# ボタンの追加
btn_forward = ui.Button()
btn_forward.frame = (1*width_unit, 0*height_unit, width_unit, height_unit)
btn_forward.title = 'forward'
btn_forward.action = btn_forward_tapped
btn_forward.background_color = (0, 0, 0, 0.5)
btn_forward.tint_color = ('white')
main_view.add_subview(btn_forward)
# ボタンの追加
btn_acceloff = ui.Button()
btn_acceloff.frame = (1*width_unit, 1*height_unit, width_unit, height_unit)
btn_acceloff.title = 'acceloff'
btn_acceloff.action = btn_acceloff_tapped
btn_acceloff.background_color = (0, 0, 0, 0.5)
btn_acceloff.tint_color = ('white')
main_view.add_subview(btn_acceloff)
# ボタンの追加
btn_back = ui.Button()
btn_back.frame = (1*width_unit, 2*height_unit, width_unit, height_unit)
btn_back.title = 'back'
btn_back.action = btn_back_tapped
btn_back.background_color = (0, 0, 0, 0.5)
btn_back.tint_color = ('white')
main_view.add_subview(btn_back)
# ボタンの追加
btn_turn_left = ui.Button()
btn_turn_left.frame = (0*width_unit, 1*height_unit, width_unit, height_unit)
btn_turn_left.title = 'turn_left'
btn_turn_left.action = btn_turn_left_tapped
btn_turn_left.background_color = (0, 0, 0, 0.5)
btn_turn_left.tint_color = ('white')
main_view.add_subview(btn_turn_left)
# ボタンの追加
btn_turn_right = ui.Button()
btn_turn_right.frame = (2*width_unit, 1*height_unit, width_unit, height_unit)
btn_turn_right.title = 'turn_right'
btn_turn_right.action = btn_turn_right_tapped
btn_turn_right.background_color = (0, 0, 0, 0.5)
btn_turn_right.tint_color = ('white')
main_view.add_subview(btn_turn_right)
main_view.present('sheet')
main_view.wait_modal()
if __name__ == '__main__':
main()
実行
iPhone - PythonistaのUIよりプログラムを実行します。
さいごに
とりあえず、イメージした動きになってよかったです。
余裕があれば、カメラを搭載して、自動で動作するようにしたいです。
あと、ラズパイゼロ or ESP32に置き換えて、完全コードレスにしようと思います。