当前位置: 首页 > news >正文

Tower 实战一:MavLink的连接与通信

1 废话不多说,Tower的连接方式之一是通过android通过手机自带蓝牙模块,和遥控器蓝牙通信,最后在连接飞空,飞空是一块单片机,里面也有一套程序处理逻辑,然后遥控器坐传输媒介

这样做的好处就是把一些用户操作放到android上面,比如航点规划,客服端控制飞机的起飞,降落等,最后飞空来控制无人机玩成一系列的操作

连接方式如图

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方法去实现的

3 我们看看listener是个什么东西

    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 方法

    @Override
    public void notifyReceivedData(MAVLinkMessage msg) {
        mavLinkMsgHandler.receiveData(msg);
    }

 

5 这样你就很容易看到在哪里处理 MAVLinkMessage 了,so , MavLinkMsgHandler 就是 MAVLinkMessage 的处类了,你可以看到关于多种MAVLinkMessage 的处理,这些消息有心跳消息,事件消息等。。。

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);
    }

 

转载于:https://www.cnblogs.com/seanzhoutao/p/6094613.html

相关文章:

  • hive 数据清理--数据去重
  • rails生成器生成自定义controller模板
  • 关于适配器中设置显示与隐藏的问题
  • 递归的例子
  • 各种居中对齐
  • 面向对象 封装 、继承
  • [学习笔记]背包问题(一)
  • SQL 基础语法(一)
  • HTTP慢速DOS(slow http denial of service attack)
  • PAT甲题题解-1104. Sum of Number Segments (20)-(水题)
  • Java 8 Lambda表达式,让你的代码更简洁
  • 使用scrapy创建工程
  • 文件属性
  • 插入排序
  • python核心编程第六章练习--6.5.d
  • JS 中的深拷贝与浅拷贝
  • iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码...
  • JavaScript设计模式之工厂模式
  • LeetCode18.四数之和 JavaScript
  • SpiderData 2019年2月13日 DApp数据排行榜
  • Swift 中的尾递归和蹦床
  • 程序员最讨厌的9句话,你可有补充?
  • 回流、重绘及其优化
  • 基于HAProxy的高性能缓存服务器nuster
  • 开源SQL-on-Hadoop系统一览
  • 前端学习笔记之原型——一张图说明`prototype`和`__proto__`的区别
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 浅谈web中前端模板引擎的使用
  • 微信小程序实战练习(仿五洲到家微信版)
  • 学习HTTP相关知识笔记
  • 用 Swift 编写面向协议的视图
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • ​直流电和交流电有什么区别为什么这个时候又要变成直流电呢?交流转换到直流(整流器)直流变交流(逆变器)​
  • #pragma 指令
  • $$$$GB2312-80区位编码表$$$$
  • (12)目标检测_SSD基于pytorch搭建代码
  • (173)FPGA约束:单周期时序分析或默认时序分析
  • (Java实习生)每日10道面试题打卡——JavaWeb篇
  • (分类)KNN算法- 参数调优
  • (附源码)springboot家庭装修管理系统 毕业设计 613205
  • (提供数据集下载)基于大语言模型LangChain与ChatGLM3-6B本地知识库调优:数据集优化、参数调整、Prompt提示词优化实战
  • (转)Groupon前传:从10个月的失败作品修改,1个月找到成功
  • (转)linux下的时间函数使用
  • (轉)JSON.stringify 语法实例讲解
  • .[hudsonL@cock.li].mkp勒索病毒数据怎么处理|数据解密恢复
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .NET Core MongoDB数据仓储和工作单元模式封装
  • .NET Framework与.NET Framework SDK有什么不同?
  • .NET 将多个程序集合并成单一程序集的 4+3 种方法
  • .Net 路由处理厉害了
  • .net操作Excel出错解决
  • .NET框架
  • .net专家(高海东的专栏)
  • @RestController注解的使用
  • [ CTF ] WriteUp- 2022年第三届“网鼎杯”网络安全大赛(朱雀组)