[pixhawk笔记]7-mavlink消息机制

邵朋院的代码世界 邵朋院的代码世界     2022-09-17     408

关键词:

前一篇学习了uORB,用于px4中各个模块的进程间通信,下来学习MAVLink,用于飞控和地面站之间的通信。教程中主要给出了使用MAVLink的发送和接收消息的方法。
完整的MAVLink消息列表见该网页

  • 创建一个自定义MAVLink消息
    假设存在/msg/ca_trajectory.msg定义了ca_trajectory的uORB主题。(笔者下载到的代码中没有自定义的ca_trajectory主题)
    如果没有,自行在/msg文件夹下面添加ca_trajectory.msg,笔者添加内容如下(该内容来自于Fantasy大神的博客):
    uint64_t time_start_usec
    uint64_t time_stop_usec
    uint32_t coefficients
    uint16_t seq_id
    
    #TOPICS ca_trajectory
    

    同时在mavlink/include/mavlink/v2.0/custom_message/mavlink_msg_ca_trajectory.h中存在ca_trajectory的自定义mavlink消息。(笔者下载的代码中也没有该部分)  
    没有的话可以自己添加自定义mavlink消息,教程见官方文档
    先自定义在mavlink/include/mavlink/v2.0/message_definitions/下创建自定义消息custom_message.xml文件,与ca_trajectory中结构一致,内容如下:

    <?xml version="1.0"?>
    <mavlink>
        <include>common.xml</include>
        <!-- NOTE: If the included file already contains a version tag, remove the version tag here, else uncomment to enable. -->
        <!--<version>3</version>-->
        <enums>
        </enums>
        <messages>
            <message id="166" name="CA_TRAJECTORY">
                <description>This message encodes all of the raw rudder sensor data from the USV.</description>
                <field type="uint64_t" name="timestamp">Timestamp in milliseconds since system boot</field>
                <field type="uint64_t" name="time_start_usec">start time, unit usec.</field>
                <field type="uint64_t" name="time_stop_usec">stop time, unit usec.</field>
                <field type="uint32_t" name="coefficients">as it says.</field>
                <field type="uint16_t" name="seq_id">can not cheat any more.</field>
            </message>
        </messages>
    </mavlink>
    

    注意需要添加一个timestamp的成员,因为在编译时为了记录,会增加一个timestamp的成员。然后使用mavlink generator生成c语言源文件。
    没有mavlink generator的同学可以用git下载并使用:

    git clone https://github.com/mavlink/mavlink mavlink-generator
    cd mavlink-generator
    python mavgenerate.py
    

    XML文件定位可以直接定位到mavlink/include/mavlink/v2.0/message_definitions/custom_message.xml,Out目录定位到mavlink/include/mavlink/v2.0/,注意语言选择C,协议选择2.0,如下图所示:

    然后点击Generate即可生成c代码源文件。

  • 发送自定义MAVLink消息
    自定义信息的发送主要通过修改src/modules/mavlink/下的mavlink_messsages.cpp文件来实现。
    • 添加自定义消息的头文件
      #include <uORB/topics/ca_trajectory.h>
      #include <v2.0/custom_messages/mavlink_msg_ca_trajectory.h>
      

      注意添加到已有包含文件的尾部,否则编译时可能会出现类型为定义的错误。

    • 创建自定义消息对应的类

      class MavlinkStreamCaTrajectory : public MavlinkStream
      {
      public:
          const char *get_name() const
          {
              return MavlinkStreamCaTrajectory::get_name_static();
          }
      
          static const char *get_name_static()
          {
              return "CA_TRAJECTORY";
          }
      
          static uint16_t get_id_static()
          {
              return MAVLINK_MSG_ID_CA_TRAJECTORY;
          }
      
          uint16_t get_id()
          {
              return get_id_static();
          }
      
          static MavlinkStream *new_instance(Mavlink *mavlink)
          {
              return new MavlinkStreamCaTrajectory(mavlink);
          }
      
          unsigned get_size()
          {
              return MAVLINK_MSG_ID_CA_TRAJECTORY_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES;
          }
      
      private:
          MavlinkOrbSubscription *_sub;
          uint64_t _ca_traj_time;
      
          /* do not allow top copying this class */
          MavlinkStreamCaTrajectory(MavlinkStreamCaTrajectory &);
          MavlinkStreamCaTrajectory& operator = (const MavlinkStreamCaTrajectory &);
      
      protected:
          explicit MavlinkStreamCaTrajectory(Mavlink *mavlink) : MavlinkStream(mavlink),
              _sub(_mavlink->add_orb_subscription(ORB_ID(ca_trajectory))),  // make sure you enter the name of your uorb topic here
              _ca_traj_time(0)
          {}
      
          bool send(const hrt_abstime t)
          {
              struct ca_trajectory_s _ca_trajectory;    //make sure ca_trajectory_s is the definition of your uorb topic
      
              if (_sub->update(&_ca_traj_time, &_ca_trajectory)) {
      
                  mavlink_ca_trajectory_t msg;//make sure mavlink_ca_trajectory_t is the definition of your custom mavlink message 
      
                  msg.timestamp = _ca_trajectory.timestamp;
                  msg.time_start_usec = _ca_trajectory.time_start_usec;
                  msg.time_stop_usec  = _ca_trajectory.time_stop_usec;
                  msg.coefficients =_ca_trajectory.coefficients;
                  msg.seq_id = _ca_trajectory.seq_id;
      
                  mavlink_msg_ca_trajectory_send_struct(_mavlink->get_channel(), &msg);
                  return true;
              }
              return false;
          }
      };
      

      注意该类的函数成员返回类型和MAVLink v1.0稍有不同,笔者发现下载到的master分支和stable分支的函数类型都有所不同,具体以下载代码为准,可以参考代码中已有的其他消息例子来编写。

    • 在附加流类中添加该自定义项

      StreamListItem *streams_list[] = {
      ...
      new StreamListItem(&MavlinkStreamCaTrajectory::new_instance, &MavlinkStreamCaTrajectory::get_name_static, &MavlinkStreamCaTrajectory::get_id_static),
      nullptr
      };
    • 在mavlink_main.cpp中加入自定义消息的更新频率:
      configure_stream("CA_TRAJECTORY", 100.0f);  
  • 接收自定义MAVLink消息
    接收自定义消息主要通过修改mavlink_receiver.hmavlink_receiver.cpp来实现,加入一个消息处理函数,并调用他。
    • 在mavlink_receiver.h中加入如下代码:
      • 添加自定义消息头文件:
        #include <uORB/topics/ca_trajectory.h>
        #include <v2.0/custom_messages/mavlink_msg_ca_trajectory.h>
      • 在类中添加一个uORB消息发布者
        orb_advert_t _ca_traj_msg_pub;
      • 在类Mavlink_Receiver中增加一个消息处理函数

        void handle_message_ca_trajectory_msg(mavlink_message_t *msg);
    • 在mavlink_receiver.cpp中加入如下代码:

      • 实现消息处理函数
        void
        MavlinkReceiver::handle_message_ca_trajectory_msg(mavlink_message_t *msg)
        {
            mavlink_ca_trajectory_t traj;
            mavlink_msg_ca_trajectory_decode(msg, &traj);
        
            struct ca_trajectory_s f;
            memset(&f, 0, sizeof(f));
        
            f.timestamp = hrt_absolute_time();
            f.seq_id = traj.seq_id;
            f.time_start_usec = traj.time_start_usec;
            f.time_stop_usec = traj.time_stop_usec;
            f.coefficients = traj.coefficients;
        
            if (_ca_traj_msg_pub == nullptr) {
                _ca_traj_msg_pub = orb_advertise(ORB_ID(ca_trajectory), &f);
        
            } else {
                orb_publish(ORB_ID(ca_trajectory), _ca_traj_msg_pub, &f);
            }
        }
        

        在该函数中实现了对消息的解包及发布。

      • MavlinkReceiver::handle_message()中调用消息处理函数

        MavlinkReceiver::handle_message(mavlink_message_t *msg)
         {
             switch (msg->msgid) {
                ...
            case MAVLINK_MSG_ID_CA_TRAJECTORY:
                handle_message_ca_trajectory_msg(msg);
                break;
                ...
             }
                ...
        }    
        

        但是,在nsh里面看不到该消息发布的数据,哪位高手能告诉我哪错了……

          

