読者です 読者をやめる 読者になる 読者になる

Take’s diary

Macとマイコンに関すること--ワクワクの製作日記

Edison と スイッチサイエンス版 Eaglet でiPhoneをWifiで連携させる(MEMS非接触温度センサー応用編その4:ソース公開)

その3では、OpenframeworksのiPhone実機テストと、Wifi連携の概要までを説明しました。takesan.hatenablog.com今回はiPhoneとEdison双方のプログラムソースを紹介します。
プログラムが動作するまで、ライブラリのインストールなども必要なので、必要部分に記載します。また、OMURON D6Tが動く環境であれば、スイッチサイエンス版Eagletでなくとも同じソフトで動作可能です。まず、復習の意味でどんなことをするのか、動画確認から。
        
 この動画ではEdisonに接続されたμOled3028でiPhoneの設定を変更していますが、この表示機器についての制御方法は、今回含まれません(次回以降)。赤外線非接触センサーの解像度が、今の4X4から16X16くらいになったら、まさにサーモグラフィーですね!!。(OMRONでは16X16のSPIセンサーが企業向けに販売されてるようですが、ボクに売ってくれないかな)www.omron.co.jp

f:id:TAKEsan:20150822151956j:plain:w300:left








4X4(センサー本来の能力)で温度表示。最高最低温度が表示されている。Edisonとの通信状態はランプイラストの点滅。
f:id:TAKEsan:20150822151926j:plain:w300:left
















スライダーで61X61に補間。ドットの大きさを変えられるので、カメラ画像を確認できる。同じセンサーとは思えないのでは?(写真はセンサーとカメラ位置がちょっとずれ気味。カメラとセンサーの画角がたまたまほとんど同じなので、合わせるのはとても簡単ですが)

動作内容

 ポート番号を設定して、bonjourで相手のipアドレスを手に入れ、そのアドレスを使ってOSCプロトコルを使ってEdisonからOMURON D6TのデータをWifi送信します。
 iPhoneのopenframeworks環境ととEdisonのPython環境には、それぞれbonjourとOSC通信ライブラリが必要になります。今回iPhone側はiOSGUIを使っていますので、そのあたりも簡単に説明します。今回のソースを利用すれば、Edisonに接続したセンサー値を利用してiPhoneでカッコよく処理するなんてことが簡単に実現できますぞ!!。
 OSC通信は、同一LAN内でしか送受信できませんが、iPhoneのデザリングでなんとかなりそうな気がします。そうすればBLEなんかわざわざ勉強しなくてもいいかも。(今後の楽しみに取っときますーー>10/27下記の記事を書きました)takesan.hatenablog.com

iOSのOpenframeworksによるプログラムソース構築

まず、自分のMacにOpenframeworksをインストールしてください。ダウンロードして解凍したフォルダの中の addonsフォルダの中に以下のaddonを追加します
robotconscience/ofxBonjour · GitHub前にも書きましたがダウンロードして解凍したフォルダ名をofxBonjourに変更します。このaddonは古いので最新の方が良いかもしれませんが、動いたのでここでは最新版を使いません。ofxOSCは、標準addonなのでインストールの必要はありません。
 さらにダウンロードして解凍したOpenframeworksフォルダの中「projectGenerator_ios/projectGenerator.app 」をダブルクリック。f:id:TAKEsan:20150821155649p:plainプロジェクト名を付け、addonにofxOSCとofxBonjourを選択したら、GENERTE PROJECTボタンを押します。
 今作ったプロジェクトは、/apps/myApps に入っていますので、その中のプロジェクトファイルをダブルクリックします。Xcodeが立ち上がったら、前回説明したように、iOS Deployment Targetを最新版にします。これで一応プログラムを入力する準備ができました。
 ビルド時の注意なのですが、今回紹介する ofxOSC で ‘ip/UdpSocket.h’ file not found が出る時は、Build SettingsのUser Header Serch Pathsに次のパスを入れると「 ../../../addons/ofxOsc/libs/oscpack/src 」正常にビルドできるようになります。
 Xcodeに慣れていないと、予想外のところを触ってしまって、エラーが続出してしまうことがあります。そんな時は迷わずOpenframeworks自体を新しいものに変えてしまいます。(時間の無駄なので、初心者に超オススメ。)
 それでは、ソースです。GUIフォルダの作り方は、ofApp.mmのコメント中に入れておきました。このフォルダを作った後、内容を変更してください。今回は自分のためにもコレデモか!!と言えるくらいコメントを入れておきましたので、内容を確認してみてください。対象のiPhone は6plus です。
