置頂文字

歡迎來訪 !! 如有任何問題歡迎一起討論或是 eMail 給我 legorunmail@Gmail.com

2015年4月9日 星期四

Android 手機透過藍芽與 NXT Lejos 應用

 NXT主機上有藍芽BlueTooth因此能傳送與接收其他裝置的藍芽資料,本篇要實做用一般常見的Android手機與Lego NXT主機透過藍芽做資料交換。

準備的物件
1.Android手機一隻新舊款沒關係但要有藍芽功能。
2.Lego Mindstorms NXT 或EV3,馬達3顆接 A、B、C Port
3.先將手機與NXT 的藍芽都打開,讓手機尋找NXT主機內定密碼為1234,連結成功後手機上就有這台NXT的資訊與名字作為手機App要連結的目標。

由於Android手機有很多Sensor如重力感應器、方向感應器、光線感應器、GPS等如能加以應用等於幫NXT省下不少外購Sensor費用。

如果大家有淘汰的Android手機可以試試看本篇的應用。

一部份開發 Android App程式:

我在App主畫面上放了 9個 Button以方便未來擴充應用

執行 App 程式的主畫面


顯示手機上 Sensor 資訊




原始碼如下:開發環境 Eclipse 與 Android、Lejos套件

package com.example.lego_android;

import android.app.Activity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.LinearLayout;
import android.graphics.Color;
import android.view.Window;
import android.widget.*;
import android.graphics.drawable.Drawable;
import android.view.Gravity;
import android.text.TextPaint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import java.util.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import android.content.*;


public class MainActivity extends Activity {

private  int MP=LinearLayout.LayoutParams.MATCH_PARENT;
private  int WC=LinearLayout.LayoutParams.WRAP_CONTENT;
private TableRow.LayoutParams view_layout2;
 private TextView txtID;
 private TextView txtSync;
 private TextView txtTitle01;
 private TextView txtTrending;
 private TextView txtTitle02;
 private String strTimeCnt="";
 private TextView txtVer;
 private boolean chkvername=false;
 private String strVer="";
 private int ifisze=18;
 private int iChnl=0;  
 private String strTitleH="LegoRun 資 訊 管 理";
 
 
   private BluetoothAdapter adapter;
private BluetoothSocket nxtSocket;
public DataInputStream nxtDataIn;
public DataOutputStream nxtDataOut;
   public final int MODE_CONTROL = 1;
   private int mode;
 
   private boolean bConnect_NXT=false;
   private String NXTUUID = "00001101-0000-1000-8000-00805F9B34FB";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

LinearLayout layout=new LinearLayout(this);
        layout.setOrientation(LinearLayout.VERTICAL);    
        layout.setLayoutParams(new LinearLayout.LayoutParams(MP,MP));
        layout.setBackgroundColor(Color.rgb(19,92,160));

        //標題隱藏
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(layout);
     
     
        TableLayout tl= new TableLayout(this);
        tl.setLayoutParams(new LinearLayout.LayoutParams(MP,MP));
        tl.setBackgroundColor(Color.parseColor("#333333"));
        tl.setStretchAllColumns(true);
        layout.addView(tl);  
     
 
        TableLayout.LayoutParams row_layout_mid = new TableLayout.LayoutParams();
        row_layout_mid.weight=1f;
        row_layout_mid.setMargins(0,1,0,1); //setMargins(left, top, right, bottom);

        TableLayout.LayoutParams row_layout_max = new TableLayout.LayoutParams();
        row_layout_max.weight=8f;
        row_layout_max.setMargins(0,1,0,1); //setMargins(left, top, right, bottom);

        TableLayout.LayoutParams row_layout_min = new TableLayout.LayoutParams();
        row_layout_min.weight=0.2f;
        row_layout_min.setMargins(0,1,0,1); //setMargins(left, top, right, bottom);

        TableRow.LayoutParams view_layout1 = new TableRow.LayoutParams(MP,MP);
        view_layout1.span=2;

