mavros.cpp
Go to the documentation of this file.
00001 
00006 /*
00007  * Copyright 2013,2014 Vladimir Ermakov.
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 3 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful, but
00015  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
00016  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
00017  * for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License along
00020  * with this program; if not, write to the Free Software Foundation, Inc.,
00021  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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"), // for compatible reasons
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                 // may be overridden by URL
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         // ROS mavlink bridge
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         /* sample code from QGC */
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); /* NOTE in original init[3] */
00218 }
00219 
00220 void MavRos::log_connect_change(bool connected) {
00221         /* note: sys_status plugin required */
00222         if (connected)
00223                 ROS_INFO("CON: Got HEARTBEAT, connected.");
00224         else
00225                 ROS_WARN("CON: Lost connection, HEARTBEAT timed out.");
00226 }
00227 


mavros
Author(s): Vladimir Ermakov
autogenerated on Wed Aug 26 2015 12:29:13