ファイル構成は下図参照
f:id:TAKEsan:20150821164532p:plain

ofApp.h

#pragma once
#include "ofMain.h"
#include "ofxiOS.h"
#include "ofxiOSExtras.h"
#include "ofxBonjourIp.h"
#include "ofxOsc.h"
// listen on port 7777
#define PORT 7777
#define NUM_MSG_STRINGS 20

class ofApp : public ofxiOSApp {
        public:
        void setup();
        void update();
        void draw();
        void exit();
        void touchDown(ofTouchEventArgs & touch);
        void touchMoved(ofTouchEventArgs & touch);
        void touchUp(ofTouchEventArgs & touch);
        void touchDoubleTap(ofTouchEventArgs & touch);
        void touchCancelled(ofTouchEventArgs & touch);
        void lostFocus();
        void gotFocus();
        void gotMemoryWarning();
        void deviceOrientationChanged(int newOrientation);
        // OSC イベント追加
        void onPublishedService(const void* sender, string &serviceIp);
        void onDiscoveredService(const void* sender, string &serviceIp);
        void onRemovedService(const void* sender, string &serviceIp);  
    // remember to add the CFNetwork framework for ios
    ofxBonjourIp* bonjour;
    
    // iOSGUI
    int botton_new,botton_old,sli,div1,temp_sw;    
    ofxOscReceiver receiver;
    
    int current_msg_string;
    string msg_strings[NUM_MSG_STRINGS];
    float timers[NUM_MSG_STRINGS],scale_cam;    
    float tdata[16],ttdata[3800];  
    //font
    ofTrueTypeFont  verdana14,verdana30,cooperBlack60;
    //OSC data
    int cam_no,camdata;
    string ondoState;
    //iPHONE CAMERA
    ofVideoGrabber cam;
    ofImage	 lamp_on,lamp_off;
};

main.mm

#include "ofMain.h"
#include "ofApp.h"
                      //以下 WEB上では色々な設定があるが、その中で一番安定しているiPhone6+のRetina詳細画面の設定
int main(){
    ofAppiOSWindow * window = new ofAppiOSWindow();
    window->enableAntiAliasing(2);
    window->enableRetina();
    window->enableRendererES2();
    ofSetupOpenGL(1704,960, OF_FULLSCREEN);         //<--この値を変えても1704,960のまま!!はっきり言えば数値はなんでも良い
    
    ofRunApp(new ofApp);
}

ofApp.mm

#include "ofApp.h"
#include "MyGuiView.h"
MyGuiView *gui;
//kyokusenn
int a1,b1,c1,d1,aaa;
float a,b,c,d;
//--------------------------------------------------------------
float sp(int x){      //ラグランジュ変換用関数
  
    return (x-aaa)*(x-aaa*2)*(x-aaa*3)*a+x*(x-aaa*2)*(x-aaa*3)*b+x*(x-aaa)*(x-aaa*3)*c+x*(x-aaa)*(x-aaa*2)*d;
}

