Здравствуй!
У меня есть симулятор самолета, который отправляет некоторую информацию о полете через темы ROS. Я хотел бы взять его и отправить в QGroundControl с помощью MAVLink.
Чтобы начать тестирование, я попытался отправить одно сообщение с поддельным статусом батареи (mavros_msgs / BatteryStatus.msg):
1 - Сначала я запускаю mavros_node с gcs_url = udp: //: [email protected] : 14551.
2 - Я запускаю свой узел, который должен отправить сообщение о батарее:
#include <ros/ros.h>
#include <mavros_msgs/BatteryStatus.h>
int main(int argc, char *argv[])
{
ros::init(argc, argv, "battery_node");
ros::NodeHandle n;
ros::Publisher battery_pub = n.advertise<mavros_msgs::BatteryStatus>("/mavros/battery", 1000);
ros::Rate loop_rate(10);
while (ros::ok())
{
mavros_msgs::BatteryStatus baterry_msg;
baterry_msg.voltage = 5;
baterry_msg.current = 0.5;
baterry_msg.remaining = 0.36;
battery_pub.publish(baterry_msg);
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
3 - Подключаю QGroundControl к UDP: 127.0.0.1:14551
... и ничего не происходит = /
Я уверен, что связь между mavros и QGC работает, потому что, если я запускаю симуляцию с MAVProxy через 127.0.0.1:14540, используя mavros в качестве «моста», самолет распознается.
Что я делаю не так?
Я использую Ubuntu 14, ROS Indigo и QGC 2.9.7.
Заранее большое спасибо,
Пабло
sys_status : как видите, mavros - это _publisher_, а не подписчик.
Привет, вуон,
Спасибо за ваш ответ. Если я правильно понял, это сообщение не может быть отправлено, и оно принимается и отображается только в ROS, я прав?
Могу ли я использовать _mavlink / to_ для отправки этих сообщений?
Как я мог это сделать?
Еще раз спасибо!
mavlink/to
отправляет сообщение в FCU, а не в GCS.
Но вы можете использовать узел gcs_bridge и mavlink/from
.
Привет еще раз,
хорошо, я изменил код так, чтобы он отправлял простое сообщение сердцебиения:
#include <ros/ros.h>
#include <mavros_msgs/Mavlink.h>
int main(int argc, char **argv){
ros::init(argc, argv, "hertbeat_publisher");
ros::NodeHandle n;
ros::Publisher example_pub = n.advertise<mavros_msgs::Mavlink>("/mavlink/from", 1000);
ros::Rate loop_rate(1); // 1 Hz
mavros_msgs::Mavlink mavlink_msg;
mavlink_msg.len = 2;
mavlink_msg.sysid = 1;
mavlink_msg.compid = 1;
mavlink_msg.msgid = 0;
std::vector<long unsigned int> payload64(7, 0);
mavlink_msg.payload64 = payload64;
while (ros::ok())
{
mavlink_msg.header.stamp = ros::Time::now();
if (mavlink_msg.seq < 255){
mavlink_msg.seq++;
}
else {mavlink_msg.seq = 0;}
// publish message
example_pub.publish(mavlink_msg);
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
1 - Я запускаю mavros_node с fcu_url = udp: //: 14540 @ и gcs_url = udp: //: [email protected] : 14551, получая:
[ INFO] [1468659493.280504313]: FCU URL: udp://:14540@
[ INFO] [1468659493.289025098]: udp0: Bind address: 0.0.0.0:14540
[ INFO] [1468659493.289457240]: GCS URL: udp://:[email protected]:14551
[ INFO] [1468659493.289691565]: udp1: Bind address: 0.0.0.0:14570
[ INFO] [1468659493.289824558]: udp1: Remote address: 127.0.0.1:14551
...
[ INFO] [1468659494.906066742]: MAVROS started. MY ID 1.240, TARGET ID 1.1
2 - Я запускаю gcs_bridge с gcs_url: = 'udp: //@127.0.0.1', получаю:
[ INFO] [1468659758.392659411]: udp0: Bind address: 0.0.0.0:14555
[ INFO] [1468659758.392800665]: udp0: Remote address: 127.0.0.1:14550
3 - Я запускаю указанный выше узел, публикуя его в / mavlink / с частотой 1 Гц.
4 - Я подключаю QGroundControl через UDP 127.0.0.1:14550, используя System ID 1
... и снова инспектор MAVLink пуст.
Вначале ничего не происходит, но в какой-то момент QGroundControl выдает эту ошибку:
Имеется версия MAVLink или несоответствие скорости передачи. Пожалуйста, проверьте, совпадают ли скорости передачи QGroundControl и вашего автопилота.
Я думаю, что каким-то образом QGC меняет порт UDP в какой-то момент до этой ошибки.
Что я делаю не так?
Спасибо!
а) Не используйте gcs_url
mavros! Вам следует подключиться к gcs_bridge
!
б) Неверный код для заполнения Mavlink.msg. Должно получиться примерно так:
mavlink::common::msg::HEARTBEAT hb{};
...
mavlink::mavlink_message_t msg;
mavlink::MsgMap map(msg);
hb.serialize(map);
mavlink::finalize_message_buffer(&msg, sysid, compid, ...);
mavros_msgs::Mavlink ml;
mavros_msgs::mavlink::convert(msg, ml);
Видеть:
Здравствуй!
Спасибо! Наконец-то я заставил это работать. Я использовал разные классы, так как использую Индиго. Я оставляю здесь код на случай, если кто-то еще задается вопросом, как именно это сделать. Я отправляю сердцебиение и сообщение о высоте и получаю их в QGroundControl:
1- Запустите узел mavros с fcu_url = udp: //: 14540 @ и gcs_url = udp: //: [email protected] : 14551.
2- Запустите gcs_bridge с gcs_url: = udp: //@127.0.0.1: 14560.
3- Запустите этот узел:
#include <ros/ros.h>
#include <mavconn/interface.h>
#include <mavros_msgs/Mavlink.h>
#include <mavros_msgs/mavlink_convert.h>
// General parameters
uint8_t system_id = 1;
uint8_t component_id = 1;
uint8_t type = 1;
uint8_t autopilot = 0;
uint8_t base_mode = 128;
uint32_t custom_mode = 0;
uint8_t system_status = 0;
// Parameters of the altitude message
float alt_monotonic = 10.0;
float alt_amsl = 100;
float alt_local = 10.0;
float alt_relative = 10.0;
float alt_terrain = 10;
float bottom_clearance = 0;
int main(int argc, char **argv){
// Create heartbeat message
mavlink_message_t msg_heartbeat;
mavlink_msg_heartbeat_pack(system_id, component_id, &msg_heartbeat, type, autopilot, base_mode, custom_mode, system_status);
mavros_msgs::Mavlink ml_heartbeat;
mavros_msgs::mavlink::convert(msg_heartbeat, ml_heartbeat);
// Create altitude message
mavlink_message_t msg_altitude;
mavros_msgs::Mavlink ml_altitude;
ros::init(argc, argv, "telemetry_publisher");
ros::NodeHandle n;
ros::Publisher example_pub = n.advertise<mavros_msgs::Mavlink>("/mavlink/from", 1000);
ros::Rate loop_rate(1); // 1 Hz
while (ros::ok())
{
uint64_t time_stamp = ros::Time::now().nsec;
// Finish altitude message
mavlink_msg_altitude_pack(system_id, component_id, &msg_altitude, time_stamp, alt_monotonic, alt_amsl, alt_local, alt_relative, alt_terrain, bottom_clearance);
mavros_msgs::mavlink::convert(msg_altitude, ml_altitude);
// Publish messages
example_pub.publish(ml_heartbeat);
example_pub.publish(ml_altitude);
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
4- Запустите QGroundControl и настройте соединение на 127.0.0.1:14560
Если вы откроете MavLink Inspector, вы должны увидеть сердцебиение и сообщение о высоте примерно с частотой ~ 1 Гц.
Я пытаюсь сделать это, но получаю ошибку, я действительно не понимаю, почему, может ли кто-нибудь мне помочь?
Функция mavlink_msg_heartbeat_pack должна быть включена, когда #include
Может я ошибся в cmake?
#include "ros/ros.h"
#include <mavros_msgs/mavlink_convert.h>
#include <mavconn/interface.h>
int main(int argc, char **argv)
{
ros::init(argc, argv, "talker");
ros::NodeHandle n;
ros::Publisher pub = n.advertise<mavros_msgs::Mavlink>("/mavlink/from", 1000);
ros::Rate loop_rate(10);
uint8_t system_id = 1;
uint8_t component_id = 1;
uint8_t type = 1;
uint8_t autopilot = 0;
uint8_t base_mode = 128;
uint32_t custom_mode = 0;
uint8_t system_status = 0;
mavlink_message_t msg;
mavlink_msg_heartbeat_pack(system_id, component_id, &msg, type, autopilot, base_mode, custom_mode, system_status);
return 0;
}
cmake_minimum_required(VERSION 2.8.3)
project(talker)
find_package(catkin REQUIRED COMPONENTS mavros mavros_msgs mavlink)
catkin_package()
include(EnableCXX11)
include(MavrosMavlink)
include_directories(
${catkin_INCLUDE_DIRS}
${mavlink_INCLUDE_DIRS}
)
add_executable(talker talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
ошибка: 'mavlink_message_t' не был объявлен в этой области
mavlink_message_t msg;
ошибка: 'mavlink_msg_heartbeat_pack' не был объявлен в этой области
mavlink_msg_heartbeat_pack (system_id, component_id, & msg, type, автопилот, base_mode, custom_mode, system_status);
@shawinmihail какая версия мавроса? 0.18+ будет включать только mavlink_helpers.h и C ++ 11 lib.
Я нашел решение своей проблемы. Вероятно, mavros v0.18 + использует только заголовки mavlink v2.0. Для создания любого сообщения мы должны использовать MsgMap.serialize () вместо msg_name_pack ()
mavlink::mavlink_message_t msg;
mavlink::MsgMap map(msg);
mavlink::groupcontrol::msg::GROUP_COEFFS_PART1 msgPart1 //my custom msg;
msgPart1.kc = kc;
msgPart1.ks = ks;
//........................... - fill msg
msgPart1.serialize(map);
map.reset();
auto mi = msgPart1.get_message_info();
mavlink::mavlink_finalize_message(&msg, system_id, component_id, mi.min_length, mi.length, mi.crc_extra);
mavros_msgs::Mavlink mavrosMsg;
mavros_msgs::mavlink::convert(msg, mavrosMsg);
Может кому поможет. Если вы знаете способ лучше, напишите, пожалуйста.
Спасибо за подсказку.
Message::serialize()
выполняет MsgMap::reset()
, не вызывайте его напрямую! Это может нарушить сообщение.
Также, возможно, лучше написать собственный gcs_bridge
, так как у вас есть класс MAVConnInterface
, куда вы можете отправить свое сообщение:
auto gcs_link = MAVConnInterface::open_url("udp-b://@");
mavlink::common::msg::HEARTBEAT hb{};
// fill hb
gcs_link->send_message_ignore_drop(hb);
@vooon , спасибо за комментарии. Я считаю, что мое решение некорректно работает с протоколом mavlink v1.0. Сейчас делаю и тестирую новую, работает!
#include "ros/ros.h"
#include <mavros_msgs/mavlink_convert.h>
#include <mavconn/interface.h>
#include <iostream>
#include <mavlink/v2.0/mavlink_helpers.h>
float kc = 0.0f; /*< gravity coeff */
float ks = 0.0f; /*< repulsive coeff */
float ka = 0.0f; /*< speed alignment coeff */
float kp = 0.0f; /*< chasing coeff */
float km = 0.0f; /*< waypoint gravity coeff */
float kh = 0.0f; /*< rotate speed coeff */
float vmax = 0.0f; /*< max autopilot velocity */
float rn = 0.0f; /*< search radius of groupmate */
float rs = 0.0f; /*< repulsiveOn radius */
float rm = 0.0f; /*< getting waypoint radius */
float rmb = 0.0f; /*< change gravity law radius */
void packMavlinkMessage(const mavlink::Message& mavMsg, mavros_msgs::Mavlink &rosMsg)
{
mavlink::mavlink_message_t msg;
mavlink::MsgMap map(msg);
mavMsg.serialize(map);
auto mi = mavMsg.get_message_info();
mavlink::mavlink_status_t *status = mavlink::mavlink_get_channel_status(mavlink::MAVLINK_COMM_0);
status->flags |= MAVLINK_STATUS_FLAG_OUT_MAVLINK1;
mavlink::mavlink_finalize_message_buffer(&msg, 1, 1, status, mi.min_length, mi.length, mi.crc_extra);
mavros_msgs::mavlink::convert(msg, rosMsg);
}
void mavlinkCallback(const mavros_msgs::Mavlink& msg)
{
mavlink::mavlink_message_t mavMsg;
mavros_msgs::mavlink::convert(msg, mavMsg);
if(mavMsg.msgid == mavlink::groupcontrol::msg::SET_GROUP_PARAMS::MSG_ID)
{
ROS_WARN("SET GROUP_PARAMS");
mavlink::MsgMap map(mavMsg);
mavlink::groupcontrol::msg::SET_GROUP_PARAMS setParamsMsg;
setParamsMsg.deserialize(map);
std::cout << setParamsMsg.kc;
}
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "talker");
ros::NodeHandle n;
ros::Publisher pub = n.advertise<mavros_msgs::Mavlink>("/mavlink/from", 1000);
ros::Subscriber sub = n.subscribe("mavlink/to", 1000, mavlinkCallback);
ros::Rate loop_rate(10);
ROS_INFO("%s", "Talker started");
mavlink::groupcontrol::msg::GROUP_PARAMS msgPart1;
msgPart1.kc = kc;
msgPart1.ks = ks;
msgPart1.ka = ka;
msgPart1.kp = kp;
msgPart1.km = km;
msgPart1.kh = kh;
msgPart1.vmax = vmax;
msgPart1.rn = rn;
msgPart1.rs = rs;
msgPart1.rm = rm;
msgPart1.rmb = rmb;
while (ros::ok())
{
mavros_msgs::Mavlink mavrosMsg;
packMavlinkMessage(msgPart1, mavrosMsg);
pub.publish(mavrosMsg);
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
может быть кто-нибудь может мне помочь и напишет
как я могу сделать то же самое с python, например
создать mavlink msg и преобразовать его в mavros msg?
Также, возможно, лучше написать собственный
gcs_bridge
, так как у вас есть классMAVConnInterface
, куда вы можете отправить свое сообщение:auto gcs_link = MAVConnInterface::open_url("udp-b://@"); mavlink::common::msg::HEARTBEAT hb{}; // fill hb gcs_link->send_message_ignore_drop(hb);
Этот метод может просто отправить пользовательское сообщение, но есть ли риск? @vooon
Самый полезный комментарий
Также, возможно, лучше написать собственный
gcs_bridge
, так как у вас есть классMAVConnInterface
, куда вы можете отправить свое сообщение: