1 廢話很少說,Tower的鏈接方式之一是經過android經過手機自帶藍牙模塊,和遙控器藍牙通訊,最後在鏈接飛空,飛空是一塊單片機,裏面也有一套程序處理邏輯,而後遙控器坐傳輸媒介android
這樣作的好處就是把一些用戶操做放到android上面,好比航點規劃,客服端控制飛機的起飛,降落等,最後飛空來控制無人機玩成一系列的操做安全
鏈接方式如圖ide
2 今天主要說一下Mavlink的鏈接首先在Tower的源碼裏構建了一個類函數
public class MAVLinkClient implements MAVLinkStreams.MAVLinkOutputStream { public MAVLinkClient(Context context, MAVLinkStreams.MavlinkInputStream listener) { this.listener = listener; } private void connectMAVConnection() { } public void sendMavPacket(MAVLinkPacket pack) { } @Override public void toggleConnectionState() { if (isConnected()) { closeConnection(); } else { openConnection(); } } }
這個了主要實習了 鏈接,切換鏈接,發送數據包,和注入一個listener , 這個listener主要是接受到數據的時候回調,因此這個類主要就是實習這個幾個功能,Tower向無人機發送數據基本都是經過這個sendMavPacket方法去實現的this
3 咱們看看listener是個什麼東西spa
public interface MavlinkInputStream { void notifyConnected(); void notifyDisconnected(); void notifyReceivedData(MAVLinkMessage m); }
這個listener的聲明 ,他是用來處理收到消息的 ,調用notifyReceivedData 接受一個MavLinkmessage線程
4 接來咱們看MavLinkClient的初始化,差看源碼能夠看到,在Application的初始化OnCreatef 方法裏面 MAVLinkClient MAVClient = new MAVLinkClient(this, this); 能夠看到Application 實現了MavlinkInputStream 接口,而且實現了 notifyReceivedData 方法code
@Override public void notifyReceivedData(MAVLinkMessage msg) { mavLinkMsgHandler.receiveData(msg); }
5 這樣你就很容易看到在哪裏處理 MAVLinkMessage 了,so , MavLinkMsgHandler 就是 MAVLinkMessage 的處類了,你能夠看到關於多種MAVLinkMessage 的處理,這些消息有心跳消息,事件消息等。。。blog
6 如今條理是否是很清楚了,那咱們就來看android若是經過藍牙鏈接飛控的,首先你必須會藍牙鏈接的基礎知識,網上資料不少接口
7 咱們看鏈接函數
private void connectMAVConnection() { bluetoothConnection.addMavLinkConnectionListener("blue",mConnectionListener); Toast.makeText(parent, R.string.status_connecting, Toast.LENGTH_SHORT).show(); if (bluetoothConnection.getConnectionStatus() == MavLinkConnection.MAVLINK_DISCONNECTED) { bluetoothConnection.connect(); } }
直接調用了bluetoothConnection.connect(), MavLinkConnection bluetoothConnection是一個抽象類,也住無人機地面站裏面的一個比較核心的類,
/** * Listen for incoming data on the mavlink connection. */ private final Runnable mConnectingTask = new Runnable() { @Override public void run() { Thread sendingThread = null, loggingThread = null; try { // Open the connection openConnection(); mConnectionStatus.set(MAVLINK_CONNECTED); // Launch the 'Sending', and 'Logging' threads sendingThread = new Thread(mSendingTask, "MavLinkConnection-Sending Thread"); sendingThread.start(); final Parser parser = new Parser(); parser.stats.mavlinkResetStats(); final byte[] readBuffer = new byte[READ_BUFFER_SIZE]; while (mConnectionStatus.get() == MAVLINK_CONNECTED&&!isAndroidfor4_4()) { int bufferSize = readDataBlock(readBuffer); if (readBuffer==null||readBuffer.length==0){ continue; } handleData(parser, bufferSize, readBuffer); } } catch (Exception e) { Log.i("===>>","disconent"); if (loggingThread != null && loggingThread.isAlive()) { loggingThread.interrupt(); } if (sendingThread != null && sendingThread.isAlive()) { sendingThread.interrupt(); } mConnectionStatus.set(MAVLINK_DISCONNECTED); disconnect(); } }
8 這個類有幾個核心的方法 1打開鏈接 openConnection(),2 sendingThread不停地發送數據 3 handleData()處理數據,在其實現類裏面主要也是完成這3個方法,
public Bluetoothfor2_0Connection(Context parentContext) { prefs = new DroidPlannerPrefs(parentContext); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) { Log.d(BLUE, "Null adapters"); } } protected void openAndroidConnection() throws IOException { Log.d(BLUE, "Connect"); // Reset the bluetooth connection resetConnection(); // Retrieve the stored device BluetoothDevice device = null; final String addressName = prefs.getBluetoothDeviceAddress(); if (addressName != null) { // strip name, use address part - stored as <address>;<name> final String part[] = addressName.split(";"); try { device = mBluetoothAdapter.getRemoteDevice(part[0]); } catch (IllegalArgumentException ex) { // invalid configuration (device may have been removed) // NOP fall through to 'no device' } } // no device if (device == null) device = findSerialBluetoothBoard(); Log.d(BLUE, "Trying to connect to device with address " + device.getAddress()); Log.d(BLUE, "BT Create Socket Call..."); bluetoothSocket = device.createInsecureRfcommSocketToServiceRecord(UUID .fromString(UUID_SPP_DEVICE)); Log.d(BLUE, "BT Cancel Discovery Call..."); mBluetoothAdapter.cancelDiscovery(); Log.d(BLUE, "BT Connect Call..."); bluetoothSocket.connect(); // Here the IOException will rise on BT // protocol/handshake error. Log.d(BLUE, "## BT Connected ##"); out = bluetoothSocket.getOutputStream(); in = bluetoothSocket.getInputStream(); } @Override protected int readDataBlock(byte[] buffer) throws IOException { return in.read(buffer); } @Override protected void sendBuffer(byte[] buffer) throws IOException { if (out != null) { out.write(buffer); } }
9 handledata 方法就是回調以前的 listener.notifydatareceiver(),是否是以前地方了,至於發送數據
private final Runnable mSendingTask = new Runnable() { @Override public void run() { int msgSeqNumber = 0; try { while (mConnectionStatus.get() == MAVLINK_CONNECTED) { final MAVLinkPacket packet = mPacketsToSend.take(); packet.seq = msgSeqNumber; byte[] buffer = packet.encodePacket(); if (buffer==null|| buffer.length==0){ continue; } try { sendBuffer(buffer); queueToLog(packet); } catch (IOException e) { reportComError(e.getMessage()); mLogger.logErr(TAG, e); } msgSeqNumber = (msgSeqNumber + 1) % (MAX_PACKET_SEQUENCE + 1); } } catch (InterruptedException e) { };
發送數據其實也是Mavclient的 sendMavPacket方法,裏面有一個阻塞隊列的東西,線程安全的雙端隊列,可能須要你看看,思路很清晰,2可能會講 MavlinkMessage
@Override public void sendMavPacket(MAVLinkPacket pack) { if (!isConnected()) { return; } bluetoothConnection.sendMavPacket(pack); }