• PX4/Pixhawk uORB


    PX4/Pixhawk的软件体系结构主要被分为四个层次

    应用程序的API:这个接口提供给应用程序开发人员,此API旨在尽可能的精简、扁平及隐藏其复杂性
    应用程序框架:这是为操作基础飞行控制的默认程序集(节点)
    库:这一层包含了所有的系统库和基本交通控制的函数
    操作系统:提供硬件驱动程序、网络、UAVCAN和故障安全系统

    1

      uORB(Micro Object Request Broker,微对象请求代理器)是PX4/Pixhawk系统中非常重要且关键的一个模块,它肩负了整个系统的数据传输任务,所有的传感器数据、GPS、PPM信号等都要从芯片获取后通过uORB进行传输到各个模块进行计算处理。实际上uORB是一套跨「进程」 的IPC通讯模块。在Pixhawk中, 所有的功能被独立以进程模块为单位进行实现并工作。而进程间的数据交互就由为重要,必须要能够符合实时、有序的特点
      
      Pixhawk使用的是NuttX实时ARM系统,uORB实际上是多个进程打开同一个设备文件,进程间通过此文件节点进行数据交互和共享。进程通过命名的「总线」交换的消息称之为「主题」(topic),在Pixhawk 中,一个主题仅包含一种消息类型,通俗点就是数据类型。每个进程可以「订阅」或者「发布」主题,可以存在多个发布者,或者一个进程可以订阅多个主题,但是一条总线上始终只有一条消息

    PX4/Pixhawk应用程序框架
    2

    uORB文件夹
    3

    文件/目录说明

    topics:系统通用接口定义的标准主题,比如电池电量转态、GPS的位置参数等
    objects_common.cpp:通用接口标准主题定义集合,如添加新主题在这里定义
    Publication.cpp:在不同的发布中遍历使用
    Subscription.cpp:在不同的订阅中遍历使用
    uORB.cpp:uORB的实现
    uORBCommon.hpp:uORB公共部分变量定义实现
    uORBCommunicator.hpp:远程订阅的接口实现,实现了对不同的通信通道管理,如添加/移除订阅者,可以基于TCP/IP或fastRPC;传递给通信链路的实现,以提供在信道上接收消息的回调
    uORBDevices_nuttx.cpp:节点操作,close,open,read,write
    uORBMain.cpp:uORB入口
    uORBManager.hpp:uORB功能函数实现头文件
    uORBManager_nuttx.cpp:uORB功能函数实现(Nuttx)
    uORBManager_posix.cpp:uORB功能函数实现(Posix)
    uORBTest_UnitTest.cpp:uORB测试

    函数功能解析

    //orb_subscribe
    int  orb_subscribe(const struct orb_metadata *meta)
    功能:订阅主题
    说明:即使订阅的主题没有被公告,但是也能订阅成功;但是在这种情况下,却得不到数据,直到主题被公告;
    参数:
        meta:uORB元对象,可以认为是主题id,一般是通过ORB_ID(主题名)来赋值;
    返回值:
        错误则返回ERROR;成功则返回一个可以读取数据、更新话题的句柄;如果待订阅的主题没有定义或声明则会返回-1,然后会将errno赋值为ENOENT;
    eg:
        int fd = orb_subscribe(ORB_ID(topicName));
    
    //orb_copy
    int  orb_copy(const struct orb_metadata *meta, int handle, void *buffer)
    功能:从订阅的主题中获取数据并将数据保存到buffer中;
    参数:
        meta:uORB元对象,可以认为是主题id,一般是通过ORB_ID(主题名)来赋值;
        handle:订阅主题返回的句柄;
        buffer:从主题中获取的数据;
    返回值:
        返回OK表示获取数据成功,错误返回ERROR;否则则有根据的去设置errno;
    eg:
        struct sensor_combined_s raw;
        orb_copy(ORB_ID(sensor_combined), sensor_sub_fd, &raw);
    
    //orb_advertise
    orb_advert_t orb_advertise(const struct orb_metadata *meta, const void *data)
    功能:公告发布者的主题;
    说明:在发布主题之前是必须的;否则订阅者虽然能订阅,但是得不到数据;
    参数:
        meta:uORB元对象,可以认为是主题id,一般是通过ORB_ID(主题名)来赋值;
        data:指向一个已被初始化,发布者要发布的数据存储变量的指针;
    返回值:错误则返回ERROR;成功则返回一个可以发布主题的句柄;如果待发布的主题没有定义或声明则会返回-1,然后会将errno赋值为ENOENT;
    eg:
        struct vehicle_attitude_s att;
        memset(&att, 0, sizeof(att));
        int att_pub_fd = orb_advertise(ORB_ID(vehicle_attitude), &att);
    
    //orb_publish
    int  orb_publish(const struct orb_metadata *meta, orb_advert_t handle, const void *data)
    功能:发布新数据到主题;
    参数:
        meta:uORB元对象,可以认为是主题id,一般是通过ORB_ID(主题名)来赋值;
        handle:orb_advertise函数返回的句柄;
        data:指向待发布数据的指针;
    返回值:OK表示成功;错误返回ERROR;否则则有根据的去设置errno;
    eg: 
        orb_publish(ORB_ID(vehicle_attitude), att_pub_fd, &att);
    
    //orb_set_interval
    int  orb_set_interval(int handle, unsigned interval)
    功能:设置订阅的最小时间间隔;
    说明:如果设置了,则在这间隔内发布的数据将订阅不到;需要注意的是,设置后,第一次的数据订阅还是由起初设置的频率来获取,
    参数:
        handle:orb_subscribe函数返回的句柄;
        interval:间隔时间,单位ms;
    返回值:OK表示成功;错误返回ERROR;否则则有根据的去设置errno;
    eg:
        orb_set_interval(sensor_sub_fd, 1000);
    
    //orb_advertise_multi
    orb_advert_t orb_advertise_multi(const struct orb_metadata *meta, const void *data, int *instance, int priority)
    功能:设备/驱动器的多个实例实现公告,利用此函数可以注册多个类似的驱动程序;
    说明:例如在飞行器中有多个相同的传感器,那他们的数据类型则类似,不必要注册几个不同的话题;
    参数:
        meta:uORB元对象,可以认为是主题id,一般是通过ORB_ID(主题名)来赋值;
        data:指向一个已被初始化,发布者要发布的数据存储变量的指针;
        instance:整型指针,指向实例的ID(从0开始);
        priority:实例的优先级。如果用户订阅多个实例,优先级的设定可以使用户使用优先级高的最优数据源;
    返回值:
        错误则返回ERROR;成功则返回一个可以发布主题的句柄;如果待发布的主题没有定义或声明则会返回-1,然后会将errno赋值为ENOENT;
    eg:
        struct orb_test t;
        t.val = 0;
        int instance0;
        orb_advert_t pfd0 = orb_advertise_multi(ORB_ID(orb_multitest), &t, &instance0, ORB_PRIO_MAX);
    
    //orb_subscribe_multi
    int  orb_subscribe_multi(const struct orb_metadata *meta, unsigned instance)
    功能:订阅主题(topic);
    说明:通过实例的ID索引来确定是主题的哪个实例;
    参数:
        meta:uORB元对象,可以认为是主题id,一般是通过ORB_ID(主题名)来赋值;
        instance:主题实例ID;实例ID=0与orb_subscribe()实现相同;
    返回值:
        错误则返回ERROR;成功则返回一个可以读取数据、更新话题的句柄;如果待订阅的主题没有定义或声明则会返回-1,然后会将errno赋值为ENOENT;
    eg:
        int sfd1 = orb_subscribe_multi(ORB_ID(orb_multitest), 1);
    
    //orb_unsubscribe
    int  orb_unsubscribe(int handle)
    功能:取消订阅主题;
    参数:
        handle:主题句柄;
    返回值:
        OK表示成功;错误返回ERROR;否则则有根据的去设置errno;
    eg:
        ret = orb_unsubscribe(handle);
    
    //orb_check
    int  orb_check(int handle, bool *updated)
    功能:订阅者可以用来检查一个主题在发布者上一次更新数据后,有没有订阅者调用过ob_copy来接收、处理过;
    说明:如果主题在在被公告前就有人订阅,那么这个API将返回“not-updated”直到主题被公告。可以不用poll,只用这个函数实现数据的获取。
    参数:
        handle:主题句柄;
        updated:如果当最后一次更新的数据被获取了,检测到并设置updated为ture;
    返回值:
        OK表示检测成功;错误返回ERROR;否则则有根据的去设置errno;
    
    //orb_stat
    int  orb_stat(int handle, uint64_t *time)
    功能:订阅者可以用来检查一个主题最后的发布时间;
    参数:
        handle:主题句柄;
        time:存放主题最后发布的时间;0表示该主题没有发布或公告;
    返回值:
        OK表示检测成功;错误返回ERROR;否则则有根据的去设置errno;
    eg:
        ret = orb_stat(handle,time);
    
    //orb_exists
    int  orb_exists(const struct orb_metadata *meta, int instance)
    功能:检测一个主题是否存在;
    参数:
        meta:uORB元对象,可以认为是主题id,一般是通过ORB_ID(主题名)来赋值;
        instance:ORB 实例ID;
    返回值:
        OK表示检测成功;错误返回ERROR;否则则有根据的去设置errno;
    eg:
        ret = orb_exists(ORB_ID(vehicle_attitude), 0);
    
    //orb_priority
    int  orb_priority(int handle, int32_t *priority)
    功能:获取主题优先级别;
    参数:
        handle:主题句柄;
        priority:存放获取的优先级别;
    返回值:
        OK表示检测成功;错误返回ERROR;否则则有根据的去设置errno;
    eg:
        ret = orb_priority(handle, &priority);

    举例
    发布方

    orb_advert_t _report_pub;
    auto report; //自定义数据
    
    ORB_DECLARE(vehicle_gps_position);
    
    if (_report_pub != nullptr) {
        //发布新数据到主题
        orb_publish(ORB_ID(vehicle_gps_position), _report_pub, &report);
    } else {
        //如果还没有公告主题,首先公布
        _report_pub = orb_advertise(ORB_ID(vehicle_gps_position), &report);
    }

    订阅方

    int _gps_sub;
    bool updated = false;
    
    _gps_sub = orb_subscribe(ORB_ID(vehicle_gps_position));
    
    orb_check(_gps_sub, &updated);
    
    struct vehicle_gps_position_s _gps_pos; //vehicle_gps_position_s自定义类型
    
    if (updated) {
        if (OK == orb_copy(ORB_ID(vehicle_gps_position), _gps_sub, &_gps_pos)) {
            ;
        }
  • 相关阅读:
    03 类与对象
    课堂作业02程序设计
    动手动脑
    做课题时的一些问题
    课题一
    《大道至简》JAVA伪代码读后感
    题目-兔子繁衍问题
    题目-求一个日期是该年中的第几天
    题目-查验身份证
    题目-删除重复字符
  • 原文地址:https://www.cnblogs.com/zhangxuechao/p/11709522.html
Copyright © 2020-2023  润新知