        view_layout2 = new TableRow.LayoutParams(getScrWH(MainActivity.this)[0]/2,MP);
        view_layout2.setMargins(1,0,0,0);

        TableRow tr1 = new TableRow(this);
        tr1.setLayoutParams(row_layout_mid);
        tr1.setGravity(Gravity.CENTER_HORIZONTAL);
        txtTitle01 = new TextView(this);
        txtTitle01.setLayoutParams(view_layout1);
        txtTitle01.setText(strTitleH);
        txtTitle01.setBackgroundColor(Color.parseColor("#00C9C9"));  //#46C7C7
        txtTitle01.setGravity(Gravity.CENTER);
        TextPaint tp = txtTitle01.getPaint();
        tp.setFakeBoldText(true);
        txtTitle01.setTextColor(Color.parseColor("#EEEEEE"));
        txtTitle01.setOnClickListener(new ButtonClickListener());
        txtTitle01.setTextSize(ifisze);
        txtTitle01.setTag("txtTitle01");
        tr1.addView(txtTitle01);
        tl.addView(tr1);

        TableRow tr2 = new TableRow(this);
        tr2.setLayoutParams(row_layout_mid);
        tr2.setGravity(Gravity.CENTER_HORIZONTAL);
        txtTitle02 = new TextView(this);
     
     
        txtTitle02.setText("尚未連結Lego NXT...");
     
        txtTitle02.setTextSize(18);
        txtTitle02.setLayoutParams(view_layout1);
        txtTitle02.setGravity(Gravity.CENTER);
        txtTitle02.setBackgroundColor(Color.WHITE);
        tr2.addView(txtTitle02);
        tl.addView(tr2);


        TableRow tr3 = new TableRow(this);
        tr3.setLayoutParams(row_layout_max);
        tr3.setGravity(Gravity.CENTER_HORIZONTAL);
        tl.addView(tr3);

        LinearLayout layoutBrick=new LinearLayout(this);
        layoutBrick.setOrientation(LinearLayout.VERTICAL);
        layoutBrick.setLayoutParams(view_layout1);
        layoutBrick.setBackgroundColor(Color.parseColor("#95B9C7"));
        tr3.addView(layoutBrick);


        TableLayout tl_Brick= new TableLayout(this);
        tl_Brick.setLayoutParams(new LinearLayout.LayoutParams(MP,MP));
        tl_Brick.setBackgroundColor(Color.parseColor("#FFFFFF"));
        tl_Brick.setStretchAllColumns(true);
        layoutBrick.addView(tl_Brick);

        TableLayout.LayoutParams row_layout_Brick = new TableLayout.LayoutParams();
        row_layout_Brick.weight=1f;
   
        TableRow.LayoutParams view_layout_Brick = new TableRow.LayoutParams(MP,MP);
        view_layout_Brick.weight=0.7f;
 
     
        int ibtn=0;
        for(int i=0;i<=2;i++){

            TableRow tr_Brick = new TableRow(this);
            tr_Brick.setLayoutParams(row_layout_Brick);
            tr_Brick.setGravity(Gravity.CENTER_HORIZONTAL);
            tl_Brick.addView(tr_Brick);

            for(int j=0;j<=2;j++){
                Button btn_Brick = new Button(this);
                btn_Brick.setLayoutParams(view_layout_Brick);              
                btn_setup(btn_Brick,ibtn); //設定按鈕外觀圖形
                btn_Brick.setOnClickListener(new ButtonClickListener());
             
                tr_Brick.addView(btn_Brick);
                ibtn++;
            }

        }



        TableRow tr4 = new TableRow(this);
        tr4.setLayoutParams(row_layout_min);
        tr4.setGravity(Gravity.CENTER_HORIZONTAL);

        txtTrending = new TextView(this);
        txtTrending.setText("資料設定");
        txtTrending.setTextSize(18);
        txtTrending.setLayoutParams(view_layout1);
        txtTrending.setGravity(Gravity.CENTER);
        txtTrending.setTag("txtTrending");
        txtTrending.setOnClickListener(new ButtonClickListener());
        txtTrending.setBackgroundColor(Color.parseColor("#E5E4E2"));
        tr4.addView(txtTrending);
        tl.addView(tr4);


