UMEHOSHI ITA TOP PAGE COMPUTER SHIEN LAB
このページはRaspberry PI Zeroをスマフォの代わりに使って、
[UMEHOSHI ITA]制御基板を
PCやAndroidの「umehoshiアプリ」で遠隔操作を可能とするまでの内容です。
この作品の前に作ったRaspberry PI 3B と接続した作品紹介は、こちらです。
この作品の後に作ったHTTPで制御する作品紹介は、こちらです。
以下では、最終的に「/home/pi/umehoshi/umehoshi.py」をsystemctlシステムで、起動時に実行さています。
このumehoshi.pyプログラムはpythonのTCPサーバで、[UMEHOSHI ITA]基板の制御コマンドの送受信を仲介しています。
umehoshi.pyの起動時にこちらで作成したモータ制御の"app_pwm_pizero.c.hex"を[UMEHOSHI ITA]へロードしています。
そしてその中の各関数の起動アドレスを、直接呼び出すコマンドでロボットを制御しています。
外装は『
ABS樹脂ケース(蝶番式・中) 112−TS(P-00277)』
に穴などの加工をして、
それに、
Camera を付けた[Raspberry PI Zero WH]と[UMEHOSHI ITA ]をUSBで繋いだ構成を IoT機器対応モバイルバッテリー(5000mAh)と共に詰め込んでいます。
この組み立て過程をこのページで紹介しています。
モバイルバッテリーから[Raspberry PI Zero W]に電源が供給され、[Raspberry PI Zero WH]からUSB接続で[UMEHOSHI ITA]に供給される構成です。
([Raspberry PI Zero WH]と[UMEHOSHI ITA ]のUSB接続は通信も兼ねて、[Raspberry PI Zero W]から[UMEHOSHI ITA]を制御します)
そしてモータ用の電源は、下部に配置した単3×4の電池で[UMEHOSHI ITA]のDCジャックより供給しています。
(Raspberry 用のシャットダウン用スイッチも追加しました)
(下記画像のクリックでイメージが変わります。) 
 このClickでYoutube 紹介動画へ移動できます。  

[Raspberry PI Zero WH]はこのページでセットアップをしたものを
使って組み立てています
このセットアップにより、[Raspberry PI Zero WH]をWifiで接続する方法は次の2通りです。
(両者ともSSHのクライアントを使って[Raspberry PI]を操作します。(「pi」のIDで[abc123]のパスワードで接続)
 Are you sure you want to continue connecting (yes/no/[fingerprint])?でyesを入力します。
 Host key verification failed.のエラーであれば「ssh-keygen -R IPアドレス」入力で、該当のIPアドレス情報を消して再接続します。)
(1)
[Raspberry PI]を192.168.0.1のアクセスポイントに接続して、
同一ネットワーク内のPCから[Raspberry PI]にSSHで接続する方法です。
PC側の端末で、[Raspberry PI]の「ssh pi@192.168.0.123」で接続してできます。
Wifi環境のアクセスポイントがない所ではできませんが、[Raspberry PI]でインターネットも使える設定が可能です。
(アクセスポイントに合わせて[Raspberry PI]のセットアップを変更してください。)
(2) [Raspberry PI]自身をWifiのアクセスポイントにする方法です。 操作するPCやAndroidでは、[Raspberry PI]のSSID:pizero、パスプレーズ:abcd1234のWifiアクセスポイントに接続します。 この場合に[Raspberry PI]へのアクセスは、「ssh pi@192.168.100.1」で接続します。
以上どちらかのWifiを介して次のような遠隔操作できる環境を作ります

