Tower 實戰一:MavLink的鏈接與通訊

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);
    }
相關文章
相關標籤/搜索