Repository: mit-racecar/racecar Branch: master Commit: b464bf1f8534 Files: 52 Total size: 102.1 KB Directory structure: gitextract_ho3gnwhp/ ├── .gitignore ├── ackermann_cmd_mux/ │ ├── .cproject │ ├── .gitignore │ ├── .project │ ├── .pydevproject │ ├── .settings/ │ │ └── language.settings.xml │ ├── CHANGELOG.rst │ ├── CMakeLists.txt │ ├── LICENSE │ ├── cfg/ │ │ └── reload.cfg │ ├── include/ │ │ └── ackermann_cmd_mux/ │ │ ├── ackermann_cmd_mux_nodelet.hpp │ │ ├── ackermann_cmd_subscribers.hpp │ │ └── exceptions.hpp │ ├── launch/ │ │ ├── ackermann_cmd_mux.launch │ │ ├── reconfigure.launch │ │ └── standalone.launch │ ├── package.xml │ ├── param/ │ │ ├── example.yaml │ │ └── reconfigure.yaml │ ├── plugins/ │ │ └── nodelets.xml │ └── src/ │ ├── ackermann_cmd_mux_nodelet.cpp │ ├── ackermann_cmd_subscribers.cpp │ └── throttle_interpolator.py ├── racecar/ │ ├── CMakeLists.txt │ ├── LICENSE │ ├── config/ │ │ └── racecar-v2/ │ │ ├── high_level_mux.yaml │ │ ├── joy_teleop.yaml │ │ ├── low_level_mux.yaml │ │ ├── sensors.yaml │ │ └── vesc.yaml │ ├── launch/ │ │ ├── includes/ │ │ │ ├── common/ │ │ │ │ ├── joy_teleop.launch.xml │ │ │ │ └── sensors.launch.xml │ │ │ ├── racecar-v2/ │ │ │ │ ├── static_transforms.launch.xml │ │ │ │ ├── velodyne.launch.xml │ │ │ │ └── vesc.launch.xml │ │ │ └── racecar-v2-teleop.launch.xml │ │ ├── known_map_localization.launch │ │ ├── mux.launch │ │ ├── replay_bag_file/ │ │ │ ├── replay_bag_file.launch │ │ │ ├── replay_bag_mapping.launch │ │ │ └── replay_bag_with_lidar_processing.launch │ │ └── teleop.launch │ ├── maps/ │ │ ├── basement_hallways_10cm.yaml │ │ ├── basement_hallways_5cm.yml │ │ └── short-course-33.yml │ ├── package.xml │ ├── rviz/ │ │ ├── known_map_localization.rviz │ │ ├── laser_scan_matcher.rviz │ │ └── mapping.rviz │ └── scripts/ │ └── joy_teleop.py ├── racecar-vm.rosinstall └── racecar.rosinstall ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # -*- mode: gitignore; -*- *~ \#*\# ================================================ FILE: ackermann_cmd_mux/.cproject ================================================ ================================================ FILE: ackermann_cmd_mux/.gitignore ================================================ /bin /build /lib ================================================ FILE: ackermann_cmd_mux/.project ================================================ ackermann_cmd_mux org.python.pydev.PyDevBuilder org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, ?name? org.eclipse.cdt.make.core.append_environment true org.eclipse.cdt.make.core.autoBuildTarget all org.eclipse.cdt.make.core.buildArguments org.eclipse.cdt.make.core.buildCommand make org.eclipse.cdt.make.core.cleanBuildTarget clean org.eclipse.cdt.make.core.contents org.eclipse.cdt.make.core.activeConfigSettings org.eclipse.cdt.make.core.enableAutoBuild false org.eclipse.cdt.make.core.enableCleanBuild true org.eclipse.cdt.make.core.enableFullBuild true org.eclipse.cdt.make.core.fullBuildTarget all org.eclipse.cdt.make.core.stopOnError true org.eclipse.cdt.make.core.useDefaultBuildCmd true org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder full,incremental, org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature org.python.pydev.pythonNature ================================================ FILE: ackermann_cmd_mux/.pydevproject ================================================ Default python 2.7 ================================================ FILE: ackermann_cmd_mux/.settings/language.settings.xml ================================================ ================================================ FILE: ackermann_cmd_mux/CHANGELOG.rst ================================================ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Changelog for package ackermann_cmd_mux ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0.6.3 (2014-12-05) ------------------ 0.6.2 (2014-11-30) ------------------ * ackermann_cmd_mux: fixes node handle for output pub to keep backwards compatibility * adds a little launcher restructing for muxer and smoother * Contributors: Marcus Liebhardt 0.6.0 (2014-07-08) ------------------ * updating package informations. remove email for authors. updating maintainer * Contributors: Jihoon Lee 0.5.3 (2014-03-24) ------------------ * Added support for YAML-CPP 0.5+. The new yaml-cpp API removes the "node >> outputvar;" operator, and it has a new way of loading documents. There's no version hint in the library's headers, so I'm getting the version number from pkg-config. This part of the patch is a port of the ones created by @ktossell for map_server and other packages. The new yaml-cpp also does not have FindValue. * Contributors: Scott K Logan 0.5.2 (2013-11-05) ------------------ 0.5.1 (2013-10-14) ------------------ * Unify naming politics for binaries and plugins. 0.5.0 (2013-10-11) ------------------ * Renamed as ackermann_cmd_mux. 0.4.1 (2013-10-08) ------------------ 0.4.0 (2013-08-29) ------------------ * Add bugtracker and repo info URLs. * Changelogs at package level. * License link fixed. 0.3.0 (2013-07-02) ------------------ 0.2.3 (2013-04-15) ------------------ 0.2.2 (2013-02-10) ------------------ 0.2.1 (2013-02-08) ------------------ 0.2.0 (2013-02-07) ------------------ * Catkinized. 0.1.3 (2013-01-08) ------------------ * More generous description. 0.1.2 (2013-01-02) ------------------ * Dynamically reconfigurable. * Upgraded to new groovy plugin formats. * Add reconfigure launcher and parameter file. * Add a dynamic reconfigure script to accept a yaml filename. 0.1.1 (2012-12-21) ------------------ 0.1.0 (2012-12-05) ------------------ * Initial version. ================================================ FILE: ackermann_cmd_mux/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 2.8.3) project(ackermann_cmd_mux) find_package(catkin REQUIRED COMPONENTS roscpp pluginlib nodelet dynamic_reconfigure ackermann_msgs std_msgs rospy ) # pkg-config support find_package(PkgConfig) pkg_search_module(yaml-cpp REQUIRED yaml-cpp) if(NOT ${yaml-cpp_VERSION} VERSION_LESS "0.5") add_definitions(-DHAVE_NEW_YAMLCPP) endif() # Dynamic reconfigure support generate_dynamic_reconfigure_options(cfg/reload.cfg) catkin_package( INCLUDE_DIRS include LIBRARIES ${PROJECT_NAME}_nodelet CATKIN_DEPENDS roscpp pluginlib nodelet dynamic_reconfigure ackermann_msgs rospy std_msgs DEPENDS yaml-cpp ) include_directories(include ${catkin_INCLUDE_DIRS} ${yaml-cpp_INCLUDE_DIRS}) # Nodelet library add_library(${PROJECT_NAME}_nodelet src/ackermann_cmd_mux_nodelet.cpp src/ackermann_cmd_subscribers.cpp) #add_dependencies(${PROJECT_NAME}_nodelet ackermann_msgs) add_dependencies(${PROJECT_NAME}_nodelet ${PROJECT_NAME}_gencfg) target_link_libraries(${PROJECT_NAME}_nodelet ${catkin_LIBRARIES} ${yaml-cpp_LIBRARIES}) install(TARGETS ${PROJECT_NAME}_nodelet DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} ) install(DIRECTORY include/${PROJECT_NAME}/ DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} ) install(DIRECTORY plugins DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} ) install(DIRECTORY launch DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} ) install(DIRECTORY param DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} ) ================================================ FILE: ackermann_cmd_mux/LICENSE ================================================ # Software License Agreement (BSD License) # # Copyright (c) 2012 Yujin Robot, Daniel Stonier, Jorge Santos # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Yujin Robot nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: ackermann_cmd_mux/cfg/reload.cfg ================================================ #!/usr/bin/env python2 PACKAGE = "ackermann_cmd_mux" from dynamic_reconfigure.parameter_generator_catkin import * gen = ParameterGenerator() gen.add("yaml_cfg_file", str_t, 0, "Pathname to a yaml file for re-configuration of the mux", "") # Second arg is node name it will run in (doc purposes only), third is generated filename prefix exit(gen.generate(PACKAGE, "ackermann_cmd_mux_reload", "reload")) ================================================ FILE: ackermann_cmd_mux/include/ackermann_cmd_mux/ackermann_cmd_mux_nodelet.hpp ================================================ /** * @file /include/ackermann_cmd_mux/ackermann_cmd_mux_nodelet.hpp * * @brief Structure for the ackermann_cmd_mux. * * License: BSD * https://raw.github.com/yujinrobot/yujin_ocs/hydro/yocs_ackermann_cmd_mux/LICENSE **/ /***************************************************************************** ** Ifdefs *****************************************************************************/ #ifndef RACECAR_ACKERMANN_CMD_MUX_HPP_ #define RACECAR_ACKERMANN_CMD_MUX_HPP_ /***************************************************************************** ** Includes *****************************************************************************/ #include #include #include #include "ackermann_cmd_mux/reloadConfig.h" #include "ackermann_cmd_mux/ackermann_cmd_subscribers.hpp" /***************************************************************************** ** Namespaces *****************************************************************************/ namespace ackermann_cmd_mux { /***************************************************************************** ** AckermannCmdMux *****************************************************************************/ class AckermannCmdMuxNodelet : public nodelet::Nodelet { public: virtual void onInit(); AckermannCmdMuxNodelet() { dynamic_reconfigure_server = NULL; } ~AckermannCmdMuxNodelet() { if (dynamic_reconfigure_server != NULL) delete dynamic_reconfigure_server; } private: AckermannCmdSubscribers ackermann_cmd_sub; /**< Pool of ackermann_cmd topics subscribers */ ros::Publisher mux_ackermann_cmd_pub; /**< Multiplexed ackermann command topic */ ros::Publisher active_subscriber; /**< Currently allowed ackermann_cmd subscriber */ void timerCallback(const ros::TimerEvent& event, unsigned int idx); void ackermannCmdCallback(const ackermann_msgs::AckermannDriveStamped::ConstPtr& msg, unsigned int idx); /********************* ** Dynamic Reconfigure **********************/ dynamic_reconfigure::Server * dynamic_reconfigure_server; dynamic_reconfigure::Server::CallbackType dynamic_reconfigure_cb; void reloadConfiguration(ackermann_cmd_mux::reloadConfig &config, uint32_t unused_level); /********************* ** Private Classes **********************/ // Functor assigned to each incoming ackermann command topic to bind it to ackermann_cmd callback class AckermannCmdFunctor { private: unsigned int idx; AckermannCmdMuxNodelet* node; public: AckermannCmdFunctor(unsigned int idx, AckermannCmdMuxNodelet* node) : idx(idx), node(node) { } void operator()(const ackermann_msgs::AckermannDriveStamped::ConstPtr& msg) { node->ackermannCmdCallback(msg, idx); } }; // Functor assigned to each ackermann command messages source to bind it to timer callback class TimerFunctor { private: unsigned int idx; AckermannCmdMuxNodelet* node; public: TimerFunctor(unsigned int idx, AckermannCmdMuxNodelet* node) : idx(idx), node(node) { } void operator()(const ros::TimerEvent& event) { node->timerCallback(event, idx); } }; }; } // namespace ackermann_cmd_mux #endif /* RACECAR_ACKERMANN_CMD_MUX_HPP_ */ ================================================ FILE: ackermann_cmd_mux/include/ackermann_cmd_mux/ackermann_cmd_subscribers.hpp ================================================ /** * @file /include/ackermann_cmd_mux/ackermann_cmd_subscribers.hpp * * @brief Structure for the ackermann_cmd_mux. * * License: BSD * https://raw.github.com/yujinrobot/yujin_ocs/hydro/yocs_ackermann_cmd_mux/LICENSE **/ /***************************************************************************** ** Ifdefs *****************************************************************************/ #ifndef RACECAR_ACKERMANN_CMD_SUBSCRIBERS_HPP_ #define RACECAR_ACKERMANN_CMD_SUBSCRIBERS_HPP_ /***************************************************************************** ** Includes *****************************************************************************/ #include #include #include #ifdef HAVE_NEW_YAMLCPP // The >> operator disappeared in yaml-cpp 0.5, so this function is // added to provide support for code written under the yaml-cpp 0.3 API. template void operator >> (const YAML::Node& node, T& i) { i = node.as(); } #endif /***************************************************************************** ** Preprocessing *****************************************************************************/ // move to a static const? #define VACANT std::numeric_limits::max() /***************************************************************************** ** Namespaces *****************************************************************************/ namespace ackermann_cmd_mux { /***************************************************************************** ** AckermannCmdSubscribers *****************************************************************************/ /** * Pool of ackermann_cmd topics subscribers */ class AckermannCmdSubscribers { public: /** * Inner class describing an individual subscriber to a ackermann_cmd topic */ class AckermannCmdSubs { public: unsigned int idx; /**< Index; assigned according to the order on YAML file */ std::string name; /**< Descriptive name */ ros::Subscriber subs; /**< The subscriber itself */ std::string topic; /**< The name of the topic */ ros::Timer timer; /**< No incoming messages timeout */ double timeout; /**< Timer's timeout, in seconds */ unsigned int priority; /**< UNIQUE integer from 0 (lowest priority) to MAX_INT */ std::string short_desc; /**< Short description (optional) */ bool active; /**< Whether this source is active */ AckermannCmdSubs(unsigned int idx) : idx(idx), active(false) {}; void operator << (const YAML::Node& node); }; AckermannCmdSubscribers() : allowed(VACANT) { } ~AckermannCmdSubscribers() { } std::vector::size_type size() { return list.size(); }; AckermannCmdSubs& operator [] (unsigned int idx) { return list[idx]; }; /** * @brief Configures the subscribers from a yaml file. * * @exception FileNotFoundException : yaml file not found * @exception YamlException : problem parsing the yaml * @exception EmptyCfgException : empty configuration file * @param node : node holding all the subscriber configuration */ void configure(const YAML::Node& node); unsigned int allowed; private: std::vector list; }; } // namespace ackermann_cmd_mux #endif /* ACKERMANN_CMD_SUBSCRIBERS_HPP_ */ ================================================ FILE: ackermann_cmd_mux/include/ackermann_cmd_mux/exceptions.hpp ================================================ /** * @file /ackermann_cmd_mux/include/ackermann_cmd_mux/exceptions.hpp * * @brief Exception classes for ackermann_cmd_mux. * * License: BSD * https://raw.github.com/yujinrobot/yujin_ocs/hydro/yocs_ackermann_cmd_mux/LICENSE **/ /***************************************************************************** ** Ifdefs *****************************************************************************/ #ifndef RACECAR_ACKERMANN_CMD_EXCEPTIONS_HPP_ #define RACECAR_ACKERMANN_CMD_EXCEPTIONS_HPP_ /***************************************************************************** ** Includes *****************************************************************************/ #include /***************************************************************************** ** Namespaces *****************************************************************************/ namespace ackermann_cmd_mux { /***************************************************************************** ** Exceptions *****************************************************************************/ class FileNotFoundException: public std::runtime_error { public: FileNotFoundException(const std::string& msg) : std::runtime_error(msg) {} virtual ~FileNotFoundException() throw() {} }; class EmptyCfgException: public std::runtime_error { public: EmptyCfgException() : std::runtime_error("") {} virtual ~EmptyCfgException() throw() {} }; class YamlException: public std::runtime_error { public: YamlException(const std::string& msg) : std::runtime_error(msg) {} virtual ~YamlException() throw() {} }; } // namespace ackermann_cmd_mux #endif /* RACECAR_ACKERMANN_CMD_EXCEPTIONS_HPP_ */ ================================================ FILE: ackermann_cmd_mux/launch/ackermann_cmd_mux.launch ================================================ ================================================ FILE: ackermann_cmd_mux/launch/reconfigure.launch ================================================ ================================================ FILE: ackermann_cmd_mux/launch/standalone.launch ================================================ ================================================ FILE: ackermann_cmd_mux/package.xml ================================================ ackermann_cmd_mux 0.7.0 A multiplexer for ackermann command velocity inputs. Arbitrates incoming ackermann_cmd messages from several topics, allowing one topic at a time to command the robot, based on priorities. It also deallocates current allowed topic if no messages are received after a configured timeout. All topics, together with their priority and timeout are configured through a YAML file, that can be reload at runtime. Blatantly derived / copied from yujin_ocs/yocs_cmd_vel_mux. Jorge Santos Simon Michael Boulet Michael Boulet BSD http://ros.org/wiki/ackermann_cmd_mux https://github.mit.edu/racecar/racecar https://github.mit.edu/racecar/racecar/issues catkin roscpp nodelet dynamic_reconfigure pluginlib ackermann_msgs yaml-cpp rospy std_msgs roscpp ackermann_msgs pluginlib nodelet dynamic_reconfigure yaml-cpp rospy std_msgs ================================================ FILE: ackermann_cmd_mux/param/example.yaml ================================================ # Created on: Oct 29, 2012 # Author: jorge # Configuration for subscribers to ackermann_cmd sources. This file is provided just as an example. # Typically automatic controllers, as ROS navigation stack should have the minimum priority # # Used with example.launch # # Individual subscriber configuration: # name: Source name # topic: The topic that provides ackermann_cmd messages # timeout: Time in seconds without incoming messages to consider this topic inactive # priority: Priority: an UNIQUE unsigned integer from 0 (lowest) to MAX_INT # short_desc: Short description (optional) subscribers: - name: "Default input" topic: "input/default" timeout: 0.1 priority: 0 short_desc: "The default ackermann_cmd, controllers unaware that we are multiplexing ackermann_cmd should come here" - name: "Navigation stack" topic: "input/navigation" timeout: 0.5 priority: 1 short_desc: "Navigation stack controller" - name: "Onboard joystick" topic: "input/joystick" timeout: 0.1 priority: 10 - name: "Remote control" topic: "input/remote" timeout: 0.1 priority: 9 - name: "Web application" topic: "input/webapp" timeout: 0.3 priority: 8 - name: "Keyboard operation" topic: "input/keyop" timeout: 0.1 priority: 7 publisher: "output/ackermann_cmd" ================================================ FILE: ackermann_cmd_mux/param/reconfigure.yaml ================================================ # Another example configuration file, though this one is used to test the dynamic reconfiguration # of the ackermann_cmd_mux. Used with reconfigure.launch. subscribers: - name: "Default input" topic: "input/default" timeout: 0.1 priority: 0 short_desc: "The default ackermann_cmd, controllers unaware that we are multiplexing ackermann_cmd should come here" - name: "Navigation stack" topic: "input/navigation" timeout: 0.5 priority: 1 short_desc: "Navigation stack controller" - name: "Safety controller" topic: "input/safety" timeout: 0.1 priority: 10 short_desc: "Used with the reactive velocity control provided by the bumper/cliff sensor safety controller" ================================================ FILE: ackermann_cmd_mux/plugins/nodelets.xml ================================================ Implementation for the ackermann command multiplexer as a nodelet. ================================================ FILE: ackermann_cmd_mux/src/ackermann_cmd_mux_nodelet.cpp ================================================ /** * @file /src/ackermann_cmd_mux_nodelet.cpp * * @brief Implementation for the ackermann command multiplexer * * License: BSD * https://raw.github.com/yujinrobot/yujin_ocs/hydro/yocs_ackermann_cmd_mux/LICENSE **/ /***************************************************************************** ** Includes *****************************************************************************/ #include #include #include #include "ackermann_cmd_mux/ackermann_cmd_mux_nodelet.hpp" #include "ackermann_cmd_mux/exceptions.hpp" /***************************************************************************** ** Namespaces *****************************************************************************/ namespace ackermann_cmd_mux { /***************************************************************************** ** Implementation *****************************************************************************/ void AckermannCmdMuxNodelet::ackermannCmdCallback(const ackermann_msgs::AckermannDriveStamped::ConstPtr& msg, unsigned int idx) { // Reset timer for this source ackermann_cmd_sub[idx].timer.stop(); ackermann_cmd_sub[idx].timer.start(); ackermann_cmd_sub[idx].active = true; // obviously his source is sending commands, so active // Give permit to publish to this source if it's the only active or is // already allowed or has higher priority that the currently allowed if ((ackermann_cmd_sub.allowed == VACANT) || (ackermann_cmd_sub.allowed == idx) || (ackermann_cmd_sub[idx].priority > ackermann_cmd_sub[ackermann_cmd_sub.allowed].priority)) { if (ackermann_cmd_sub.allowed != idx) { ackermann_cmd_sub.allowed = idx; // Notify the world that a new ackermann_cmd source took the control std_msgs::StringPtr acv_msg(new std_msgs::String); acv_msg->data = ackermann_cmd_sub[idx].name; if (active_subscriber) { active_subscriber.publish(acv_msg); } } if (mux_ackermann_cmd_pub){ mux_ackermann_cmd_pub.publish(msg); } } } void AckermannCmdMuxNodelet::timerCallback(const ros::TimerEvent& event, unsigned int idx) { if (ackermann_cmd_sub.allowed == idx) { // No ackermann_cmd messages timeout happened to currently active source, so... ackermann_cmd_sub.allowed = VACANT; // ...notify the world that nobody is publishing on ackermann_cmd; its vacant std_msgs::StringPtr acv_msg(new std_msgs::String); acv_msg->data = "idle"; if (active_subscriber){ active_subscriber.publish(acv_msg); } } ackermann_cmd_sub[idx].active = false; } void AckermannCmdMuxNodelet::onInit() { ros::NodeHandle &nh = this->getPrivateNodeHandle(); /********************* ** Dynamic Reconfigure **********************/ dynamic_reconfigure_cb = boost::bind(&AckermannCmdMuxNodelet::reloadConfiguration, this, _1, _2); dynamic_reconfigure_server = new dynamic_reconfigure::Server(nh); dynamic_reconfigure_server->setCallback(dynamic_reconfigure_cb); active_subscriber = nh.advertise ("active", 1, true); // latched topic // Notify the world that by now nobody is publishing on ackermann_cmd yet std_msgs::StringPtr active_msg(new std_msgs::String); active_msg->data = "idle"; if (active_subscriber) { active_subscriber.publish(active_msg); } // could use a call to reloadConfiguration here, but it seems to automatically call it once with defaults anyway. NODELET_DEBUG("AckermannCmdMux : successfully initialised"); } void AckermannCmdMuxNodelet::reloadConfiguration(ackermann_cmd_mux::reloadConfig &config, uint32_t unused_level) { std::string yaml_cfg_file; ros::NodeHandle &nh = this->getNodeHandle(); ros::NodeHandle &nh_priv = this->getPrivateNodeHandle(); if( config.yaml_cfg_file == "" ) { // typically fired on startup, so look for a parameter to set a default nh_priv.getParam("yaml_cfg_file", yaml_cfg_file); } else { yaml_cfg_file = config.yaml_cfg_file; } /********************* ** Yaml File Parsing **********************/ std::ifstream ifs(yaml_cfg_file.c_str(), std::ifstream::in); if (ifs.good() == false) { NODELET_ERROR_STREAM("AckermannCmdMux : configuration file not found [" << yaml_cfg_file << "]"); return; } // probably need to bring the try catches back here YAML::Node doc; #ifdef HAVE_NEW_YAMLCPP doc = YAML::Load(ifs); #else YAML::Parser parser(ifs); parser.GetNextDocument(doc); #endif /********************* ** Output Publisher **********************/ std::string output_name("output"); #ifdef HAVE_NEW_YAMLCPP if ( doc["publisher"] ) { doc["publisher"] >> output_name; } #else const YAML::Node *node = doc.FindValue("publisher"); if ( node != NULL ) { *node >> output_name; } #endif mux_ackermann_cmd_pub = nh_priv.advertise (output_name, 10); /********************* ** Input Subscribers **********************/ try { ackermann_cmd_sub.configure(doc["subscribers"]); } catch(EmptyCfgException& e) { NODELET_WARN("AckermannCmdMux : yaml configured zero subscribers, check yaml content."); } catch(YamlException& e) { NODELET_ERROR_STREAM("AckermannCmdMux : yaml parsing problem [" << std::string(e.what()) + "]"); } // Publishers and subscribers for (unsigned int i = 0; i < ackermann_cmd_sub.size(); i++) { ackermann_cmd_sub[i].subs = nh_priv.subscribe(ackermann_cmd_sub[i].topic, 10, AckermannCmdFunctor(i, this)); // Create (stopped by now) a one-shot timer for every subscriber ackermann_cmd_sub[i].timer = nh_priv.createTimer(ros::Duration(ackermann_cmd_sub[i].timeout), TimerFunctor(i, this), true, false); NODELET_DEBUG("AckermannCmdMux : subscribed to '%s' on topic '%s'. pr: %d, to: %.2f", ackermann_cmd_sub[i].name.c_str(), ackermann_cmd_sub[i].topic.c_str(), ackermann_cmd_sub[i].priority, ackermann_cmd_sub[i].timeout); } NODELET_INFO_STREAM("AckermannCmdMux : (re)configured [" << yaml_cfg_file << "]"); ifs.close(); } } // namespace ackermann_cmd_mux PLUGINLIB_EXPORT_CLASS(ackermann_cmd_mux::AckermannCmdMuxNodelet, nodelet::Nodelet); ================================================ FILE: ackermann_cmd_mux/src/ackermann_cmd_subscribers.cpp ================================================ /** * @file /src/ackermann_cmd_subscribers.cpp * * @brief Subscriber handlers for the ackermann_cmd_mux * * License: BSD * https://raw.github.com/yujinrobot/yujin_ocs/hydro/yocs_ackermann_cmd_mux/LICENSE **/ /***************************************************************************** ** Includes *****************************************************************************/ #include #include "ackermann_cmd_mux/ackermann_cmd_subscribers.hpp" #include "ackermann_cmd_mux/exceptions.hpp" /***************************************************************************** ** Namespaces *****************************************************************************/ namespace ackermann_cmd_mux { /***************************************************************************** ** Implementation *****************************************************************************/ void AckermannCmdSubscribers::AckermannCmdSubs::operator << (const YAML::Node& node) { node["name"] >> name; node["topic"] >> topic; node["timeout"] >> timeout; node["priority"] >> priority; #ifdef HAVE_NEW_YAMLCPP if (node["short_desc"]) { #else if (node.FindValue("short_desc") != NULL) { #endif node["short_desc"] >> short_desc; } } void AckermannCmdSubscribers::configure(const YAML::Node& node) { list.clear(); try { if ( node.size() == 0 ) { throw EmptyCfgException(); } for (unsigned int i = 0; i < node.size(); i++) { // Parse every entries on YAML AckermannCmdSubs subscriber(i); subscriber << node[i]; list.push_back(subscriber); } } catch(EmptyCfgException& e) { throw e; } catch(YAML::ParserException& e) { throw YamlException(e.what()); } catch(YAML::RepresentationException& e) { throw YamlException(e.what()); } } } // namespace ackermann_cmd_mux ================================================ FILE: ackermann_cmd_mux/src/throttle_interpolator.py ================================================ #!/usr/bin/env python import rospy from std_msgs.msg import Float64 # import some utils. import numpy as np import copy as copy class InterpolateThrottle: def __init__(self): # Allow our topics to be dynamic. self.rpm_input_topic = rospy.get_param('~rpm_input_topic', '/vesc/commands/motor/unsmoothed_speed') self.rpm_output_topic = rospy.get_param('~rpm_output_topic', '/vesc/commands/motor/speed') self.servo_input_topic = rospy.get_param('~servo_input_topic', '/vesc/commands/servo/unsmoothed_position') self.servo_output_topic = rospy.get_param('~servo_output_topic', '/vesc/commands/servo/position') self.max_acceleration = rospy.get_param('/vesc/max_acceleration') self.max_rpm = rospy.get_param('/vesc/vesc_driver/speed_max') self.min_rpm = rospy.get_param('/vesc/vesc_driver/speed_min') self.throttle_smoother_rate = rospy.get_param('/vesc/throttle_smoother_rate') self.speed_to_erpm_gain = rospy.get_param('/vesc/speed_to_erpm_gain') self.max_servo_speed = rospy.get_param('/vesc/max_servo_speed') self.steering_angle_to_servo_gain = rospy.get_param('/vesc/steering_angle_to_servo_gain') self.servo_smoother_rate = rospy.get_param('/vesc/servo_smoother_rate') self.max_servo = rospy.get_param('/vesc/vesc_driver/servo_max') self.min_servo = rospy.get_param('/vesc/vesc_driver/servo_min') # Variables self.last_rpm = 0 self.desired_rpm = self.last_rpm self.last_servo = rospy.get_param('/vesc/steering_angle_to_servo_offset') self.desired_servo_position = self.last_servo # Create topic subscribers and publishers self.rpm_output = rospy.Publisher(self.rpm_output_topic, Float64,queue_size=1) self.servo_output = rospy.Publisher(self.servo_output_topic, Float64,queue_size=1) rospy.Subscriber(self.rpm_input_topic, Float64, self._process_throttle_command) rospy.Subscriber(self.servo_input_topic, Float64, self._process_servo_command) self.max_delta_servo = abs(self.steering_angle_to_servo_gain * self.max_servo_speed / self.servo_smoother_rate) rospy.Timer(rospy.Duration(1.0/self.servo_smoother_rate), self._publish_servo_command) self.max_delta_rpm = abs(self.speed_to_erpm_gain * self.max_acceleration / self.throttle_smoother_rate) rospy.Timer(rospy.Duration(1.0/self.max_delta_rpm), self._publish_throttle_command) # run the node self._run() # Keep the node alive def _run(self): rospy.spin() def _publish_throttle_command(self, evt): desired_delta = self.desired_rpm-self.last_rpm clipped_delta = max(min(desired_delta, self.max_delta_rpm), -self.max_delta_rpm) smoothed_rpm = self.last_rpm + clipped_delta self.last_rpm = smoothed_rpm # print self.desired_rpm, smoothed_rpm self.rpm_output.publish(Float64(smoothed_rpm)) def _process_throttle_command(self,msg): input_rpm = msg.data # Do some sanity clipping input_rpm = min(max(input_rpm, self.min_rpm), self.max_rpm) self.desired_rpm = input_rpm def _publish_servo_command(self, evt): desired_delta = self.desired_servo_position-self.last_servo clipped_delta = max(min(desired_delta, self.max_delta_servo), -self.max_delta_servo) smoothed_servo = self.last_servo + clipped_delta self.last_servo = smoothed_servo self.servo_output.publish(Float64(smoothed_servo)) def _process_servo_command(self,msg): input_servo = msg.data # Do some sanity clipping input_servo = min(max(input_servo, self.min_servo), self.max_servo) # set the target servo position self.desired_servo_position = input_servo # Boilerplate node spin up. if __name__ == '__main__': try: rospy.init_node('Throttle_Interpolator') p = InterpolateThrottle() except rospy.ROSInterruptException: pass ================================================ FILE: racecar/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 2.8.3) project(racecar) ## Find catkin macros and libraries ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) ## is used, also find other catkin packages find_package(catkin REQUIRED) ## System dependencies are found with CMake's conventions # find_package(Boost REQUIRED COMPONENTS system) ## Uncomment this if the package has a setup.py. This macro ensures ## modules and global scripts declared therein get installed ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html # catkin_python_setup() ################################################ ## Declare ROS messages, services and actions ## ################################################ ## To declare and build messages, services or actions from within this ## package, follow these steps: ## * Let MSG_DEP_SET be the set of packages whose message types you use in ## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). ## * In the file package.xml: ## * add a build_depend and a run_depend tag for each package in MSG_DEP_SET ## * If MSG_DEP_SET isn't empty the following dependencies might have been ## pulled in transitively but can be declared for certainty nonetheless: ## * add a build_depend tag for "message_generation" ## * add a run_depend tag for "message_runtime" ## * In this file (CMakeLists.txt): ## * add "message_generation" and every package in MSG_DEP_SET to ## find_package(catkin REQUIRED COMPONENTS ...) ## * add "message_runtime" and every package in MSG_DEP_SET to ## catkin_package(CATKIN_DEPENDS ...) ## * uncomment the add_*_files sections below as needed ## and list every .msg/.srv/.action file to be processed ## * uncomment the generate_messages entry below ## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) ## Generate messages in the 'msg' folder # add_message_files( # FILES # Message1.msg # Message2.msg # ) ## Generate services in the 'srv' folder # add_service_files( # FILES # Service1.srv # Service2.srv # ) ## Generate actions in the 'action' folder # add_action_files( # FILES # Action1.action # Action2.action # ) ## Generate added messages and services with any dependencies listed here # generate_messages( # DEPENDENCIES # std_msgs # Or other packages containing msgs # ) ################################### ## catkin specific configuration ## ################################### ## The catkin_package macro generates cmake config files for your package ## Declare things to be passed to dependent projects ## INCLUDE_DIRS: uncomment this if you package contains header files ## LIBRARIES: libraries you create in this project that dependent projects also need ## CATKIN_DEPENDS: catkin_packages dependent projects also need ## DEPENDS: system dependencies of this project that dependent projects also need catkin_package( # INCLUDE_DIRS include # LIBRARIES racecar_launch CATKIN_DEPENDS razor_imu_9dof tf tf2_ros urg_node joy rosbag rostopic rviz # specific to racecar-v1 #pointgrey_camera_driver #px4flow #pwm_sysfs_driver # specific to racecar-v2 # mapping gmapping hector_mapping robot_pose_ekf # DEPENDS system_lib ) ########### ## Build ## ########### ## Specify additional locations of header files ## Your package locations should be listed before other locations # include_directories(include) ## Declare a cpp library # add_library(racecar_launch # src/${PROJECT_NAME}/racecar_launch.cpp # ) ## Declare a cpp executable # add_executable(racecar_launch_node src/racecar_launch_node.cpp) ## Add cmake target dependencies of the executable/library ## as an example, message headers may need to be generated before nodes # add_dependencies(racecar_launch_node racecar_launch_generate_messages_cpp) ## Specify libraries to link a library or executable target against # target_link_libraries(racecar_launch_node # ${catkin_LIBRARIES} # ) ############# ## Install ## ############# # all install targets should use catkin DESTINATION variables # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html ## Mark executable scripts (Python etc.) for installation ## in contrast to setup.py, you can choose the destination # install(PROGRAMS # scripts/my_python_script # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} # ) ## Mark executables and/or libraries for installation # install(TARGETS racecar_launch racecar_launch_node # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} # ) ## Mark cpp header files for installation # install(DIRECTORY include/${PROJECT_NAME}/ # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} # FILES_MATCHING PATTERN "*.h" # PATTERN ".svn" EXCLUDE # ) ## Mark other files for installation (e.g. launch and bag files, etc.) # install(FILES # # myfile1 # # myfile2 # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} # ) install(DIRECTORY launch DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} ) ############# ## Testing ## ############# ## Add gtest based cpp test target and link libraries # catkin_add_gtest(${PROJECT_NAME}-test test/test_racecar_launch.cpp) # if(TARGET ${PROJECT_NAME}-test) # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) # endif() ## Add folders to be run by python nosetests # catkin_add_nosetests(test) ================================================ FILE: racecar/LICENSE ================================================ # Software License Agreement (BSD License) # # Copyright (c) 2016 Massachusetts Institute of Technology. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Massachusetts Institute of Technology nor the # names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: racecar/config/racecar-v2/high_level_mux.yaml ================================================ # Individual subscriber configuration: # name: Source name # topic: The topic that provides ackermann_cmd messages # timeout: Time in seconds without incoming messages to consider this topic inactive # priority: Priority: an UNIQUE unsigned integer from 0 (lowest) to MAX_INT # short_desc: Short description (optional) subscribers: - name: "Nav_0" topic: "input/nav_0" timeout: 0.2 priority: 20 short_desc: "Input for autonomous navigation, highest priority" - name: "Nav_1" topic: "input/nav_1" timeout: 0.2 priority: 15 short_desc: "Input for autonomous navigation" - name: "Nav_2" topic: "input/nav_2" timeout: 0.2 priority: 10 short_desc: "Input for autonomous navigation" - name: "Nav_3" topic: "input/nav_3" timeout: 0.2 priority: 5 short_desc: "Input for autonomous navigation" - name: "Default" topic: "input/default" timeout: 1.0 priority: 0 short_desc: "Default input, lowest priority" publisher: "output" ================================================ FILE: racecar/config/racecar-v2/joy_teleop.yaml ================================================ joy_node: deadzone: 0.01 autorepeat_rate: 20 coalesce_interval: 0.01 teleop: # Default mode - Stop for safety default: type: topic is_default: true message_type: ackermann_msgs/AckermannDriveStamped topic_name: low_level/ackermann_cmd_mux/input/teleop message_value: - target: drive.speed value: 0.0 - target: drive.steering_angle value: 0.0 # Enable Human control by holding Left Bumper human_control: type: topic message_type: ackermann_msgs/AckermannDriveStamped topic_name: low_level/ackermann_cmd_mux/input/teleop deadman_buttons: [4] axis_mappings: - axis: 1 target: drive.speed scale: 2.0 # joystick will command plus or minus 2 meters / second offset: 0.0 - axis: 3 target: drive.steering_angle scale: 0.34 # joystick will command plus or minus ~20 degrees steering angle offset: 0.0 # Enable autonomous control by pressing right bumper # This switch causes the joy_teleop to stop sending messages to input/teleop # And send messages to /dev/null (an unused ROS topic) autonomous_control: type: topic message_type: std_msgs/Int8 topic_name: /dev/null deadman_buttons: [5] message_value: - target: data value: 0 ================================================ FILE: racecar/config/racecar-v2/low_level_mux.yaml ================================================ # Individual subscriber configuration: # name: Source name # topic: The topic that provides ackermann_cmd messages # timeout: Time in seconds without incoming messages to consider this topic inactive # priority: Priority: an UNIQUE unsigned integer from 0 (lowest) to MAX_INT # short_desc: Short description (optional) subscribers: - name: "Teleoperation" topic: "input/teleop" timeout: 0.2 priority: 10 short_desc: "Input for human teleoperation (joystick). Highest priority." - name: "Safety" topic: "input/safety" timeout: 0.2 priority: 5 short_desc: "Input for safety monitor." - name: "Navigation" topic: "input/navigation" timeout: 0.2 priority: 0 short_desc: "Input for autonomous navigation" publisher: "output" ================================================ FILE: racecar/config/racecar-v2/sensors.yaml ================================================ laser_node: ip_address: 192.168.0.10 imu_node: device: /dev/imu port: /dev/ttyIMU ================================================ FILE: racecar/config/racecar-v2/vesc.yaml ================================================ # erpm (electrical rpm) = speed_to_erpm_gain * speed (meters / second) + speed_to_erpm_offset # for offset=0. speed_to_erpm_gain = num_motor_poles*60/circumference_wheel_in_meters speed_to_erpm_gain: 4614 speed_to_erpm_offset: 0.0 tachometer_ticks_to_meters_gain: 0.00225 # servo smoother - limits rotation speed and smooths anything above limit max_servo_speed: 3.2 # radians/second servo_smoother_rate: 75.0 # messages/sec # servo smoother - limits acceleration and smooths anything above limit max_acceleration: 3.5 # meters/second^2 throttle_smoother_rate: 75.0 # messages/sec # servo value (0 to 1) = steering_angle_to_servo_gain * steering angle (radians) + steering_angle_to_servo_offset steering_angle_to_servo_gain: -1.2135 steering_angle_to_servo_offset: 0.5304 # publish odom to base link tf vesc_to_odom/publish_tf: false # car wheelbase is about 25cm wheelbase: .25 vesc_driver: port: /dev/ttyVESC duty_cycle_min: 0.0 duty_cycle_max: 0.0 current_min: 0.0 current_max: 20.0 brake_min: -20000.0 brake_max: 200000.0 speed_min: -3250 speed_max: 10000 position_min: 0.0 position_max: 0.0 servo_min: 0.15 servo_max: 0.85 ================================================ FILE: racecar/launch/includes/common/joy_teleop.launch.xml ================================================ ================================================ FILE: racecar/launch/includes/common/sensors.launch.xml ================================================ ================================================ FILE: racecar/launch/includes/racecar-v2/static_transforms.launch.xml ================================================ ================================================ FILE: racecar/launch/includes/racecar-v2/velodyne.launch.xml ================================================ ================================================ FILE: racecar/launch/includes/racecar-v2/vesc.launch.xml ================================================ ================================================ FILE: racecar/launch/includes/racecar-v2-teleop.launch.xml ================================================ ================================================ FILE: racecar/launch/known_map_localization.launch ================================================ ================================================ FILE: racecar/launch/mux.launch ================================================ ================================================ FILE: racecar/launch/replay_bag_file/replay_bag_file.launch ================================================ ================================================ FILE: racecar/launch/replay_bag_file/replay_bag_mapping.launch ================================================ ================================================ FILE: racecar/launch/replay_bag_file/replay_bag_with_lidar_processing.launch ================================================ ================================================ FILE: racecar/launch/teleop.launch ================================================ ================================================ FILE: racecar/maps/basement_hallways_10cm.yaml ================================================ image: basement_hallways_10cm.png resolution: 0.100000 origin: [-30.000000, -30.000000, 0.000000] negate: 0 occupied_thresh: 0.65 free_thresh: 0.196 ================================================ FILE: racecar/maps/basement_hallways_5cm.yml ================================================ image: basement_hallways_5cm.png resolution: 0.050000 origin: [-30.000000, -30.000000, 0.000000] negate: 0 occupied_thresh: 0.65 free_thresh: 0.196 ================================================ FILE: racecar/maps/short-course-33.yml ================================================ image: short-course-33.png resolution: 0.025000 origin: [-11.50000, -5.000000, -0.090000] negate: 0 occupied_thresh: 0.65 free_thresh: 0.196 ================================================ FILE: racecar/package.xml ================================================ racecar 0.0.1 RACECAR launch scripts Michael Boulet Michael Boulet BSD catkin razor_imu_9dof tf tf2_ros urg_node joy rosbag rostopic rviz gmapping hector_mapping robot_pose_ekf ================================================ FILE: racecar/rviz/known_map_localization.rviz ================================================ Panels: - Class: rviz/Displays Help Height: 78 Name: Displays Property Tree Widget: Expanded: - /Global Options1 - /TF1/Tree1/map1 - /TF1/Tree1/map1/odom1 - /TF1/Tree1/map1/odom1/base_footprint1 - /TF1/Tree1/map1/odom1/base_footprint1/base_link1 Splitter Ratio: 0.5 Tree Height: 531 - Class: rviz/Selection Name: Selection - Class: rviz/Tool Properties Expanded: - /2D Pose Estimate1 - /2D Nav Goal1 Name: Tool Properties Splitter Ratio: 0.588679 - Class: rviz/Views Expanded: - /Current View1 Name: Views Splitter Ratio: 0.5 - Class: rviz/Time Experimental: false Name: Time SyncMode: 0 SyncSource: LaserScan Visualization Manager: Class: "" Displays: - Alpha: 0.5 Cell Size: 1 Class: rviz/Grid Color: 160; 160; 164 Enabled: true Line Style: Line Width: 0.03 Value: Lines Name: Grid Normal Cell Count: 0 Offset: X: 0 Y: 0 Z: 0 Plane: XY Plane Cell Count: 10 Reference Frame: map Value: true - Class: rviz/TF Enabled: false Frame Timeout: 15 Frames: All Enabled: false base_footprint: Value: true base_link: Value: false camera_depth_frame: Value: false camera_depth_optical_frame: Value: false camera_link: Value: false camera_rgb_frame: Value: false camera_rgb_optical_frame: Value: false caster_back_link: Value: false caster_front_link: Value: false cliff_sensor_front_link: Value: false cliff_sensor_left_link: Value: false cliff_sensor_right_link: Value: false gyro_link: Value: false map: Value: true odom: Value: true plate_bottom_link: Value: false plate_middle_link: Value: false plate_top_link: Value: false pole_bottom_0_link: Value: false pole_bottom_1_link: Value: false pole_bottom_2_link: Value: false pole_bottom_3_link: Value: false pole_bottom_4_link: Value: false pole_bottom_5_link: Value: false pole_kinect_0_link: Value: false pole_kinect_1_link: Value: false pole_middle_0_link: Value: false pole_middle_1_link: Value: false pole_middle_2_link: Value: false pole_middle_3_link: Value: false pole_top_0_link: Value: false pole_top_1_link: Value: false pole_top_2_link: Value: false pole_top_3_link: Value: false wheel_left_link: Value: false wheel_right_link: Value: false Marker Scale: 1 Name: TF Show Arrows: true Show Axes: true Show Names: true Tree: map: odom: base_footprint: base_link: camera_rgb_frame: camera_depth_frame: camera_depth_optical_frame: {} camera_link: {} camera_rgb_optical_frame: {} caster_back_link: {} caster_front_link: {} cliff_sensor_front_link: {} cliff_sensor_left_link: {} cliff_sensor_right_link: {} gyro_link: {} plate_bottom_link: {} plate_middle_link: {} plate_top_link: {} pole_bottom_0_link: {} pole_bottom_1_link: {} pole_bottom_2_link: {} pole_bottom_3_link: {} pole_bottom_4_link: {} pole_bottom_5_link: {} pole_kinect_0_link: {} pole_kinect_1_link: {} pole_middle_0_link: {} pole_middle_1_link: {} pole_middle_2_link: {} pole_middle_3_link: {} pole_top_0_link: {} pole_top_1_link: {} pole_top_2_link: {} pole_top_3_link: {} wheel_left_link: {} wheel_right_link: {} Update Interval: 0 Value: false - Alpha: 1 Autocompute Intensity Bounds: true Autocompute Value Bounds: Max Value: 10 Min Value: -10 Value: true Axis: Z Channel Name: intensity Class: rviz/LaserScan Color: 255; 0; 0 Color Transformer: FlatColor Decay Time: 0 Enabled: true Invert Rainbow: false Max Color: 255; 255; 255 Max Intensity: 4096 Min Color: 0; 0; 0 Min Intensity: 0 Name: LaserScan Position Transformer: XYZ Queue Size: 10 Selectable: true Size (Pixels): 3 Size (m): 0.03 Style: Points Topic: /scan Use Fixed Frame: true Use rainbow: true Value: true - Alpha: 0.7 Class: rviz/Map Color Scheme: map Draw Behind: false Enabled: true Name: Map Topic: /map Value: true - Arrow Length: 0.2 Class: rviz/PoseArray Color: 0; 192; 0 Enabled: true Name: Amcl Particles Topic: /particlecloud Value: true - Angle Tolerance: 0.1 Class: rviz/Odometry Color: 0; 255; 255 Enabled: true Keep: 500 Length: 0.1 Name: Odometry Position Tolerance: 0.1 Topic: /vesc/odom Value: true Enabled: true Global Options: Background Color: 48; 48; 48 Fixed Frame: map Frame Rate: 30 Name: root Tools: - Class: rviz/MoveCamera - Class: rviz/Interact Hide Inactive Objects: true - Class: rviz/Select - Class: rviz/SetInitialPose Topic: /initialpose - Class: rviz/SetGoal Topic: /move_base_simple/goal - Class: rviz/Measure Value: true Views: Current: Angle: -1.935 Class: rviz/TopDownOrtho Enable Stereo Rendering: Stereo Eye Separation: 0.06 Stereo Focal Distance: 1 Swap Stereo Eyes: false Value: false Name: Current View Near Clip Distance: 0.01 Scale: 100.79 Target Frame: base_footprint Value: TopDownOrtho (rviz) X: 1.71641 Y: 0.715559 Saved: ~ Window Geometry: Displays: collapsed: false Height: 744 Hide Left Dock: false Hide Right Dock: false QMainWindow State: 000000ff00000000fd000000040000000000000142000002a2fc0200000005fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006400fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c0061007900730100000028000002a2000000dd00ffffff000000010000010f000002a2fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a005600690065007700730100000028000002a2000000b000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004a00000003efc0100000002fb0000000800540069006d00650000000000000004a0000002f600fffffffb0000000800540069006d00650100000000000004500000000000000000000002b8000002a200000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 Selection: collapsed: false Time: collapsed: false Tool Properties: collapsed: false Views: collapsed: false Width: 1301 X: 57 Y: -4 ================================================ FILE: racecar/rviz/laser_scan_matcher.rviz ================================================ Panels: - Class: rviz/Displays Help Height: 78 Name: Displays Property Tree Widget: Expanded: - /Global Options1 - /Status1 - /Grid1 - /LaserScan1 - /TF1 - /TF1/Frames1 Splitter Ratio: 0.5 Tree Height: 434 - Class: rviz/Selection Name: Selection - Class: rviz/Tool Properties Expanded: - /2D Pose Estimate1 - /2D Nav Goal1 - /Publish Point1 Name: Tool Properties Splitter Ratio: 0.588679 - Class: rviz/Views Expanded: - /Current View1 Name: Views Splitter Ratio: 0.5 - Class: rviz/Time Experimental: false Name: Time SyncMode: 0 SyncSource: LaserScan Visualization Manager: Class: "" Displays: - Alpha: 0.5 Cell Size: 1 Class: rviz/Grid Color: 160; 160; 164 Enabled: true Line Style: Line Width: 0.03 Value: Lines Name: Grid Normal Cell Count: 0 Offset: X: 0 Y: 0 Z: 0 Plane: XY Plane Cell Count: 10 Reference Frame: Value: true - Alpha: 0.2 Autocompute Intensity Bounds: true Autocompute Value Bounds: Max Value: 10 Min Value: -10 Value: true Axis: Z Channel Name: intensity Class: rviz/LaserScan Color: 255; 0; 0 Color Transformer: FlatColor Decay Time: 0 Enabled: true Invert Rainbow: false Max Color: 255; 0; 0 Max Intensity: 4096 Min Color: 0; 0; 0 Min Intensity: 0 Name: LaserScan Position Transformer: XYZ Queue Size: 10 Selectable: true Size (Pixels): 3 Size (m): 0.025 Style: Flat Squares Topic: /scan Use Fixed Frame: true Use rainbow: true Value: true - Class: rviz/TF Enabled: true Frame Timeout: 15 Frames: All Enabled: true base_link: Value: true laser: Value: true world: Value: true Marker Scale: 1 Name: TF Show Arrows: true Show Axes: true Show Names: true Tree: world: base_link: laser: {} Update Interval: 0 Value: true Enabled: true Global Options: Background Color: 0; 0; 0 Fixed Frame: world Frame Rate: 30 Name: root Tools: - Class: rviz/Interact Hide Inactive Objects: true - Class: rviz/MoveCamera - Class: rviz/Select - Class: rviz/FocusCamera - Class: rviz/Measure - Class: rviz/SetInitialPose Topic: /initialpose - Class: rviz/SetGoal Topic: /move_base_simple/goal - Class: rviz/PublishPoint Single click: true Topic: /clicked_point Value: true Views: Current: Angle: 0 Class: rviz/TopDownOrtho Enable Stereo Rendering: Stereo Eye Separation: 0.06 Stereo Focal Distance: 1 Swap Stereo Eyes: false Value: false Name: Current View Near Clip Distance: 0.01 Scale: 150 Target Frame: Value: TopDownOrtho (rviz) X: 0 Y: 0 Saved: ~ Window Geometry: Displays: collapsed: false Height: 721 Hide Left Dock: false Hide Right Dock: false QMainWindow State: 000000ff00000000fd00000004000000000000013c0000023dfc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005300fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c00610079007301000000360000023d000000b700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f0000023dfc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a0056006900650077007301000000360000023d0000009b00fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004000000003efc0100000002fb0000000800540069006d00650100000000000004000000024500fffffffb0000000800540069006d00650100000000000004500000000000000000000001a90000023d00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 Selection: collapsed: false Time: collapsed: false Tool Properties: collapsed: false Views: collapsed: false Width: 1024 X: -2 Y: -2 ================================================ FILE: racecar/rviz/mapping.rviz ================================================ Panels: - Class: rviz/Displays Help Height: 78 Name: Displays Property Tree Widget: Expanded: - /Global Options1 - /Status1 - /Map1 - /LaserScan1 Splitter Ratio: 0.5 Tree Height: 565 - Class: rviz/Selection Name: Selection - Class: rviz/Tool Properties Expanded: - /2D Pose Estimate1 - /2D Nav Goal1 - /Publish Point1 Name: Tool Properties Splitter Ratio: 0.588679 - Class: rviz/Views Expanded: - /Current View1 Name: Views Splitter Ratio: 0.5 - Class: rviz/Time Experimental: false Name: Time SyncMode: 0 SyncSource: LaserScan Visualization Manager: Class: "" Displays: - Alpha: 0.5 Cell Size: 1 Class: rviz/Grid Color: 160; 160; 164 Enabled: true Line Style: Line Width: 0.03 Value: Lines Name: Grid Normal Cell Count: 0 Offset: X: 0 Y: 0 Z: 0 Plane: XY Plane Cell Count: 10 Reference Frame: Value: true - Alpha: 0.7 Class: rviz/Map Color Scheme: map Draw Behind: false Enabled: true Name: Map Topic: /map Value: true - Class: rviz/TF Enabled: true Frame Timeout: 15 Frames: All Enabled: true base_footprint: Value: true base_imu_link: Value: true base_link: Value: true camera: Value: true gmapping_map: Value: true hector_map: Value: true hector_odom: Value: true hector_scanmatcher_frame: Value: true laser: Value: true px4flow: Value: true Marker Scale: 1 Name: TF Show Arrows: true Show Axes: true Show Names: true Tree: gmapping_map: hector_map: hector_odom: base_link: base_footprint: {} base_imu_link: {} camera: {} laser: {} px4flow: {} hector_scanmatcher_frame: {} Update Interval: 0 Value: true - Alpha: 1 Autocompute Intensity Bounds: true Autocompute Value Bounds: Max Value: 10 Min Value: -10 Value: true Axis: Z Channel Name: intensity Class: rviz/LaserScan Color: 255; 255; 255 Color Transformer: Intensity Decay Time: 0 Enabled: true Invert Rainbow: false Max Color: 255; 255; 255 Max Intensity: 1030 Min Color: 0; 0; 0 Min Intensity: 370 Name: LaserScan Position Transformer: XYZ Queue Size: 10 Selectable: true Size (Pixels): 3 Size (m): 0.08 Style: Flat Squares Topic: /scan Use Fixed Frame: true Use rainbow: true Value: true Enabled: true Global Options: Background Color: 48; 48; 48 Fixed Frame: gmapping_map Frame Rate: 30 Name: root Tools: - Class: rviz/Interact Hide Inactive Objects: true - Class: rviz/MoveCamera - Class: rviz/Select - Class: rviz/FocusCamera - Class: rviz/Measure - Class: rviz/SetInitialPose Topic: /initialpose - Class: rviz/SetGoal Topic: /move_base_simple/goal - Class: rviz/PublishPoint Single click: true Topic: /clicked_point Value: true Views: Current: Angle: 0 Class: rviz/TopDownOrtho Enable Stereo Rendering: Stereo Eye Separation: 0.06 Stereo Focal Distance: 1 Swap Stereo Eyes: false Value: false Name: Current View Near Clip Distance: 0.01 Scale: 8.5022 Target Frame: Value: TopDownOrtho (rviz) X: -0.8955 Y: -15.9022 Saved: ~ Window Geometry: Displays: collapsed: false Height: 846 Hide Left Dock: false Hide Right Dock: false QMainWindow State: 000000ff00000000fd00000004000000000000013c000002c4fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006400fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c0061007900730100000028000002c4000000dd00fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002c4fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a005600690065007700730100000028000002c4000000b000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004b00000003efc0100000002fb0000000800540069006d00650100000000000004b0000002f600fffffffb0000000800540069006d0065010000000000000450000000000000000000000259000002c400000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 Selection: collapsed: false Time: collapsed: false Tool Properties: collapsed: false Views: collapsed: false Width: 1200 X: 372 Y: 50 ================================================ FILE: racecar/scripts/joy_teleop.py ================================================ #!/usr/bin/env python import importlib import rospy import genpy.message from rospy import ROSException import sensor_msgs.msg import actionlib import rostopic import rosservice from threading import Thread from rosservice import ROSServiceException import numpy as np class JoyTeleopException(Exception): pass ''' Originally from https://github.com/ros-teleop/teleop_tools Pulled on April 28, 2017. Edited by Winter Guerra on April 28, 2017 to allow for default actions. ''' class JoyTeleop: """ Generic joystick teleoperation node. Will not start without configuration, has to be stored in 'teleop' parameter. See config/joy_teleop.yaml for an example. """ def __init__(self): if not rospy.has_param("teleop"): rospy.logfatal("no configuration was found, taking node down") raise JoyTeleopException("no config") self.publishers = {} self.al_clients = {} self.srv_clients = {} self.service_types = {} self.message_types = {} self.command_list = {} self.offline_actions = [] self.offline_services = [] self.old_buttons = [] teleop_cfg = rospy.get_param("teleop") for i in teleop_cfg: if i in self.command_list: rospy.logerr("command {} was duplicated".format(i)) continue action_type = teleop_cfg[i]['type'] self.add_command(i, teleop_cfg[i]) if action_type == 'topic': self.register_topic(i, teleop_cfg[i]) elif action_type == 'action': self.register_action(i, teleop_cfg[i]) elif action_type == 'service': self.register_service(i, teleop_cfg[i]) else: rospy.logerr("unknown type '%s' for command '%s'", action_type, i) # Don't subscribe until everything has been initialized. rospy.Subscriber('joy', sensor_msgs.msg.Joy, self.joy_callback) # Run a low-freq action updater rospy.Timer(rospy.Duration(2.0), self.update_actions) def joy_callback(self, data): try: for c in self.command_list: if self.match_command(c, data.buttons): self.run_command(c, data) # Only run 1 command at a time break except JoyTeleopException as e: rospy.logerr("error while parsing joystick input: %s", str(e)) self.old_buttons = data.buttons def register_topic(self, name, command): """Add a topic publisher for a joystick command""" topic_name = command['topic_name'] try: topic_type = self.get_message_type(command['message_type']) self.publishers[topic_name] = rospy.Publisher(topic_name, topic_type, queue_size=1) except JoyTeleopException as e: rospy.logerr("could not register topic for command {}: {}".format(name, str(e))) def register_action(self, name, command): """Add an action client for a joystick command""" action_name = command['action_name'] try: action_type = self.get_message_type(self.get_action_type(action_name)) self.al_clients[action_name] = actionlib.SimpleActionClient(action_name, action_type) if action_name in self.offline_actions: self.offline_actions.remove(action_name) except JoyTeleopException: if action_name not in self.offline_actions: self.offline_actions.append(action_name) class AsyncServiceProxy(object): def __init__(self, name, service_class, persistent=True): try: rospy.wait_for_service(name, timeout=2.0) except ROSException: raise JoyTeleopException("Service {} is not available".format(name)) self._service_proxy = rospy.ServiceProxy(name, service_class, persistent) self._thread = Thread(target=self._service_proxy, args=[]) def __del__(self): # try to join our thread - no way I know of to interrupt a service # request if self._thread.is_alive(): self._thread.join(1.0) def __call__(self, request): if self._thread.is_alive(): self._thread.join(0.01) if self._thread.is_alive(): return False self._thread = Thread(target=self._service_proxy, args=[request]) self._thread.start() return True def register_service(self, name, command): """ Add an AsyncServiceProxy for a joystick command """ service_name = command['service_name'] try: service_type = self.get_service_type(service_name) self.srv_clients[service_name] = self.AsyncServiceProxy( service_name, service_type) if service_name in self.offline_services: self.offline_services.remove(service_name) except JoyTeleopException: if service_name not in self.offline_services: self.offline_services.append(service_name) def match_command(self, c, buttons): """Find a command matching a joystick configuration""" # Buttons is a vector of the shape [0,1,0,1.... # Turn it into a vector of form [1, 3... button_indexes = np.argwhere(buttons).flatten() # Check if the pressed buttons match the commands exactly. buttons_match = np.array_equal(self.command_list[c]['buttons'], button_indexes) #print button_indexes if buttons_match: return True # This might also be a default command. # We need to check if ANY commands match this set of pressed buttons. any_commands_matched = np.any([ np.array_equal(command['buttons'], button_indexes) for name, command in self.command_list.iteritems()]) # Return the final result. return (buttons_match) or (not any_commands_matched and self.command_list[c]['is_default']) def add_command(self, name, command): """Add a command to the command list""" # Check if this is a default command if 'is_default' not in command: command['is_default'] = False if command['type'] == 'topic': if 'deadman_buttons' not in command: command['deadman_buttons'] = [] command['buttons'] = command['deadman_buttons'] elif command['type'] == 'action': if 'action_goal' not in command: command['action_goal'] = {} elif command['type'] == 'service': if 'service_request' not in command: command['service_request'] = {} self.command_list[name] = command def run_command(self, command, joy_state): """Run a joystick command""" cmd = self.command_list[command] if cmd['type'] == 'topic': self.run_topic(command, joy_state) elif cmd['type'] == 'action': if cmd['action_name'] in self.offline_actions: rospy.logerr("command {} was not played because the action " "server was unavailable. Trying to reconnect..." .format(cmd['action_name'])) self.register_action(command, self.command_list[command]) else: if joy_state.buttons != self.old_buttons: self.run_action(command, joy_state) elif cmd['type'] == 'service': if cmd['service_name'] in self.offline_services: rospy.logerr("command {} was not played because the service " "server was unavailable. Trying to reconnect..." .format(cmd['service_name'])) self.register_service(command, self.command_list[command]) else: if joy_state.buttons != self.old_buttons: self.run_service(command, joy_state) else: raise JoyTeleopException('command {} is neither a topic publisher nor an action or service client' .format(command)) def run_topic(self, c, joy_state): cmd = self.command_list[c] msg = self.get_message_type(cmd['message_type'])() if 'message_value' in cmd: for param in cmd['message_value']: self.set_member(msg, param['target'], param['value']) else: for mapping in cmd['axis_mappings']: if len(joy_state.axes)<=mapping['axis']: rospy.logerr('Joystick has only {} axes (indexed from 0), but #{} was referenced in config.'.format(len(joy_state.axes), mapping['axis'])) val = 0.0 else: val = joy_state.axes[mapping['axis']] * mapping.get('scale', 1.0) + mapping.get('offset', 0.0) self.set_member(msg, mapping['target'], val) self.publishers[cmd['topic_name']].publish(msg) def run_action(self, c, joy_state): cmd = self.command_list[c] goal = self.get_message_type(self.get_action_type(cmd['action_name'])[:-6] + 'Goal')() genpy.message.fill_message_args(goal, [cmd['action_goal']]) self.al_clients[cmd['action_name']].send_goal(goal) def run_service(self, c, joy_state): cmd = self.command_list[c] request = self.get_service_type(cmd['service_name'])._request_class() # should work for requests, too genpy.message.fill_message_args(request, [cmd['service_request']]) if not self.srv_clients[cmd['service_name']](request): rospy.loginfo('Not sending new service request for command {} because previous request has not finished' .format(c)) def set_member(self, msg, member, value): ml = member.split('.') if len(ml) < 1: return target = msg for i in ml[:-1]: target = getattr(target, i) setattr(target, ml[-1], value) def get_message_type(self, type_name): if type_name not in self.message_types: try: package, message = type_name.split('/') mod = importlib.import_module(package + '.msg') self.message_types[type_name] = getattr(mod, message) except ValueError: raise JoyTeleopException("message type format error") except ImportError: raise JoyTeleopException("module {} could not be loaded".format(package)) except AttributeError: raise JoyTeleopException("message {} could not be loaded from module {}".format(package, message)) return self.message_types[type_name] def get_action_type(self, action_name): try: return rostopic._get_topic_type(rospy.resolve_name(action_name) + '/goal')[0][:-4] except TypeError: raise JoyTeleopException("could not find action {}".format(action_name)) def get_service_type(self, service_name): if service_name not in self.service_types: try: self.service_types[service_name] = rosservice.get_service_class_by_name(service_name) except ROSServiceException, e: raise JoyTeleopException("service {} could not be loaded: {}".format(service_name, str(e))) return self.service_types[service_name] def update_actions(self, evt=None): for name, cmd in self.command_list.iteritems(): if cmd['type'] != 'action': continue if cmd['action_name'] in self.offline_actions: self.register_action(name, cmd) if __name__ == "__main__": try: rospy.init_node('joy_teleop') jt = JoyTeleop() rospy.spin() except JoyTeleopException: pass except rospy.ROSInterruptException: pass ================================================ FILE: racecar-vm.rosinstall ================================================ - setup-file: {local-name: /opt/ros/kinetic/setup.sh} - git: {local-name: src/racecar, version: master, uri: 'https://github.com/mit-racecar/racecar.git'} - git: {local-name: src/vesc, version: master, uri: 'https://github.com/mit-racecar/vesc.git'} - git: {local-name: src/racecar-simulator, version: master, uri: 'https://github.com/mit-racecar/racecar-simulator.git'} ================================================ FILE: racecar.rosinstall ================================================ - setup-file: {local-name: /opt/ros/kinetic/setup.sh} - git: {local-name: src/racecar, version: master, uri: 'https://github.com/mit-racecar/racecar.git'} - git: {local-name: src/vesc, version: master, uri: 'https://github.com/mit-racecar/vesc.git'} - git: {local-name: src/zed_wrapper, version: 6c06bb0a3c32aa2dec4a539e296f6ee1d6937518, uri: 'https://github.com/stereolabs/zed-ros-wrapper.git'}