[Raspberry PI]の自作TCPサーバで、次のよう基本的な動作ができるように作ります。
遠隔操作用の指示ファイル(.umhファイル)をTCPで受信
[Raspberry PI]は受信した.umhファイル内の(UME専用Hexコマンド)をUSBを介して[UMEHOSHI ITA]に送信して動作させます。
UME専用Hexコマンドを受信してその処理を行った[UMEHOSHI ITA]は、その応答メッセージをUSBを介して[Raspberry PI]に送信します。
[Raspberry PI]側でTCPサーバでは、USBを介して受信した応答メッセージをTCPクライアントに送信します。
つまり自作TCPサーバは、umehoshiアプリのサーバ側の処理に近い機能を盛り込んだものと言えます。
また、自作TCPサーバでは、[Raspberry PI]ロボットモータなどの制御プログラムを[Raspberry PI]を起動時に埋め込む機能を付加します。
(この[UMEHOSHI ITA]側のプログラム情報はこのページにあります。)
それによって起動後は、遠隔操作用の「.umh」の転送だけでロボットを制御できるようにします。
この主要なコマンド(プログラムを入れたファイル名)は次のようになります。
| 前進 | uGoForward.umh | 
| 後進 | uGoBack.umh | 
| 左回転 | uGoLeft.umh | 
| 右回転 | uGoRight.umh | 
以上を実現するために、次のpythonのコードを作りました。
| ソース名 | 概要 | 
|---|---|
| umeusb.py | USBで[UMEHOSHI ITA]と通信する以下の関数群と変数を定義しています。
usb:このグローバル変数が指し示す接続相手とUSB通信するためのオブジェクト
imort時にオープンされて、下記各関数はそれを利用する。
init_sub(): SUBのSerial初期化
check_sum(s:str) -> bool: check sum エラーでFalseを返す
usb_send(s, endstr=b"\n",quantity=2):sを送信して、受信したバイナリを返す。タイムアウト時は""を返す
         endstrがquantity個受信した時点でリターンする。(コマンドの応答が2行であることが前提)
send_cmd( ss, cmdchar="SRG"):  usb_sendを利用してコマンド文字列群を引数で指定可能(S R G以外の先頭行文字列は無視)
send_cmdfile(filepath, cmdchar="SRG"): send_cmdを利用して、filepathの「UME専用Hexコマンド」をUSB先の[UMEHOSHI ITA]に送信
usb_receive_func: 利用時に変更するusb受信で処理する関数を、記憶する変数
単体の実行で、キー入力したhexコマンドをUSBで[UMEHOSHI ITA]に送信可能
 | 
| umetcp.py | TCPで[UMEHOSHI ITA]と通信する以下の関数群を定義しています。(他にカメラを参照する変数も初期化) imort時にオープンされて、下記各関数はそれを利用する。 send_file(sock, filename): filenameのファイルをsockの相手に送信する。 send_message(sock,msg): msgの1行の文字列をsockの相手に送信する。 recieve_file(sock): sockからの受信ファイルでそのファイルを保存する。 recieve_message(sock): sockからの受信した文字列を表示する。 receiveData(sock): sockからの1つの受信処理で、上記の各受信処理を呼び出して作られる 単体の実行で、Wifiを介して「umehoshiアプリからのメッセージ受信、ファイル受信、カメラ撮影と送信が可能 | 
| umehoshi.py | TCPサーバとして起動して、受信したコマンドで[UMEHOSHI ITA]と通信するメインの処理を行っています。 上記モジュール(umeusb.py、umetcp.py)をimportして利用してTCP受信でUSBへコマンド送り制御します。 my_usb_receive_func(bin):usb受信に対する処理で、umeusbのデフォルトを置き換え、TCP接続相手へ応答メッセージを送出する my_tcp_receive_file_func(file): 受信したumehoshiアプリ用「.umh」のファイルより、E専用Hex文字列をusbへ出力する | 
umehoshi.pyをサービスとして、電源投入時に、実行させる設定を行います。
この自動起動には、Systemdを使った方法でを使います。
Systemdはサービスとして、起動、シャットダウン、再起動などをコマンドで操作ができるのようになります。
個々のサービスなどの設定を行うファイル「 Unitファイル」を次のように作ります。
ユーザ作成のUnitファイルの置き場は、「/etc/systemd/system」と決まって、次のファイルを使います。
「/etc/systemd/system/umehoshi.service」をsudoの編集操作で操作します。
[Unit] Description = umehoshiserver. [Service] ExecStart= /home/pi/umehoshi/umehoshi.py Type=simple [Install] WantedBy=multi-user.target
(基本的には、「Description」にサービス名、「ExecStart」に実行したいプログラムを記載しています。)
 サービス制御用のコマンドの表を以下に示します。