        //-------------------------------------------
        TableRow tr5 = new TableRow(this);
        tr5.setLayoutParams(row_layout_mid);
        tr5.setGravity(Gravity.CENTER_HORIZONTAL);

        txtID = new TextView(this);
        setTxtView(txtID,"帳 號 設 定","txtID");
        tr5.addView(txtID);

        txtSync = new TextView(this);
        setTxtView(txtSync,"資 料 更 新","txtSync");
        tr5.addView(txtSync);

        tl.addView(tr5);

        //----------------------------------------------
        TableRow tr6 = new TableRow(this);
        tr6.setLayoutParams(row_layout_mid);
        tr6.setGravity(Gravity.CENTER_HORIZONTAL);

        TextView txtHelp = new TextView(this);
        setTxtView(txtHelp,"使 用 說 明","txtHelp");
        tr6.addView(txtHelp);

        txtVer = new TextView(this);
        setTxtView(txtVer,"版 本 資 訊","txtVer");
        tr6.addView(txtVer);
        tl.addView(tr6);
     
     
     
        //藍芽啟用
        adapter = BluetoothAdapter.getDefaultAdapter();
        if(adapter==null)
        {
        Toast.makeText(getApplication(), "No Bluetooth adapter found", Toast.LENGTH_SHORT).show();
        this.finish();
        }
     
    if(!adapter.isEnabled())
startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), 1);
   
   


}




@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

public int[] getScrWH(Activity activity){
        int scrWH[]={0,0};
        DisplayMetrics dm = new DisplayMetrics();
        activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
        scrWH[0] = dm.widthPixels;
        scrWH[1] = dm.heightPixels;
        return scrWH;
    }