void ofApp::setup(){
    
    // iOS GUI 設定
    // 田所先生のWEB上のやり方だとXcode自体が少し昔のものなのでうまくいかなかった。他の方も
    // http://www.creativeapplications.net/tutorials/integrating-native-uikit-to-your-existing-openframeworks-ios-project/
    // でさらに詳しく説明されているが、これでも上手くいかない。また、OFに添付されたいるiOSのサンプル(iPhoneGuiExample)は動くが設定の経緯が分からない。
    // 結局  GUI フォルダを 作って 3つのファイルを自動で作成させ 自動で作成される xxxx.m の拡張子を .mm に変えるまでは田所先生の説明、
    //  すなわちnewfile->iOS->Source->Cocoa touch Class->Next->Class名変更、サブクラスはそのまま、Also creat XLB fileにチェック
    // 次に各ファイルの内容とボタン作成の操作を上記ブログを参考にして変更するとうまくいった。慣れればすごく簡単。以下2行ofApp.mm内での設定
    gui = [[MyGuiView alloc] initWithNibName:@"MyGuiView" bundle:nil];
        [ofxiOSGetGLParentView() addSubview:gui.view];
    
    ofSetFrameRate(20); //EDISON側のデータ送信が遅すぎ、60にするとデータが途切れてしまうので20程度まで下げる。
    ofBackground(0);
    
    //EDISONからデータが来ているときの表示画像取り込み データはこのプロジェクトの bin/data 以下に入れておく
    //iPhonではどこに入ってるかなんて考える必要なし。このフォルダに入れればiphoneで再現できる(どこかに入っている)。
    lamp_on.allocate(78, 140, OF_IMAGE_COLOR);
    lamp_on.loadImage("img01.png");
    lamp_off.allocate(78, 140, OF_IMAGE_COLOR);
    lamp_off.loadImage("img04.png");
    
    // iPHONE カメラ初期設定(Grabber)は切替が必要なためここでは実行しない
    
    // フォント読み込み->フォントファイルは プロジェクトのbin/dataホルダに入れておく。ここでサイズを変えてもOK (実行時エラーレポートが出るが)
    //  setup()内では、OF 上で表示するフォントを あらかじめ定義
    //  たまに読み込み時にFONT関連の実行時エラーとなるが iOS Deployment Taget を一旦 6.0とかに落とすと なぜか実行できる。
    //  iOS シュミレーターの問題のような気がする。
    ofTrueTypeFont::setGlobalDpi(72);
    
    verdana30.loadFont("verdana.ttf", 20, true, true);
    verdana30.setLineHeight(34.0f);
    verdana30.setLetterSpacing(1.035);
    
    cooperBlack60.loadFont("cooperBlack.ttf", 60, true, true);
    cooperBlack60.setLineHeight(64.0f);
    cooperBlack60.setLetterSpacing(1.037);
    //bonjour,OSC とも今回はサーバー設定なのでIPは必要無い。EDISON側では必要なので、bonjourでサーバーのIPを探してからOSC送信する
    // bonjour スタート
    bonjour = new ofxBonjourIp();
    bonjour->addEventListeners(this); // optional
    
    // find me (server)
    bonjour->startService(); // 引数に何も指定しなければ bonjour アドオンの ofxBonjourIp.h の設定のまま。(次のコメント内容)
    //bonjour->startService("_ofxBonjourIp._tcp.", "", 7777, "local");
    
    // find another device (client)- note will not discover itself
    bonjour->discoverService(); // discover other device with defaults.
    //bonjour->discoverService(type, domain);

    // ここからOSC設定。設定はサーバーなのでポート番号のみ。 ポート番号はofAPP.hで定義。番号設定はある程度自由。
    cout << "listening for osc messages on port " << PORT << "\n";
    receiver.setup( PORT );
    current_msg_string = 0;

    ondoState = "";
    botton_new = 0;     //イベント時の ボタンの値 iOSGUI と 4Dsysからの受信値で共用
    botton_old=0;       //現在の ボタンの値 iOSGUI と 4Dsysからの受信値で共用
    sli=100;            //スライダーGUI初期値
    div1=1;             //スライダーGUI初期値
    temp_sw=0;          //温度数値表示GUI初期値
}

//--------------------------------------------------------------
void ofApp::update(){
    //updateとdrawは同じような処理をする印象を受けるが、update 内に図形作成命令を書いても画面に表示しない。図形表示はdraw()に記述すること。
    if(botton_old!=0) {
            cam.update();
    }
     camdata=1;
    // 以下OSCデータ受信処理
    while( receiver.hasWaitingMessages() ){
        // get the next message
        ofxOscMessage m;
        receiver.getNextMessage( &m );
       
        // 温度データをSTRINGで受け取る /以下のコマンド及びデータは、送受信双方で同じ記述をするだけでOSC送受信ができてしまう!!簡単
        if( m.getAddress() == "/ondo" ){
            ondoState = m.getArgAsString( 0 ) ;
            camdata=0;
        }
        // 4DsysからのボタンデータをINTで受け取る-->カメラの切り替えだけ
       else if( m.getAddress() == "/cam" ){
            cam_no = m.getArgAsInt32( 0 ) ;
            //  printf(" CAMno=%i",cam_no);
            botton_new=cam_no;
        }
    }
}

