UMEHOSHI ITA TOP PAGE    COMPUTER SHIEN LAB

Raspberry PI Zero WとUmehoshi ITAをUSB接続したTCP制御のEEPROM化作品用クライアント側のJavaコード

ここで紹介したページの作品(EEPROM化作品)は、起動時にHTTPサーバーは、 他のPCなどからブラウザでロボットを制御できる仕様になっています。
ここで使うDHCP、HTTP、TCPサーバーは、「Raspberry PI Zero W」のLinuxで行っています。


起動すると、自身をWifiのアクセスポイントになります。
(アクセスポイント SSID:pizero、パスプレーズ:abcd1234)
そして、DHCPサーバーで、接続してきた相手に 192.168.100.2〜のIPアドレスを配信します。
このロボットのIPアドレスは192.168.100.1です。
PCでロボットのWifiアクセスポイントが見えて接続できるようになるまでには、 約1分20秒を要します。

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>の メニュー操作で制御できます。
このページでは、このPythonコードの代わりになるJavaのソースを紹介しています。
このJavaのソース(UmeClient2.java)では、外部に.umhのファイルを必要とせずに、直接EEPROMの各種制御用エントリーポイントを メッセージ送信で実行させています。
'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>wwaaaxのメニューに対する文字列を入力した場合、
wwで0.4秒前進した後、aaaで0.6秒左回転し、 その後にxで0.2秒後退させる指示になります

このコマンド操作の文字列の意味を以下に示します。
コマンド文字列意味概要
M 次に、ロボットに送信するUME専用のメッセージ入力用プロンプトがでます。
そこで例えばR009D020D00003Bの入力でブザーを鳴らせます。
f 次に、ロボットに送信する.umhのファイル入力用プロンプトがでます。
quitクライアントプログラム終了
w0.2秒だけモータ前進
x0.2秒だけモータ後進
a0.2秒だけモータ左回転
d0.2秒だけモータ右回転
Qモータ左デューティ幅アップ
Zモータ左デューティ幅ダウン
Wモータ右デューティ幅アップ
Cモータ右デューティ幅ダウン
Tカメラで撮影し、その画像ファイル(serverpicture.jpg)を要求
これで、受信した画像ファイルは起動時で出現するFrameに表示されます。
以下に、このPC側のクライアントプログラム(Java版:UmeClient2.java)を示します。
import java.io.*;   //入出力(OutputStream,InputStream)用
import java.net.Socket;//ソケット用
import java.awt.*;
import java.awt.event.*;

public class UmeClient2 extends Frame implements Runnable ,WindowListener{
    static UmeClient2 instance;// 自身のオブジェクト
    Socket socket;
    Image img;
    String imgPath = null;

    public UmeClient2(Socket socket){// コンストラクタ
        UmeClient2.instance = this;
        addWindowListener(this); // 自分自身をリスナーとして登録
        this.socket = socket;
        Thread thread = new Thread( this );
        thread.start();
        this.setSize(720, 480);
        //setImageFile("serverpicture.jpg");
        this.setVisible(true);// 表示
    }

    public void windowOpened(WindowEvent e) { }
    public void windowClosing(WindowEvent e) {
        System.exit(0);//閉じる処理を追加
    }
    public void windowClosed(WindowEvent e) {  }
    public void windowIconified(WindowEvent e) { }
    public void windowDeiconified(WindowEvent e) {  }
    public void windowActivated(WindowEvent e) { }
    public void windowDeactivated(WindowEvent e) { }

    public void paint(Graphics g) {// 描画処理のオーバーロード
        if(this.img != null) {
            g.drawImage(this.img, 0, 0, 720, 480, this);// 画像を描画
        }
    }

    public void setImageFile(String path) {// 外部から画像ファイルを指定するメソッド
        if( new File(path).exists() == false ) return;
        this.img = Toolkit.getDefaultToolkit().getImage(path);
        // Toolkit.getImage(...) は内部的に画像をキャッシュするため、同じパスを指定すると以前の画像が再利用される。
        img.flush(); // このキャッシュをクリアして、画像が再利用されないようにする
        repaint(); // 再描画を要求
        System.out.printf("setImageFile(%s), img:%s\n", path, this.img.toString());
    }

    public static void sendFile(Socket socket, String filename) throws Exception {
        File file = new File(filename);     // 送信ファイルをfileで管理
        if(file.exists() == false){
            System.out.println(filename + "が存在しません。");
            return;
        }
        int filesize = (int) file.length(); // 送信ファイルバイト取得
        byte []bin = new byte[filesize];    // 送信に使うbyte配列に、ファイル内容を全て記憶
        InputStream is = new FileInputStream(file); 
        for(int i=0; i < filesize; i++){    // ファイルから1byte読む
            bin[i] = (byte)is.read();   // 1byteを配列に記憶する繰り返し
        }
        is.close();
        String s = String.format("f%s %d\r\n", filename, filesize);
        OutputStream os = socket.getOutputStream();// 送信用byteストリーム生成
        os.write(s.getBytes("utf-8"));  // ファイル名とサイズの文字列を送信   
        os.write(bin);                  // ファイル内容を全て記憶されるbyte配列を、全て送信
        System.out.println( s );
    }

    static void sendString(Socket socket, String msg) throws Exception {// msg の文字列を送信
        OutputStream os = socket.getOutputStream();
        os.write(msg.getBytes("utf-8"));       
    }

    public static void recieveFile(Socket socket) throws Exception {// 画像ファイル受信
        byte []buff=new byte[128];
        int count=0;
        InputStream is = socket.getInputStream();
        for(;;){
            int c = is.read();//1byte入力
            // System.out.printf("%X ",c);
            if( c == -1 ) return; // 接続が閉じられたか、またはエラー
            buff[count++] = (byte)c;
            if( buff[count-1] == '\n' ){ // 1行の文字列受信終了?
                String s = new String(buff,0,count, "utf-8");
                // System.out.println(s);
                String []a=s.split(" ");
                String filename = a[0].trim();
                int filesize = Integer.parseInt(a[1].trim());
                System.out.println(filename + " size:" + filesize); // 受信ファイル名とサイズ確定
                buff=new byte[filesize];
                for(int i = 0;i < filesize; i++){
                    c = is.read();//1byte入力
                    buff[i] = (byte)c;
                }
                OutputStream os = new FileOutputStream( filename );
                os.write(buff);// 受信ファイルを保存
                os.close();
                System.out.printf("recieve filename: %s,  size=%d\n", filename, filesize);
                UmeClient2.instance.imgPath = filename;
                return;
            }
        }
    }

    static void receiveData(Socket socket) throws Exception {// 一つの受信処理(文字列のメッセージかバイナリファイルの受信)
        InputStream is = socket.getInputStream();
        try{
            int c = is.read();//1byte入力
            if( c == -1 ) {//ストリームの終わりに達した場合は-1
                socket.close();
                return;
            }
            if( c == 'M'){// メッセージ受信
                byte buff[]= new byte[512]; // 入力
                int count = 0;
                while ( true ){
                    c = is.read();//1byte入力
                    buff[count++] = (byte)c;
                    if( c== '\n') break;
                }
                System.out.print(new String(buff,0,count, "utf-8"));//メッセージ表示
            } else if( c == 'f'){
                recieveFile(socket);
            }
        }
        catch(Exception e){
            System.out.print(e.getMessage());
        }
    }

    public void run(){//上記の受信処理を、このrunの別スレッドが動かす。
        try {
            while (socket.isClosed()==false) {
                receiveData(socket);// 文字列のメッセージかバイナリファイルの受信
            }
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }

    public static void main(String []a) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String ip = "192.168.100.1";// br.readLine();
        System.out.println(ip+"に59154番で接続します。");
        Socket socket = new Socket( ip,  59154);
        System.out.println(ip+"に59154番で接続しました。----------------------!");

        UmeClient2 umeClient2 = new UmeClient2(socket);// 画像表示用Frame生成

        boolean loopFlag=true;
        while(loopFlag){
            if(umeClient2.imgPath != null){
                    umeClient2.setImageFile(umeClient2.imgPath);// 受信ファイルの設定表示
                    umeClient2.imgPath = null;
            }
            System.out.print("'M'/'f'/'quit'/w/x/a/d/Q/Z/E/C/T>");// メニュー表示
            String str = br.readLine();
            if(str.equals("M")){
                System.out.print("input message>");
                String msg = br.readLine();
                sendString(socket, "M"+msg+"\r\n");// ロボットへの文字列(UME専用Hexコマンド)送信
            }
            else if( str.startsWith("f") )  {
                System.out.print("input send filename(.umh)>");
                String filename = br.readLine();
                sendFile(socket, filename );
            }
            else if( str.startsWith("quit") ) {// 終了?
                loopFlag = false;
            }
            else if( str.startsWith("T") ) {
                sendString(socket, "T\r\n");// カメラ撮影と撮影画像ファイル("serverpicture.jpg")要求
                Thread.sleep(1000);
            }
            else while(str.length() > 0){//「UME専用Hexコマンド」の文字列送信
                if(str.startsWith("b"))  sendString(socket,"MR009D020D00003B\r\n");
                else if(str.startsWith("w"))  sendString(socket,"MR009D020200004D\r\n");//前進
                else if(str.startsWith("a"))  sendString(socket,"MR009D020500004A\r\n");//左回転
                else if(str.startsWith("d"))  sendString(socket,"MR009D020400004B\r\n");//右回転
                else if(str.startsWith("x"))  sendString(socket,"MR009D020300004C\r\n");//後進
                else if(str.startsWith("Q"))  sendString(socket,"MR009D0206000049\r\n");//モータ左デューティ幅アップ
                else if(str.startsWith("Z"))  sendString(socket,"MR009D0207000048\r\n");//モータ左デューティ幅ダウン
                else if(str.startsWith("E"))  sendString(socket,"MR009D0208000047\r\n");//モータ右デューティ幅アップ
                else if(str.startsWith("C"))  sendString(socket,"MR009D0209000046\r\n");//モータ右デューティ幅ダウン
                else if(str.startsWith("S"))  sendString(socket,"MR009D020A00003E\r\n");//モータストップ
                str=str.substring(1);// 上記の処理文字を除いた次の入力文字列を取得
            }
            Thread.sleep(200);
        }
        socket.close();// 接続を終了
   }
}