//按鈕事件
class ButtonClickListener implements OnClickListener  {
        // onClick 方法(觸碰按鈕時的事件處理器)
        public void onClick(View v){
            //取得 tag
            String tag = (String)v.getTag();

            if (tag.equals("btn0")){
           
            if(((Button)v).getText().equals("藍芽連結")){
           
            txtTitle02.setText("尋找藍芽中...");            
            //開啟藍芽
            if(connectNxt())
            ((Button)v).setText("關閉藍芽");
            }else{
            try {
            txtTitle02.setText("傳送功能 = 關閉藍芽連結");
    nxtDataOut.writeInt(999);
    nxtDataOut.flush();            
            nxtSocket.close();
            bConnect_NXT=false;
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
            ((Button)v).setText("藍芽連結");
            }
           
            }
         
         
            //傳送資料
            if (tag.equals("btn1")){
            try {
           
            if(((Button)v).getText().equals("啟動馬達A")){            
            txtTitle02.setText("傳送功能 = 啟動馬達A");
            nxtDataOut.writeInt(0);
            nxtDataOut.flush();
            ((Button)v).setText("關閉馬達A");
            }else{
            txtTitle02.setText("傳送功能 = 關閉馬達A");
            nxtDataOut.writeInt(1);
            nxtDataOut.flush();
            ((Button)v).setText("啟動馬達A");
            }
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}        
           
            }
         
            if (tag.equals("btn2")){
            try {
            if(((Button)v).getText().equals("啟動馬達B")){            
            txtTitle02.setText("傳送功能 = 啟動馬達B");
            nxtDataOut.writeInt(2);
            nxtDataOut.flush();
            ((Button)v).setText("關閉馬達B");
            }else{
            txtTitle02.setText("傳送功能 = 關閉馬達B");
            nxtDataOut.writeInt(3);
            nxtDataOut.flush();
            ((Button)v).setText("啟動馬達B");
            }
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}        
           
            }
         
         
            if (tag.equals("btn3")){
            try {
            if(((Button)v).getText().equals("啟動馬達C")){            
            txtTitle02.setText("傳送功能 = 啟動馬達C");
            nxtDataOut.writeInt(4);
            nxtDataOut.flush();
            ((Button)v).setText("關閉馬達C");
            }else{
            txtTitle02.setText("傳送功能 = 關閉馬達C");
            nxtDataOut.writeInt(5);
            nxtDataOut.flush();
            ((Button)v).setText("啟動馬達C");
            }

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}        
           
            }
         
         
        }

    }

private boolean connectNxt()
    {
    if(bConnect_NXT){
    txtTitle02.setText("手機已經連結成功不須再次連結");    
    return false;
    }
   
    String name="NXT8547";
    BluetoothDevice nxt = null;
   
   
   
        Set devicesSet = adapter.getBondedDevices(); 
     
        if(devicesSet.size()==0)
        {        
        txtTitle02.setText("手機上無任何藍芽連結裝置");
        return false;
        }
     
        for (BluetoothDevice device : devicesSet)
        {
            if (device.getName().equals(name))
            {
            nxt = device;
                break;
            }
        }
     
        if(nxt==null)
        {        
        txtTitle02.setText("找不到Lego NXT name:"+name);
        return false;
        }
     
        try
        {        
nxtSocket = nxt.createRfcommSocketToServiceRecord(UUID.fromString(NXTUUID));
nxtSocket.connect();
nxtDataOut = new DataOutputStream(nxtSocket.getOutputStream());
nxtDataIn = new DataInputStream(nxtSocket.getInputStream());
}
        catch(IOException e)
{
       
        txtTitle02.setText("連結此裝置:"+name+" 失敗!!");
        return false;
}
   
        txtTitle02.setText("連結此裝置:"+name+" 成功!!");
    bConnect_NXT=true;
    return true;


    }

private void setTxtView(TextView v,String strText,String strTag){
        v.setText(strText);
        v.setTextSize(ifisze);
        v.setLayoutParams(view_layout2);
        v.setGravity(Gravity.CENTER);
        v.setBackgroundColor(Color.parseColor("#F3F3F3"));
        v.setTag(strTag);
        v.setOnClickListener(new ButtonClickListener());
    }

private void btn_setup(Button btn_Brick,int ibtn){
        Context context=getApplicationContext();    


        Drawable[][] image=new Drawable[9][2];
        image[0][0]=context.getResources().getDrawable(R.drawable.net_42_128);
        image[0][1]=context.getResources().getDrawable(R.drawable.net_42_72);

        image[1][0]=context.getResources().getDrawable(R.drawable.net_24_128);
        image[1][1]=context.getResources().getDrawable(R.drawable.net_24_72);

        image[2][0]=context.getResources().getDrawable(R.drawable.net_18_128);
        image[2][1]=context.getResources().getDrawable(R.drawable.net_18_72);

        image[3][0]=context.getResources().getDrawable(R.drawable.net_08_128);
        image[3][1]=context.getResources().getDrawable(R.drawable.net_08_72);

        image[4][0]=context.getResources().getDrawable(R.drawable.net_21_128);
        image[4][1]=context.getResources().getDrawable(R.drawable.net_21_72);

        image[5][0]=context.getResources().getDrawable(R.drawable.net_27_128);
        image[5][1]=context.getResources().getDrawable(R.drawable.net_27_72);

        image[6][0]=context.getResources().getDrawable(R.drawable.net_22_128);
        image[6][1]=context.getResources().getDrawable(R.drawable.net_22_72);

        image[7][0]=context.getResources().getDrawable(R.drawable.net_01);
        image[7][1]=context.getResources().getDrawable(R.drawable.net_23_72);

        image[8][0]=context.getResources().getDrawable(R.drawable.net_26_128);
        image[8][1]=context.getResources().getDrawable(R.drawable.net_26_72);





        String[][] strBtn=new String[9][2];
        strBtn[0][0]="藍芽連結";
        strBtn[0][1]="btn0";
        strBtn[1][0]="啟動馬達A";
        strBtn[1][1]="btn1";
        strBtn[2][0]="啟動馬達B";
        strBtn[2][1]="btn2";
        strBtn[3][0]="啟動馬達C";
        strBtn[3][1]="btn3";

        strBtn[4][0]="啟動光線";
        strBtn[4][1]="btn6";
        strBtn[5][0]="Fun05";
        strBtn[5][1]="btn7";

        strBtn[6][0]="Fun06";
        strBtn[6][1]="btn4";
        strBtn[7][0]="Fun07";
        strBtn[7][1]="btn5";
        strBtn[8][0]="Fun08";
        strBtn[8][1]="btn8";
     
     


     

        btn_Brick.setText(strBtn[ibtn][0]);
        btn_Brick.setTextSize(ifisze);
        btn_Brick.setTag(strBtn[ibtn][1]);
        //-------------
        int spacing=0;
        int width=btn_Brick.getMeasuredWidth();
        int height=btn_Brick.getMeasuredHeight();
        int txt_width=(int)(btn_Brick.getTextSize()*btn_Brick.getText().length());
        int txt_height=(int)(btn_Brick.getLineCount()*btn_Brick.getLineHeight());

        int img_width=0;
        int img_height=0;
        int content_height=0;
        int content_width=0;
        int padding_w=0;
        int padding_h=0;
        int isel=0;

        if(getScrWH(this)[0]>=720){
            img_width=image[ibtn][0].getIntrinsicWidth();
            img_height=image[ibtn][0].getIntrinsicHeight();
            isel=0;
        }else{
            img_width=image[ibtn][1].getIntrinsicWidth();
            img_height=image[ibtn][1].getIntrinsicHeight();
            isel=1;
        }
        content_height=txt_height+img_height+spacing;
        content_width=txt_width+img_width+spacing;
        padding_w=width/2-content_width/2;
        padding_h=height/2-content_height/2;
        btn_Brick.setCompoundDrawablesWithIntrinsicBounds( null,image[ibtn][isel], null, null);
        ////setMargins(left, top, right, bottom);
        //btn_Brick.setPadding(0,padding_h,0,0);
        btn_Brick.setCompoundDrawablePadding(padding_h/2);
        //----------------

    }

}


