先允许我卖个萌:
—。—-
看了一下午关于px4中的uorb的分析,终于有所感悟了。信息量有点大,先让我缓缓,理理思绪。
先说说我之前的疑惑吧:
**
疑惑1
.** 在一开始学习px4的时候,就在网上看到很多人说uorb是一个很难理解的东西。看看概念,谁都知道他是一种通信机制,但我需要一种更加通俗易懂的解释。那就看看我的解释。
什么是uorb
在PX4中,应用程序间发送信息的独立通道叫做“topics”,在px4中很重要的一个东西就是传感器的数据信息,于是我们就需要“多传感器间的uORB消息机制”(sensor_combinedtopic)。这种消息机制使得整个系统能够同步实时传感器数据。另外我需要提的是,传感器将他的数据信息只发布(上传)到这个通道,至于传给谁他不管,而接受方订阅一个信息也是从这个通道,而不是从某个传感器,也就是接收方不管信息从哪里来。然后就可以推广到一些非传感器的器件。除此外,我们也需要这个通道去发布我们自己的信息,比如飞机的姿态,他是无法从传感器直接读出来得,是需要我们人为通过算法去解算,然后我们就将解算出来的信息在发布出去,至于谁要用这个数据,看你咯0.0
疑惑2
:我之前以为如果我们需要去实时显示某一传感器的信息,先要去写传感器的发布数据程序,然后写我们的订阅数据的程序。但后面我错了,因为我在看源码(/src/Firmware/src/modules/sensors)下的sensors.cpp时,意外发现了了不得的东西,就是publish,上图:
这段程序的前面部分是对传感器接受的数据进行处理,比如滤波,降噪等,然后选出最好的(vote机制),然后publish。
也就是说,传感器发布数据是自动的,不需要我们去写发布程序。(惊不惊喜,意不意外 0.0)
疑惑三
如何理解这个orb-id,我后来的理解是帮助你辨识和记忆这个发布或订阅的东西是啥。比如
orb_subscribe(ORB_ID(sensor_combined));
让我们知道这是订阅传感器的数据。
orb_publish(ORB_ID(vehicle_attitude), att_pub_fd, &att);
让我们知道发布的数据是关于飞机姿态的。
px4_simple_app
#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[])
{
int sensor_sub_fd = orb_subscribe(ORB_ID(sensor_combined));// 订阅
orb_set_interval(sensor_sub_fd, 1000); //设置订阅时间间隔
/* 一个应用可以等待多个主题,在这里只等待一个主题 */
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;
for (int i = 0; i < 5; i++) {
/* wait for sensor update of 1 file descriptor for 1000 ms (1 second) */
int poll_ret = px4_poll(fds, 1, 1000);
/* handle the poll result */
if (poll_ret == 0) {
/* this means none of our providers is giving us data */
PX4_ERR("[px4_simple_app] 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("[px4_simple_app] 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;//sensor_combined_s是在头文件中定义的,里面有传感器发布的数据,也可以用来储存copy来的数据
/* copy sensors raw data into local buffer */
orb_copy(ORB_ID(sensor_combined), sensor_sub_fd, &raw);//copy前必须要有subscribe,因为需要他的句柄。
PX4_WARN("[px4_simple_app] Accelerometer:\t%8.4f\t%8.4f\t%8.4f",
(double)raw.accelerometer_m_s2[0],
(double)raw.accelerometer_m_s2[1],
(double)raw.accelerometer_m_s2[2]);
}
}
}
PX4_INFO("exiting");
return 0;
}
说明:
1. sensor_combined.h,系统自带的,他就是传感器发布信息的去处。我们也是从里面订阅信息的。
sensor_combined.h里面有:
2.vehicle_attitude.h是系统写好的用来放我们自己要发布数据,当然我们也可以自己写一个topic来发布我们的数据,比如以后要加入的超声波传感器就需要我们自己去写。
vehicle_attitude.h里面有:
px4_simple_app改进版
#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[])
{
/* subscribe to sensor_combined topic */
int sensor_sub_fd = orb_subscribe(ORB_ID(sensor_combined));
orb_set_interval(sensor_sub_fd, 1000);
/* 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);
/* 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;
for (int i = 0; i < 5; i++) {
/* wait for sensor update of 1 file descriptor for 1000 ms (1 second) */
int poll_ret = px4_poll(fds, 1, 1000);
/* handle the poll result */
if (poll_ret == 0) {
/* this means none of our providers is giving us data */
PX4_ERR("[px4_simple_app] 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("[px4_simple_app] 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);
PX4_WARN("[px4_simple_app] Accelerometer:\t%8.4f\t%8.4f\t%8.4f",
(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 */
att.rollspeed = raw.accelerometer_m_s2[0];
att.pitchspeed = raw.accelerometer_m_s2[1];
att.yawspeed = raw.accelerometer_m_s2[2];
orb_publish(ORB_ID(vehicle_attitude), 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.在改进版中加入了发布的过程,即我们将订阅的传感器信息变为姿态信息后发布出去了。
2.很多topic就是既要有输入也要有输出。输入就是订阅的,输出就是发布的。
3.发布前必须要有公告,因为你需要公告的句柄。
(后面我在想起什么在补充)