diff --git a/CMakeLists.txt b/CMakeLists.txt index 0dd0b4000dd89bedd1d7ed158260bba30a33d93b..887093d2b5fb651c23de33fa68853d1bb0ad0c93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 2.8.3) -project(darwin_controller_cpp) +project(dynamixel_robot_gazebo) ## Find catkin macros and libraries ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) @@ -11,7 +11,6 @@ find_package(catkin REQUIRED roscpp urdf controller_interface hardware_interface FIND_PACKAGE(iriutils REQUIRED) FIND_PACKAGE(comm REQUIRED) FIND_PACKAGE(dynamixel REQUIRED) -FIND_PACKAGE(bno055_imu_sim REQUIRED) ## Uncomment this if the package has a setup.py. This macro ensures ## modules and global scripts declared therein get installed @@ -92,80 +91,42 @@ catkin_package( link_directories(${GAZEBO_LIBRARY_DIRS}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GAZEBO_CXX_FLAGS}") -SET(DARWIN_FW_PATH ~/humanoids/darwin_stm32_fw) -SET(STM32_HAL_PATH ~/humanoids/stm32_hal) -SET(STM32_LIBRARIES_PATH ~/humanoids/stm32_libraries) - ## Specify additional locations of header files ## Your package locations should be listed before other locations # include_directories(include) -include_directories(include include/sim ${Boost_INCLUDE_DIR} ${catkin_INCLUDE_DIRS}) -include_directories(${DARWIN_FW_PATH}/include/) -include_directories(${STM32_LIBRARIES_PATH}/dynamixel_base/include) -include_directories(${STM32_LIBRARIES_PATH}/comm/include) -include_directories(${STM32_LIBRARIES_PATH}/f1/usart/include) -include_directories(${STM32_LIBRARIES_PATH}/utils/include) -include_directories(${STM32_HAL_PATH}/f1/include) -include_directories(${STM32_HAL_PATH}/f1/include/core) +include_directories(include ${Boost_INCLUDE_DIR} ${catkin_INCLUDE_DIRS}) include_directories(${iriutils_INCLUDE_DIR}) include_directories(${comm_INCLUDE_DIR}) include_directories(${dynamixel_INCLUDE_DIR}) -include_directories(${bno055_imu_sim_INCLUDE_DIR}) - -add_definitions(-DSTM32F103xE) -add_definitions(-DUSE_HAL_DRIVER) ## Declare a cpp library -# add_library(darwin_controller -# src/${PROJECT_NAME}/darwin_controller.cpp +# add_library(dynamixel_controller +# src/${PROJECT_NAME}/dynamixel_controller.cpp # ) -add_library(${PROJECT_NAME} src/darwin_controller_cpp.cpp - ${DARWIN_FW_PATH}/src/ram.c - ${DARWIN_FW_PATH}/src/action.c - ${DARWIN_FW_PATH}/src/walking.c - ${DARWIN_FW_PATH}/src/darwin_kinematics.c - ${DARWIN_FW_PATH}/src/darwin_math.c - ${DARWIN_FW_PATH}/src/motion_pages.c - ${DARWIN_FW_PATH}/src/joint_motion.c - ${DARWIN_FW_PATH}/src/head_tracking.c - ${DARWIN_FW_PATH}/src/motion_manager.c - ${DARWIN_FW_PATH}/src/smart_charger.c - ${DARWIN_FW_PATH}/src/grippers.c - ${DARWIN_FW_PATH}/src/gpio.c - ${DARWIN_FW_PATH}/src/stairs.c - ${DARWIN_FW_PATH}/src/adc_dma.c - src/sim/stm32_hal.c - src/sim/stm32_cortex.c - src/sim/stm32_gpio.c - src/sim/stm32_timer.c - src/sim/stm32_timer_ex.c - src/sim/stm32_dma.c - src/sim/stm32_dyn_master.c - src/sim/stm32_dyn_slave.c - src/sim/stm32_dyn_master_servos.c - src/sim/stm32_dyn_master_v2_servos.c - src/sim/stm32_eeprom.c - src/sim/imu.c - include/darwin_controller_cpp.h - include/darwin_controller_cpp_impl.h) +add_library(${PROJECT_NAME} src/dynamixel_robot_gazebo.cpp + src/dynamixel_servo.cpp) ## Declare a cpp executable -# add_executable(darwin_controller_node src/darwin_controller_node.cpp) +# add_executable(dynamixel_controller_node src/dynamixel_controller_node.cpp) ## Add cmake target dependencies of the executable/library ## as an example, message headers may need to be generated before nodes -add_dependencies(darwin_controller_cpp humanoid_common_msgs_generate_messages_cpp) +# add_dependencies(dynamixel_robot_gazebo humanoid_common_msgs_generate_messages_cpp) ## Specify libraries to link a library or executable target against -# target_link_libraries(darwin_controller_node +# target_link_libraries(dynamixel_controller_node # ${catkin_LIBRARIES} # ) target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES}) TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${iriutils_LIBRARY}) TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${comm_LIBRARY}) TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${dynamixel_LIBRARY}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${bno055_imu_sim_LIBRARY}) +add_custom_command( + TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/scripts/start_socat.sh + ${CATKIN_PACKAGE_LIB_DESTINATION}/start_socat.sh) ############# ## Install ## ############# @@ -176,12 +137,12 @@ TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${bno055_imu_sim_LIBRARY}) ## Mark executable scripts (Python etc.) for installation ## in contrast to setup.py, you can choose the destination # install(PROGRAMS -# scripts/my_python_script +# scripts/start_socat.sh # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} # ) ## Mark executables and/or libraries for installation -# install(TARGETS darwin_controller darwin_controller_node +# install(TARGETS dynamixel_controller dynamixel_controller_node # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} @@ -206,7 +167,7 @@ TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${bno055_imu_sim_LIBRARY}) ############# ## Add gtest based cpp test target and link libraries -# catkin_add_gtest(${PROJECT_NAME}-test test/test_darwin_controller.cpp) +# catkin_add_gtest(${PROJECT_NAME}-test test/test_dynamixel_controller.cpp) # if(TARGET ${PROJECT_NAME}-test) # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) # endif() diff --git a/dynamixel_robot_plugin.xml b/dynamixel_robot_plugin.xml new file mode 100644 index 0000000000000000000000000000000000000000..2100cde095beb12b26aa6477cd0ac273c35b9283 --- /dev/null +++ b/dynamixel_robot_plugin.xml @@ -0,0 +1,12 @@ +<library path="lib/libdynamixel_robot_gazebo"> + + <class name="dynamixel_robot_gazebo/DynamixelRobotGazebo" + type="dynamixel_robot_gazebo::DynamixelRobotGazebo" + base_class_type="controller_interface::ControllerBase"> + <description> + this is a description + </description> + </class> + +</library> + diff --git a/include/darwin_controller_cpp_impl.h b/include/darwin_controller_cpp_impl.h deleted file mode 100644 index e10277b25955849a46006cbf448c51d5e3ee4b9b..0000000000000000000000000000000000000000 --- a/include/darwin_controller_cpp_impl.h +++ /dev/null @@ -1,380 +0,0 @@ -#ifndef DARWIN_CONTROLLER_CPP_IMP_H -#define DARWIN_CONTROLLER_CPP_IMP_H - -#include "stm32f1xx.h" -#include "motion_manager.h" -#include "action.h" -#include "action_id.h" -#include "walking.h" -#include "joint_motion.h" -#include "head_tracking.h" -#include "grippers.h" -#include "ram.h" -#include "imu.h" -#include "darwin_math.h" -#include "stairs.h" -#include "darwin_dyn_slave.h" - -#ifdef _HAVE_XSD -#include "../src/xml/darwin_config.hxx" -#endif - -#include "exceptions.h" - -extern "C" { - // motion_manager private function declaration - void TIM5_IRQHandler(void); -} - -// motion manager external variables -extern int num_servos; -extern double real_angles[PAGE_MAX_NUM_SERVOS]; - -// action module external variables -extern TServoInfo manager_servos[MANAGER_MAX_NUM_SERVOS]; - -//IMU module external variables -extern int32_t gyro_data[3]; -extern int32_t accel_data[3]; - -// dynamixel slave external variables -extern "C" { - extern void darwin_on_ping(void); - extern unsigned char darwin_on_read(unsigned short int address, unsigned short int length, unsigned char *data); - extern unsigned char darwin_on_write(unsigned short int address, unsigned short int length, unsigned char *data); -} - -//parameters default values -#define DEFAULT_ENABLE_SMART_CHARGER false -#define DEFAULT_INITIAL_CHARGE 2200.0 -#define DEFAULT_DISCHARGE_RATE 6000.0 -#define DEFAULT_CHARGE_CURRENT 2200.0 -#define DEFAULT_CHARGE_STATION_LINK "none" -#define DEFAULT_CHARGE_ROBOT_LINK "none" - -namespace darwin_controller_cpp -{ - namespace internal - { - std::vector<std::string> getStrings(const ros::NodeHandle& nh, const std::string& param_name) - { - using namespace XmlRpc; - XmlRpcValue xml_array; - if (!nh.getParam(param_name, xml_array)) - { - ROS_ERROR_STREAM("CDarwinSim : Could not find '" << param_name << "' parameter (namespace: " << nh.getNamespace() << ")."); - return std::vector<std::string>(); - } - if (xml_array.getType() != XmlRpcValue::TypeArray) - { - ROS_ERROR_STREAM("CDarwinSim : The '" << param_name << "' parameter is not an array (namespace: " << - nh.getNamespace() << ")."); - return std::vector<std::string>(); - } - - std::vector<std::string> out; - for (int i = 0; i < xml_array.size(); ++i) - { - if (xml_array[i].getType() != XmlRpcValue::TypeString) - { - ROS_ERROR_STREAM("CDarwinSim : The '" << param_name << "' parameter contains a non-string element (namespace: " << - nh.getNamespace() << ")."); - return std::vector<std::string>(); - } - out.push_back(static_cast<std::string>(xml_array[i])); - } - return out; - } - - boost::shared_ptr<urdf::Model> getUrdf(const ros::NodeHandle& nh, const std::string& param_name) - { - boost::shared_ptr<urdf::Model> urdf(new urdf::Model); - - std::string urdf_str; - // Check for robot_description in proper namespace - if (nh.getParam(param_name, urdf_str)) - { - if (!urdf->initString(urdf_str)) - { - ROS_ERROR_STREAM("CDarwinSim : Failed to parse URDF contained in '" << param_name << "' parameter (namespace: " << - nh.getNamespace() << ")."); - return boost::shared_ptr<urdf::Model>(); - } - } - // Check for robot_description in root - else if (!urdf->initParam("robot_description")) - { - ROS_ERROR_STREAM("CDarwinSim : Failed to parse URDF contained in '" << param_name << "' parameter"); - return boost::shared_ptr<urdf::Model>(); - } - return urdf; - } - - typedef boost::shared_ptr<const urdf::Joint> UrdfJointConstPtr; - std::vector<UrdfJointConstPtr> getUrdfJoints(const urdf::Model& urdf, const std::vector<std::string>& joint_names) - { - std::vector<UrdfJointConstPtr> out; - for (unsigned int i = 0; i < joint_names.size(); ++i) - { - UrdfJointConstPtr urdf_joint = urdf.getJoint(joint_names[i]); - if (urdf_joint) - { - out.push_back(urdf_joint); - } - else - { - ROS_ERROR_STREAM("CDarwinSim : Could not find joint '" << joint_names[i] << "' in URDF model."); - return std::vector<UrdfJointConstPtr>(); - } - } - return out; - } - - std::string getLeafNamespace(const ros::NodeHandle& nh) - { - const std::string complete_ns = nh.getNamespace(); - std::size_t id = complete_ns.find_last_of("/"); - return complete_ns.substr(id + 1); - } - - } // namespace - - template <class HardwareInterface> - inline void DarwinControllerCPP<HardwareInterface>::starting(const ros::Time& time) - { - for(unsigned int i = 0; i <this->joints_.size(); ++i) - { - pids_[i]->reset(); - this->joints_[i].setCommand(0.0); - } - } - - template <class HardwareInterface> - inline void DarwinControllerCPP<HardwareInterface>::stopping(const ros::Time& time) - { - } - - template <class HardwareInterface> - DarwinControllerCPP<HardwareInterface>::DarwinControllerCPP() - { - this->dyn_slave=NULL; - this->imu_sim=NULL; - } - - template <class HardwareInterface> - bool DarwinControllerCPP<HardwareInterface>::init(HardwareInterface* hw,ros::NodeHandle& root_nh,ros::NodeHandle& controller_nh) - { - using namespace internal; - std::string serial_device; - - // Cache controller node handle - controller_nh_ = controller_nh; - - // initialize topics - this->gyro_sub=root_nh.subscribe("sensors/raw_gyro", 1, &DarwinControllerCPP<HardwareInterface>::gyro_callback,this); - this->accel_sub=root_nh.subscribe("sensors/raw_accel", 1, &DarwinControllerCPP<HardwareInterface>::accel_callback,this); - this->imu_sub=root_nh.subscribe("sensors/raw_imu", 1, &DarwinControllerCPP<HardwareInterface>::imu_callback,this); - - // Controller name - name_=getLeafNamespace(controller_nh_); - - // List of controlled joints - joint_names_=getStrings(controller_nh_,"joints"); - if(joint_names_.empty()) - return false; - const unsigned int n_joints=joint_names_.size(); - - // URDF joints - boost::shared_ptr<urdf::Model> urdf=getUrdf(root_nh, "robot_description"); - if(!urdf) - return false; - - std::vector<UrdfJointConstPtr> urdf_joints=getUrdfJoints(*urdf, joint_names_); - if(urdf_joints.empty()) - return false; - assert(n_joints==urdf_joints.size()); - num_servos=n_joints;// set the number of servos to the number of joint of the urdf model - - // Initialize members - this->joints_.resize(n_joints); - this->pids_.resize(n_joints); - for(unsigned int i=0;i<n_joints;++i) - { - // Joint handle - try { - joints_[i]=hw->getHandle(joint_names_[i]); - }catch(...){ - ROS_ERROR_STREAM("CDarwinSim : Could not find joint '" << joint_names_[i] << "' in '" << - this->getHardwareInterfaceType() << "'."); - return false; - } - // Node handle to PID gains - ros::NodeHandle joint_nh(this->controller_nh_,std::string("gains/")+joint_names_[i]); - - // Init PID gains from ROS parameter server - this->pids_[i].reset(new control_toolbox::Pid()); - if(!this->pids_[i]->init(joint_nh)) - { - ROS_WARN_STREAM("CDarwinSim : Failed to initialize PID gains from ROS parameter server."); - return false; - } - - // Whether a joint is continuous (ie. has angle wraparound) - const std::string not_if = urdf_joints[i]->type == urdf::Joint::CONTINUOUS ? "" : "non-"; - - ROS_DEBUG_STREAM("CDarwinSim : Found " << not_if << "continuous joint '" << joint_names_[i] << "' in '" << this->getHardwareInterfaceType() << "'."); - } - - ROS_DEBUG_STREAM("CDarwinSim : Initialized controller '" << name_ << "' with:" << - "\n- Number of joints: " << joints_.size() << - "\n- Hardware interface type: '" << this->getHardwareInterfaceType() << "'"); - - /* initialize the RAM */ - ram_init(); - /* initialize the IMU */ - imu_init(); - /* initialize dynamixel slave */ - darwin_dyn_slave_init(); - // initialize dynamixel slave server - ROS_INFO("Load dynamixel slave parameters"); - serial_device="/dev/ttyUSB0"; - controller_nh_.getParam("dyn_serial_device", serial_device); - ROS_INFO_STREAM("dyn_serial_device is: " << serial_device); - try{ - this->dyn_slave=new CDynamixelSlaveSerial("dyn_slave",serial_device,dyn_version2); - this->dyn_slave->set_baudrate(2000000/(ram_data[DARWIN_BAUD_RATE]+1)); - this->dyn_slave->set_return_delay(ram_data[DARWIN_RETURN_DELAY_TIME]); - this->dyn_slave->set_return_delay(ram_data[DARWIN_RETURN_LEVEL]); - this->dyn_slave->add_slave(ram_data[DARWIN_ID],boost::bind(&darwin_on_ping),boost::bind(&darwin_on_read,_1,_2,_3),boost::bind(&darwin_on_write,_1,_2,_3)); - }catch(CException &e){ - if(this->dyn_slave!=NULL) - { - delete this->dyn_slave; - this->dyn_slave=NULL; - } - ROS_ERROR_STREAM(e.what()); - } - // initialize IMU simulator - ROS_INFO("Load IMU simulator"); - serial_device="/dev/ttyUSB0"; - controller_nh_.getParam("imu_serial_device", serial_device); - ROS_INFO_STREAM("dyn_serial_device is: " << serial_device); - try{ - this->imu_sim=new CBNO055IMUSim("darwin_imu",serial_device); - this->imu_sim->set_calibrated(); - }catch(CException &e){ - if(this->imu_sim!=NULL) - { - delete this->imu_sim; - this->imu_sim=NULL; - } - ROS_ERROR_STREAM(e.what()); - } - /* initialize motion modules */ - manager_init(7800);// motion manager period in us - ROS_INFO("CDarwinSim : motion manager initialized"); - /* go to the walk ready position */ - for(unsigned int i=0;i<20;++i) - { - manager_set_module(i+1,MM_ACTION); - manager_enable_servo(i+1); - } - for(unsigned int i=20;i<n_joints;++i) - { - manager_set_module(i+1,MM_JOINTS); - manager_enable_servo(i+1); - } - manager_enable_balance();// enable balance - action_load_page(WALK_READY); - action_start_page(); - - return true; - } - - template <class HardwareInterface> - void DarwinControllerCPP<HardwareInterface>::update(const ros::Time& time, const ros::Duration& period) - { - static bool gyro_calibrated=false; - static ros::Time last_time=ros::Time(0,0); - ros::Time current_time=ros::Time::now(); - std::vector<double> target_angles(joints_.size()); - - /* get the actual simulation angles */ - for(unsigned int i=0;i<this->joints_.size();++i) - real_angles[i]=joints_[i].getPosition(); - __HAL_TIM_SET_FLAG(TIM5,TIM_FLAG_CC1); - __HAL_TIM_SET_IT_SOURCE(TIM5,TIM_IT_CC1); - TIM5_IRQHandler(); - for (unsigned int i = 0; i < this->joints_.size(); ++i) - { - target_angles[i] = ((manager_servos[i+1].current_angle*3.14159)/180.0)/128.0; - double command = pids_[i]->computeCommand(target_angles[i]-real_angles[i],period); - this->joints_[i].setCommand(command); - } - } - -/****************************************** imu *************************************************/ - template <class HardwareInterface> - void DarwinControllerCPP<HardwareInterface>::gyro_callback(const sensor_msgs::Imu::ConstPtr& msg) - { - double gyro_x,gyro_y; - - // saturate to +/- 500 dps; - gyro_x=msg->angular_velocity.y*180.0/3.14159; - if(gyro_x>500.0) - gyro_x=500.0; - else if(gyro_x<-500.0) - gyro_x=-500.0; - gyro_data[0]=-(int32_t)(gyro_x*1000.0); - gyro_y=msg->angular_velocity.z*180.0/3.14159; - if(gyro_y>500.0) - gyro_y=500.0; - else if(gyro_y<-500.0) - gyro_y=-500.0; - gyro_data[1]=-(int32_t)(gyro_y*1000.0); - } - - template <class HardwareInterface> - void DarwinControllerCPP<HardwareInterface>::accel_callback(const sensor_msgs::Imu::ConstPtr& msg) - { - accel_data[0]=(int32_t)msg->linear_acceleration.x*1000.0; - accel_data[1]=(int32_t)msg->linear_acceleration.y*1000.0; - accel_data[2]=(int32_t)msg->linear_acceleration.z*1000.0; - } - - template <class HardwareInterface> - void DarwinControllerCPP<HardwareInterface>::imu_callback(const sensor_msgs::Imu::ConstPtr& msg) - { - if(this->imu_sim!=NULL) - { - this->imu_sim->set_quaternion_data(msg->orientation.x,msg->orientation.y,msg->orientation.z,msg->orientation.w); - tf::Quaternion q(msg->orientation.x,msg->orientation.y,msg->orientation.z,msg->orientation.w); - tf::Matrix3x3 m(q); - double roll, pitch, yaw; - m.getRPY(roll, pitch, yaw); - this->imu_sim->set_euler_angles_data(yaw,roll,pitch); - this->imu_sim->set_linear_accel_data(msg->linear_acceleration.x,msg->linear_acceleration.y,msg->linear_acceleration.z); - this->imu_sim->set_gyro_data(msg->angular_velocity.x,msg->angular_velocity.y,msg->angular_velocity.z); - } - } - -/****************************************** imu *************************************************/ - - template <class HardwareInterface> - DarwinControllerCPP<HardwareInterface>::~DarwinControllerCPP() - { - if(this->dyn_slave!=NULL) - { - delete this->dyn_slave; - this->dyn_slave=NULL; - } - if(this->imu_sim!=NULL) - { - delete this->imu_sim; - this->imu_sim=NULL; - } - } - -} // namespace - -#endif // header guard diff --git a/include/darwin_controller_cpp.h b/include/dynamixel_robot_gazebo.h similarity index 61% rename from include/darwin_controller_cpp.h rename to include/dynamixel_robot_gazebo.h index 808e89e5c6f4dac55cfee9bb316788ebad515133..2334aa88312e9680326c304ae4e7829e2d55fa04 100644 --- a/include/darwin_controller_cpp.h +++ b/include/dynamixel_robot_gazebo.h @@ -28,18 +28,11 @@ /// \author Adolfo Rodriguez Tsouroukdissian, Stuart Glaser -#ifndef DARWIN_CONTROLLER_CPP_H -#define DARWIN_CONTROLLER_CPP_H - -// C++ standard -#include <cassert> -#include <iterator> -#include <stdexcept> -#include <string> +#ifndef DYNAMIXEL_ROBOT_GAZEBO_H +#define DYNAMIXEL_ROBOT_GAZEBO_H // Boost #include <boost/shared_ptr.hpp> -#include <boost/scoped_ptr.hpp> // ROS #include <ros/node_handle.h> @@ -50,63 +43,40 @@ // ros_controls #include <controller_interface/controller.h> #include <hardware_interface/joint_command_interface.h> -#include <control_toolbox/pid.h> -#include <sensor_msgs/Imu.h> -#include <tf/transform_datatypes.h> +#include <pluginlib/class_list_macros.h> -#include "mutex.h" #include "dynamixel_slave_serial.h" -#include "bno055_imu_sim.h" +#include "dynamixel_servo.h" -namespace darwin_controller_cpp +namespace dynamixel_robot_gazebo { /** * \brief * */ - template <class HardwareInterface> - class DarwinControllerCPP : public controller_interface::Controller<HardwareInterface> + class DynamixelRobotGazebo : public controller_interface::Controller<hardware_interface::EffortJointInterface> { public: - DarwinControllerCPP(); - ~DarwinControllerCPP(); + DynamixelRobotGazebo(); + virtual ~DynamixelRobotGazebo(); - bool init(HardwareInterface* hw, ros::NodeHandle& root_nh, ros::NodeHandle& controller_nh); + using controller_interface::Controller<hardware_interface::EffortJointInterface>::init; + bool init(hardware_interface::EffortJointInterface* hw, ros::NodeHandle& root_nh, ros::NodeHandle& controller_nh); void starting(const ros::Time& time); void stopping(const ros::Time& time); void update(const ros::Time& time, const ros::Duration& period); private: - typedef typename HardwareInterface::ResourceHandleType JointHandle; - typedef boost::shared_ptr<control_toolbox::Pid> PidPtr; - CDynamixelSlaveSerial *dyn_slave; - - CBNO055IMUSim *imu_sim; - - std::string name_; ///< Controller name. - std::vector<JointHandle> joints_; ///< Handles to controlled joints. - std::vector<std::string> joint_names_; ///< Controlled joint names. - std::vector<PidPtr> pids_; + std::vector<CDynServo *> servos; + std::string name; + std::vector<std::string> joint_names; // ROS API - ros::NodeHandle controller_nh_; - - // topic subscribers - ros::Subscriber gyro_sub; - void gyro_callback(const sensor_msgs::Imu::ConstPtr& msg); - - ros::Subscriber accel_sub; - void accel_callback(const sensor_msgs::Imu::ConstPtr& msg); - - ros::Subscriber imu_sub; - void imu_callback(const sensor_msgs::Imu::ConstPtr& msg); - - CMutex walk_access; + ros::NodeHandle controller_nh; }; } // namespace -#include <darwin_controller_cpp_impl.h> #endif // header guard diff --git a/package.xml b/package.xml index 9fce760b828283f5b17541e8aaf9b78e050e27ab..10386417993b303aa23538e794ad1685d5e1608c 100644 --- a/package.xml +++ b/package.xml @@ -1,31 +1,31 @@ <?xml version="1.0"?> <package> - <name>darwin_controller_cpp</name> + <name>dynamixel_robot_gazebo</name> <version>0.0.0</version> - <description>The darwin_controller_cpp package</description> + <description>The dynamixel_robot_gazebo package</description> <!-- One maintainer tag required, multiple allowed, one person per tag --> <!-- Example: --> <!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> --> - <maintainer email="sergi@todo.todo">sergi</maintainer> + <maintainer email="shernand@iri.upc.edu">Sergi Hernandez Juan</maintainer> <!-- One license tag required, multiple allowed, one license per tag --> <!-- Commonly used license strings: --> <!-- BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 --> - <license>TODO</license> + <license>GPLv3</license> <!-- Url tags are optional, but mutiple are allowed, one per tag --> <!-- Optional attribute type can be: website, bugtracker, or repository --> <!-- Example: --> - <!-- <url type="website">http://wiki.ros.org/darwin_controller_cpp</url> --> + <!-- <url type="website">http://wiki.ros.org/dynamixel_robot_gazebo</url> --> <!-- Author tags are optional, mutiple are allowed, one per tag --> <!-- Authors do not have to be maintianers, but could be --> <!-- Example: --> - <!-- <author email="jane.doe@example.com">Jane Doe</author> --> + <author email="shernand@iri.upc.edu">Sergi Hernandez Juan</author> <!-- The *_depend tags are used to specify dependencies --> @@ -61,6 +61,6 @@ <run_depend>gazebo_ros</run_depend> <export> - <controller_interface plugin="${prefix}/ros_control_plugins.xml"/> + <controller_interface plugin="${prefix}/dynamixel_robot_plugin.xml"/> </export> </package> diff --git a/ros_control_plugins.xml b/ros_control_plugins.xml deleted file mode 100644 index bfaaac29381451b0c74236eea2f066702b47b1fe..0000000000000000000000000000000000000000 --- a/ros_control_plugins.xml +++ /dev/null @@ -1,12 +0,0 @@ -<library path="lib/libdarwin_controller_cpp"> - - <class name="effort_controllers/DarwinControllerCPP" - type="effort_controllers::DarwinControllerCPP" - base_class_type="controller_interface::ControllerBase"> - <description> - this is a description - </description> - </class> - -</library> - diff --git a/src/darwin_controller_cpp.cpp b/src/darwin_controller_cpp.cpp deleted file mode 100644 index f24c4ae4288c54a64c07ca3750f770ecb8dfb2bf..0000000000000000000000000000000000000000 --- a/src/darwin_controller_cpp.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2013, PAL Robotics S.L. -// Copyright (c) 2008, Willow Garage, Inc. -// -// 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 PAL Robotics S.L. 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. -////////////////////////////////////////////////////////////////////////////// - -// Pluginlib -#include <pluginlib/class_list_macros.h> - -// Project -#include <darwin_controller_cpp.h> - -namespace effort_controllers -{ - /** - * \brief Joint trajectory controller that represents trajectory segments as <b>quintic splines</b> and sends - * commands to a \b position interface. - */ - typedef darwin_controller_cpp::DarwinControllerCPP<hardware_interface::EffortJointInterface> DarwinControllerCPP; -} - -PLUGINLIB_EXPORT_CLASS(effort_controllers::DarwinControllerCPP, controller_interface::ControllerBase) diff --git a/src/dynamixel_robot_gazebo.cpp b/src/dynamixel_robot_gazebo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b3ce8163168fde1a495e51788736b6afa532b62e --- /dev/null +++ b/src/dynamixel_robot_gazebo.cpp @@ -0,0 +1,237 @@ +#ifndef DYNAMIXEL_ROBOT_GAZEBO_IMP_H +#define DYNAMIXEL_ROBOT_GAZEBO_IMP_H + +#include <sys/stat.h> + +#include "exceptions.h" +#include "dynamixel_robot_gazebo.h" + +namespace dynamixel_robot_gazebo +{ + namespace internal + { + std::vector<std::string> getStrings(const ros::NodeHandle& nh, const std::string& param_name) + { + using namespace XmlRpc; + XmlRpcValue xml_array; + if (!nh.getParam(param_name, xml_array)) + { + ROS_ERROR_STREAM("Dynamixel robot gazebo: Could not find '" << param_name << "' parameter (namespace: " << nh.getNamespace() << ")."); + return std::vector<std::string>(); + } + if (xml_array.getType() != XmlRpcValue::TypeArray) + { + ROS_ERROR_STREAM("Dynamixel robot gazebo: The '" << param_name << "' parameter is not an array (namespace: " << + nh.getNamespace() << ")."); + return std::vector<std::string>(); + } + + std::vector<std::string> out; + for (int i = 0; i < xml_array.size(); ++i) + { + if (xml_array[i].getType() != XmlRpcValue::TypeString) + { + ROS_ERROR_STREAM("Dynamixel robot gazebo: The '" << param_name << "' parameter contains a non-string element (namespace: " << + nh.getNamespace() << ")."); + return std::vector<std::string>(); + } + out.push_back(static_cast<std::string>(xml_array[i])); + } + return out; + } + + boost::shared_ptr<urdf::Model> getUrdf(const ros::NodeHandle& nh, const std::string& param_name) + { + boost::shared_ptr<urdf::Model> urdf(new urdf::Model); + + std::string urdf_str; + // Check for robot_description in proper namespace + if (nh.getParam(param_name, urdf_str)) + { + if (!urdf->initString(urdf_str)) + { + ROS_ERROR_STREAM("Dynamixel robot gazebo: Failed to parse URDF contained in '" << param_name << "' parameter (namespace: " << + nh.getNamespace() << ")."); + return boost::shared_ptr<urdf::Model>(); + } + } + // Check for robot_description in root + else if (!urdf->initParam("robot_description")) + { + ROS_ERROR_STREAM("Dynamixel robot gazebo: Failed to parse URDF contained in '" << param_name << "' parameter"); + return boost::shared_ptr<urdf::Model>(); + } + return urdf; + } + + typedef boost::shared_ptr<const urdf::Joint> UrdfJointConstPtr; + std::vector<UrdfJointConstPtr> getUrdfJoints(const urdf::Model& urdf, const std::vector<std::string>& joint_names) + { + std::vector<UrdfJointConstPtr> out; + for (unsigned int i = 0; i < joint_names.size(); ++i) + { + UrdfJointConstPtr urdf_joint = urdf.getJoint(joint_names[i]); + if (urdf_joint) + { + out.push_back(urdf_joint); + } + else + { + ROS_ERROR_STREAM("Dynamixel robot gazebo: Could not find joint '" << joint_names[i] << "' in URDF model."); + return std::vector<UrdfJointConstPtr>(); + } + } + return out; + } + + std::string getLeafNamespace(const ros::NodeHandle& nh) + { + const std::string complete_ns = nh.getNamespace(); + std::size_t id = complete_ns.find_last_of("/"); + return complete_ns.substr(id + 1); + } + + } // namespace + + inline void DynamixelRobotGazebo::starting(const ros::Time& time) + { + } + + inline void DynamixelRobotGazebo::stopping(const ros::Time& time) + { + } + + DynamixelRobotGazebo::DynamixelRobotGazebo() + { + this->dyn_slave=NULL; + } + + bool DynamixelRobotGazebo::init(hardware_interface::EffortJointInterface* hw,ros::NodeHandle& root_nh,ros::NodeHandle& controller_nh) + { + unsigned int n_joints; + std::string device_name; + int return_delay=0,return_level=2,protocol=2,baudrate=1000000; + struct stat buffer; + + // Cache controller node handle + this->controller_nh = controller_nh; + + // Controller name + this->name=internal::getLeafNamespace(this->controller_nh); + + // List of controlled joints + this->joint_names=internal::getStrings(this->controller_nh,"joints"); + if(this->joint_names.empty()) + { + ROS_ERROR_STREAM("Dynamixel gazebo plugin: no controlled joints"); + return false; + } + n_joints=this->joint_names.size(); + + // URDF joints + boost::shared_ptr<urdf::Model> urdf=internal::getUrdf(root_nh, "robot_description"); + if(!urdf) + { + ROS_ERROR_STREAM("Dynamixel gazebo plugin: impossible to read the robot_description parameter"); + return false; + } + + std::vector<internal::UrdfJointConstPtr> urdf_joints=internal::getUrdfJoints(*urdf, this->joint_names); + if(n_joints!=urdf_joints.size()) + { + ROS_ERROR_STREAM("Dynamixel gazebo plugin: some joints missing from the URDF model"); + return false; + } + + // initialize dynamixel slave server + ROS_INFO("Dynamixel gazebo plugin: Load dynamixel slave parameters"); + ros::NodeHandle dynamixel_nh(this->controller_nh,std::string("dynamixel_bus")); + device_name="/tmp"+root_nh.getNamespace()+"_gazebo"; + // wait until the serial device exists + unsigned int timeout=20; + do{ + usleep(100000); + timeout--; + }while(stat(device_name.c_str(),&buffer)!=0 && timeout>0); + if(timeout==0) + { + ROS_ERROR_STREAM("Dynamixel gazebo plugin: serial device " << device_name << " not present"); + return false; + } + + try{ + dynamixel_nh.getParam("protocol", protocol); + if(protocol==1) + this->dyn_slave=new CDynamixelSlaveSerial(root_nh.getNamespace()+"_slave",device_name,dyn_version1); + else if(protocol==2) + this->dyn_slave=new CDynamixelSlaveSerial(root_nh.getNamespace()+"_slave",device_name,dyn_version2); + else + { + ROS_ERROR_STREAM("Dynamixel gazebo plugin: Invalid protocol version"); + return false; + } + dynamixel_nh.getParam("baudrate", baudrate); + this->dyn_slave->set_baudrate(baudrate); + dynamixel_nh.getParam("return_delay", return_delay); + this->dyn_slave->set_return_delay(return_delay); + dynamixel_nh.getParam("return_level", return_level); + if(return_level==0 || return_level==1 || return_level==2) + this->dyn_slave->set_return_delay(return_level); + else + { + ROS_ERROR_STREAM("Dynamixel gazebo plugin: Invalid return level"); + delete this->dyn_slave; + this->dyn_slave=NULL; + return false; + } + }catch(CException &e){ + if(this->dyn_slave!=NULL) + { + delete this->dyn_slave; + this->dyn_slave=NULL; + } + ROS_ERROR_STREAM("Dynamixel gazebo plugin: " << e.what()); + } + // initialize joints + this->servos.resize(n_joints); + for(unsigned int i=0;i<n_joints;++i) + this->servos[i]=new CDynServo(this->joint_names[i],this->dyn_slave,hw,controller_nh); + + ROS_DEBUG_STREAM("Dynamixel gazebo plugin: Initialized controller '" << this->name << "' with:" << "\n- Number of joints: " << this->servos.size() << "\n- Hardware interface type: '" << this->getHardwareInterfaceType() << "'"); + + return true; + } + + void DynamixelRobotGazebo::update(const ros::Time& time, const ros::Duration& period) + { + try{ + /* get the actual simulation angles */ + for(unsigned int i=0;i<this->servos.size();++i) + this->servos[i]->update(period); + }catch(CException &e){ + + } + } + + DynamixelRobotGazebo::~DynamixelRobotGazebo() + { + try{ + for(unsigned int i=0;i<this->servos.size();i++) + { + this->dyn_slave->delete_slave(this->servos[i]->get_id()); + delete this->servos[i]; + this->servos[i]=NULL; + } + if(this->dyn_slave!=NULL) + { + delete this->dyn_slave; + this->dyn_slave=NULL; + } + }catch(CException &e){ + } + } +} // namespace + +PLUGINLIB_EXPORT_CLASS(dynamixel_robot_gazebo::DynamixelRobotGazebo, controller_interface::ControllerBase) + +#endif // header guard