[pixhawk笔记]2-飞行模式

...4.io/en/concept/flight_modes.html ,有不对之处,敬请指正。pixhawk的飞行模式如下:MANUAL(手动模式)固定翼/车/船MANUAL(手动模式):飞手控制输入直接到输出混控器 STABILIZED(增稳模式):飞手控制作为俯仰和滚转角度指令... 查看详情

pixhawk原生固件在windows下环境搭建笔记

首先参考了以下几篇博客博客1:https://zhuanlan.zhihu.com/p/25198079博客2:http://blog.csdn.net/oqqenvy12/article/details/52035127博客3:http://blog.csdn.net/whyscience/article/details/524243641.开始还傻傻的装git,其实不必,其实PX4Toolch 查看详情

[pixhawk笔记]3-架构概览

本文主要内容翻译自:https://dev.px4.io/en/concept/architecture.html总体架构:PX4代码由两层组成:PX4飞行栈和PX4中间件。其中,前者是一套飞行控制软件,后者是一套通用的机器人中间件,可以支持任意类型的自主机器人。PX4代码具有... 查看详情

-android的消息机制读书笔记(代码片段)

目录1.Android的消息机制概述1.1Android的消息机制是什么?1.2Handler就是专门用来更新UI的,这种说法对吗?为什么?1.3在子线程真的不能更新UI吗?1.4Android系统为什么使用单线程模型来访问UI?1.5为什么说Handle... 查看详情

