!REDIRECT “https://docs.px4.io/master/zh/ros/mavros_custom_messages.html

将自定义消息从 MOVROS 发送到 PX4

Warning 本文已经过如下测试:

  • Ubuntu:18.04
  • ROS:Melodic
  • PX4 Firmware:1.9.0

    这些步骤普遍适用于其他发行版,或者只需要稍微修改。

MAVROS 安装

按照 Source Installation 中的指导,从 mavlink/mavros 安装“ROS Kinetic”版本。

MAVROS

  1. 首先,我们创建一个新的MAVROS 插件,在keyboard_command.cpp(workspace/src/mavros/mavros_extras/src/plugins)示例中添加以下代码:

    代码功能是从ROS消息主题/mavros/keyboard_command/keyboard_sub中订阅了一个字符消息,并且将其作为MAVLink 消息发送出去。

    1. #include <mavros/mavros_plugin.h>
    2. #include <pluginlib/class_list_macros.h>
    3. #include <iostream>
    4. #include <std_msgs/Char.h>
    5. namespace mavros {
    6. namespace extra_plugins{
    7. class KeyboardCommandPlugin : public plugin::PluginBase {
    8. public:
    9. KeyboardCommandPlugin() : PluginBase(),
    10. nh("~keyboard_command")
    11. { };
    12. void initialize(UAS &uas_)
    13. {
    14. PluginBase::initialize(uas_);
    15. keyboard_sub = nh.subscribe("keyboard_sub", 10, &KeyboardCommandPlugin::keyboard_cb, this);
    16. };
    17. Subscriptions get_subscriptions()
    18. {
    19. return {/* RX disabled */ };
    20. }
    21. private:
    22. ros::NodeHandle nh;
    23. ros::Subscriber keyboard_sub;
    24. void keyboard_cb(const std_msgs::Char::ConstPtr &req)
    25. {
    26. std::cout << "Got Char : " << req->data << std::endl;
    27. UAS_FCU(m_uas)->send_message_ignore_drop(req->data);
    28. }
    29. };
    30. } // namespace extra_plugins
    31. } // namespace mavros
    32. PLUGINLIB_EXPORT_CLASS(mavros::extra_plugins::KeyboardCommandPlugin, mavros::plugin::PluginBase)
  2. 编辑 mavros_plugins.xml 文件(在workspace/src/mavros/mavros_extras文件夹中),并添加以下内容:

    1. <class name="keyboard_command" type="mavros::extra_plugins::KeyboardCommandPlugin" base_class_type="mavros::plugin::PluginBase">
    2. <description>Accepts keyboard command.</description>
    3. </class>
  3. 编辑 CMakeLists.txtworkspace/src/mavros/mavros_extras)文件,并在add_library中添加以下内容:

    1. add_library(
    2. ...
    3. src/plugins/keyboard_command.cpp
    4. )
  4. 打开common.xmlworkspace/src/mavlink/message_definitions/v1.0)文件,复制下面内容到你的MAVLink 消息中:

    1. ...
    2. <message id="229" name="KEY_COMMAND">
    3. <description>Keyboard char command.</description>
    4. <field type="char" name="command"> </field>
    5. </message>
    6. ...

PX4 修改

  1. Inside common.xml (in PX4-Autopilot/mavlink/include/mavlink/v2.0/message_definitions), add your MAVLink message as following (same procedure as for MAVROS section above):

    1. ...
    2. <message id="229" name="KEY_COMMAND">
    3. <description>Keyboard char command.</description>
    4. <field type="char" name="command"> </field>
    5. </message>
    6. ...
  2. Remove common, standard directories in (PX4-Autopilot/mavlink/include/mavlink/v2.0).

    1. rm -r common
    2. rm -r standard
  3. git 克隆”mavlink_generator”到你想要的文件夹下并执行。

    1. git clone https://github.com/mavlink/mavlink mavlink-generator
    2. cd mavlink-generator
    3. python mavgenerate.py
  4. 你会看到一个“MAVLink Generator”应用程序窗口:

    • For XML, “Browse” to /PX4-Autopilot/mavlink/include/mavlink/v2.0/message_definitions/standard.xml.
    • For Out, “Browse” to /PX4-Autopilot/mavlink/include/mavlink/v2.0/.
    • 语言一栏选择C
    • 选择2.0协议
    • 勾选Validate

      然后点击 Generate 按钮。 You will see common, and standard directories created in /PX4-Autopilot/mavlink/include/mavlink/v2.0/.

  5. Make your own uORB message file key_command.msg in (PX4-Autopilot/msg). 示例中的“key_command.msg”文件只包含以下代码:

    1. char cmd

