在Pixhawk中,所有的功能被独立以进程模块为单位进行实现并工作。而每个进程模块都有一个(或多个?)主题信息topic(topic可以在Firmware/msg里查看到所有的可使用的)。所有的进程进行数据交互,其实就是将这些topic扔在一个市场上供大家选取。而uORB(Micro Object Request Broker,微对象请求代理器)就是这个市场。uORB在Pixhawk系统中肩负了整个系统的数据传输任务,所有的传感器信息或者中间计算量得到之后都通过UORB进行传输。
uORB的规则如下:
对应uORB的话题发布者:公告(advertise) + 发布(publish);
对于uORB的话题接收者:订阅(subscribe) + 查询(poll阻塞式等待或check更新) + 复制(copy)。
以Pixhawk中提供的例子为例(src/examples/px4_simple_app),利用对程序的注释,详细说明以上规则。
/****************************************************************************
*
* Copyright (c) 2012-2016 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file px4_simple_app.c
* Minimal application example for PX4 autopilot
*
* @author Example User <mail@example.com>
*/
#include <px4_config.h>
#include <px4_tasks.h>
#include <px4_posix.h>
#include <unistd.h>
#include <stdio.h>
#include <poll.h>
#include <string.h>
#include <uORB/uORB.h>
#include <uORB/topics/sensor_combined.h>
#include <uORB/topics/vehicle_attitude.h>
__EXPORT int px4_simple_app_main(int argc, char *argv[]);
int px4_simple_app_main(int argc, char *argv[])
{
PX4_INFO("Hello Sky!");
/* subscribe to sensor_combined topic */
/* 订阅 一个sensor_combined (传感器——联合)主题*/
int sensor_sub_fd = orb_subscribe(ORB_ID(sensor_combined));
/*
sensor_combined 为所要订阅信息的ID,所有能够被订阅的信息ID都在Firmware/msg中能看到
sensor_sub_fd 为订阅函数的返回值,有以下几种情况:
1:错误则返回ERROR;
2:成功则返回一个可以读取数据、更新话题的句柄;
3:如果待订阅的主题没有定义或声明则会返回-1
*/
/* limit the update rate to 5 Hz*/
/* 限制更新频率为5HZ */
orb_set_interval(sensor_sub_fd, 200);
/* advertise attitude topic*/
/* 定义结构体,表示广播信息 */
struct vehicle_attitude_s att;
memset(&att, 0, sizeof(att)); // 申请内存并初始化
/* 广播(公告)信息*/
orb_advert_t att_pub = orb_advertise(ORB_ID(vehicle_attitude), &att);
/*
vehicle_attitude为要广播的信息ID;
att为实际要广播的信息;
att_pub为返回的对象指针,有以下几种情况:
1:错误则返回ERROR;
2:成功则返回一个可以读取数据、更新话题的句柄;
3:如果待广播的主题没有定义或声明则会返回-1
*/
/* one could wait for multiple topics with this technique, just using one here */
px4_pollfd_struct_t fds[] = {
{ .fd = sensor_sub_fd, .events = POLLIN },
/* there could be more file descriptors here, in the form like:
* { .fd = other_sub_fd, .events = POLLIN },
*/
};
int error_counter = 0;
/*×××××××××××××××××××检测更新 阻塞等待x××××××××××××××××××*/
for (int i = 0; i < 5; i++) {
/* wait for sensor update of 1 file descriptor for 1000 ms (1 second) */
/*阻塞等待函数,时间为1s*/
int poll_ret = px4_poll(fds, 1, 1000);
/*
该函数返回值有几种情况:
大于0:表示等到数据更新;
等于0:表示没有等到数据更新,
小于0则表示发生错误。
*/
/* handle the poll result */
/* 根据返回值进行数据处理*/
if (poll_ret == 0) {
/* this means none of our providers is giving us data */
PX4_ERR("Got no data within a second");
} else if (poll_ret < 0) {
/* this is seriously bad - should be an emergency */
if (error_counter < 10 || error_counter % 50 == 0) {
/* use a counter to prevent flooding (and slowing us down) */
PX4_ERR("ERROR return value from poll(): %d", poll_ret);
}
error_counter++;
} else { // 表示数据有更新
if (fds[0].revents & POLLIN) {
/* obtained data for the first file descriptor */
struct sensor_combined_s raw;
/* copy sensors raw data into local buffer*/
/* 复制出原始数据 */
orb_copy(ORB_ID(sensor_combined), sensor_sub_fd, &raw);
/*
sensor_combined为所要复制的主题ID;
sensor_sub_fd文件描述符(订阅返回值);
raw为需要复制的缓存地址)。
*/
PX4_INFO("Accelerometer:\t%8.4f\t%8.4f\t%8.4f", // PX4——INFO类似于C语言的printf 函数
(double)raw.accelerometer_m_s2[0],
(double)raw.accelerometer_m_s2[1],
(double)raw.accelerometer_m_s2[2]);
/* set att and publish this information for other apps
the following does not have any meaning, it's just an example
*/
att.q[0] = raw.accelerometer_m_s2[0];
att.q[1] = raw.accelerometer_m_s2[1];
att.q[2] = raw.accelerometer_m_s2[2];
/* 发布数据 */
orb_publish(ORB_ID(vehicle_attitude), att_pub, &att);
/*
vehicle_attitude为需要发布的主题ID,后续可以通过该ID订阅数据att;
att_pub为广播时返回的对象指针;
att为需要发布的真实数据。
*/
}
/* there could be more file descriptors here, in the form like:
* if (fds[1..n].revents & POLLIN) {}
*/
}
}
PX4_INFO("exiting");
return 0;
}
该段代码的流程为:
1、订阅ID为sensor_combined 的信息
2、广播ID为vehicle_attitude的信息
3、采用阻塞等待方式等候sensor_combined 的信息到来
4、等到数据来之后Copy ID为sensor_combined下的数据给raw数据
5、将raw中需要的数据赋值给att
6、发布ID为vehicle_attitude的信息,其中的数据为att