Program Listing for File mavros_router.hpp
↰ Return to documentation for file (include/mavros/mavros_router.hpp
)
/*
* Copyright 2021 Vladimir Ermakov.
*
* This file is part of the mavros package and subject to the license terms
* in the top-level LICENSE file of the mavros repository.
* https://github.com/mavlink/mavros/tree/master/LICENSE.md
*/
#pragma once
#ifndef MAVROS__MAVROS_ROUTER_HPP_
#define MAVROS__MAVROS_ROUTER_HPP_
#include <array>
#include <memory>
#include <set>
#include <string>
#include <shared_mutex> // NOLINT
#include <utility>
#include <vector>
#include <unordered_map>
#include <Eigen/Eigen> // NOLINT
#include "mavconn/interface.hpp"
#include "mavconn/mavlink_dialect.hpp"
#include "mavros/utils.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/rclcpp.hpp"
#include "diagnostic_updater/diagnostic_updater.hpp"
#include "mavros_msgs/msg/mavlink.hpp"
#include "mavros_msgs/srv/endpoint_add.hpp"
#include "mavros_msgs/srv/endpoint_del.hpp"
namespace mavros
{
namespace router
{
using id_t = uint32_t;
using addr_t = uint32_t;
using mavconn::Framing;
using ::mavlink::mavlink_message_t;
using ::mavlink::msgid_t;
using namespace std::placeholders; // NOLINT
using namespace std::chrono_literals; // NOLINT
class Router;
class Endpoint : public std::enable_shared_from_this<Endpoint>
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(Endpoint)
enum class Type
{
fcu = 0,
gcs = 1,
uas = 2,
};
Endpoint()
: parent(),
id(0),
link_type(Type::fcu),
url{},
remote_addrs{},
stale_addrs{}
{
const addr_t broadcast_addr = 0;
// Accept broadcasts by default
remote_addrs.emplace(broadcast_addr);
}
std::shared_ptr<Router> parent;
uint32_t id; // id of the endpoint
Type link_type; // class of the endpoint
std::string url; // url to open that endpoint
std::set<addr_t> remote_addrs; // remotes that we heard there
std::set<addr_t> stale_addrs; // temporary storage for stale remote addrs
virtual bool is_open() = 0;
virtual std::pair<bool, std::string> open() = 0;
virtual void close() = 0;
virtual void send_message(
const mavlink_message_t * msg, const Framing framing = Framing::ok,
id_t src_id = 0) = 0;
virtual void recv_message(const mavlink_message_t * msg, const Framing framing = Framing::ok);
virtual std::string diag_name();
virtual void diag_run(diagnostic_updater::DiagnosticStatusWrapper & stat) = 0;
};
class Router : public rclcpp::Node
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(Router)
using StrV = std::vector<std::string>;
explicit Router(const std::string & node_name = "mavros_router")
: Router(rclcpp::NodeOptions(), node_name) {}
explicit Router(
const rclcpp::NodeOptions & options,
const std::string & node_name = "mavros_router")
: rclcpp::Node(node_name,
options /* rclcpp::NodeOptions(options).use_intra_process_comms(true) */),
endpoints{}, stat_msg_routed(0), stat_msg_sent(0), stat_msg_dropped(0),
diagnostic_updater(this, 1.0)
{
RCLCPP_DEBUG(this->get_logger(), "Start mavros::router::Router initialization...");
set_parameters_handle_ptr =
this->add_on_set_parameters_callback(std::bind(&Router::on_set_parameters_cb, this, _1));
this->declare_parameter<StrV>("fcu_urls", StrV());
this->declare_parameter<StrV>("gcs_urls", StrV());
this->declare_parameter<StrV>("uas_urls", StrV());
add_service = this->create_service<mavros_msgs::srv::EndpointAdd>(
"~/add_endpoint",
std::bind(&Router::add_endpoint, this, _1, _2));
del_service = this->create_service<mavros_msgs::srv::EndpointDel>(
"~/del_endpoint",
std::bind(&Router::del_endpoint, this, _1, _2));
// try to reconnect endpoint each 30 seconds
reconnect_timer =
this->create_wall_timer(30s, std::bind(&Router::periodic_reconnect_endpoints, this));
// collect garbage addrs each minute
stale_addrs_timer =
this->create_wall_timer(60s, std::bind(&Router::periodic_clear_stale_remote_addrs, this));
diagnostic_updater.setHardwareID("none"); // NOTE: router connects several hardwares
diagnostic_updater.add("MAVROS Router", this, &Router::diag_run);
std::stringstream ss;
for (auto & s : mavconn::MAVConnInterface::get_known_dialects()) {
ss << " " << s;
}
RCLCPP_INFO(get_logger(), "Built-in SIMD instructions: %s", Eigen::SimdInstructionSetsInUse());
RCLCPP_INFO(get_logger(), "Built-in MAVLink package version: %s", mavlink::version);
RCLCPP_INFO(get_logger(), "Known MAVLink dialects:%s", ss.str().c_str());
RCLCPP_INFO(get_logger(), "MAVROS Router started");
}
void route_message(Endpoint::SharedPtr src, const mavlink_message_t * msg, const Framing framing);
private:
friend class Endpoint;
friend class TestRouter;
static std::atomic<id_t> id_counter;
std::shared_timed_mutex mu;
// map stores all routing endpoints
std::unordered_map<id_t, Endpoint::SharedPtr> endpoints;
std::atomic<size_t> stat_msg_routed;
std::atomic<size_t> stat_msg_sent;
std::atomic<size_t> stat_msg_dropped;
rclcpp::Service<mavros_msgs::srv::EndpointAdd>::SharedPtr add_service;
rclcpp::Service<mavros_msgs::srv::EndpointDel>::SharedPtr del_service;
rclcpp::TimerBase::SharedPtr reconnect_timer;
rclcpp::TimerBase::SharedPtr stale_addrs_timer;
rclcpp::Node::OnSetParametersCallbackHandle::SharedPtr set_parameters_handle_ptr;
diagnostic_updater::Updater diagnostic_updater;
void add_endpoint(
const mavros_msgs::srv::EndpointAdd::Request::SharedPtr request,
mavros_msgs::srv::EndpointAdd::Response::SharedPtr response);
void del_endpoint(
const mavros_msgs::srv::EndpointDel::Request::SharedPtr request,
mavros_msgs::srv::EndpointDel::Response::SharedPtr response);
void periodic_reconnect_endpoints();
void periodic_clear_stale_remote_addrs();
rcl_interfaces::msg::SetParametersResult on_set_parameters_cb(
const std::vector<rclcpp::Parameter> & parameters);
void diag_run(diagnostic_updater::DiagnosticStatusWrapper & stat);
};
class MAVConnEndpoint : public Endpoint
{
public:
MAVConnEndpoint()
: Endpoint(),
stat_last_drop_count(0)
{}
~MAVConnEndpoint()
{
close();
}
mavconn::MAVConnInterface::Ptr link; // connection
size_t stat_last_drop_count;
bool is_open() override;
std::pair<bool, std::string> open() override;
void close() override;
void send_message(
const mavlink_message_t * msg, const Framing framing = Framing::ok,
id_t src_id = 0) override;
void diag_run(diagnostic_updater::DiagnosticStatusWrapper & stat) override;
};
class ROSEndpoint : public Endpoint
{
public:
ROSEndpoint()
: Endpoint()
{}
~ROSEndpoint()
{
close();
}
rclcpp::Subscription<mavros_msgs::msg::Mavlink>::SharedPtr sink; // UAS -> FCU
rclcpp::Publisher<mavros_msgs::msg::Mavlink>::SharedPtr source; // FCU -> UAS
bool is_open() override;
std::pair<bool, std::string> open() override;
void close() override;
void send_message(
const mavlink_message_t * msg, const Framing framing = Framing::ok,
id_t src_id = 0) override;
void diag_run(diagnostic_updater::DiagnosticStatusWrapper & stat) override;
private:
void ros_recv_message(const mavros_msgs::msg::Mavlink::SharedPtr rmsg);
};
} // namespace router
} // namespace mavros
#endif // MAVROS__MAVROS_ROUTER_HPP_