UMEHOSHI ITA TOP PAGE
COMPUTER SHIEN LAB
Raspberry PI Zero WととUmehoshi ITAをUSB接続し、Wifi接続してWebブラウザ制御 兼 TCP制御作品その2(EEPROM化作品)
前に紹介したページの作品は、HTTPサーバー起動時に[UMEHOSHI ITA]基板のRAM領域へ
モータ制御プログラム転送し、他のPCなどからブラウザでロボットを制御できる仕様になっています。
ここで使うDHCP、HTTP、TCPサーバーは、「Raspberry PI Zero W」のLinuxで行っています。
(PI Zero Wは、このリンク先で紹介したraspbianをインストールしています。)
そして、HTTPサーバーやモータ制御プログラム転送のpythonプログラムをsystemctlで起動しています。
このロボットは、起動してブラウザで接続して制御できるまでに、約2分程度の時間が必要でした。
(http://192.168.100.1/index.htm)
このページではこの起動時間を短縮するため、[UMEHOSHI ITA]基板のRAM領域へモータ制御プログラム転送をせず、
プログラムEEPROMに書き込んで使う改良を行った資料です。
(「Raspberry PI Zero W」と[UMEHOSHI ITA]基板と接続詳細情報は、
別ページなど参照してください。)
機能は、改良前と同じです。
起動すると、自身をWifiのアクセスポイントになります。
(アクセスポイント SSID:pizero、パスプレーズ:abcd1234)
そして、DHCPサーバーで、接続してきた相手に
192.168.100.2〜のIPアドレスを配信します。
このロボットのIPアドレスは192.168.100.1で
起動時は、Webサーバーとして起動します。
ロボットのカメラ画像配信ページ:
http://192.168.100.1/index.html)
ロボットの遠隔操作ページ:
http://192.168.100.1/index.htm)
ロボットの撮影画像閲覧URL:
http://192.168.100.1/imgs)
ロボットの撮影画像を消去するページ:
http://192.168.100.1/clear.jpg)
ロボットのWebサーバーのプログラムを終了ページ:
http://192.168.100.1/quit.jpg)
上記操作でWebサーバーが終了すると、
TCP制御サーバーが起動します。
このサーバーへPC側よりでpython umeclient2.pyで接続して'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>の
メニュー操作で制御できます。
この umeclient2.py のリンク先にこのソースを紹介しています。
[UMEHOSHI ITA]基板のEEPROM領域にモータ制御プログラムを書き込んで制御するための変更
起動させた後、PCからのWifiを介した遠隔操作で操作するので、PCが接続するアクセスポイントをロボットの
アクセスポイント(SSID:pizero, パスフレーズ「abcd1234」)で接続します。
「ssh pi@192.168.100.1」で接続して、操作します。
(このページでセットアップしていれば[abc123]のパスワードで接続)
Are you sure you want to continue connecting (yes/no/[fingerprint])?でyesを入力します。
Host key verification failed.のエラーであれば「ssh-keygen -R 192.168.0.123」入力で、該当のIPアドレス情報を消して再接続します。)
これまで、
UMEHOSI ITA のRAM領域に初期コードを転送して動作させる手法は、このサービスから
/home/pi/umehoshi/umehoshi.pyを起動させていました。
umehoshi.py中で[UMEHOSHI ITA]のRAMに、モータ制御プログラムを転送していました。これを転送しないでROM利用するプログラムに変更した
/home/pi/umehoshi2/umehoshi2.pyを使う変更です。
そこでまず、次のコマンド操作でサービスを停止します。
sudo systemctl disable umehoshi.service
新しいサービスをumehoshi2で作るので、必要な
umeusb.pyと
umetcp.pyをumehoshフォルダからコピーします。
それ以外にも、必要なファイル次のようにコピーします。
これらは、
このリンク先で作成したWebサーバー用ファイルです。
(
myweb.pyは以前と同じWebサーバー用モジュールです)
またWebサーバー時に使うumeutil.pyもcgi-binフォルダを作ってumeutil.pyもコピーしておきます。
(
umeutil.pyはUSBでコマンドファイルを転送する関数定義ファイルです)
他に、受信ファイルを格納するためのdatasフォルダや、カメラ画像を格納するimgsフォルダを作っています。
pi@raspberrypi:~ $ mkdir -p ~/umehoshi2
pi@raspberrypi:~ $ cd ~/umehoshi2
pi@raspberrypi:~/umehoshi2 $ cp ~/umehoshi/umeusb.py .
pi@raspberrypi:~/umehoshi2 $ cp ~/umehoshi/umetcp.py .
pi@raspberrypi:~/umehoshi2 $ cp ~/umehoshi/myweb.py .
pi@raspberrypi:~/umehoshi2 $ cp ~/umehoshi/index.html .
pi@raspberrypi:~/umehoshi2 $ cp ~/umehoshi/index.htm .
pi@raspberrypi:~/umehoshi2 $ cp ~/umehoshi/quit.jpg .
pi@raspberrypi:~/umehoshi2 $ mkdir cgi-bin
pi@raspberrypi:~/umehoshi2 $ cp ~/umehoshi/cgi-bin/umeutil.py ./cgi-bin/umeutil.py
pi@raspberrypi:~/umehoshi2 $ mkdir datas
pi@raspberrypi:~/umehoshi2 $ mkdir imgs
これでumetcp.pyを起動するとTCPのサーバーが起動し、
対応する後述のPC側プログラム(
umehosi2.pyh)を使えばファイルを送り込むことができます。
umetcp.pyの実行前にumetcp.pyを編集してのmainのip変数の設定にを、そのRaspberry PI Zeroに合わせる必要があります。
(nano umetcp.pyを編集して、
ip = "192.168.100.1"と設定しました。)
そして次の操作により、後述する『
umehosi2.pyh』のファイルを送信し、そのファイルを~/umehoshi/に移動しています。
(一部に表示を省略しています)
Pi Zero のumetcp.py実行側 | PCでのumeclient2.py実行側 |
pi@raspberrypi:~/umehoshi2 $ python3 umetcp.py
Serverの情報: ('192.168.100.1', 59154)
接続要求を待つ
start receiveData
umehoshi2.py 2510
recieve file:umehoshi2.py,size:2510
pi@raspberrypi:~/umehoshi2 $ mv datas/umehoshi2.py .
|
D:raspi_zero>python umeclient2.py
IP (defualt:192.168.100.1)Address>
接続成功
start receiveData
送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>f
[ ・・・・カレントディレクトリの表示・・・・・]
送信したいファイル名入力>app_pwm_esp32.umh
b'fapp_pwm_esp32.umh 5715\r\n' 送信byte: 5715
送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>quit
終了時のエラー表示は無視してください
|
上記で転送した『
umehosi2.py』ファイルは、umehosi.pyの代わり使う後述するROM領域利用のサーバープログラムです。
このumehosi2.pyを次の操作により起動して、『
app_pwm_esp32.umh』のファイルを送信します。(一部に表示を省略しています)
Pi Zero のumehosi2.py実行側 | PCでのumeclient2.py実行側 |
pi@raspberrypi:~/umehoshi2 $ python3 umehoshi2.py
Serial(port='/dev/ttyACM0', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
Serverの情報: raspberrypi ('192.168.100.1', 59154)
接続要求を待つ
接続を待って、接続してきたら許可
接続相手: ('192.168.100.5', 53057)
start receiveData
app_pwm_esp32.umh 5715
S109D02001000E8FFBD271400BFAF1000BEAF21F0A00304
・・・・・書き込み応答が続く
S109D020A400000904234080040AC21E8C0030400BE8F73
S0C9D020A50000800BD270800E003000000004E
クライアントがquitで終了すると、エラーの表示がでるが無視
接続を待って、接続してきたら許可
Ctrl+C で強制終了させてください。
KeyboardInterrupt
pi@raspberrypi:~/umehoshi2 $
|
D:raspi_zero>python umeclient2.py
IP (defualt:192.168.100.1)Address>
接続成功
start receiveData
送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>f
[ ・・・・カレントディレクトリの表示・・・・・]
送信したいファイル名入力>app_pwm_esp32.umh
b'fapp_pwm_esp32.umh 5715\r\n' 送信byte: 5715
S109D02001000E8FFBD271400BFAF1000BEAF21F0A00304
SET:9D020010
・・・・ 書き込みと応答の表示が続く・・・・・
S0C9D020A50000800BD270800E003000000004E
SET:9D020A50
転送が止まったら、SPACE,ENTERを入力してメニューを出す。
送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>quit
・・・・・・
ConnectionAbortedError: [WinError 10053]
確立された接続がホスト コンピューターのソウトウェアによって中止されました。
この終了時のエラー表示は無視してください
D:raspi_zero>
|
上記はWifiを介したファイル
app_pwm_esp32.umhの送信でSSHで行っている操作です。
この送信したファイルは、
[UMEHOSHI ITA]基板のEEPROM領域に書き込むにモータ制御プログラムで、このEEPROM用のコードは、
このリンク先ページで
紹介したものです。
umehoshiEditの開発ツールで直接に書き込むこともできますが、上記方法でこの翻訳済みファイルの
app_pwm_esp32.umh
を送信するだけで、同様にEEPROMへの書き込み処理が完了します。
次の各種エントリーポイントの「.umh」を用意し、
転送による実行で各モータなどの動作を確認できます。
(モータの制御前に、EEPROM領域にあるモータ制御の初期化が必要で、起動時に一回だけ
uStartInit.umhを実行させる必要があります。)
ファイル名 | 内容 | 概要 |
uBeep.umh | Beep
R009D020D00003B | 音パターン[・・・・]を登録 |
uStartInit.umh | StartInit
R009D020010004E | 下記初期設定と調整(PWDなどの初期化で、下記モータ制御を行う前に一回だけ実行しなければならない。) |
uForward.umh | Forward
R009D020200004D | モータ前進 |
uBack.umh | Back
R009D020300004C | モータ後進 |
uRight.umh | Right
R009D020400004B | モータ右回転
|
uLeft.umh | Left
R009D020500004A | モータ左回転 |
uLeftUp.umh | UpLeft
R009D0206000049 | モータ左デューティ幅アップルーチン |
uLeftDown.umh | DownLeft
R009D0207000048 | モータ左デューティ幅ダウンルーチン |
uRightUp.umh | UpRight
R009D0208000047 | モータ右デューティ幅アップ |
uRightDown.umh | DownRight
R009D0209000046 | モータ右デューティ幅ダウン |
uStop.umh | Stop
R009D020A00003E | モータストップ |
上記のファイル転送してモータを動作させる例を下記に示します。
(以下は、
モータ制御初期化の転送実行と、
モータ前進処理の転送実行を実行です。)
Pi Zero のumehosi2.py実行側 | PCでのumeclient2.py実行側 |
pi@raspberrypi:~/umehoshi2 $ python3 umehoshi2.py
Serial(port='/dev/ttyACM0', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
Serverの情報: raspberrypi ('192.168.100.1', 59154)
接続要求を待つ
接続を待って、接続してきたら許可
接続相手: ('192.168.100.5', 53129)
start receiveData
uStartInit.umh 28
R009D020010004E
uForward.umh 26
R009D020200004D
クライアントがquitで終了すると、エラーの表示がでるが無視
接続を待って、接続してきたら許可
Ctrl+C で強制終了させてください。
KeyboardInterrupt
pi@raspberrypi:~/umehoshi2 $
|
D:raspi_zero>python umeclient2.py
IP (defualt:192.168.100.1)Address>
接続成功
start receiveData
送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>f
[ ・・・・カレントディレクトリの表示・・・・・]
送信したいファイル名入力>uStartInit.umh
b'fuStartInit.umh 28\r\n' 送信byte: 28
R009D020010004E
START:9D020010
送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>f
[ ・・・・カレントディレクトリの表示・・・・・]
送信したいファイル名入力>uForward.umh
b'fuForward.umh 26\r\n' 送信byte: 26
R009D020200004D
START:9D020200
送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>quit
・・・・・・
ConnectionAbortedError: [WinError 10053]
確立された接続がホスト コンピューターのソウトウェアによって中止されました。
この終了時のエラー表示は無視してください
|
Systemdのサービスで使うPi Zero用の制御サーバープログラム(umehoshi2.py)の内容(使い方は上で紹介)
次に示すumehoshi2.pyは、[UMEHOSHI ITA]基板のEEPROM領域にあるモータ制御をTCPで制御するコードです。
(赤の所が、以前と異なる部分で、EEPROM領域にあるモータ制御の初期化関数を呼び出しています。
上述の
"uStartInit.umh"を『umehosi2.py』を使って、ファイルを転送しておく必要があります。)
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# TCPサーバ側「sudo python3 umehosi2.py」で動かす
# Webサーバ、TCPサーバー実行「sudo python3 umehoshi2.py SV」で動かす(myweb.py内os.chmod利用のためsudo権限が必要)
import os
import umetcp
from umetcp import send_file, send_message, recieve_file, recieve_message, \
receiveData , path_datas
import socket
import umeusb
import traceback
import sys
#import time
sock = None # クライアント側のソケット
os.chdir("/home/pi/umehoshi2/") # カレントディレクトリ変更
umeusb.init_sub()
def my_tcp_receive_file_func(filename):
''' 受信したumehoshiアプリ用「.umh」のファイルより、
「UME専用Hexコマンド」の文字列をusbへ出力する'''
name,ext = os.path.splitext(filename)
if not ext == ".umh" : return
with open(path_datas + "/" + filename) as f: ss=f.readlines()
ss="".join(ss[1:])
print(ss)
umeusb.send_cmd(ss) # TCPで受信した 「.umh」データを[UMEHOSHI ITA]へ送る
my_tcp_receive_file_func( "uStartInit.umh" ) # このロボット制御用の[UMEHOSHI ITA EEPROM]用初期化エントリーファイル実行
if len(sys.argv) > 1:
argument = sys.argv[1]
#print(f"受け取った引数: {argument}")
#======================= myweb start
umetcp.camera.close()
umeusb.usb.close()
import myweb # ここで、Webサーバを起動して、サーバを使い終わたら、改めてデバイスを初期化して使う。
umeusb.init_sub()
import picamera
umetcp.camera = picamera.PiCamera()
#======================= myweb end
def my_usb_receive_func(bin):
'usb受信のイベントで実行するデフォルト処理'
global sock
#print("-----------",bin)
ss = bin.decode('utf-8')
a=ss.split('\n')
for s in a:
s = s.strip()
if sock != None:
send_message(sock, s) # [UMEHOSHI ITA]からの応答メッセージをTCPで返す
else: print( s )
umeusb.usb_receive_func = my_usb_receive_func # USB受信データの処理を置き換える。
umetcp.tcp_receive_file_func = my_tcp_receive_file_func # tcp受信データの処理を置き換え
def my_tcp_recieve_message(msg):
umeusb.send_cmd(msg)
umetcp.tcp_receive_message_func=my_tcp_recieve_message # ★ umehoshi.py に対して新しく追加(20250720)
ip = "192.168.100.1" #[Raspberry PI Zero WH]の設定に合わせてください
portnumber=59154
hostname=socket.gethostname()
server_addr =(ip, portnumber)
print("Serverの情報:",hostname, server_addr)
serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversock.bind(server_addr) # IPとポート番号を指定します
print("接続要求を待つ")
serversock.listen()
while True:
print("接続を待って、接続してきたら許可")
sock, address = serversock.accept()#サーバの接続受け入れ
print("接続相手:",address)
try:
receiveData( sock ) # 受信ループ
except Exception as e:
print(f"例外の種類: {type(e)}")
print(f"スタックトレース: {traceback.format_exc()}")
print(e, "sock.close()")
sock.close()
上記のumehoshi2.pyをWebサーバーとして動かすため、"/cgi-bin/ume.py"を変更
「sudo python3 umehoshi2.py SV」で上記を動かすと、
import mywebでWebサーバーを起動します。
ここで使っている
モジュール(myweb.py)は、
このリンク先で示すソースを使っています。
閲覧用の
index.htmlの内容や、
制御用の
index.htmの内容は各リンク先にありますが、以前と変更していません。
ロボットのカメラを単純に閲覧するだけでであれば、これまで変更で見えているはずです。(このイメージは
このリンク先と同じです)
ですが、モータ制御を行うページのindex.htm(
操作イメージ)でume.pyを変更せずにボタン操作すると失敗します。
index.htm内のボタン操作で、"/cgi-bin/ume.py"を呼び出しで「UMEHOSHI ITA」基板のモータ制御関数のエントリーポイントを起動するようになっていますが、
このアドレスが以前のRAM領域のままでは正しく実行できないことになりります。
以前のume.pyの内容を、以下の赤のように変更したume.pyを作成したファイルを用意します。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# このume.pyは、 http://192.168.100.1/cgi-bin/ume.py?PWD=abc123&CMD=Beep のような呼び出しが可能
import serial
import cgi
import os
import sys
import io
import cgitb
cgitb.enable()
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') # print命令のエンコードを指定
print("Content-Type: text/html; charset=utf-8\n\n")
import serial
cmd="X"
rtn="None"
try:
serial = serial.Serial(port ='/dev/ttyACM0' , baudrate = 115200,timeout = 1)
import umeutil
# フォームから値を取得
form = cgi.FieldStorage()
pwd = ""
if 'PWD' in form:
pwd = form['PWD'].value
if 'CMD' in form and pwd == "abc123":
cmd = form['CMD'].value
if cmd=='Forward':
rtn=umeutil.send_cmd(serial, "R009D020200004D")
rtn=str(rtn)
elif cmd=='Backword':
rtn=umeutil.send_cmd(serial, "R009D020300004C")
rtn=str(rtn)
elif cmd=='Left':
rtn=umeutil.send_cmd(serial, "R009D020500004A")
rtn=str(rtn)
elif cmd=='Right':
rtn=umeutil.send_cmd(serial, "R009D020400004B")
rtn=str(rtn)
elif cmd=='UL':
rtn=umeutil.send_cmd(serial, "R009D0206000049")
rtn=str(rtn)
elif cmd=='DL':
rtn=umeutil.send_cmd(serial, "R009D0207000048")
rtn=str(rtn)
elif cmd=='UR':
rtn=umeutil.send_cmd(serial, "R009D0208000047")
rtn=str(rtn)
elif cmd=='DR':
rtn=umeutil.send_cmd(serial, "R009D0209000046")
rtn=str(rtn)
elif cmd=='Stop':
rtn=umeutil.send_cmd(serial, "R009D020A00003E")
rtn=str(rtn)
elif cmd[:1]=='R' or cmd[:1]=='S' or cmd[:1]=='G':
rtn=umeutil.send_cmd(serial, cmd)
rtn=str(rtn)
else: # cmd=='Beep'
rtn=umeutil.send_cmd(serial, "R009D020D00003B")
rtn=str(rtn)
#
serial.close()
except Exception as e:
print(e)
print(cmd + ":" + rtn)
上記ume.pyファイルは、次の操作でファイルを転送して、cgi-binのディレクトリへ移動し、実行権限を与えます。
Pi Zero のumetcp.py実行側 | PCでのumeclient2.py実行側 |
pi@raspberrypi:~/umehoshi2 $ python3 umetcp.py
Serverの情報: ('192.168.100.1', 59154)
接続要求を待つ
start receiveData
ume.py 2047
recieve file:ume.py,size:2047
pi@raspberrypi:~/umehoshi2 $ mv datas/ume.py cgi-bin/ume.py
pi@raspberrypi:~/umehoshi2 $ chmod +x cgi-bin/ume.py
pi@raspberrypi:~/umehoshi2 $
|
D:raspi_zero>python umeclient2.py
IP (defualt:192.168.100.1)Address>
接続成功
start receiveData
送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>f
[ ・・・・カレントディレクトリの表示・・・・・]
送信したいファイル名入力>ume.py
b'fume.py 2047\r\n' 送信byte: 2047
送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>quit
終了時のエラー表示は無視してください
|
以上で、Webサーバー関連の準備は終了です。次のように検証します。
まず、Webサーバーを次のように起動します。
pi@raspberrypi:~/umehoshi2 $ sudo python3 myweb.py
のURLでカメラ画像が見えればOKです。
http://192.168.100.1/index.html
続いて、上記で作成したcgi-bin/ume.pyの検証で、次のブラウズでビープ音が出ればOKです。
http://192.168.100.1/cgi-bin/ume.py?PWD=abc123&CMD=Beep
なおモータを動作させる場合は、先にuStartInit.umhを実行させなければなりません。
それを起動に行っているサーバーがumehoshi2.pyで、この中でmyweb.pyを起動しています。
(次の
http://192.168.100.1/QUIT.jpgを閲覧でWebサーバーを終了できます。)
Web兼制御サーバープログラムのumehoshi2.pyを起動するコマンドは、次のように起動します。
pi@raspberrypi:~/umehoshi2 $ sudo python3 umehoshi2.py SV
次のURLでボタン操作でモータうぃ制御できるページが開きます。
http://192.168.100.1/index.htm
このWebサーバーを終了は、次の
http://192.168.100.1/QUIT.jpgの閲覧で行います。
Webサーバーが終了終了すると、TCP制御サーバーが始まります。
このサーバーは、PC側で上記でも紹介しているように、python umeclient2.pyで接続して
M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>
のメニュー操作で制御できます。
Systemdのサービスにumehoshi2.pyを登録
umehoshi2.pyをSystemdを使ったサービスとして、電源投入時に、実行させる設定です。
まず、umehoshi2.pyに実行権限を次のコマンドで与えます。
sudo chmod +x /home/pi/umehoshi2/umehoshi2.py
これをサービスなどの設定を行うファイル「 Unitファイル」を次のように作ります。
ユーザ作成のUnitファイルの置き場は、「/etc/systemd/system」と決まって、次のファイルを作ります。
「/etc/systemd/system/umehoshi2.service」をsudoの編集操作で操作します。
[Unit]
Description = umehoshiserver2.
[Service]
ExecStart=/usr/bin/python3 /home/pi/umehoshi2/umehoshi2.py SV
Type=simple
[Install]
WantedBy=multi-user.target
これは、次のコマンド操作で動作を確認します。(Webサーバーの動作説明はこのページ先頭で紹介しています。TCP制御サーバーは下記で後述しています)
sudo systemctl start umehoshi2.service (自動実行の登録前の検証時の実行で使う)
次のコマンド操作でサービスの実行状態を確認します。
sudo systemctl status umehoshi2.service
動作の確認後、このサービスを次のコマンド操作で登録します。
sudo systemctl enable umehoshi2.service
以上で、サービス登録が終了です。
sudo rebootまたは、シャットダウンして、再度電源コネクタを抜き差しして、動作を確かめます。
前に紹介したページの作品は、HTTPサーバー起動時に[UMEHOSHI ITA]基板のRAM領域へ モータ制御プログラムを転送し、
約2分程度の時間が必要でした。
対して、モータ制御プログラムをEEPROMに書き込んで、起動時はその初期化関数を呼び出すだけに改良しています。
この初期化関数の起動時にブザーが鳴るようになっており、そこまでの時間は約42秒掛かりました。
なお、PCでロボットのWifiアクセスポイントが見えて接続できるようになるまでには、約1分20秒を要しました。
アクセスポイント SSID:pizero、パスプレーズ:abcd1234 のWifiのアクセスポイントにPCで接続します。
始めはWebサーバーが起動しているので、そして、
http://192.168.100.1/index.htmに接続します。
このブラウザ閲覧で、モーター動作を確認します。
その後、quit.jpg閲覧で、Webサーバーの代わりに、TCP制御サーバーの状態にします。(次の行のクリック操作)
「Webサーバー終了してTCP制御サーバー起動」の隠し操作
これは、http://192.168.100.1/quit.jpgの閲覧で終了し、TCPの制御サーバーが動作を始めます。
このTCP制御サーバーに対応するクライアントソフト(umeclient2.pyなど)をPC側で動かして制御を確かめます。
PC側でこのロボットを制御するためのクライアントプログラム例:umeclient2.py
PC側よりでpython umeclient2.pyの実行でロボットのTCP制御サーバーに
接続して
'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>の
メニュー操作で制御できます。
このumeclient2.pyは、
このリンク先で紹介したumeclient.pyのエントリーポイントのファイル(.umh)を変更し、
別モジュールであった
umetcp.pyを一つのソースにまとめた次のコードです。
また、メニューの
T Enter の操作でロボットに撮影を要求し、応答した画像は'serverpicture.jpg'の名前で保存していますが、
この表示処理(show_imageメソッド)を、メインスレッドで行うように変更しています。
import socket
import os
import sys
import time
import threading
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
def send_message(sock,msg):
bin=('M'+msg+"\r\n").encode("utf-8")#binaryへ変換
sock.sendall(bin)#一括送信
def send_file(sock, filepath):
filesize = os.path.getsize(filepath)
filename = os.path.basename(filepath)
s = "f{} {}".format(filename, filesize)
bin=(s+"\r\n").encode("utf-8")#binaryへ変換
print(bin, end=" ")
sock.sendall(bin) #filename filesize 送信
with open(filepath, "rb") as f:
bin = f.read(filesize)
# print("送信data:" , bin )
sock.sendall(bin) # ファイル内容一括送信
print("送信byte:" , len(bin) )
serverpicture_receive_filepath = None # 受信画像ファイル
def show_image(): # serverpicture_receive_filepath の画像を表示
global serverpicture_receive_filepath
if serverpicture_receive_filepath == None: return
img = Image.open(serverpicture_receive_filepath) # 元となる画像の読み込み
serverpicture_receive_filepath = None
np_img = np.array( img )
plt.imshow( np_img ) # 各OSの標準ビューアが開く。
plt.show( block= True )
plt.close()
def recieve_file(sock):
global serverpicture_receive_filepath
buf=b""
while True:
bin = sock.recv(1)#1byte受信
if len(bin) != 1: break
buf += bin
if buf[-2:] == b"\r\n":# 1行の文字列受信終了?
s = buf[0:-2].decode('utf-8')#バイナリから
#print(s)
a=s.split(' ')
filename, filesize = a[0], int(a[1])
print(f"recieve file:{filename},size:{filesize}")# 受信したファイル名とサイズを表示
#bin = sock.recv(filesize) # ファイルの一括受信
bin=b""
while len(bin) < filesize:
bin += sock.recv(filesize-len(bin)) # ファイルの受信
#print( bin )
with open( filename, "wb") as f:
f.write(bin)
if filename == 'serverpicture.jpg': serverpicture_receive_filepath = filename
break
#
def recieve_message(sock):
buf=b""
while True:
bin = sock.recv(1)#1byte受信
if len(bin) != 1: break
buf += bin
#print("----", buf)
if buf[-2:] == b"\r\n":# 1行の文字列受信終了?
s = buf[0:-2].decode('utf-8')#バイナリから
print(s) # 受信文字列表示
break
def receiveData(sock):
try :
print( "start receiveData" )
while True:
bin = sock.recv(1)#1byte受信
if len(bin) != 1: break
if bin == b"f" : recieve_file(sock)
elif bin == b"M" : recieve_message(sock)
else:
print(bin , end="")
#
print( "receiveData ended." )
#
except Exception as e:
print(f"例外: {e}")
portnumber=59154
ip="192.168.100.1" #[Raspberry PI Zero WH]の設定に合わせてください
s = input("IP (defualt:{})Address>".format(ip))
if s != "": ip = s
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((ip, portnumber))
print("接続成功")
t_id = threading.Thread(target=receiveData, args=(sock,) )
t_id.start()
loopFlag = True
cmd=""
path_datas = '.'
while loopFlag:
show_image() # serverpicture_receive_filepathがあれば表示
s = input("送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>")
if s != "": cmd = s
if cmd == 'M':
msg = input("送信したい文字列入力>")
send_message(sock,msg+"\r\n")
elif cmd == 'f':
print(os.listdir(path_datas))
filename = input("送信したいファイル名入力>")
if not os.path.isfile(path_datas + "/" + filename):
print( filename, "no exist")
continue
send_file(sock, path_datas + "/" + filename)
elif cmd == 'quit': loopFlag=False
elif cmd == 'b': # ビープ音要求 (隠しコマンド)
send_message(sock,"R009D020D00003B\r\n")
elif cmd == 'w':
send_file(sock, path_datas + "/" + "uForward.umh")
elif cmd == 'x':
send_file(sock, path_datas + "/" + "uBack.umh")
elif cmd == 'a':
send_file(sock, path_datas + "/" + "uLeft.umh")
elif cmd == 'd':
send_file(sock, path_datas + "/" + "uRight.umh")
elif cmd == 'Q':
send_file(sock, path_datas + "/" + "uLeftUp.umh")
elif cmd == 'Z':
send_file(sock, path_datas + "/" + "uLeftDown.umh")
elif cmd == 'E':
send_file(sock, path_datas + "/" + "uRightUp.umh")
elif cmd == 'C':
send_file(sock, path_datas + "/" + "uRightDown.umh")
elif cmd == 'T':
sock.sendall( ('T'+"\r\n").encode("utf-8") )# 写真を撮って、そのファイルを要求
cmd = ""
#
time.sleep(0.5)
sock.close()
sys.exit(0)
上記のコードでは、わざとsend_fileメソッドで、各種"〜.umh"ファイルを送信しているので、そのファイルがカレントディレクトリに
配置しておく必要があります。
上記のコードのsend_message(sock,"R009D020D00003B\r\n")のビープ音要求のように、「UME専用Hexコマンド」の文字列を直接送る方法に改良すれば
"〜.umh"ファイル群の配置は必要無くなります。
このように
「UME専用Hexコマンド」の文字列を直接送る方法にしたJavaのコードを
このリンク先で紹介しています。