ロボットで遊ぶ その2(スマホでロボット操作)

はじめに

前回はWEB GUI経由でロボットに指示を出してLEDを変更する処理を作ったので、
同じ仕組みを流用してWEB GUIからロボとを操作する仕組みを作ります。

da-yamax.hatenablog.jp



ロボット側のサンプルコードの確認

server.pyrunメソッドでクライアントから送信されたデータの文字列を見て処理を分岐しています。

前後移動、旋回、停止をスマホから操作するためには、forward/backward/left/rightを送信すればよさそうです。
これだけだとボタンを離しても止まらないので、停止処理としてTSを送信します。
※動かしてから気が付きました...

## server.py抜粋
       elif 'forward' == data:
            SpiderG.walk('forward')
        
        elif 'backward' == data:
            SpiderG.walk('backward')

        elif 'left' == data:
            SpiderG.walk('turnleft')

        elif 'right' == data:
            SpiderG.walk('turnright')

        elif 'TS' in data:
            if direction_command == 'no':
                SpiderG.servoStop()

スマホ操作画面の実装

仕組み

前回と同じようにpythonとflaskを使ったWEBサーバを作ります。

WEBサーバのコントローラUIとして、HTMLでボタンを配置、押されたボタンに応じてjavascriptforward/backward/left/rightの文字列をflaskへ送信します。

flask側の処理

WEB UIのjavascriptからflaskへ送信したデータを、TCPでserver.pyへ渡すだけなので、python側は以下のようにシンプルな処理を追加しました。

@app.route('/post', methods=['POST'])
def post():
	result = request.form["param"]
	print(result)
	# robotに指示を出す
	tcpClicSock.send(result.encode())
	
	return "OK"

WEB UI側の処理

概要

基本的には前回のColorPickerと同じで、ボタンをクリックしたらjavascriptpythonへデータを渡します。
DarkPawのサンプルコードは、forward/backward/left/rifhtを送ったら停止信号を送るまでは継続して処理が実行されるため、ボタンを離したら停止信号を送る処理を追加します。

HTMLのボタン

divタグとaタグでボタンを実装しました。
後述するボタンを押す処理で、divのidがsendDataに渡されます

	<div id="btn_box set_l" class="btn_box set_l">
		<div id="forward" class="up"><a class="btn_emboss"></a></div>
		<div id="left" class="left"><a class="btn_emboss"></a></div>
		<div id="home" class="center no_action"><a class="btn_emboss"></a></div>
		<div id="right" class="right"><a class="btn_emboss"></a></div>
		<div id="backward" class="down"><a class="btn_emboss"></a></div>
	</div>
データを送信する処理

dataに格納された文字列をpythonへ送信するだけです。
python側のIPアドレス指定はpythonで変数を定義しているので、{{data.serverIp}}で取り出しています。

<script language="javascript" type="text/javascript">
	var serverIp = "{{ data.serverIp }}";
	var serverUrl = "http://"+serverIp+":8080/control";
	function sendData(data) {
		console.log(data);
		// ボタン入力の停止
		let formData = new FormData();
			formData.append('param', data);
			fetch(serverUrl, {
			  method: 'POST',  
			  body: formData,  
		});
		return false;
	}
</script>
ボタンを押す処理

onClickでの実装だとボタンを離す処理ができなかったため、toucheventを使いました。

	// デフォルトのタッチ動作を無効
	function TouchEventPreventDefaultFunc(e){
        	e.preventDefault();
	}
	// タッチ開始時に対応するデータ尾を送信する
	function TouchEventTouchStartFunc(e) {
		sendData(e.currentTarget.id);
	}
	// タッチ終了時に停止信号を送信する
	function TouchEventTouchEndFunc(e){
		sendData("TS");
	}
        // タッチ開始、終了、デフォルト動作をdivに紐づける
	function setEventListener(nodes) {
		for (i = 0 ; i < nodes.length; i++) {
			var element_hit = document.getElementById(nodes[i].id);
			element_hit.addEventListener("touchend",TouchEventTouchEndFunc);
			element_hit.addEventListener("touchcancel",TouchEventTouchEndFunc);
			element_hit.addEventListener("touchstart", TouchEventTouchStartFunc);
			element_hit.addEventListener("touchend",TouchEventPreventDefaultFunc);
		}
	}
	// コントロールキーのDIVをタッチイベントに追加する
	setEventListener(window.document.getElementById('btn_box set_l').children);
	setEventListener(window.document.getElementById('btn_box set_r').children);
	

完成

UIイメージ

作成したボタン処理にいい感じの画像とCSSを適用してコントローラが完成しました。

f:id:da-yamax:20200503111712p:plain:w400
コントローラー風UI

動作確認



まとめ

サンプルプログラムでは未提供のスマホから操作する仕組みを作ってみました。
WEBプログラミングも初めてなのでボタン操作の実装に手間取りましたが、
本題のロボット制御はサンプルプログラムへデータを渡すだけなので、比較的簡単に実現することができました。

次回はカメラ映像を取得してWEB UIに表示したいと思います。