//--------------------------------------------------------------
void ofApp::draw(){
    ofSetColor(255);
    
    
    if(botton_old!=0){
        float scale_cam=680/cam.getWidth();  //カメラデータの拡大率を計算
        cam.draw((ofGetWidth()-680)/2, 200,int(cam.getWidth()*scale_cam),int(cam.getHeight()*scale_cam));
    }
    if(botton_new != botton_old){
        switch (botton_new) {
            case 0:
                cam.close();       //カメラを表示しない場合
                botton_old=botton_new;
                break;
            case 1:
                if(botton_old != 0) cam.close();
                cam.setDeviceID(0);   // 0又は省略で通常カメラ 必ずinitGrabberの前に設定する
                cam.initGrabber(640,480, OF_IMAGE_COLOR);//カメラ表示の大きさは何種類かあるが左が一番無難。数字を適当に
                                                         //変えてもシステム設定通りでないと変更されない。
                scale_cam=680/cam.getWidth();
                cam.draw((ofGetWidth()-680)/2, 200,int(cam.getWidth()*scale_cam),int(cam.getHeight()*scale_cam));
                botton_old=botton_new;
                break;
                
            case 2:
                if(botton_old != 0) cam.close();
                cam.setDeviceID(1);   // 1はfacetime カメラ
                cam.initGrabber(640,480, OF_IMAGE_COLOR);
                scale_cam=680/cam.getWidth();
                cam.draw((ofGetWidth()-680)/2, 200,int(cam.getWidth()*scale_cam),int(cam.getHeight()*scale_cam));
                botton_old=botton_new;
                break;
            default:
                break;
        }
    }
    //Edison側の命令をボタンに反映させたいが、設定方法がわからないのでダメ押しの表示。
    if(botton_old==0){
        ofSetColor(139, 137, 137);
        cooperBlack60.drawString("NoCamera", 300, 1250);
    }
    else if(botton_old==1){
        ofSetColor(124, 205, 124);
        cooperBlack60.drawString("FrontCamera", 250, 1250);
    }
    else{
        ofSetColor(205, 85, 85);
        cooperBlack60.drawString("FaceCamera", 250, 1250);
    }
    
    //****************ここから 温度データを 4X4->最大61X61 に変換して 画面に表示********************
    //               頭が現役じゃないので原始的です。
    //     ここをなんとかすると表示が速くなるが、EDISON側のPYTHON処理データ送信が遅いのであまり影響ない

    if(ondoState.length()>= 48){
        
        ofDisableAlphaBlending();     //データが送られて来た場合のサイン表示
        ofSetColor(105,105,105);
        ofRect(142, 20, 676, 140);
        ofSetColor(255,210,0);
        cooperBlack60.drawString("   Edison---->", 100, 100);
        lamp_on.draw(650,20);
        
        //4X4の文字データを浮動小数点に変換  245ー>24.5
        int   kk=0; //カメラ連動なしでセンサー内容表示の場合
        if(botton_old==0 ){
            for (int k=0; k<16; k++){
                tdata[k]=ofToFloat(ondoState.substr((3+int(k/4)*4-k%4)*3,3))*0.1;
                kk++;
            }
        }
        //反転の場合-->センサーとカメラを連動(前も後ろも同じ)
        else {
            int kk=0;
            for (int k=0; k<48; k=k+3){
                tdata[kk]=ofToFloat(ondoState.substr(k,3))*0.1;
                kk++;
            }
        }
        // たかだか 4X4 のセンサーなのに 補間で 画像が立体的に見えてくる。以下補間処理部分
        // 送信スピードが(python側)が遅いので、スピードを考慮していない。2次元ではなく1次元配列とした
        // 補間方法は4点のラグランジュ 計算は複雑だが 等分に比べピークが出ない。あくまでも推測値なので現実とは多少違う。
        // 描画終了までに1画面最大 3721+244=3964点について膨大な単純計算をしているが、スピードはあまり気にならない。ネイティブすごい!!

        
        aaa=div1;     //最大20等分 X方向 等分補間  iOS GUI のスライダーとリンク(div1) 4X4-->61X61 可変
        //aaa=10;     //テスト用
        //以下X方向についてtdata を 補間用配列ttdataに温度を補間して配置
        //ラグランジュ用定数 X方向距離は1単位 正方形なので、Y方向も共用
        a1=-aaa*-aaa*2*-aaa*3;
        b1=aaa*(aaa-aaa*2)*(aaa-aaa*3);
        c1=aaa*2*(aaa*2-aaa)*(aaa*2-aaa*3);
        d1=aaa*3*(aaa*3-aaa)*(aaa*3-aaa*2);

        
        for(int y=0;y<4;y++){
            
            //ラグランジュ用定数 X方向4点の温度
            a=tdata[0+y*4]/a1;
            b=tdata[1+y*4]/b1;
            c=tdata[2+y*4]/c1;
            d=tdata[3+y*4]/d1;
            int xxx=y*aaa*(3*aaa+1);
            
            for (int xx=0 ;xx < aaa*3+1 ; xx++){
                ttdata[xx+xxx]=sp(xx);
            }
        }
        //以下Y方向の処理。上記で引き伸ばしたX方向4点について、全点の温度補間処理実行
        int yy1=aaa*3+1;
        
        for(int xx=0;xx<yy1;xx++){
            //スプライン用定数 Y方向4点の温度
            a=ttdata[xx]/a1;
            b=ttdata[xx+yy1*aaa]/b1;
            c=ttdata[xx+yy1*aaa*2]/c1;
            d=ttdata[xx+yy1*aaa*3]/d1;
            
            for(int yy=0;yy<yy1;yy++){    //基準4点も再計算してるので効率悪いが(最大244箇所)めんどくさいのでこのまま
                ttdata[xx+yy1*yy]=sp(yy);
            }
        }
        
        //色分け用 最大最小値抽出->元のデータ16個について
        float omin=100;
        float omax=tdata[0];
        int min_no=0,max_no=0;
        
        for (int k=0; k<16; k++){
            if(tdata[k] >= omax) {omax=tdata[k]; max_no=k;}
            if(tdata[k] <= omin) {omin=tdata[k]; min_no=k;}
        }
        //最大最小値の位置を最大3721個に補間したデータ位置に変換
        //ラグランジュ補間なので測定値より最大最小が大きくなる場合があり色変換時、山が削られるが、この次挑戦
        int min_R=(min_no%4)*aaa+int(min_no/4)*yy1*aaa;
        int max_R=(max_no%4)*aaa+int(max_no/4)*yy1*aaa;
        
        //************************描画開始**************************
        
        //   if (botton_old!=0) ofEnableBlendMode(OF_BLENDMODE_MULTIPLY);  //画像とブレンド 透明にするため
        float pic=676.0/yy1;  //1ヶ所毎の分割表示の大きさ int型だと大きさが変わるのでfloat
        for (int tt=0;tt<yy1*yy1;tt++){
            //色の差をはっきり出すために画面ごとに最小最大値の濃淡を変える。結果的に動いているものを目で追いやすくなった。
            int min_max=ofMap(ttdata[tt],omin, omax, 0, 255);     //画面再描画ごとに 濃淡の上下を変える RGB 0〜255
            ofSetColor(min_max,0,255-min_max,100);                              //単純な赤青の濃淡が一番綺麗かも。
            ofRect((tt%yy1)*pic+142,(tt/yy1)*pic+307,pic*sli/100,pic*sli/100);  // ピクセルの大きさは iOS GUI のスライダーとリンク(sli)
        }
            // せっかく温度を測定できるセンサーなので,数値を表示ー>センサーの一応正確な読み取り場所である 4X4 の場所に限定
        ofSetColor(255);
        if(temp_sw==0){   //iOS GUI のスイッチで、最大最小値だけを表示
            verdana30.drawString(ofToString(ttdata[min_R],1),(min_R%yy1)*pic+142,(min_R/yy1)*pic+307+pic);
            verdana30.drawString(ofToString(ttdata[max_R],1),(max_R%yy1)*pic+142,(max_R/yy1)*pic+307+pic);
        }
        else{
            for(int tt=0;tt<16;tt++){      //iOS GUI のスイッチで、測点数値を全て表示 4X4 位置
                    int sokutei=(tt%4)*aaa+int(tt/4)*yy1*aaa;
                    verdana30.drawString(ofToString(ttdata[sokutei],1),(sokutei%yy1)*pic+142,(sokutei/yy1)*pic+307+pic);
            }
        }
           if (botton_old!=0) ofDisableBlendMode();
    }
    if(camdata==1) {
           ofDisableAlphaBlending();   //データが送られてこない場合の表示
        ofSetColor(105,105,105);
        ofRect(142, 20, 676, 140);
        ofSetColor(255,210,0);
        cooperBlack60.drawString("   Edison---->", 100, 100);
        lamp_off.draw(650,20);
    }
    
}

