00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <mavros/mavros.h>
00025 #include <ros/console.h>
00026 #include <mavros/utils.h>
00027 #include <fnmatch.h>
00028
00029 using namespace mavros;
00030 using namespace mavconn;
00031 using namespace mavplugin;
00032
00033
00034 MavRos::MavRos(const ros::NodeHandle &nh_) :
00035 node_handle(nh_),
00036 mavlink_node_handle("/mavlink"),
00037 fcu_link_diag("FCU connection"),
00038 gcs_link_diag("GCS bridge"),
00039 plugin_loader("mavros", "mavplugin::MavRosPlugin"),
00040 message_route_table{}
00041 {
00042 std::string fcu_url, gcs_url;
00043 int system_id, component_id;
00044 int tgt_system_id, tgt_component_id;
00045 bool px4_usb_quirk;
00046 MAVConnInterface::Ptr fcu_link;
00047
00048 node_handle.param<std::string>("fcu_url", fcu_url, "serial:///dev/ttyACM0");
00049 node_handle.param<std::string>("gcs_url", gcs_url, "udp://@");
00050 node_handle.param("system_id", system_id, 1);
00051 node_handle.param<int>("component_id", component_id, MAV_COMP_ID_UDP_BRIDGE);
00052 node_handle.param("target_system_id", tgt_system_id, 1);
00053 node_handle.param("target_component_id", tgt_component_id, 1);
00054 node_handle.param("startup_px4_usb_quirk", px4_usb_quirk, false);
00055 node_handle.getParam("plugin_blacklist", plugin_blacklist);
00056
00057 diag_updater.setHardwareID("Mavlink");
00058
00059 ROS_INFO_STREAM("FCU URL: " << fcu_url);
00060 try {
00061 fcu_link = MAVConnInterface::open_url(fcu_url, system_id, component_id);
00062
00063 system_id = fcu_link->get_system_id();
00064 component_id = fcu_link->get_component_id();
00065
00066 fcu_link_diag.set_mavconn(fcu_link);
00067 diag_updater.add(fcu_link_diag);
00068 }
00069 catch (mavconn::DeviceError &ex) {
00070 ROS_FATAL("FCU: %s", ex.what());
00071 ros::shutdown();
00072 return;
00073 }
00074
00075 if (gcs_url != "") {
00076 ROS_INFO_STREAM("GCS URL: " << gcs_url);
00077 try {
00078 gcs_link = MAVConnInterface::open_url(gcs_url, system_id, component_id);
00079
00080 gcs_link_diag.set_mavconn(gcs_link);
00081 diag_updater.add(gcs_link_diag);
00082 }
00083 catch (mavconn::DeviceError &ex) {
00084 ROS_FATAL("GCS: %s", ex.what());
00085 ros::shutdown();
00086 return;
00087 }
00088 }
00089 else
00090 ROS_INFO("GCS bridge disabled");
00091
00092
00093 mavlink_pub = mavlink_node_handle.advertise<Mavlink>("from", 100);
00094 mavlink_sub = mavlink_node_handle.subscribe("to", 100, &MavRos::mavlink_sub_cb, this,
00095 ros::TransportHints()
00096 .unreliable()
00097 .maxDatagramSize(1024));
00098
00099 fcu_link->message_received.connect(boost::bind(&MavRos::mavlink_pub_cb, this, _1, _2, _3));
00100 fcu_link->message_received.connect(boost::bind(&MavRos::plugin_route_cb, this, _1, _2, _3));
00101 fcu_link->port_closed.connect(boost::bind(&MavRos::terminate_cb, this));
00102
00103 if (gcs_link) {
00104 fcu_link->message_received.connect(
00105 boost::bind(&MAVConnInterface::send_message, gcs_link, _1, _2, _3));
00106 gcs_link->message_received.connect(
00107 boost::bind(&MAVConnInterface::send_message, fcu_link, _1, _2, _3));
00108 gcs_link_diag.set_connection_status(true);
00109 }
00110
00111 mav_uas.set_tgt(tgt_system_id, tgt_component_id);
00112 UAS_FCU(&mav_uas) = fcu_link;
00113 mav_uas.sig_connection_changed.connect(boost::bind(&MavlinkDiag::set_connection_status, &fcu_link_diag, _1));
00114 mav_uas.sig_connection_changed.connect(boost::bind(&MavRos::log_connect_change, this, _1));
00115
00116 for (auto &name : plugin_loader.getDeclaredClasses())
00117 add_plugin(name);
00118
00119 if (px4_usb_quirk)
00120 startup_px4_usb_quirk();
00121
00122 ROS_INFO("MAVROS started. MY ID [%d, %d], TARGET ID [%d, %d]",
00123 system_id, component_id,
00124 tgt_system_id, tgt_component_id);
00125 }
00126
00127 void MavRos::spin() {
00128 ros::Rate loop_rate(1000);
00129 while (node_handle.ok()) {
00130 ros::spinOnce();
00131 diag_updater.update();
00132
00133 loop_rate.sleep();
00134 }
00135
00136 ROS_INFO("Stopping mavros...");
00137 mav_uas.stop();
00138 }
00139
00140 void MavRos::mavlink_pub_cb(const mavlink_message_t *mmsg, uint8_t sysid, uint8_t compid) {
00141 MavlinkPtr rmsg = boost::make_shared<Mavlink>();
00142
00143 if (mavlink_pub.getNumSubscribers() == 0)
00144 return;
00145
00146 rmsg->header.stamp = ros::Time::now();
00147 mavutils::copy_mavlink_to_ros(mmsg, rmsg);
00148 mavlink_pub.publish(rmsg);
00149 }
00150
00151 void MavRos::mavlink_sub_cb(const Mavlink::ConstPtr &rmsg) {
00152 mavlink_message_t mmsg;
00153
00154 if (mavutils::copy_ros_to_mavlink(rmsg, mmsg))
00155 UAS_FCU(&mav_uas)->send_message(&mmsg, rmsg->sysid, rmsg->compid);
00156 else
00157 ROS_ERROR("Drop mavlink packet: illegal payload64 size");
00158 }
00159
00160 void MavRos::plugin_route_cb(const mavlink_message_t *mmsg, uint8_t sysid, uint8_t compid) {
00161 message_route_table[mmsg->msgid](mmsg, sysid, compid);
00162 }
00163
00164 bool MavRos::check_in_blacklist(std::string &pl_name) {
00165 for (auto &pattern : plugin_blacklist) {
00166 int cmp = fnmatch(pattern.c_str(), pl_name.c_str(), FNM_CASEFOLD);
00167 if (cmp == 0)
00168 return true;
00169 else if (cmp != FNM_NOMATCH)
00170 ROS_ERROR("Blacklist check error! fnmatch('%s', '%s', FNM_CASEFOLD) -> %d",
00171 pattern.c_str(), pl_name.c_str(), cmp);
00172 }
00173
00174 return false;
00175 }
00176
00177 void MavRos::add_plugin(std::string &pl_name) {
00178 boost::shared_ptr<mavplugin::MavRosPlugin> plugin;
00179
00180 if (check_in_blacklist(pl_name)) {
00181 ROS_INFO_STREAM("Plugin [alias " << pl_name << "] blacklisted");
00182 return;
00183 }
00184
00185 try {
00186 plugin = plugin_loader.createInstance(pl_name);
00187 plugin->initialize(mav_uas, node_handle, diag_updater);
00188 loaded_plugins.push_back(plugin);
00189 std::string repr_name = plugin->get_name();
00190
00191 ROS_INFO_STREAM("Plugin " << repr_name <<
00192 " [alias " << pl_name << "] loaded and initialized");
00193
00194 for (auto &pair : plugin->get_rx_handlers()) {
00195 ROS_DEBUG("Route msgid %d to %s", pair.first, repr_name.c_str());
00196 message_route_table[pair.first].connect(pair.second);
00197 }
00198
00199 } catch (pluginlib::PluginlibException &ex) {
00200 ROS_ERROR_STREAM("Plugin [alias " << pl_name << "] load exception: " << ex.what());
00201 }
00202 }
00203
00204 void MavRos::terminate_cb() {
00205 ROS_ERROR("FCU connection closed, mavros will be terminated.");
00206 ros::requestShutdown();
00207 }
00208
00209 void MavRos::startup_px4_usb_quirk(void) {
00210
00211 const uint8_t init[] = {0x0d, 0x0d, 0x0d, 0};
00212 const uint8_t nsh[] = "sh /etc/init.d/rc.usb\n";
00213
00214 ROS_INFO("Autostarting mavlink via USB on PX4");
00215 UAS_FCU(&mav_uas)->send_bytes(init, 3);
00216 UAS_FCU(&mav_uas)->send_bytes(nsh, sizeof(nsh) - 1);
00217 UAS_FCU(&mav_uas)->send_bytes(init, 4);
00218 }
00219
00220 void MavRos::log_connect_change(bool connected) {
00221
00222 if (connected)
00223 ROS_INFO("CON: Got HEARTBEAT, connected.");
00224 else
00225 ROS_WARN("CON: Lost connection, HEARTBEAT timed out.");
00226 }
00227