UMEHOSHI ITA TOP PAGE COMPUTER SHIEN LAB
ここで紹介したページの作品(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 | クライアントプログラム終了 |
w | 0.2秒だけモータ前進 |
x | 0.2秒だけモータ後進 |
a | 0.2秒だけモータ左回転 |
d | 0.2秒だけモータ右回転 |
Q | モータ左デューティ幅アップ |
Z | モータ左デューティ幅ダウン |
W | モータ右デューティ幅アップ |
C | モータ右デューティ幅ダウン |
T | カメラで撮影し、その画像ファイル(serverpicture.jpg)を要求 これで、受信した画像ファイルは起動時で出現するFrameに表示されます。 |
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();// 接続を終了 } }