//--------------------------------------------------------------

void ofApp::onPublishedService(const void* sender, string &serviceIp) {
    ofLog() << "Received published service event: " << serviceIp;
}

void ofApp::onDiscoveredService(const void* sender, string &serviceIp) {
    ofLog() << "Received discovered service event: " << serviceIp;
}

void ofApp::onRemovedService(const void* sender, string &serviceIp) {
    ofLog() << "Received removed service event: " << serviceIp;

}

//----------------以下今回は必要なし-------------------------------
void ofApp::exit(){

}

//--------------------------------------------------------------
void ofApp::touchDown(ofTouchEventArgs & touch){

}

//--------------------------------------------------------------
void ofApp::touchMoved(ofTouchEventArgs & touch){

}

//--------------------------------------------------------------
void ofApp::touchUp(ofTouchEventArgs & touch){

}

//--------------------------------------------------------------
void ofApp::touchDoubleTap(ofTouchEventArgs & touch){

}

//--------------------------------------------------------------
void ofApp::touchCancelled(ofTouchEventArgs & touch){
    
}

//--------------------------------------------------------------
void ofApp::lostFocus(){

}

//--------------------------------------------------------------
void ofApp::gotFocus(){

}

//--------------------------------------------------------------
void ofApp::gotMemoryWarning(){

}