源码解析——消息机制

映象笔记的链接:源码解析——消息机制 本文出自“wauoen”博客,请务必保留此出处http://7183397.blog.51cto.com/7173397/1968269 查看详情

[pixhawk笔记]11-windows下px4代码查看

由于项目需要做基于Simulink的PX4二次开发,在Windows下面做,所以需要在Windows下查看PX4的代码,故写该文档,记录环境安装和配置过程。按照该网页安装工具链:WindowsInstallationInstructions。安装后用工具链中的eclipse查看代码,由于... 查看详情

objc_msgsend消息传递学习笔记–消息转发

该文是objc_msgSend消息传递学习笔记–对象方法消息传递流程的基础上继续探究源码,请先阅读上文。 消息转发机制(messageforwarding) Objective-C在调用对象方法的时候,是通过消息传递机制来查询且执行方法。如果想令该... 查看详情

android学习笔记——handler消息分发

Handler消息分发Handler事件分发机制是基于生产者/消费者模型,使用Linux下的pipe(管道)实现的,读取和写入相互协调实现等待/通知。Handler机制是用于处理线程间消息分发的。主要角色:Handler(事件处理&#x... 查看详情

android:安卓学习笔记之handler机制的简单理解和使用(代码片段)

AndroidHandler机制的简单理解和使用Handler机制1、Handler使用的引出2、背景和定义3、作用和意义4、主要参数5、工作原理及流程5.1、对应关系6、深入分析Handler机制源码6.1、Handler机制的核心类6.2、核心方法6.3、方式1:使用Handler.s... 查看详情

activemq笔记2-消息持久化(代码片段)

为了避免意外宕机以后丢失信息,需要做到重启后可以恢复消息队列,消息系统一般都会采用持久化机制。ActiveMQ的消息持久化机制有JDBC,AMQ,KahaDB和LevelDB,无论使用哪种持久化方式,消息的存储逻辑都是一致的。也就是说发... 查看详情

rabbitmq笔记-工作队列

工作队列的主要思想是不用等待资源密集型的任务处理完成,为了确保消息或者任务不会丢失,rabbitmq支持消息确信ACK。ACK机制是消费者端从rabbitmq收到消息并处理完成后,反馈给rabbitmq,rabbitmq收到反馈信息后将消息从队列中删... 查看详情

关于handler的学习笔记

1,Handler机制和原理?    Handler是一个消息分发对象,先进先出。当Hanlder发送消息时,首先进入消息队列,通过Looper对消息队列进来轮询,处理未处理的消息,并发给对应Handler进行处理。消息的发送和接收不是同... 查看详情

rabbitmq笔记08消息队列rabbitmq之防止消息丢失的三种方式(生产者消息确认消费者消息确认消息持久化)(代码片段)

这篇文章,主要介绍消息队列RabbitMQ之防止消息丢失的三种方式(生产者消息确认、消费者消息确认、消息持久化)。目录一、防止消息丢失1.1、消息确认机制(生产者)(1)生产者丢失消息(2... 查看详情

rabbitmq笔记(代码片段)

RabbitMQ1MQ引言1.1什么是MQMQ(MessageQuene):翻译为消息队列,通过典型的生产者和消费者模型,生产者不断向消息队列中生产消息,消费者不断的从队列中获取消息。因为消息的生产和消费都是异步的,而且只关心消息的发送和接... 查看详情

rabbitmq笔记(代码片段)

RabbitMQ1MQ引言1.1什么是MQMQ(MessageQuene):翻译为消息队列,通过典型的生产者和消费者模型,生产者不断向消息队列中生产消息,消费者不断的从队列中获取消息。因为消息的生产和消费都是异步的,而且只关心消息的发送和接... 查看详情

cloudstream官方文档阅读笔记3

核心概念4.1应用模型一个springcloudStream应用包括了一个消息中间件作为核心。某个应用通过springcloudStream使用input和output通道与外界(注:消息队列)进行消息交换。通道通过中间件专用的绑定机制连接到外部的虚拟主机(注:原文为br... 查看详情

handler机制源码分析笔记(代码片段)

前言Handler机制作为AndroidFramework层的基础,很多问题需要研究一下源码才可以弄清楚,如果只是停留在对于一些面试答案的背诵上是没有更好的代码理解的。所以我想结合面试问题来研究Handler源码。文章内容主要分成以... 查看详情

三.简单绘图--windows编程课程学习笔记(代码片段)

3.1MFC消息映射机制首先新建一个单文档类型的MFCAPPWizard(exe)工程,取名MyMFCApp。试完成左键消息的捕捉。在3.1.1ClassWizard(类向导)      项目->类向导。有命令、消息、虚函数、成员变量、方法五个选项... 查看详情