Then, in CMakeLists.txt (in PX4-Autopilot/msg), include

  1. set(
  2. ...
  3. key_command.msg
  4. )
  1. Edit mavlink_receiver.h (in PX4-Autopilot/src/modules/mavlink)

    1. ...
    2. #include <uORB/topics/key_command.h>
    3. ...
    4. class MavlinkReceiver
    5. {
    6. ...
    7. private:
    8. void handle_message_key_command(mavlink_message_t *msg);
    9. ...
    10. orb_advert_t _key_command_pub{nullptr};
    11. }
  2. Edit mavlink_receiver.cpp (in PX4-Autopilot/src/modules/mavlink). 这是 PX4 接收 ROS 发送过来的 MAVLink 消息的地方,并且将消息作为 uORB 主题发布。

    1. ...
    2. void MavlinkReceiver::handle_message(mavlink_message_t *msg)
    3. {
    4. ...
    5. case MAVLINK_MSG_ID_KEY_COMMAND:
    6. handle_message_key_command(msg);
    7. break;
    8. ...
    9. }
    10. ...
    11. void
    12. MavlinkReceiver::handle_message_key_command(mavlink_message_t *msg)
    13. {
    14. mavlink_key_command_t man;
    15. mavlink_msg_key_command_decode(msg, &man);
    16. struct key_command_s key = {};
    17. key.timestamp = hrt_absolute_time();
    18. key.cmd = man.command;
    19. if (_key_command_pub == nullptr) {
    20. _key_command_pub = orb_advertise(ORB_ID(key_command), &key);
    21. } else {
    22. orb_publish(ORB_ID(key_command), _key_command_pub, &key);
    23. }
    24. }
  3. 像其他示例一样订阅你自己的uORB主题。 For this example lets create the model in (/PX4-Autopilot/src/modules/key_receiver). 在此模型目录下创建两个文件 CMakeLists.txtkey_receiver.cpp。 两个文件如下所示。

    -CMakeLists.txt

    1. px4_add_module(
    2. MODULE modules__key_receiver
    3. MAIN key_receiver
    4. STACK_MAIN 2500
    5. STACK_MAX 4000
    6. SRCS
    7. key_receiver.cpp
    8. DEPENDS
    9. platforms__common
    10. )

-key_receiver.cpp

  1. #include <px4_config.h>
  2. #include <px4_tasks.h>
  3. #include <px4_posix.h>
  4. #include <unistd.h>
  5. #include <stdio.h>
  6. #include <poll.h>
  7. #include <string.h>
  8. #include <math.h>
  9. #include <uORB/uORB.h>
  10. #include <uORB/topics/key_command.h>
  11. extern "C" __EXPORT int key_receiver_main(int argc, char **argv);
  12. int key_receiver_main(int argc, char **argv)
  13. {
  14. int key_sub_fd = orb_subscribe(ORB_ID(key_command));
  15. orb_set_interval(key_sub_fd, 200); // limit the update rate to 200ms
  16. px4_pollfd_struct_t fds[1];
  17. fds[0].fd = key_sub_fd, fds[0].events = POLLIN;
  18. int error_counter = 0;
  19. while(true)
  20. {
  21. int poll_ret = px4_poll(fds, 1, 1000);
  22. if (poll_ret == 0)
  23. {
  24. PX4_ERR("Got no data within a second");
  25. }
  26. else if (poll_ret < 0)
  27. {
  28. if (error_counter < 10 || error_counter % 50 == 0)
  29. {
  30. PX4_ERR("ERROR return value from poll(): %d", poll_ret);
  31. }
  32. error_counter++;
  33. }
  34. else
  35. {
  36. if (fds[0].revents & POLLIN)
  37. {
  38. struct key_command_s input;
  39. orb_copy(ORB_ID(key_command), key_sub_fd, &input);
  40. PX4_INFO("Recieved Char : %c", input.cmd);
  41. }
  42. }
  43. }
  44. return 0;
  45. }

详情请见 Writing your first application 文档。

  1. Lastly add your module in the default.cmake file correspondent to your board in PX4-Autopilot/boards/. For example for the Pixhawk 4 add the following code in PX4-Autopilot/boards/px4/fmu-v5/default.cmake:

    1. MODULES
    2. ...
    3. key_receiver
    4. ...

    现在开始编译你的代码。

编译

ROS编译

  1. 在你的工作空间目录下运行catkin build命令。
  2. 在此之前,你必须设置你的“px4.launch”(/workspace/src/mavros/mavros/launch)文件。 编辑“px4.launch”文件如下: 如果你使用USB来连接你的电脑和Pixhawk,你必须设置“fcu_url”如下所示。 但是,如果你使用CP2102来连接你的电脑和Pixhawk,你必须将“ttyACM0” 替换为”ttyUSB0”。 修改“gcs_url”是为了连接你的 Pixhawk 和 UDP,因为串口通信不能同时接收 MAVROS 和 nutshell。

  3. 将你的 IP 地址写在 “xxx.xx.xxx.xxx”

    1. ...
    2. <arg name="fcu_url" default="/dev/ttyACM0:57600" />
    3. <arg name="gcs_url" default="udp://:14550@xxx.xx.xxx.xxx:14557" />
    4. ...

PX4 编译

  1. Build PX4-Autopilot and upload in the normal way.

    For example, to build for Pixhawk 4/FMUv5 execute the following command in the root of the PX4-Autopilot directory:

    1. make px4_fmu-v5_default upload

    运行代码

    接下来测试MAVROS消息是否发送给PX4。

运行 ROS

  1. 在终端中输入

    1. roslaunch mavros px4.launch
  2. 在第二个终端中运行:

    1. rostopic pub -r 10 /mavros/keyboard_command/keyboard_sub std_msgs/Char 97

这意味着以“std_msgs/Char”消息类型发布97(ASCII码的‘a’)到ROS主题“/mavros/keyboard_command/keyboard_sub” “-r 10”意味着以“10Hz”频率持续发布。

PX4 运行

  1. 通过UDP进入Pixhawk 的 nutshell。 用你的IP地址替换xxx.xx.xxx.xxx

    1. cd PX4-Autopilot/Tools
    2. ./mavlink_shell.py xxx.xx.xxx.xxx:14557 --baudrate 57600
  2. 几秒钟之后,敲击 Enter按键几次。 你会看到终端中以下提示:

    1. nsh>
    2. nsh>

输入“key_receiver”命令来运行你的订阅模块。

  1. nsh> key_receiver

测试是否从你的 ROS 话题中接收到 a 字符。