//--------------------------------------------------------------
void ofApp::deviceOrientationChanged(int newOrientation){

}

MyGuiView.h

//
//  MyGuiView.h
//  bon
//
//  Created by Take on 2015/02/18.
//
//

#import <UIKit/UIKit.h>

@interface MyGuiView : UIViewController
@property(retain, nonatomic) IBOutlet UISlider *radiusSlider;
@property(retain, nonatomic) IBOutlet UISwitch *fillSwitch;
@property(retain, nonatomic) IBOutlet UISegmentedControl *Camera;
@property(retain, nonatomic) IBOutlet UISegmentedControl *Devid;
@property(retain, nonatomic) IBOutlet UISwitch *Temp;
@end

MyGuiView.mm

//
//  MyGuiView.m
//  bon
//
//  Created by Take on 2015/02/18.
//
//

#import "MyGuiView.h"
#include "ofxiOSExtras.h"
#include "ofApp.h"


@implementation MyGuiView

ofApp *myApp;


- (void)viewDidLoad {
    [super viewDidLoad];
    myApp = (ofApp*)ofGetAppPtr();
    }


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated
    }

-(IBAction)radiusSliderHandler:(id)sender {
        UISlider *sliderObj = sender;
                myApp->sli = [sliderObj value];
    
    }
-(IBAction)Devid:(id)sender {
    UISlider *sliderObj = sender;
    myApp->div1 = [sliderObj value];
    
}

-(IBAction)Camera:(id)sender{
     //なぜ switchObj を仲介するのかわからないが、スイッチ関連はswitchObjを使えばOFに値を渡せる。
    UISegmentedControl * switchObj = sender;
   //switchObj.selectedSegmentIndex=myApp->botton_old;
    //printf("switch value is - %i\n", [switchObj selectedSegmentIndex]);
    myApp->botton_new=  switchObj.selectedSegmentIndex;
    

    }
-(IBAction)Temp:(id)sender{
    //UISwitchはof サンプル(iPhoneGuiExample)の toggle でも 以下の switchObj でもなぜかOK!!
    UISwitch * switchObj = sender;
    myApp->temp_sw = [switchObj isOn];

}
@end

MyGuiView.xib

f:id:TAKEsan:20150821170634p:plain
MyGuiView.xibは、自分で好きなようにデザインして下さい。

その他 /bin/data/ 以下に下図のような二つの画像と、fontファイルcooperBlack.ttf、frabk.ttf、verdana.ttfを入れてます。