第二部份開發Lejos NXT 程式

import lejos.nxt.Button;
import lejos.nxt.ButtonListener;
import lejos.nxt.LCD;
import lejos.nxt.Motor;
import lejos.nxt.comm.BTConnection;
import lejos.nxt.comm.Bluetooth;

import java.io.DataInputStream;
import java.io.DataOutputStream;

import lejos.nxt.comm.*;
import lejos.util.Delay;


public class BT_Frm01 {

public static void main(String[] args)throws Exception  {
// TODO Auto-generated method stub

Button.ESCAPE.addButtonListener(new ButtonListener(){
public void buttonPressed(Button b){System.exit(1);}
public void buttonReleased(Button b){}
});


LCD.drawString("Waiting",0,0);
BTConnection btc = Bluetooth.waitForConnection(0, NXTConnection.RAW);
DataInputStream din = btc.openDataInputStream();
DataOutputStream dout = btc.openDataOutputStream();
LCD.drawString("Connected",0,0);

Motor.A.setSpeed(450);
Motor.B.setSpeed(450);
Motor.C.setSpeed(450);

while(true){
int iData=din.readInt();
LCD.clear();
LCD.drawString("value="+String.valueOf(iData),0,2);


if(iData==999){
btc.close();
System.exit(1);
break;
}

switch(iData){
case 0:
Motor.A.forward();
break;
case 1:
Motor.A.stop();
break;
case 2:
Motor.B.forward();
break;
case 3:
Motor.B.stop();
break;
case 4:
Motor.C.forward();
break;
case 5:
Motor.C.stop();
break;

}



Delay.msDelay(1000);

}


}

}


除了手機可跟NTX互動溝通外不同的NXT主機也可以互動,這是我用第一台NXT主機當控制器透過BT遙控第二台NXT車輛的影片,第一隻馬達控制前輪方向動作、第二隻馬達控制後輪前進後退動作




2 則留言: