The purpose of this thesis to research how to build a bluetooth connection between Android and LEGO-Mindstorm-NXT.
一開始用意不是做這個,是在做玩超音波的時候,
突然想到著不是跟台大研發的倒車雷達一樣嗎?
然後看著超音波偵測器想那跟手機結合那不是很好玩
又讓我想到RGB光源偵測器如果跟手機結合,那麼偵測器偵測到顏色把資料傳到手機,
手機在去呼叫聲音檔案例如:紅色叫聲 聲音檔案或者用手機的無線上網在另外傳送資料
所以才發著一篇 ~
(著一篇的Android 連結跟傳輸我並沒有寫分開有點令人詬病~所以請多多包涵)
==> 連結跟傳輸以分開(主程式碼已修改)
1.NXT 控制器左上角會顯示藍芽是否也連結的符號 (<:未連結 <>:已連結 )
Note the screen in the upper-right corner of the picture ,
symbol mean ( <:Not To Connect bluetooth <>:To Connect bluetooth )
程式的介面(program interface):
開發環境: Windows 7 32Bit
使用:Eclipse + Android SDK + Java SDK
記得到AndroidManifest.xml寫入准許加入藍芽權限:
you need to add the BLUETOOTH permission to your application
<uses-permission android:name=”android.permission.BLUETOOTH”/>
<uses-permission android:name=”android.permission.BLUETOOTH_ADMIN”/>
要看比教詳細的介紹請看
http://www.mindstorms.rwth-aachen.de/trac/wiki/MotorControl
到Message format:開頭你會看到連結埠
然後參考馬達跟超音波的範例:
http://cellbots.googlecode.com/svn-history/r15/trunk/android/Mindstorms_NXT/src/com/googlecode/cellbots/nxt/NxtConnectionService.java
你會看到
public int setMotor(String srcApp, int motor, int power) { =>馬達
public int setUltraSonicSensor(String srcApp, int port) { =>超音波
介面得程式碼:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="開起藍芽裝置" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="搜尋藍芽裝置" />
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="連接藍芽裝置" />
<Button
android:id="@+id/button3"
android:layout_width="146dp"
android:layout_height="wrap_content"
android:text="更新藍芽搜尋" />
<Spinner
android:id="@+id/spinner1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Spinner
android:id="@+id/spinner2"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/button5"
android:layout_width="190dp"
android:layout_height="wrap_content"
android:text="馬達A" />
</LinearLayout>
然後主程式碼:
package com.test;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
import java.util.UUID;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.provider.ContactsContract.CommonDataKinds.Im;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.TextView;
public class MenuActivityActivity extends Activity {
public static final String TAG = "test";
private static final int REQUEST_ENABLE_BT = 2;
public static final String MyUUID = "00001101-0000-1000-8000-00805F9B34FB";
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private TextView text_View1 ;
BluetoothAdapter mBluetoothAdapter;
ArrayAdapter<String> bondedDevices;
ArrayAdapter<String> foundedDevices;
Button turnOnButton, showPairedDevicesButton, scanForDevicesButton,connectButton,RunMotorA;
TextView text;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//=============== main.xml Set up =======================
text_View1 = (TextView) findViewById(R.id.textView1);
text = (TextView) findViewById(R.id.textView1);
turnOnButton = (Button) findViewById(R.id.button1);
showPairedDevicesButton = (Button) findViewById(R.id.button2);
scanForDevicesButton = (Button) findViewById(R.id.button3);
connectButton = (Button) findViewById(R.id.button4);
RunMotorA = (Button) findViewById(R.id.button5);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter != null) {text.setText("BlueTooth adapter found");}
turnOnButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
turnOnBluetooth();
}
});
showPairedDevicesButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
showPairedDevices();
}
});
scanForDevicesButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
scanForDevices();
}
});
connectButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
connectToDevice();
}
});
RunMotorA.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
int motor=0; // NXT Port = 0:A Port , 1:B Port ,2:Port .....
int power=50;
byte[] setCmd = new byte[13];
setCmd[0] = (byte) 0x80;
setCmd[1] = (byte) 0x04;
setCmd[2] = (byte) motor;
setCmd[3] = (byte) power;
setCmd[4] = (byte) 0x01;
setCmd[5] = (byte) 0x01;
setCmd[6] = (byte) 0x00;
setCmd[7] = (byte) 0x20;
setCmd[8] = (byte) 0x00;
setCmd[9] = (byte) 0x00;
setCmd[10] = (byte) 0x00;
setCmd[11] = (byte) 0x00;
setCmd[12] = (byte) 0x00;
long t2=0;
while(1000>t2)
{
mConnectedThread.write(setCmd);
t2++;
}
}});
bondedDevices = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
foundedDevices = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
}
public void turnOnBluetooth(){
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
public void showPairedDevices(){
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
// Add the name and address to an array adapter to show in a ListView
bondedDevices.add(device.getName() + "\n" + device.getAddress());
Log.d("debug",device.getName() + "\n" + device.getAddress() );
}
}
Spinner s1 = (Spinner) findViewById(R.id.spinner1);
bondedDevices.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
s1.setAdapter(bondedDevices);
s1.showContextMenu();
}
// Create a BroadcastReceiver for ACTION_FOUND
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// Add the name and address to an array adapter to show in a ListView
foundedDevices.add(device.getName() + "\n" + device.getAddress());
refreshNewDevices();
}
}
};
public void refreshNewDevices(){
Spinner s2 = (Spinner) findViewById(R.id.spinner2);
foundedDevices.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
s2.setAdapter(foundedDevices);
s2.showContextMenu();
}
public void scanForDevices(){
// Register the BroadcastReceiver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
mBluetoothAdapter.startDiscovery();
}
public synchronized void connectToDevice(){
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
BluetoothDevice stvorka = null;
int t=0; // Device Count
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
// if(device.getName().equals("stvorka"))
// stvorka = mBluetoothAdapter.getRemoteDevice(device.getAddress());
mConnectThread = new ConnectThread(device);
mConnectThread.start();
text_View1.setText(device.getAddress()+""+ t);
t++;
}
}
// Start the thread to connect with the given device
// mConnectThread = new ConnectThread(stvorka);
// mConnectThread.start();
// text_View1.setText(stvorka.getName());
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == REQUEST_ENABLE_BT){
if(resultCode == Activity.RESULT_OK){
text.setText("Bluetooth enabled");
}else if (resultCode == Activity.RESULT_CANCELED){
text.setText("Bluetooth not enabled");
}
}
}
/**
* Start the ConnectedThread to begin managing a Bluetooth connection
* @param socket The BluetoothSocket on which the connection was made
* @param device The BluetoothDevice that has been connected
*/
public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
// Cancel the thread that completed the connection
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
Log.d(TAG,"starting connecting to device");
mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
}
public void move() {
byte[] data = { 0x0c, 0x00, (byte) 0x80, 0x04, 0x02, 0x32, 0x07, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00 };
int motor = 0;
if (motor == 0) {
data[4] = 0x02;
} else {
data[4] = 0x01;
}
data[5] = 0x20;
if(mConnectedThread != null)
mConnectedThread.write(data);
else
Log.d(TAG,"mConnectedThread is NULL");
}
/**
* This thread runs while attempting to make an outgoing connection
* with a device. It runs straight through; the connection either
* succeeds or fails.
*/
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
try {
tmp = device.createRfcommSocketToServiceRecord(UUID.fromString(MyUUID));
} catch (IOException e) {
Log.d(TAG,"socket creation failed" ,e);
}
mmSocket = tmp;
}
@Override
public void run() {
setName("ConnectThread");
Log.d(TAG,"running connected thread");
mBluetoothAdapter.cancelDiscovery();
try {
mmSocket.connect();
Log.d(TAG, "connection success");
} catch (IOException e) {
connectionFailed();
Log.d(TAG,"connection failed" ,e);
try {
mmSocket.close();
} catch (IOException e1) {
Log.e(TAG,"connection failed" ,e);
}
return;
}
synchronized (MenuActivityActivity.this) {
mConnectThread = null;
}
connected(mmSocket, mmDevice);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* This thread runs during a connection with a remote device.
* It handles all incoming and outgoing transmissions.
*/
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "create ConnectedThread");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.d(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void write(int i) {
// TODO Auto-generated method stub
}
@Override
public void run() {
Log.d(TAG, "run listening");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
Log.d(TAG, "listening.."+bytes);
} catch (Exception e) {
Log.d(TAG, "disconnected");
connectionLost();
break;
}
}
}
/**
* Write to the connected OutStream.
* @param buffer The bytes to write
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
Log.d(TAG, "sending to device"+buffer.toString());
} catch (IOException e) {
Log.d(TAG, "Exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.d(TAG, "close() of connect socket failed", e);
}
}
}
/**
* Indicate that the connection was lost and notify the UI Activity.
*/
private void connectionLost() {
// Start the service over to restart listening mode
MenuActivityActivity.this.connectToDevice();
}
/**
* Indicate that the connection attempt failed and notify the UI Activity.
*/
private void connectionFailed() {
connectionLost();
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onPause() {
super.onPause();
}
@Override
protected void onStop() {
super.onStop();
}
@Override
protected void onDestroy() {
if(mReceiver != null)
unregisterReceiver(mReceiver); // Don't forget to unregister during onDestroy
super.onDestroy();
}
}
恩 ~ 不好意思 ~ 當初硬體搜尋 ~ 我寫成第一次搜尋到硬體ID才能連
回覆刪除在第二次搜尋到的硬體ID會造成錯誤
因為都沒有時間去看跟修改 ~
如果想直接套用建議可以使用lejos網站有直接寫成jar套件使用
(比較方便又簡單明瞭)
網站
http://lejos.sourceforge.net/
Bluetooth (leJOS NXJ API documentation)
文件:
下載lejos.jar檔案
http://lejos.sourceforge.net/tools/eclipse/plugin/nxj/
直接在Google 下載DOC檔案就有範例可以參考
Bluetooth communications sample code
然後如何加入jar
http://stackoverflow.com/questions/3280353/how-to-import-a-jar-in-eclipse
偵測訊號的強弱嗎?
回覆刪除lejos API 的涵式說明文件
回覆刪除http://lejos.sourceforge.net/p_technologies/nxt/nxj/api/index-all.html
你可以看到getSignalStrength是不是符合您的需求嗎?
^.^
作者已經移除這則留言。
回覆刪除您好~請問有單純利用藍芽傳輸字串的程式碼嗎?(我是新手)
回覆刪除不好意思 ~ 最近都在忙 ~ 那麼晚才發現您的留言!!
回覆刪除你可以參考 android 官方的文件跟程式碼
您的SDK裡面有下載Sample有著一個BluetoothChat - Bluetooth Chat
1.藍芽聊天室
http://jayxie.com/mirrors/android-sdk/resources/samples/BluetoothChat/index.html
2.詳細的介紹流程
http://developer.android.com/guide/topics/connectivity/bluetooth.html#SettingUp
^.^ (可用GOOGLE IE 自動把網頁翻成中文)
你好~我想知道其他封包的格式
回覆刪除例如:觸碰或光感
超音波是用LSWRITE和LSREAD這兩個直接指令
其他SENSOR通用嗎?
意思是說我要其他SENSOR的值,只需要去修改這部分的陣列嗎?
感謝你
抱歉~不好意思~那麼晚才回
回覆刪除是沒錯,因為是要對I2C晶片下指令
http://hsrc.static.net/Research/NXT%20I2C%20Communication/
中文:
http://www.appinventor.tw/mindsensors
像lejos API 的涵式說明文件:都有說的
http://www.lejos.org/nxt/icommand/api/icommand/nxt/comm/NXTCommand.html
比較詳細中文介紹,可以參考CH Lego Blog
http://tw.myblog.yahoo.com/ch-lego/article?mid=516
不好意思,想請教一下
回覆刪除這支程式連leJos NXT是可行的嗎?(藍芽連線的部分)
因為有試過,但Android端的程式按下連線就跳掉了
想請問有沒有跟leJos NXT藍芽連Android的相關的文獻可以參考
找了好久都找不到想要的
不是使用App Inventor 而是純正的Android的手寫程式
lejos是可行的 ^.^ , 我的程式是直接用android的藍芽事件去傳輸功能(所以沒有用lejos)
回覆刪除當初在寫的時候搜尋裝置跟連結部分寫的不太好
發現到lejos都已經把藍芽事件寫程模組化,方便大家連線又簡單易懂
我幫你找一個比較詳細的繁體PDF文件:
http://www.csie.chu.edu.tw/ezfiles/11/1011/bbs/67/bbs_67_577555_82275.pdf
簡體解說版:
http://www.diy-robots.com/resources/LejosNxtTutorial_cn/communications/communications.php
如果有什麼問題歡迎發問 ^.^
請問是否有 藍芽 發送 接收的範例嗎?
回覆刪除我有用bluetooth chat 但是手機上不能執行 謝謝
不好意思 ~ 可以問一下你的手機版本跟編譯器的版本是否相同?
刪除因為官方的範例,照理說應該不可能出錯 ^.^
所以我們來看是不是設定上有問題或者有版本互衝之類的問題..
(一步一步找問題,看問題在哪 ^.^)
請問一下喔,我還是有點看不懂,就是兩個Spinner一個是顯示設備,另外一個是顯示與哪個設備做連接是嗎?
回覆刪除其實兩個都一樣的說 ~ 那時候在想為什麼搜尋第二次裝備值會跑掉
回覆刪除所以故意新增兩個一樣,來驗證看看(其實是多此一舉)
用下面搜尋方式,你就可以找到相關連的事件了 ^.^
spinner1 => bondedDevices
spinner2 => foundedDevices
foundedDevices.add(device.getName() + "\n" + device.getAddress());
bondedDevices.add(device.getName() + "\n" + device.getAddress());
Dear Yen-Chu:
回覆刪除不好意思 請問一下 你有實作Android java mailbox read/write message from smartphone的sample??
在Android 做MailBox部分 ~ 我沒有實做過
回覆刪除不過如果要做的話 ~ 我會利用架設WebService
http://bigbabaychu.blogspot.tw/2013/07/android-eclipse-web-service.html
然後再利用JavaMail收發Mail ~ (JavaMail 範例可以搜尋Google ~ 有一堆範例的說)
忘了補充 Android 怎麼連WebService
刪除我以前是利用ksoap2.jar 檔案
http://javatutorialspoint.blogspot.tw/2012/02/android-web-service-access-using-ksoap2.html
請問 我直接套用你的程式
回覆刪除把 text 和 btn5 拿掉
然後把一些名稱改好
可以進行模擬
但是按按鍵後就錯誤跳出了
我有試著用手機安裝 手機 開啟後 直接跳出
請問是不是哪裡沒設定
還是不能這樣用 //我是新手 如果問了 笨問題 請包涵...
抱歉,最近比較忙,才那麼晚回
刪除text = 顯示訊息
btn5 = 傳送啟動A馬達指令
照理說你刪得沒錯的說
XML應該有加入藍芽的權限吧!!
如果是我Debug模式:
考慮
1.Andorid SDK版本
2.LEGO控制器版本
先做一個開啟藍芽裝置,看看有沒有異常
turnOnBluetooth
所以建議從一步一步做起比較好方面看錯誤在哪裡!!
我想問關於連線的,我有好多都看不懂
回覆刪除不知道要怎麼問才好,所以先問一點點
我沒有弄馬達的
stvorka←這個是甚麼,是指搜尋到的裝置嗎?
還有ConnectThread跟ConnectedThread差在哪裡?
不好意思..程度比較不好....><
您好阿 ^.^
刪除1.
BluetoothDevice stvorka = null;
stvork只是一個變數,以BluetoothDevice(藍芽裝置)宣告的變數
2.
mConnectThread => 用來連線上面的藍芽裝置
mConnectedThread => 確認已連線,傳送我所標示的紅色指令
作者已經移除這則留言。
回覆刪除作者已經移除這則留言。
刪除作者已經移除這則留言。
刪除作者已經移除這則留言。
刪除作者已經移除這則留言。
刪除作者已經移除這則留言。
刪除給你一個網址: 介紹的蠻詳細的說
刪除http://lp43.blogspot.tw/2012/04/bluetoothchat.html
您好:
回覆刪除不曉得在這裡請教這個問題適不適當
我目前在做一支手機對多隻機器人,目前是可以連上兩個裝置了,但是在傳值的部分
遇到了麻煩ˊˋ,按下播放鍵只有其中一隻連線的做動作,另一隻完全沒反應
想請教一下這是為什麼?要如何解決這個問題呢?
因為我沒有做過~怕無法給你詳細的解決方法(請多多包涵)
回覆刪除我自己猜測是否是藍芽的連接方式的傳送
我會把它當作TCP/IP的連接方式 ~ 把藍芽當作伺服器去連接客戶端
而有A裝置跟B裝置 ~ 兩個裝置都是客戶端 ~ 假設A裝置的連線IP為001
B裝置的連線IP為002 ~ 當你連上兩個裝置 ~ 對A裝置 藍芽發送001裝置啟動馬達
相對你要對 B裝置啟動馬達 ~ 藍芽必須發動 002 裝置啟動馬達
而我自己猜想你應該要對B裝置啟動馬達的時後 ~ 是發送001裝置啟動馬達
給你看ㄧ個網站範例跟影片(在uniqueID的部分就可以看出來 )
http://sariel.pl/2012/10/nxt-multiple-units-simple-control/
請問一下,我用bluetoothchat 範例,因為看起來跟你發布的code類似,所以請問看看,因為我手機跟其他人手機可以用這範例app互傳訊息,但是我手機配對其他藍芽模組可以配對,但是用這程式在連接那邊一直無法連接,請問這跟app code 有關係,還是藍芽模組有關係,如果可以就回我信箱 chiuka12@gmail.com ,謝謝!!如果需要我在把程式寄給你,謝謝
回覆刪除不好意思~最近忙到翻了~所以才那麼慢回
刪除我在猜想~程式如果沒有問題
那麼有可能是硬體的速率問題
可以參考這一篇:
http://gsyan888.blogspot.tw/2014/03/arduino-hc-06-at-command.html
然後我也順便寄信給你