f:id:TAKEsan:20150821171328p:plain:w200:left f:id:TAKEsan:20150821171327p:plain:w200:left

EdisonのPythonによるプログラムソース構築

Bonjourライブラリのインストールは
http://code.google.com/p/pybonjour/からダウンロード、解凍して
    cd pybonjour-1.1.1
    python setup.py build
    python setup.py install
でOK。
OSCライブラリのインストールは、
    pip install pyOSC
でOK。
bonjourの基本プログラムは、この方を参考にさせていただきました。Python で通信 : Bonjour と TCPServer を使って|毎日の向こうに

⚪︎⚪︎⚪︎⚪︎.py

# OSC Bonjoul

import mraa,time, threading,select,sys,pybonjour,socket
import operator,  signal
from OSC import OSCClient, OSCMessage
from datetime import datetime

regtype  = "_ofxBonjourIp._tcp"
timeout  = 5
resolved = []

addr="192.168.0.8"  # damy!!
port=1234           # damy!!

# **********Bnjoul handle kill & ctrl-C**************

def handleSigTERM(signum, frame):
    print "kill signal"
    exit(0)

def handleCtrlC(signum, frame):
    print "Ctrl-C signal"
    exit(0)
# ****************bonjour*******************
def myMsgPrinter_handler(addr, tags, data, client_address):
    print "osc://%server%server ->" % (OSC.getUrlStr(client_address), addr),
    print "(tags, data): (%server, %server)" % (tags, data)
# ****************OSC Start!!***************
def resolve_callback(sdRef, flags, interfaceIndex, errorCode, 
    fullname, hosttarget, port, txtRecord):
  global client
  if errorCode != pybonjour.kDNSServiceErr_NoError:
    return

  addr = socket.gethostbyname(hosttarget)
  print 'Resolved service:'
  print '  fullname   =', fullname.encode('utf_8')
  print '  hosttarget =', hosttarget
  print '  port       =', port
  print '  IP Address =', addr
  resolved.append(True)

  # ********************ONDO i2C********************
  D6T_addr = 0x0A
  D6T_cmd =  0x4C
  
  tdata=""
  client = OSCClient()
  client.connect( (addr, port) )
  x = mraa.I2c( 6 )         #EDISON i2C PORT
  try:
     	while True:
                x.address(D6T_addr)
            	x.writeByte(0x4C)
            	time.sleep(0.025)
            	y=x.read(35)
            	if y!=-1:
                     for var in range(0, 16):
                        tdata=tdata+str((y[(var*2+2)]+(y[(var*2+3)]<<8)))
                     msg=OSCMessage("/ondo")
                     msg.append(tdata)
                     client.send(msg )
            	tdata=""
  except IndexError:
            print "I2C Data error!! Next try......."
            time.sleep(1)
            pass
  sys.exit(0)

def browse_callback(sdRef, flags, interfaceIndex, errorCode, 
    serviceName, regtype, replyDomain):
  if errorCode != pybonjour.kDNSServiceErr_NoError:
    return

  if not (flags & pybonjour.kDNSServiceFlagsAdd):
    print 'Service removed'
    return

  print 'Service added; resolving'

  resolve_sdRef = pybonjour.DNSServiceResolve(0, interfaceIndex, 
    serviceName, regtype, replyDomain, resolve_callback)

  try:
    while not resolved:
      ready = select.select([resolve_sdRef], [], [], timeout)
      if resolve_sdRef not in ready[0]:
        print 'Resolve timed out'
        break
      pybonjour.DNSServiceProcessResult(resolve_sdRef)
    else:
      resolved.pop()
  finally:
    resolve_sdRef.close()
# ***********************Bonjour Start!!*****************************
browse_sdRef = pybonjour.DNSServiceBrowse(regtype = regtype,
                                   callBack = browse_callback)
try:
  try:
    while True:
      ready = select.select([browse_sdRef], [], [])
      if browse_sdRef in ready[0]:
        pybonjour.DNSServiceProcessResult(browse_sdRef)
  except KeyboardInterrupt:
    pass
finally:
  browse_sdRef.close()

動かし方

 特に難しいことはありません。起動順序はiPhoneからでもEdisonからでもOKです。自分たちで勝手に相手を見つけて接続しちゃいます。