raspberry piというたのしいおもちゃを買ってしまったのでxbeeは投げ捨ててwifiを使った通信を試みる今日この頃。今回はその辺のメモ
・今回はデータをandroidタブレット→(wifi)→raspberrypi(python)→(シリアル)→arduino の経路で流すシステムを考えます。
・pythonをソケットのサーバ、androidをソケットのクライアントとします。
■まずpythonのソケット通信から、これは以前もやったのでわりとスムーズだった。
通信用のスレッド(抜粋)↓ ※メインのスレッド(main())が回ってないとおかしいことになる。main()は適当に無限ループにしておく
class tcpthread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
host = '○○○.○○○.○○○.○○○' ←IPアドレス
port =(ポート番号)
tcpcom=0 ←ポート処理用のフラグ(後述)
↓ソケットのインスタンスを作成
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while tcpcom==0: ←ポートが詰まってたら別のポートを探す処理(何度もテストしてるとたまにポートが詰まる。時間経過でまた開くが面倒なので別のポートをスキャンする)
try:
s.bind((host,port))
tcpcom=1 ←ポートがあったらフラグを立ててループ脱出
print "connection port:",port ←つながったポートを表示。android側はこれを入力 except:
port =port +1 ←詰まってたら次のポートへ
s.listen(1) ←受け付けるクライアントは1つのみ
↓通信ループ
while True:
print "waiting"
conn,addr=s.accept() ←クライアントからの接続待ちつながるまでここで止まる
print "accept port :",conn,"addr :",addr ←つながったIPを表示
data=conn.recv(120) ←クライアントからデータ受け取る()内は受け取るバイト数
conn.send("send python\n") ←クライアントにデータ送信
//s.close() ←ソケットのクローズ。通信ループの外にあることに注目。今のところソケットは開けっ放しである。
if __name__ == '__main__':
tcp= tcpthread()
tcp.setDaemon(True) ←スレッドを綺麗に終わらせる呪文。
tcp.start()
time.sleep(1)
main()
■次にandroid。初心者だったので辛かったが以下の参考資料などを参考にどうにか実装
http://yamato-iphone.blogspot.jp/2012/06/blog-post_5123.html
まずマルチスレッドのやり方。AsyncTaskというクラスを使うのが正道っぽいがなんだか面倒くさそうだったのでもっと楽なやり方(ハンドラを使った普通のマルチスレッド)で実装
public class MainActivity extends Activity {
↓(実質的な)グローバル変数
private Handler mHandler; ←ハンドラを作っておく
serverflag =0; ←サーバーがあるかどうかのフラグ。後述
↑ここまでグローバル変数
protected void onCreate(Bundle savedInstanceState) {
~略~
mHandler =new Handler(); ←ハンドラのインスタンス作成
/////マルチスレッド、ハンドラを使っているからGUI書き換えもできる。onCreateの中に書いてしまっている
(new Thread(new Runnable() {
@Override
public void run() {
while(true){
mHandler.post(new Runnable(){
@Override
public void run(){
↑ここまでほぼ呪文。普通のマルチスレッドの中でハンドラを経由した処理を実行している(と思う)。GUIの更新が絡む処理がこのrun()のなかでやること。でないと例外が出る仕様
socketcom("test") ←後述するソケット通信関数
textview1.setText(Integer.toString(”文字”));
System.out.println("マルチスレッド 通過");
}
});
try { ←マルチスレッドのtry
Thread.sleep(30); ←ウエイトを設定。別にここじゃなくてもいい。通信が絡む場合はウエイトが必要
↓以下も呪文
} catch (InterruptedException e) {}
}
}
})).start();
///////ここまでマルチスレッド
○ここからソケット通信の話↓ というか自分用テンプレート関数
public void socketcom(String str){ ←引数は別になんでもいい。無くてもいい
if (serverflag != 1){ ←サーバ無かったら以下の処理素通り
try {
//タイムアウトを設定。この辺は重要。タイムアウトを手動設定しないと通信途絶と同時にアプリも止まる。socket =new Socket(IP,PORT) で一発接続しないのがコツ
InetSocketAddress addr = new InetSocketAddress(ipaddr, port); ←とりあえずアドレスだけ専用のインスタンスにまとめておく。あと当然だがアドレスとポートはサーバのものを設定する
socket =new Socket(); ←カラのソケットを作る
socket.connect(addr,500); ←ソケットを接続。引数の数字はタイムアウト時間(ms)。時間はお好みで
↓ 入力と出力のストリームを作っておく。ほぼ呪文。生の通信データ(byte)を使いやすい形に変換しているためなんか複雑になっている模様
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
BufferedReader inp = new BufferedReader(new inputStreamReader(socket.getInputStream()));
↑入出力定義
out.writeBytes(str); ←ソケットへの出力。pythonに届く
String responseLine=""; 入力を入れる変数。↓のifの中で作ってもいいかも
if ((responseLine = inp.readLine()) != null) { ←「何かサーバから来てたら(呪文)」
//System.out.println("Server: " + responseLine+cnt);
textview.setText("Server: " + responseLine); 来たデータを任意に処理
}else{
System.out.println("null in");
}
out.close();
inp.close();
socket.close(); ←クライアント側はサーバと違って開けっ放しにしない。一通信ごとに閉じる。開けっ放しにしようとして半日つぶした(個人的には開けっ放しにしたいが・・・)。
} catch (UnknownHostException e) { ↓勝手に生成される例外処理IOのほうは重要
e.printStackTrace();
System.out.println("UnknownHost err"+e);
textview.setText("Server:none (unknownhost)" );
return;
} catch (IOException e) {
e.printStackTrace();
System.out.println("io err"+e);
tv.setText("Server:none (IO) " );
serverflag=1; ←「サーバー無し」のフラグを立てる。後から別のボタンとかでこれを0にすると再接続できる(実装してないから予想)
return;
}
}else{
tv.setText("サーバーが見つかりませんでした " ); ←サーバ無かったときの処理。適当に。
}
androidのソケット通信ここまで
おまけメモ : ~とりあえずボタン~ ちょっとボタンがいるときに
public class MainActivity extends Activity { Button bt;
protected void onCreate(Bundle savedInstanceState) {
bt = new Button(this);
bt.setText("button");
(レイアウト).addView(bt);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
(ボタンが押されたときの処理)
}
});
~androidでwebカメラの映像を見る~ ここも死ぬほど詰まった。どうにもならず結局外部ライブラリ(MjpegView Class)を使うことに(GNU GPL v3 注意)。
使い方抜粋(大きさ固定の仕方)
mjv=new MjpegView(this) {//表示の大きさを固定にする
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension( 320 , 240 );
}
};
mjv.setSource(MjpegInputStream.read("http://(IPアドレス):(ポート)/?action=stream.mjpeg"));
以上。これでとりあえずandroidからpythonにデータを送れる(wifiでも)、しかもraspberry piにつないだwebカメラの映像もandroidで見れる(raspi側で mjpeg streamer などが必要)。
参考資料
http://linux.yebisu.jp/memo/800
これであとはpython-arduinoのプロトコルを作ればめでたくAndroidでコントロールできるカメラつきラジコンが出来上がる・・・予定。テストプロトコルでモーター動かすだけで満足してしまっている自分が怖い
2013年5月6日月曜日
2013年4月29日月曜日
GWの工作(1) androidとarduino(ややこしい)を無線でシリアル通信
~GWは東京観光でもしようかと思っていたが気がついたらまた電子工作に入れ込んでいたでござる の巻~
最近流行りのタブレットでArduino Microをとりあえず動かしてみました。今回はそのあたりのメモ
~材料~
nexus7 : android 3.0以上くらいなら大体okだと思う
USB ホストケーブル: 片方はスマホに挿すやつ(usb-miniB)、もう片方が普通のUSB(メス)になってるやつ
arduino micro : 別にunoでもなんでもok シリアル通信するだけなので
xbee 2個 : ZBの普通のやつ(あとUSBドングルとブレッドボード変換基板)。使い方は過去記事参照のこと
~使ったソフト~
Arduino1.0.4 :これじゃないとボードにmicroが入ってない?
神が作ってくださったandroid usbシリアル通信ライブラリ「FTDriver」と「Android USB Serial Monitor Lite(google playで入手可)
参考 : http://ksksue.com/wiki/doku.php?id=wiki:android:hardware:usb:ftdriver
~参考資料~
「xbeeで作るワイヤレスセンサーネットワーク」:オライリーの本。一家に一冊は欲しいね。
nexus7のUSBドライバーのインストールについて。
・今回の内容ではいらんけど、これがないとPCで書いたeclipseがnexus7認識しないので注意。あと「タブレット情報」ボタンを7回連打するのも忘れずに。他にも入れ方は色々あるようだがとりあえず公式からのインストールのやり方。
http://blogs.yahoo.co.jp/momo_poem/67257950.html
やり方
0、Xbeeの設定をする(親機をUSBドングル、子機をarduino)やり方は参考資料とか過去記事を
1、nexsus7でAndroid USB Serial Monitor Liteを入手
2、nexsus7にUSBホストケーブルとxbeeドングル(親機)を接続・・・できるようにしておく
3、 arduinoとXbeeの配線
※注意:arduinoのTX出力が5VなのでXbeeのRXとの間で3.3Vに降圧すべき。でないとxbeeぶっ壊れる こんな便利なものがあるみたいです→http://www.switch-science.com/products/detail.php?product_id=1216
・arduino の3.3VとxbeeのVin
・arduinoのTXとxbeeのRX
・arduinoのRXとxbeeのTX
・arduinoのPIN2とGNDにLED(抵抗入り)
・・・筆者のXbee(子機)はもうだめかもわからんね
4、arduinoのプログラムを書く。シリアルで’a’を受信したらLED ON’b’を受信したらOFFするプログラムを書いただけ。
要点:
Arduino microでシリアル通信するときはSerial1クラスを使うこと(3時間くらい詰まった) 例:Serial1.begin(9600)
なんか普通のSerialのほうはPCとの接続に使ってるみたい。Arduino Leonardも同様
5、nexus7にホストケーブルを挿してAndroid USB Serial Monitor Liteを起動
6、プログラムアップロード。この時点でもnexus7からLチカできるがarduinoとPCがつながっててちょっとアレだったので線を引っこ抜いて外部電源に切り替え
7、nexus7から「a」を送ったり「b」を送ったりして遊ぶ。なんとなく感度が良くない気がする。
結果↓
arduinoのコード(抜粋) : ほぼarduino IDE に入っているサンプルのまんま、serial部分を足しただけ。
int led = 2;
void setup() {
pinMode(led, OUTPUT);
Serial1.begin(9600);
}
void loop() {
if(Serial1.available()>0){
char data1=Serial1.read();
if(data1=='a'){
digitalWrite(led, HIGH);
Serial1.print("a received led on\n"); // turn the LED on (HIGH is the voltage level)
delay(1000);
}
else if(data1=='b'){
digitalWrite(led, LOW);
Serial1.print("b received led off\n");
delay(1000);
}else
{
Serial1.read();
}
}
Serial1.println("serial from arduino");
delay(2000);
}
今後の展開(2日後予定) : android側で出来合いのソフトじゃなくてFTDriverライブラリを使ってラジコンとか操縦できるといいね(android傾けたりして)
おわり
最近流行りのタブレットでArduino Microをとりあえず動かしてみました。今回はそのあたりのメモ
~材料~
nexus7 : android 3.0以上くらいなら大体okだと思う
USB ホストケーブル: 片方はスマホに挿すやつ(usb-miniB)、もう片方が普通のUSB(メス)になってるやつ
arduino micro : 別にunoでもなんでもok シリアル通信するだけなので
xbee 2個 : ZBの普通のやつ(あとUSBドングルとブレッドボード変換基板)。使い方は過去記事参照のこと
~使ったソフト~
Arduino1.0.4 :これじゃないとボードにmicroが入ってない?
神が作ってくださったandroid usbシリアル通信ライブラリ「FTDriver」と「Android USB Serial Monitor Lite(google playで入手可)
参考 : http://ksksue.com/wiki/doku.php?id=wiki:android:hardware:usb:ftdriver
~参考資料~
「xbeeで作るワイヤレスセンサーネットワーク」:オライリーの本。一家に一冊は欲しいね。
nexus7のUSBドライバーのインストールについて。
・今回の内容ではいらんけど、これがないとPCで書いたeclipseがnexus7認識しないので注意。あと「タブレット情報」ボタンを7回連打するのも忘れずに。他にも入れ方は色々あるようだがとりあえず公式からのインストールのやり方。
http://blogs.yahoo.co.jp/momo_poem/67257950.html
やり方
0、Xbeeの設定をする(親機をUSBドングル、子機をarduino)やり方は参考資料とか過去記事を
1、nexsus7でAndroid USB Serial Monitor Liteを入手
2、nexsus7にUSBホストケーブルとxbeeドングル(親機)を接続・・・できるようにしておく
3、 arduinoとXbeeの配線
※注意:arduinoのTX出力が5VなのでXbeeのRXとの間で3.3Vに降圧すべき。でないとxbeeぶっ壊れる こんな便利なものがあるみたいです→http://www.switch-science.com/products/detail.php?product_id=1216
・arduino の3.3VとxbeeのVin
・arduinoのTXとxbeeのRX
・arduinoのRXとxbeeのTX
・arduinoのPIN2とGNDにLED(抵抗入り)
・・・筆者のXbee(子機)はもうだめかもわからんね
4、arduinoのプログラムを書く。シリアルで’a’を受信したらLED ON’b’を受信したらOFFするプログラムを書いただけ。
要点:
Arduino microでシリアル通信するときはSerial1クラスを使うこと(3時間くらい詰まった) 例:Serial1.begin(9600)
なんか普通のSerialのほうはPCとの接続に使ってるみたい。Arduino Leonardも同様
5、nexus7にホストケーブルを挿してAndroid USB Serial Monitor Liteを起動
6、プログラムアップロード。この時点でもnexus7からLチカできるがarduinoとPCがつながっててちょっとアレだったので線を引っこ抜いて外部電源に切り替え
7、nexus7から「a」を送ったり「b」を送ったりして遊ぶ。なんとなく感度が良くない気がする。
結果↓
arduinoのコード(抜粋) : ほぼarduino IDE に入っているサンプルのまんま、serial部分を足しただけ。
int led = 2;
void setup() {
pinMode(led, OUTPUT);
Serial1.begin(9600);
}
void loop() {
if(Serial1.available()>0){
char data1=Serial1.read();
if(data1=='a'){
digitalWrite(led, HIGH);
Serial1.print("a received led on\n"); // turn the LED on (HIGH is the voltage level)
delay(1000);
}
else if(data1=='b'){
digitalWrite(led, LOW);
Serial1.print("b received led off\n");
delay(1000);
}else
{
Serial1.read();
}
}
Serial1.println("serial from arduino");
delay(2000);
}
今後の展開(2日後予定) : android側で出来合いのソフトじゃなくてFTDriverライブラリを使ってラジコンとか操縦できるといいね(android傾けたりして)
おわり
2013年3月30日土曜日
さしあたってwindowsでc++でgui(wxwidets)を作るために必要な情報まとめ(作成中)
参考リンク1(mingwへのwxwidetsのコンパイル、インストールの仕方)
ここを参考にしないと今のところwxwidetsがコンパイルできずに詰む
http://mynote.mydns.jp/blog/wordpress/?tag=wxwidgets
2012年12月9日日曜日
ソケット通信によるpythonとC++の連携
pythonでインターフェース作ったり、Arduinoのコントロールしながら、
C++での画像処理結果(前に何があるか、とか)をpythonに送りたくなったのでソケット通信でやって見ました。
pythonだとopencvで特徴量記述とかが出来ないし(そもそも遅いし)、C++でインターフェースとかシリアル通信なんかやってられないので、双方の弱点をカバーする方法としてプロセス間通信が最も横着な方法であると判断。
参考文献:
1、Pythonメモ 様の記事 ttp://yoshi-python.blogspot.jp/2009/10/blog-post_19.html
2、Geekなぺーじ 様の記事 ttp://www.geekpage.jp/programming/linux-network/tcp-1.php
3、信州大学HP 様 ttp://intuniv.cs.shinshu-u.ac.jp/Lecture/NetProg/chapter3/struct.html
4、pythonのリファレンス
■ 今回はpythonをサーバとしてC++側と双方向通信させました。 ちなみにサーバとクライアントの違いについてはよくわかってません。接続を待つ方がサーバぐらいの認識でいいのだろうか。
以下、参考文献のページのコードをほぼ引用した自分用のメモ
python側:
import socket
def server(host, port):
s = socket.socket() ←ソケットのインスタンスを作る
s.bind((host, port)) ←バインド(IPとポートを設定する)
s.listen(1) ←接続待ちに必要。引数は接続できるノードの数。
print "waiting"
conn, addr = s.accept() # ←クライアントの接続を待つ。connはつながってきたソケット
addrはノードのアドレス(使い所は不明)
while True: ←ずっとループ
data = conn.recv(1024) # クライアントからのデータを受信する(ここでは1024byte)
↑ここでのdataの形式がよくわからないが多分char(C++側ではconst charで送ってる)
print "server: receive '%s'" % data
datalist=str(data) ←とりあえずデータをstring化
datasp=datalist.split(",") ←データをカンマで区切る。数字をカンマ区切りで送ることを考えている。
print datasp
object.set_value(float(datasp[0]))
↑任意の変数に受信データの値を入力。これでArduinoでもなんでも動かせる(pythonと繋がってれば)
conn.send("sendfrompython") # クライアントにデータを送信する。ここでpythonからの命令(右に曲がるから右に注目しろ、とか)をC++に送ることが出来る。
conn.close() ←クライアントのソケットを閉じる。
s.close() ←こっちのソケットを閉じる。
閉じてもすぐに切断されるわけではないらしい。連続で同じポート使ったりできないことがあるので時間開けるかポート番号変えるのが吉。いまのところpython-C++ではこの事象は起こってないがpythonのプログラム間(同ソース別スレッド)でこの事象を確認。
class Server(threading.Thread):######### C++との通信スレッド
def run(self):
server(HOST, PORT) ←上記関数。HOST(127.0.0.1とか)とPORT(12345とか)はグローバル変数か何かにしとく
C++側:参考資料2からほぼ引用、難しそうな構造体については参考文献3を参照
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
↑必要なヘッダの皆さん。特に意識せずに使えたので最初から入ってると思われる。
void* thread(void* pParam) //pythonへの情報送信用スレッド
{
////ソケット通信による通信
int sockmode=1; ////1ならソケット通信ON ←通信をONOFFできて便利
if(sockmode==1){
struct sockaddr_in server; ←アドレスなんかを入れておく構造体インスタンスを定義
int sock; ←ソケットをとりあえず定義
char buf[64]; ←バッファを定義[]内はバイト数。多すぎず少なすぎずで。(少ないと即死)
int n; ←データ読み込み用
/* ソケットの作成 */
sock = socket(AF_INET, SOCK_STREAM, 0);
↑AF_INETはIPv4であること、SOCK_STREAMはTCPであることを表している。多分どの言語でも共通の定数。ここらを変えるとIPv6にしたりUDPにもできる。サーバと共通じゃないとだめ。
/* 接続先指定用構造体の準備 */↓python側の設定を書く。つまり宛先の設定
server.sin_family = AF_INET;
server.sin_port = htons(12347); ←ポート番号。htons()はバイトオーダを変換する関数
(詳細不明。接続のための何らかの規格化だろう)
server.sin_addr.s_addr = inet_addr("127.0.0.1");←このIPは自分自身(PC)を示す。変えると別の機器(PC他)にももちろんつながる。はず。関数は文字列をちゃんとアドレスの形式にする関数
/* サーバに接続 */↓詳細は「C++ connect socket」でぐぐってね
connect(sock, (struct sockaddr *)&server, sizeof(server));
while(1){ /* サーバからデータを受信。 送信も */
memset(buf, 0, sizeof(buf)); ←バッファのリセット
stringstream sts; ←とっても便利なstringstream(以下ss)オブジェクトを定義
string str="0,0,end"; ←送信文字列の初期化。文字は適当に
最後の「,end」はとても大事。python側でsplitするときとか特に
↓ 別のところで「進んでOK」とか「止まれ」とかのフラグ出すようにしてる。それに応じて送信値変更。明らかに改善の余地あり。
if(forwardflag ==1){str="100,100,end";}
if(stopflag==1){str="0,0,end";}
cout << "send:" <<str <<endl;
char sdata[64]; ←送信用バッファの定義
sts << str; ←事前に作った文字列をssへ
sts >> sdata; ←ssから送信用charへ自動変換&代入。このツールまじ便利
const char* sdataconst= sdata; ←charをconst charへ送信関数の引数がconst〜なので(このへんの変換でちょっと詰まった。)
write(sock, sdataconst, strlen(sdataconst));←データをあっちに送信。第3引数は送信データの文字数にする。strlenは全角文字入ると正確じゃなくなるので注意
cout<<"senddata"<<sdataconst <<endl;
int n = read(sock, buf, sizeof(buf)); ←pythonからbufへ読み込み。nは読み込めたかどうかとかを確認するための数字(読み込め無かったら-1とか)。読み込みデータじゃないので注意
cout <<"resdata" <<buf << endl;
sleep(1);←1秒に1回通信。もっと少なくてもいいけどスリープ入れないと多分ろくなことにならない
sts.clear(); ←ssの中身をクリア
}
/* socketの終了 */
close(sock); ←ソケット閉じる
}
return 0;
以上。
これでとりあえず通信ができることを確認。強制終了前提のコードなのであくまで参考で。
↓左がC++で右がpython(eclipseのコンソール)。なんとか通信している。
C++での画像処理結果(前に何があるか、とか)をpythonに送りたくなったのでソケット通信でやって見ました。
pythonだとopencvで特徴量記述とかが出来ないし(そもそも遅いし)、C++でインターフェースとかシリアル通信なんかやってられないので、双方の弱点をカバーする方法としてプロセス間通信が最も横着な方法であると判断。
参考文献:
1、Pythonメモ 様の記事 ttp://yoshi-python.blogspot.jp/2009/10/blog-post_19.html
2、Geekなぺーじ 様の記事 ttp://www.geekpage.jp/programming/linux-network/tcp-1.php
3、信州大学HP 様 ttp://intuniv.cs.shinshu-u.ac.jp/Lecture/NetProg/chapter3/struct.html
4、pythonのリファレンス
■ 今回はpythonをサーバとしてC++側と双方向通信させました。 ちなみにサーバとクライアントの違いについてはよくわかってません。接続を待つ方がサーバぐらいの認識でいいのだろうか。
以下、参考文献のページのコードをほぼ引用した自分用のメモ
python側:
import socket
def server(host, port):
s = socket.socket() ←ソケットのインスタンスを作る
s.bind((host, port)) ←バインド(IPとポートを設定する)
s.listen(1) ←接続待ちに必要。引数は接続できるノードの数。
print "waiting"
conn, addr = s.accept() # ←クライアントの接続を待つ。connはつながってきたソケット
addrはノードのアドレス(使い所は不明)
while True: ←ずっとループ
data = conn.recv(1024) # クライアントからのデータを受信する(ここでは1024byte)
↑ここでのdataの形式がよくわからないが多分char(C++側ではconst charで送ってる)
print "server: receive '%s'" % data
datalist=str(data) ←とりあえずデータをstring化
datasp=datalist.split(",") ←データをカンマで区切る。数字をカンマ区切りで送ることを考えている。
print datasp
object.set_value(float(datasp[0]))
↑任意の変数に受信データの値を入力。これでArduinoでもなんでも動かせる(pythonと繋がってれば)
conn.send("sendfrompython") # クライアントにデータを送信する。ここでpythonからの命令(右に曲がるから右に注目しろ、とか)をC++に送ることが出来る。
conn.close() ←クライアントのソケットを閉じる。
s.close() ←こっちのソケットを閉じる。
閉じてもすぐに切断されるわけではないらしい。連続で同じポート使ったりできないことがあるので時間開けるかポート番号変えるのが吉。いまのところpython-C++ではこの事象は起こってないがpythonのプログラム間(同ソース別スレッド)でこの事象を確認。
class Server(threading.Thread):######### C++との通信スレッド
def run(self):
server(HOST, PORT) ←上記関数。HOST(127.0.0.1とか)とPORT(12345とか)はグローバル変数か何かにしとく
C++側:参考資料2からほぼ引用、難しそうな構造体については参考文献3を参照
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
↑必要なヘッダの皆さん。特に意識せずに使えたので最初から入ってると思われる。
void* thread(void* pParam) //pythonへの情報送信用スレッド
{
////ソケット通信による通信
int sockmode=1; ////1ならソケット通信ON ←通信をONOFFできて便利
if(sockmode==1){
struct sockaddr_in server; ←アドレスなんかを入れておく構造体インスタンスを定義
int sock; ←ソケットをとりあえず定義
char buf[64]; ←バッファを定義[]内はバイト数。多すぎず少なすぎずで。(少ないと即死)
int n; ←データ読み込み用
/* ソケットの作成 */
sock = socket(AF_INET, SOCK_STREAM, 0);
↑AF_INETはIPv4であること、SOCK_STREAMはTCPであることを表している。多分どの言語でも共通の定数。ここらを変えるとIPv6にしたりUDPにもできる。サーバと共通じゃないとだめ。
/* 接続先指定用構造体の準備 */↓python側の設定を書く。つまり宛先の設定
server.sin_family = AF_INET;
server.sin_port = htons(12347); ←ポート番号。htons()はバイトオーダを変換する関数
(詳細不明。接続のための何らかの規格化だろう)
server.sin_addr.s_addr = inet_addr("127.0.0.1");←このIPは自分自身(PC)を示す。変えると別の機器(PC他)にももちろんつながる。はず。関数は文字列をちゃんとアドレスの形式にする関数
/* サーバに接続 */↓詳細は「C++ connect socket」でぐぐってね
connect(sock, (struct sockaddr *)&server, sizeof(server));
while(1){ /* サーバからデータを受信。 送信も */
memset(buf, 0, sizeof(buf)); ←バッファのリセット
stringstream sts; ←とっても便利なstringstream(以下ss)オブジェクトを定義
string str="0,0,end"; ←送信文字列の初期化。文字は適当に
最後の「,end」はとても大事。python側でsplitするときとか特に
↓ 別のところで「進んでOK」とか「止まれ」とかのフラグ出すようにしてる。それに応じて送信値変更。明らかに改善の余地あり。
if(forwardflag ==1){str="100,100,end";}
if(stopflag==1){str="0,0,end";}
cout << "send:" <<str <<endl;
char sdata[64]; ←送信用バッファの定義
sts << str; ←事前に作った文字列をssへ
sts >> sdata; ←ssから送信用charへ自動変換&代入。このツールまじ便利
const char* sdataconst= sdata; ←charをconst charへ送信関数の引数がconst〜なので(このへんの変換でちょっと詰まった。)
write(sock, sdataconst, strlen(sdataconst));←データをあっちに送信。第3引数は送信データの文字数にする。strlenは全角文字入ると正確じゃなくなるので注意
cout<<"senddata"<<sdataconst <<endl;
int n = read(sock, buf, sizeof(buf)); ←pythonからbufへ読み込み。nは読み込めたかどうかとかを確認するための数字(読み込め無かったら-1とか)。読み込みデータじゃないので注意
cout <<"resdata" <<buf << endl;
sleep(1);←1秒に1回通信。もっと少なくてもいいけどスリープ入れないと多分ろくなことにならない
sts.clear(); ←ssの中身をクリア
}
/* socketの終了 */
close(sock); ←ソケット閉じる
}
return 0;
以上。
これでとりあえず通信ができることを確認。強制終了前提のコードなのであくまで参考で。
↓左がC++で右がpython(eclipseのコンソール)。なんとか通信している。
2012年12月1日土曜日
ここのところ覚えた小技のメモ
いろいろアイデアを考えるのはいいけど、結構実装の面で詰まることも多かったので詰まったところをメモ。主にC++の基本的なところとちょっとした小技(?)、忘れると1〜数日潰す可能性あり。
参考資料 : ググって出てきた様々なページ。ヤフー知恵袋、stackoverflow
1.vectorのvectorの作り方とvectorのきほん
vector<vector<double> > ←最後の「>」の手前に半角スペース入れないとだめ(環境に因るかも)
2.vectorの要素の追加
(vector).push_back(入れたい値) でvectorの最後尾に新しい要素を入れる。
カラのvectorの定義だけして vector[n]=値 とかで代入しようとするとエラーになる。
まずvector.push_back=値 またはassign()とかresize()適当なサイズと初期値を設定する。
vectorのvectorならvector.push_back=2層目vector<〜〜> みたいな感じで使う 。
pythonのリストなら適当でなんとかなるのにね。不便だね。
3.opencvのROIの使い方
Rect roirect=Rect(0,0,150,150);// まず四角を定義してROIの設定
Mat imgroi=img;// ←ここでimg(roirect) にすると定義した四角がROIになったimgをimgroiとして定義できる。
ここまではいいがROIのオフセット(ROIの四角の起点になる座標)が(0,0)じゃないときオフセットを考慮する必要がある。 やらないと例えばROIが画面中心らへんだった時検出したキーポイントが画面中心じゃなくて左上とかにずれて表示される。
↓こんな感じ
for(int i=0;i<keypoint.size();i++){
keypoint.pt.x += roirect.x; ←検出したキーポイントの座標をオフセット分だけずらす
keypoint.pt.y += roirect.y; ←キーポイント構造体の座標取り出し方法
(〜.pt.x, 〜.pt.y)も意外に忘れやすいので注意
}
↑キーポイントはROIの中だけで検出されるけどキーポイント座標(pt.x pt.y)もROIのローカル座標でが決定されるのでオフセット分ずらす必要がある(オフセットが(0,0)なら別にずらさなくていい)。
4.文字扱いの数字を数値として取り出す方法
ファイルとかから読み込んだ数値をちゃんとintなりdoubleで読み込む(変換する)コツ。stringstream を使うだけ。これもpythonなら意識する必要すらない部分。C++万歳!(皮肉)
↓以下やり方。
stringstream ss; ←stringstreamのインスタンスをつくる
string str; ←stringと任意の形式(この例ではdouble)を定義
double dbl;
ss << str;// ←stringstreamにstringをぶち込む
ss >>dbl; ←stringstreamからdoubleに取り出す。これで変換完了。
ss.clear(); ←ssの中身をクリア、しないとろくなことにならないよ。ループで使う時とか。
5.opencv:任意の座標の色情報の取り出し方
意外に手こずった部分。Vec3bという型を作って以下の書式で取り出す。
Vec3b color = img.at<Vec3b>(Y座標,X座標); ←.at<Vec3b>はおそらくY座標、X座標の順で定義されている。普通と違うので注意(環境やimgの種類によってちがうかも)。
また、取り出した色情報((B,G,R),0〜256の数字)はデフォルトだと多分charで入ってるので
intへのキャストが必要↓
(int)ccolor[0]+100 ; ←例えば取り出した色の青色成分に100足すとき
今日のところはとりあえず終了。
参考資料 : ググって出てきた様々なページ。ヤフー知恵袋、stackoverflow
1.vectorのvectorの作り方とvectorのきほん
vector<vector<double> > ←最後の「>」の手前に半角スペース入れないとだめ(環境に因るかも)
2.vectorの要素の追加
(vector).push_back(入れたい値) でvectorの最後尾に新しい要素を入れる。
カラのvectorの定義だけして vector[n]=値 とかで代入しようとするとエラーになる。
まずvector.push_back=値 またはassign()とかresize()適当なサイズと初期値を設定する。
vectorのvectorならvector.push_back=2層目vector<〜〜> みたいな感じで使う 。
pythonのリストなら適当でなんとかなるのにね。不便だね。
3.opencvのROIの使い方
Rect roirect=Rect(0,0,150,150);// まず四角を定義してROIの設定
Mat imgroi=img;// ←ここでimg(roirect) にすると定義した四角がROIになったimgをimgroiとして定義できる。
ここまではいいがROIのオフセット(ROIの四角の起点になる座標)が(0,0)じゃないときオフセットを考慮する必要がある。 やらないと例えばROIが画面中心らへんだった時検出したキーポイントが画面中心じゃなくて左上とかにずれて表示される。
↓こんな感じ
for(int i=0;i<keypoint.size();i++){
keypoint.pt.x += roirect.x; ←検出したキーポイントの座標をオフセット分だけずらす
keypoint.pt.y += roirect.y; ←キーポイント構造体の座標取り出し方法
(〜.pt.x, 〜.pt.y)も意外に忘れやすいので注意
}
↑キーポイントはROIの中だけで検出されるけどキーポイント座標(pt.x pt.y)もROIのローカル座標でが決定されるのでオフセット分ずらす必要がある(オフセットが(0,0)なら別にずらさなくていい)。
4.文字扱いの数字を数値として取り出す方法
ファイルとかから読み込んだ数値をちゃんとintなりdoubleで読み込む(変換する)コツ。stringstream を使うだけ。これもpythonなら意識する必要すらない部分。C++万歳!(皮肉)
↓以下やり方。
stringstream ss; ←stringstreamのインスタンスをつくる
string str; ←stringと任意の形式(この例ではdouble)を定義
double dbl;
ss << str;// ←stringstreamにstringをぶち込む
ss >>dbl; ←stringstreamからdoubleに取り出す。これで変換完了。
ss.clear(); ←ssの中身をクリア、しないとろくなことにならないよ。ループで使う時とか。
5.opencv:任意の座標の色情報の取り出し方
意外に手こずった部分。Vec3bという型を作って以下の書式で取り出す。
Vec3b color = img.at<Vec3b>(Y座標,X座標); ←.at<Vec3b>はおそらくY座標、X座標の順で定義されている。普通と違うので注意(環境やimgの種類によってちがうかも)。
また、取り出した色情報((B,G,R),0〜256の数字)はデフォルトだと多分charで入ってるので
intへのキャストが必要↓
(int)ccolor[0]+100 ; ←例えば取り出した色の青色成分に100足すとき
今日のところはとりあえず終了。
2012年11月18日日曜日
しょぼいけど特定物体認識できたよ〜(´∀`)〜
苦節数カ月、やっとここまで来たよ・・・(つд`)
考えうるもっともしょぼい方法だけど、FAST(キーポイント検出)、FREAK(特徴量記述)を使った特定物体認識(というほどのものでもないかもしれないが)に成功したのでメモ。
・・・と思ったけど、今日はとても疲れたので実行結果だけ↓
特徴量を記述、指標化して(参考資料:FREAKの論文)総当り比較(画像が増えてくると間違いなく遅くなる)で、ひげ剃りとかカロリーメイトとか本棚(上段、下段)をまあだいたい識別できるようになった。ちなみに左上の数字はFPS。その横が似ている画像ファイル名。
↓比較用ひげ剃り画像、こんな感じで写真をフォルダに入れまくることで、どれに一番近いかを判別してくれる。
まだ課題も多いけど、これをラジコンと接続して目的の物まで向かわせるとかは頑張れば出来そう。
〜おわり〜
考えうるもっともしょぼい方法だけど、FAST(キーポイント検出)、FREAK(特徴量記述)を使った特定物体認識(というほどのものでもないかもしれないが)に成功したのでメモ。
・・・と思ったけど、今日はとても疲れたので実行結果だけ↓
特徴量を記述、指標化して(参考資料:FREAKの論文)総当り比較(画像が増えてくると間違いなく遅くなる)で、ひげ剃りとかカロリーメイトとか本棚(上段、下段)をまあだいたい識別できるようになった。ちなみに左上の数字はFPS。その横が似ている画像ファイル名。
↓比較用ひげ剃り画像、こんな感じで写真をフォルダに入れまくることで、どれに一番近いかを判別してくれる。
まだ課題も多いけど、これをラジコンと接続して目的の物まで向かわせるとかは頑張れば出来そう。
〜おわり〜
2012年11月17日土曜日
opencvでAi-Ball(小型WiFiカメラ)を使う
わかってしまえば簡単だが、わからないと一生わからない気がするのでメモ
※重要※
今回のコードによって発生した問題につきましては一切の責任を負いかねますのでご注意の上ご利用ください(トリセツとかに載っていない使い方の為)。
今回(3週間くらい前だが)は、Ai-Ball(公式サイト?)をopwncvで普通に使う方法をメモっておきます。
主な参考資料
・Ai-Ballの取説
・海外の質問掲示板(ここの情報がメインだが、場所を失念)
・九州工業大学 宮本研究室HP様(ttp://www.brain.kyutech.ac.jp/~miyamo/index.php/)
要約
c++:
VideoCapture cap("http://(Ai-BallのIPアドレス)/?action=stream.mjpeg");
python:
capture=cv.CaptureFromFile("http://(Ai-BallのIPアドレス)/?action=stream.mjpeg")
↑ちなみに普通のwebカメラだと
capture = cv.CaptureFromCAM(0) pythonでは微妙に使う関数が違うので注意
それぞれのカメラ動画使うサンプル見ればわかると思いますけど、変化点は↑だけです。
なかなか分からなかったのがアドレスの最後の「.mjpeg」の部分(どこかの海外掲示板の丸パクリ、もうどうやって検索したのか思い出せない)。
こうすることでリアルタイム(うちのPCでは18fpsくらいしか出ないが)で普通のウェブカメラとして使えます。
ちなみに宮本研究室さんの公開されているプログラムは動画(mjpeg)としてではなくスナップショット(jpg)として画像を取り込んでいるためfpsが落ちます(環境により異なると思いますが筆者環境では4fpsくらい)
今現在(2012年11月)、使いやすそうな小型無線カメラもあんまりないし、もしかしたらこの情報が役に立つ人がいるといいな・・・と思いつつ終了。
※重要※
今回のコードによって発生した問題につきましては一切の責任を負いかねますのでご注意の上ご利用ください(トリセツとかに載っていない使い方の為)。
今回(3週間くらい前だが)は、Ai-Ball(公式サイト?)をopwncvで普通に使う方法をメモっておきます。
主な参考資料
・Ai-Ballの取説
・海外の質問掲示板(ここの情報がメインだが、場所を失念)
・九州工業大学 宮本研究室HP様(ttp://www.brain.kyutech.ac.jp/~miyamo/index.php/)
要約
c++:
VideoCapture cap("http://(Ai-BallのIPアドレス)/?action=stream.mjpeg");
python:
capture=cv.CaptureFromFile("http://(Ai-BallのIPアドレス)/?action=stream.mjpeg")
↑ちなみに普通のwebカメラだと
capture = cv.CaptureFromCAM(0) pythonでは微妙に使う関数が違うので注意
それぞれのカメラ動画使うサンプル見ればわかると思いますけど、変化点は↑だけです。
なかなか分からなかったのがアドレスの最後の「.mjpeg」の部分(どこかの海外掲示板の丸パクリ、もうどうやって検索したのか思い出せない)。
こうすることでリアルタイム(うちのPCでは18fpsくらいしか出ないが)で普通のウェブカメラとして使えます。
ちなみに宮本研究室さんの公開されているプログラムは動画(mjpeg)としてではなくスナップショット(jpg)として画像を取り込んでいるためfpsが落ちます(環境により異なると思いますが筆者環境では4fpsくらい)
今現在(2012年11月)、使いやすそうな小型無線カメラもあんまりないし、もしかしたらこの情報が役に立つ人がいるといいな・・・と思いつつ終了。
登録:
投稿 (Atom)