| コマンド操作 | 意味 | |
|---|---|---|
| (1) | sudo systemctl start umehoshi.service | サービスを開始(自動実行の登録前の検証時の実行で使う) | 
| (2) | sudo systemctl stop umehoshi.service | サービスを停止 | 
| (3) | sudo systemctl enable umehoshi.service | サービスの自動起動を有効化します | 
| (4) | sudo systemctl status umehoshi.service | サービスの動作状況を確認します。 | 
| (5) | sudo systemctl disable umehoshi.service | サービスの自動起動を無効化します。 | 
下記Systemdの設定は、後述しているumeusb.py、umetcp.py、umehoshi.pyの各動作確認ができてから行った方が良いでしょう。
手順(1): 「sudo systemctl start umehoshi.service」実行して60秒後にumehoshi.pyの動作をumeclient.pyで確認します。
手順(2): (1)が動作できたら、「sudo systemctl enable umehoshi.service」で起動の登録を行い、[Raspberry PI]をシャットダウンさせて電源を差し込み直します。
以上で 「umehoshiアプリ」からの遠隔操作が可能となるはずです。
(「umehoshiアプリ」で、pizeroのアクセスポイントに接続して、192.168.100.1に接続して使います。可能な操作はメッセージを送る。
「.umh」や「.hex」ファイル(S R のhexコマンド群)を転送して実行させる。写真を撮る操作です。)
なおこのumehoshiserverのサービスが実行中の場合は、tcpやUSBのポートが使用中の状態になります。
よって、後述しているumeusb.py、umetcp.py、umehoshi.pyを別途コマンドで起動することができなくなります。
これらをコマンド操作で実行させる場合は、「sudo systemctl stop umehoshi.service」でサービスを停止して操作する必要があります。
Raspberry PIのUSBをホストとして、[UMEHOSHI ITA ]基板のUSBとケーブルを繋いで、Raspberry PI側から[UMEHOSHI ITA ]を制御するためのコードです
以前に紹介したPythonのUSB通信プログラムを変更して作ったもので、単独実行でキー入力した「UME専用Hexコマンド」を
[UMEHOSHI ITA ]にプログラムを転送して制御できるコードです。
(usb = serial.Serial(port = '/dev/ttyACM0', baudrate = 115200)のport設定は、[Raspberry PI]のUSB位置で変更する必要があるかもしれません)
send_cmdfileで、「.umh」と「.hex」のファイル両方に対応して、「UME専用Hexコマンド」だけをusbに送信しています。
import serial
import threading
import sys
import time
def defalut_usb_receive_func(bin):
    'usb受信のイベントで実行するデフォルト処理'
    print( bin.decode('utf-8') ,end="") # USBより受信したデータを表示
usb_receive_func = defalut_usb_receive_func # usb受信で実行する処理
# 上記を変更することで、USB受信に対する振る舞いを変更できる。
"usb:このグローバル変数が指し示す接続相手とUSB通信するためのオブジェクト"
"imort時にオープンされて、下記各関数はそれを利用する。"
usb = None
def init_sub(): 
    global usb
    try:
        usb = serial.Serial(port = '/dev/ttyACM0', baudrate = 115200)
        #usb = serial.Serial(port = 'COM8', baudrate = 115200,timeout = 10)
    except Exception as e:
        print(e)
        sys.exit(1)
    print( usb ) # USB のシリアルオブジェクト表示
def check_sum(s):
    ''' b = check_sum("G10800090000067")
    '''
    ck = 0
    n = len(s)
    if n == 0: return
    for i in range(n-2):
        ck += ord(s[i])
        # print(ck)
        # print(s[i] , end ="")
    # print(' ',s[-2:] , end ="")
    ck += int(s[-2:] , 16)
    ck &= 0x0f
    if ck != 0 :
        print("check sum error", ck)
        return False
    return True
def usb_send(s, endstr=b"\n",quantity=2):
    '''  b = usb_send("G10800090000067", endstr=b"\n",quantity=1):
    sを送信して、受信したバイナリを返す。タイムアウト時は""を返す
    endstrがquantity個受信した時点でリターンする。
    quantity=2のデフォルト値は、送信した1行に対するエコー文字列の1行と
    応答文字列の1行を意味します。
    '''
    if check_sum(s) == False: return b""
    usb.write(s.encode('utf-8'))
    usb.write(b'\r\n')
    rtnval=b""
    while True:
        if quantity <= 0:
            return rtnval # 受信したバイナリーを返す。
        b=usb.readline()
        if b == "": return ""
        rtnval+=b
        n=b.count(endstr)
        quantity-=n
def send_cmd( ss, cmdchar="SRG"):# sの例[S048000800000FFAF000086]
    a = ss.split('\n')
    for s in a:
        s=s.strip()
        if s == "" or not s[0] in cmdchar : continue # S R G 以外のコマンドを無視
        b = usb_send(s) # デフォルトで2行のudb応答文字列の受信を含むコマンド出力
        usb_receive_func( b ) # USB受信で得られたbで行う処理
def send_cmdfile(filepath, cmdchar="SRG"):
    with open(filepath , "r", encoding="utf-8") as f:
        ss = f.readlines()
    if filepath.endswith(".umh") : ss = ss[1:] # 先頭のボタン仕様行を除去
    ss="".join(ss)
    #print(ss)
    send_cmd( ss, cmdchar)
# USB受信スレット例(b'end\r\n'受信まで繰り返す)
def read_loop():
    while True:
        try:
            b=usb.readline() # binary
            if(b == b'end\r\n'):
                print("recieve 'end'")
                break
            usb_receive_func( b ) # USB受信の処理
        except Exception as e:
            #print(e)
            break
    #
    print("end read_loop()")
if __name__ == "__main__x": # 「UME専用Hexコマンド」ファイルの送信テスト用
    init_sub()
    send_cmdfile("app_pwm.c.hex")
if __name__ == "__main__": # キー入力した「UME専用Hexコマンド」を送信して[UMEHOSHI ITA]を制御するテスト用
    # スレッドに read_loop 関数を渡して実行を始める
    init_sub()
    t_id = threading.Thread(target=read_loop)
    t_id.start()
    while True:
        s = input("USBへ送信する文字列>")# 例[G10800090000067]
        if s == "": break
        usb_send( s, quantity=0 )
        time.sleep(0.1)
    usb.close()
    print("Ended !")
上記ファイルの単独実行例を示します。(キー入力した「UME専用Hexコマンド」の文字列を[UMEHOSHI ITA]に送って、その応答メッセージを表示)pi@raspberrypi:~/umehoshi $ python3 umeusb.py Serial<id=0xb6890c30, open=True>(port='/dev/ttyACM0', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False) USBへ送信する文字列>G10800090000067 G10800090000067 :108000900000CF0ABCECC71A6C23291CA1A32139A8A223 USBへ送信する文字列> Ended !
TCPで[UMEHOSHI ITA]と通信する以下の関数群を定義しています。(他にカメラを参照する変数も初期化)
umehoshiアプリTCP送受信メッセージの仕様に従って、
その先頭文字である'M' や 'f' や 'T' から始まる文字列に対する処理を定義しています。
それぞれの先頭文字は、[メッセージ文字列受信]、[ファイル受信]、[写真を撮ってファイルを要求]
の意味になっており、
receiveData関数でこの分岐処理をしています。
import os
import sys
path_datas = "datas" # 受信したhexファイルの記憶ディレクトリ
path_pics = "pictures" # 撮影したファイルの記憶ディレクトリ
if os.path.isdir(path_datas) == False:
    os.mkdir(path_datas)
if os.path.isdir(path_pics) == False:
    os.mkdir(path_pics)
try:
   import picamera # ★ raspberry Pi用
   camera = picamera.PiCamera() # ★
except: pass
def defalut_tcp_recieve_file(filename):
    'tcpでファイルを受信した直後の処理'
    filesize = os.path.getsize(path_datas + "/" + filename)
    # 受信したファイル名とサイズを表示
    print( "recieve file:{},size:{}".format(filename, filesize)) 
tcp_receive_file_func = defalut_tcp_recieve_file # tcpファイル受信で実行する処理
def defalut_tcp_recieve_message(msg):
    print( msg ) 
tcp_receive_message_func = defalut_tcp_recieve_message # tcpメッセージ受信で実行する処理
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) )
def send_message(sock,msg):
    bin=('M'+msg+"\r\n").encode("utf-8")#binaryへ変換
    sock.sendall(bin)#一括送信
def recieve_file(sock):
    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(filename, filesize) # 受信ファイルとサイズ確定
            #bin = sock.recv(filesize) # ファイルの一括受信
            bin=b""
            while len(bin) < filesize:
                bin += sock.recv(filesize-len(bin)) # ファイルの受信
            #print( bin )
            with open( path_datas + "/" + filename, "wb") as f:
                f.write(bin)
            tcp_receive_file_func(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')#バイナリから
            tcp_receive_message_func(s) # 受信文字列の対処
            break
def receiveData(sock):
    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)
        elif bin == b"T" : 
            sock.recv(1)#'\r'受信
            sock.recv(1)#'\n'受信
            pic_file_name="serverpicture.jpg"
            if 'camera' in globals(): 
                camera.capture(path_pics + "/" + pic_file_name) # ★写真撮影
                print("写真撮影")
            send_file(sock,path_pics + "/" + pic_file_name)
            print("送信ファイル:" + pic_file_name)
        else:
            print(bin , end="")
    #
    print( "receiveData ended." )
        
if __name__ == "__main__":
    import socket
    portnumber=59154
    ip = "192.168.100.1"
    ip = "192.168.0.123" #[Raspberry PI Zero WH]の設定に合わせてください
    server_addr =(ip, portnumber)
    print("Serverの情報:",server_addr)
    serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    serversock.bind(server_addr)  # IPとポート番号を指定します
    print("接続要求を待つ")
    serversock.listen()
    sock, address = serversock.accept()#サーバの接続受け入れ
    try: 
        receiveData( sock ) # 命令を受信して処理するループ
    except: pass
    sock.close()
    serversock.close()
上記ファイルの確認用実行例を示します。
sshで「192.168.0.123」に接続した後、PC側のpythonが動作するコマンドプロンプトで「python umeclient.py]
サーバ側IPアドレス(192.168.0.123)は[Raspberry PI]の設定に合わせて変更して使ってください。
[Raspberry PI]をアクセスポイントしてWifi環境がない所でも使う最終設定は192.168.100.1ですが、
ここでは、既存アクセスポイントを介して[Raspberry PI]の192.168.0.123に接続している状態の例です。
なお、右下では「umehoshiアプリ」の代わりにその一部を実現するumeclient.pyを使って検証しています。
(写真表示の警告や終了時のエラーは無視してください)
| [Raspberry PI]に接続中のssh内容 | PC側の操作用コマンドプロンプト | 
|---|---|
| 
pi@raspberrypi:~/umehoshi $ python3 umetcp.py
Serverの情報: ('192.168.0.123', 59154)
接続要求を待つ
start receiveData
hello
uGoForward.umh 24
recieve file:uGoForward.umh,size:24
写真撮影
b'fserverpicture.jpg 250169\r\n'  送信byte: 250169
送信ファイル:serverpicture.jpg
pi@raspberrypi:~/umehoshi $
 | D:\raspi_zero\umehoshi>python umeclient.py IP (defualt:192.168.0.123)Address>192.168.0.123 接続成功 start receiveData 送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>M 送信したい文字列入力>hello 送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>w b'fuGoForward.umh 24\r\n' 送信byte: 24 送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>T serverpicture.jpg 250169 recieve file:serverpicture.jpg,size:250169 送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>quit | 
TCPサーバとして起動させて、受信したコマンドで[UMEHOSHI ITA]と通信するメインの処理を行っています。
上記モジュール(umeusb.py、umetcp.py)をimportして利用してTCP受信でUSBへコマンド送り制御します。
[Raspberry PI Zero WH]に合わせたIPアドレスでTCPサーバをバインドしていますが、[Raspberry PI Zero WH]の設定に合わせてください。
以下では、192.168.100.1にしている最終設定例です。
(これは、のSystemdを使った自動的な起動に合わせた設定です。デバックなどの確認時は192.168.0.123で動作を確認すると良いでしょう)
起動時に、app_pwm_pizero.c.hexのファイルを読み取って、[UMEHOSHI ITA]を初期化しています。
このソース(app_pwm_pizero.c)はこのページにあります。
これをビルドして作っており、これを置き換えることで、起動時の[UMEHOSHI ITA]プログラムが変更できます。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#   サーバ側「sudo python3 umehosi.py」で動かす
import os
import umetcp
from umetcp import send_file, send_message, recieve_file, recieve_message, \
   receiveData , path_datas
import socket
import umeusb
import sys
import time
sock = None # クライアント側のソケット
os.chdir("/home/pi/umehoshi/")
# ip = "192.168.0.123" #[Raspberry PI Zero WH]の設定に合わせてください
ip = "192.168.100.1"
if ip == "192.168.100.1":
    time.sleep(60) # 60秒待機
args=sys.argv
umeusb.init_sub()
start_path = path_datas + "/" + "app_pwm_pizero.c.hex"
if os.path.isfile( start_path ) == True:
    umeusb.send_cmdfile(start_path) # このロボット制御用の[UMEHOSHI ITA]用Hexファイルのロード
    umeusb.send_cmd("R00800050000061") # 上記でロードしたプログラムの初期起動
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受信データの処理を置き換える。
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:]) # 202506変更
    #print(ss)
    umeusb.send_cmd(ss) # TCPで受信した 「.umh」データを[UMEHOSHI ITA]へ送る
umetcp.tcp_receive_file_func = my_tcp_receive_file_func # tcp受信データの処理を置き換え
portnumber=59154
hostname=socket.gethostname()
if len(args) >= 2: ip = args[1] # 引数でIPアドレス指定があれば使う
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(e, "相手が閉じた?")
   sock.close()
実行例を示します。
[Raspberry PI Zero WH]のアクセスポイント(ssid:pizero)に接続してから、192.168.100.1のsshターミナルでRaspberry PIを操作します。
[Raspberry PI Zero WH]のアクセスポイント(ssid:pizero)が有効になるまでに時間がかかる
ことに合わせて、60秒ほど経過してから
各種の初期化が行われるようにしています。
よって、左下のpython3 umehoshi.py実行後、60秒間は何も表示しない状況があることに注意してください。
その後、"app_pwm_pizero.c.hex"を[UMEHOSHI IT]に転送する画面へと続きます。
この転送が終わってから、pythonが動作するPC側のコマンドプロンプトで「python umeclient.py]で遠隔操作をしている例です。
「192.168.100.1」で接続している例です。(接続で左側では「接続相手: ('192.168.100.5', 52442)」が追加表示されています)
PC側ではその後、「M」を入力して "   hello"の文字列を送り、
次に「w」を入力して [uGoForward.umh]のファイル転送でモータを正転させて、
次に「T」を入力して 写真撮影とそのファイル転送をさせた後、quit入力で終了させています。
(写真表示の警告や終了時のエラーは無視してください)
| [Raspberry PI]に接続中のssh内容 | PC側の操作用コマンドプロンプト | 
|---|---|
| pi@raspberrypi:~/umehoshi $ python3 umehoshi.py Serial | 【Raspberry PIの初期化が終わるまで60秒待ちます】 D:\raspi_zero\umehoshi>python umeclient.py IP (defualt:192.168.0.123)Address>192.168.100.1 接続成功 start receiveData 送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>M 送信したい文字列入力> hello 送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>w b'fuGoForward.umh 24\r\n' 送信byte: 24 R0080005200005F START:80005200 送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>T serverpicture.jpg 126136 recieve file:serverpicture.jpg,size:126136 送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T> quit | 
Raspberry PI側では、PCの接続が終わると、「接続を待って、接続してきたら許可」の表示が出て、次の接続が可能になっています。
以上の確認ができてから、Systemdによる自動起動の設定をすると良いでしょう。
上記の[UMEHOSHI ITA]で実行させるumehoshi.pyに対するクライアントプログラムで、実験的なコードです。
上記のサーバ側IPアドレス(192.168.100.1 or 192.168.0.123)に合わせて変更して使ってください。
[Raspberry PI]をアクセスポイントしてWifi環境がない所でも使う最終設定では192.168.100.1にして使います。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#  クライアント側 「sudo python3 umeclient.py」で動かす
import socket
from umetcp import send_file, send_message, recieve_file, recieve_message,receiveData,path_datas
import os
import sys
import time
import threading
import umetcp
import numpy as np
from PIL import Image
import matplotlib
matplotlib.use('TkAgg') #うまくいかなければ MacOSX Qt5Agg Qt4Agg Gtk3Agg GTK3Cairo TkAgg WxAgg Agg Cairo の中から選ぶ
import matplotlib.pyplot as plt
def my_tcp_recieve_file(filename):
    'tcpでファイルを受信した直後の処理'
    filepath = path_datas + "/" + filename
    filesize = os.path.getsize(filepath)
    # 受信したファイル名とサイズを表示
    print( "recieve file:{},size:{}".format(filename, filesize)) 
    if filename == 'serverpicture.jpg':
        img = Image.open(filepath) # 元となる画像の読み込み
        np_img = np.array( img )
        plt.imshow( np_img ) # 各OSの標準ビューアが開く。
        plt.show( ) #block= False )
umetcp.tcp_receive_file_func = my_tcp_recieve_file
portnumber=59154
# ip="192.168.0.123" #[Raspberry PI Zero WH]の設定に合わせてください
ip="192.168.100.1"
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=""
while loopFlag:
    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)
    elif cmd == 'f':
        print(os.listdir(path_datas))
        filename = input("送信したいファイル名入力>")
        if not os.path.isfile(path_datas + "/" + filename):
            print( filename, "no exist")
            countine
        send_file(sock, path_datas + "/" + filename)
    elif cmd == 'quit': loopFlag=False
    elif cmd == 'w':
        send_file(sock, path_datas + "/" + "uGoForward.umh")
    elif cmd == 'x':
        send_file(sock, path_datas + "/" + "uGoBack.umh")
    elif cmd == 'a':
        send_file(sock, path_datas + "/" + "uGoLeft.umh")
    elif cmd == 'd':
        send_file(sock, path_datas + "/" + "uGoRight.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") )# 写真を撮って、そのファイルを要求
    #
    time.sleep(0.5)
sock.close()
sys.exit(0)
「umehoshi.service」のサービス実行中であれば 「umehoshiアプリ」の代わりに、このファイルで動作が確認できます。
このロボットの電源投入後2分経過(実測値は1分43秒)してから、
[Raspberry PI Zero WH]のアクセスポイント(ssid:pizero)に接続し、
pythonが動作するPC側のコマンドプロンプトで「python umeclient.py]で遠隔操作をしている例です。
D:\raspi_zero\umehoshi>python umeclient.py IP (defualt:192.168.0.123)Address>192.168.100.1 接続成功 start receiveData 送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>M 送信したい文字列入力> hello 送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>w b'fuGoForward.umh 24\r\n' 送信byte: 24 R0080005200005F START:80005200 送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>T serverpicture.jpg 126136 recieve file:serverpicture.jpg,size:126136 送信したい情報を選択入力'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T> quit