From e87fc1fcf0be2069efc64e7dc1243a5b61c736a3 Mon Sep 17 00:00:00 2001 From: Olivier Stasse <ostasse@laas.fr> Date: Mon, 26 Feb 2018 11:45:12 +0100 Subject: [PATCH] Makes the class RosSotControl independent of the branch. --- .../src/roscontrol-sot-controller.cpp | 203 +++++++++++++++--- .../src/roscontrol-sot-controller.hh | 73 +++++-- 2 files changed, 239 insertions(+), 37 deletions(-) diff --git a/talos_roscontrol_sot/src/roscontrol-sot-controller.cpp b/talos_roscontrol_sot/src/roscontrol-sot-controller.cpp index b072ba6..d4a8479 100644 --- a/talos_roscontrol_sot/src/roscontrol-sot-controller.cpp +++ b/talos_roscontrol_sot/src/roscontrol-sot-controller.cpp @@ -35,13 +35,31 @@ #define ODEBUG4FULL(x) #define ODEBUG4(x) +#ifdef REAL_ROBOT using namespace hardware_interface; +#else +using namespace talos_hardware_interface; +#endif + using namespace rc_sot_system; namespace talos_sot_controller { typedef std::map<std::string,std::string>::iterator it_map_rt_to_sot; + + - + EffortControlPDMotorControlData::EffortControlPDMotorControlData() + { + prev = 0.0; vel_prev = 0.0; des_pos=0.0; + integ_err=0.0; + } + void EffortControlPDMotorControlData::read_from_xmlrpc_value + (const std::string &prefix) + { + pid_controller.initParam(prefix); + } + RCSotController:: RCSotController(): // Store 32 DoFs for 5 minutes (1 Khz: 5*60*1000) @@ -68,7 +86,11 @@ namespace talos_sot_controller } bool RCSotController:: - initRequest (hardware_interface::RobotHW * robot_hw, +#ifdef REAL_ROBOT + initRequest (hardware_interface::RobotHW * robot_hw, +#else + initRequest (talos_hardware_interface::RobotHW * robot_hw, +#endif ros::NodeHandle &robot_nh, ros::NodeHandle &controller_nh, std::set<std::string> & claimed_resources) @@ -86,16 +108,42 @@ namespace talos_sot_controller /// If we are in effort mode then the device should not do any integration. if (control_mode_==EFFORT) - sotController_->setNoIntegration(); + { + sotController_->setNoIntegration(); + /// Fill desired position during the phase where the robot is waiting. + for(unsigned int idJoint=0;idJoint<joints_.size();idJoint++) + { + std::string joint_name = joints_name_[idJoint]; + std::map<std::string,EffortControlPDMotorControlData>::iterator + search_ecpd = effort_mode_pd_motors_.find(joint_name); + + if (search_ecpd!=effort_mode_pd_motors_.end()) + { + EffortControlPDMotorControlData & ecpdcdata = + search_ecpd->second; + ecpdcdata.des_pos = joints_[idJoint].getPosition(); + } + } + } return true; } bool RCSotController:: +#ifdef REAL_ROBOT initInterfaces(hardware_interface::RobotHW * robot_hw, +#else + initInterfaces(talos_hardware_interface::RobotHW * robot_hw, +#endif ros::NodeHandle &, ros::NodeHandle &, std::set<std::string> & claimed_resources) { + std::string lns; + #ifdef REAL_ROBOT + lns="hardware_interface"; + #else + lns="talos_hardware_interface"; + #endif // Check if construction finished cleanly if (state_!=CONSTRUCTED) { @@ -107,8 +155,8 @@ namespace talos_sot_controller if (! pos_iface_) { ROS_ERROR("This controller requires a hardware interface of type '%s'." - " Make sure this is registered in the hardware_interface::RobotHW class.", - getHardwareInterfaceType().c_str()); + " Make sure this is registered in the %s::RobotHW class.", + getHardwareInterfaceType().c_str(), lns.c_str()); return false ; } @@ -117,8 +165,8 @@ namespace talos_sot_controller if (! effort_iface_) { ROS_ERROR("This controller requires a hardware interface of type '%s'." - " Make sure this is registered in the hardware_interface::RobotHW class.", - getHardwareInterfaceType().c_str()); + " Make sure this is registered in the %s::RobotHW class.", + getHardwareInterfaceType().c_str(),lns.c_str()); return false ; } @@ -127,8 +175,8 @@ namespace talos_sot_controller if (! ft_iface_ ) { ROS_ERROR("This controller requires a hardware interface of type '%s '. " - " Make sure this is registered inthe hardware_interface::RobotHW class.", - internal :: demangledTypeName<ForceTorqueSensorInterface>().c_str()); + " Make sure this is registered inthe %s::RobotHW class.", + internal :: demangledTypeName<ForceTorqueSensorInterface>().c_str(),lns.c_str()); return false ; } // Get a pointer to the IMU sensor interface @@ -136,8 +184,8 @@ namespace talos_sot_controller if (! imu_iface_) { ROS_ERROR("This controller requires a hardware interface of type '%s'." - " Make sure this is registered in the thardware_interface::RobotHW class.", - internal :: demangledTypeName<ImuSensorInterface>().c_str()); + " Make sure this is registered in the %s::RobotHW class.", + internal :: demangledTypeName<ImuSensorInterface>().c_str(),lns.c_str()); return false ; } @@ -149,8 +197,8 @@ namespace talos_sot_controller if (!act_temp_iface_) { ROS_ERROR("This controller requires a hardware interface of type '%s'." - " Make sure this is registered in the hardware_interface::RobotHW class.", - internal :: demangledTypeName<ActuatorTemperatureSensorInterface>().c_str()); + " Make sure this is registered in the %s::RobotHW class.", + internal :: demangledTypeName<ActuatorTemperatureSensorInterface>().c_str(),lns.c_str()); return false ; } } @@ -234,6 +282,47 @@ namespace talos_sot_controller return true; } + bool RCSotController:: + readParamsEffortControlPDMotorControlData(ros::NodeHandle &robot_nh) + { + // Read libname + if (robot_nh.hasParam("/sot_controller/effort_control_pd_motor_init/gains")) + { + XmlRpc::XmlRpcValue xml_rpc_ecpd_init; + robot_nh.getParamCached("/sot_controller/effort_control_pd_motor_init/gains", + xml_rpc_ecpd_init); + + ROS_INFO("/sot_controller/effort_control_pd_motor_init/gains: %d %d %d\n", + xml_rpc_ecpd_init.getType(),XmlRpc::XmlRpcValue::TypeArray,XmlRpc::XmlRpcValue::TypeStruct); + effort_mode_pd_motors_.clear(); + + for (int i=0;i<joints_name_.size();i++) + { + if (xml_rpc_ecpd_init.hasMember(joints_name_[i])) + { + /* + XmlRpc::XmlRpcValue &aDataSet= xml_rpc_ecpd_init[joints_name_[i]]; + ROS_INFO("/sot_controller/effort_control_pd_motor_init %s type: %d\n",joints_name_[i],aDataSet.getType()); + if (aDataSet.getType()!=XmlRpc::XmlRpcValue::TypeStruct) + { + ROS_ERROR("In /sot_controller/effort_control_pd_motor_init/gains/%s not a struct" + ,joints_name_[i]); + throw XmlrpcHelperException("Pb in readParamsEffortControlPDMotorControlData"); + } + */ + std::string prefix= "/sot_controller/effort_control_pd_motor_init/gains/" + joints_name_[i]; + effort_mode_pd_motors_[joints_name_[i]].read_from_xmlrpc_value(prefix); + } + else + ROS_INFO("joint %s not in /sot_controller/effort_control_pd_motor_init/gains\n", + joints_name_[i].c_str()); + } + return true; + } + + ROS_ERROR("No parameter /sot_controller/effort_controler_pd_motor_init"); + return false; + } bool RCSotController:: readParamsFromRCToSotDevice(ros::NodeHandle &robot_nh) @@ -241,12 +330,13 @@ namespace talos_sot_controller // Read libname if (robot_nh.hasParam("/sot_controller/map_rc_to_sot_device")) { - if (robot_nh.getParam("/sot_controller/map_rc_to_sot_device",mapFromRCToSotDevice)) + if (robot_nh.getParam("/sot_controller/map_rc_to_sot_device", + mapFromRCToSotDevice_)) { /// TODO: Check if the mapping is complete wrt to the interface and the mapping. ROS_INFO_STREAM("Loading map rc to sot device: "); - for (it_map_rt_to_sot it = mapFromRCToSotDevice.begin(); - it != mapFromRCToSotDevice.end(); ++it) + for (it_map_rt_to_sot it = mapFromRCToSotDevice_.begin(); + it != mapFromRCToSotDevice_.end(); ++it) ROS_INFO_STREAM( it->first << ", " << it->second); } else @@ -347,6 +437,10 @@ namespace talos_sot_controller /// Calls readParamsFromRCToSotDevice // Mapping from ros-controll to sot device readParamsFromRCToSotDevice(robot_nh); + + if (control_mode_==EFFORT) + readParamsEffortControlPDMotorControlData(robot_nh); + return true; } @@ -455,9 +549,9 @@ namespace talos_sot_controller { /// Tries to find the mapping from the local validation /// to the SoT device. - it_map_rt_to_sot it_mapRC2Sot= mapFromRCToSotDevice.find(title); + it_map_rt_to_sot it_mapRC2Sot= mapFromRCToSotDevice_.find(title); /// If the mapping is found - if (it_mapRC2Sot!=mapFromRCToSotDevice.end()) + if (it_mapRC2Sot!=mapFromRCToSotDevice_.end()) { /// Expose the data to the SoT device. std::string lmapRC2Sot = it_mapRC2Sot->second; @@ -608,8 +702,8 @@ namespace talos_sot_controller else if (control_mode_==EFFORT) cmdTitle="cmd-effort"; - it_map_rt_to_sot it_mapRC2Sot= mapFromRCToSotDevice.find(cmdTitle); - if (it_mapRC2Sot!=mapFromRCToSotDevice.end()) + it_map_rt_to_sot it_mapRC2Sot= mapFromRCToSotDevice_.find(cmdTitle); + if (it_mapRC2Sot!=mapFromRCToSotDevice_.end()) { std::string lmapRC2Sot = it_mapRC2Sot->second; command_ = controlValues[lmapRC2Sot].getValues(); @@ -643,11 +737,64 @@ namespace talos_sot_controller } void RCSotController:: - update(const ros::Time&, const ros::Duration& ) - { - if (!isDynamicGraphStopped()) - one_iteration(); - } + update(const ros::Time&, const ros::Duration& period) + { + // Do not send any control if the dynamic graph is not started + if (!isDynamicGraphStopped()) + { + try + { + one_iteration(); + } + catch (std::exception const &exc) + { + std::cerr << "Failure happened during one_iteration evaluation: std_exception" << std::endl; + std::cerr << "Use gdb on this line together with gdb to investiguate the problem: " <<std::endl; + std::cerr << __FILE__ << " " << __LINE__ << std::endl; + throw exc; + } + catch (...) + { + std::cerr << "Failure happened during one_iteration evaluation: unknown exception" << std::endl; + std::cerr << "Use gdb on this line together with gdb to investiguate the problem: " <<std::endl; + std::cerr << __FILE__ << " " << __LINE__ << std::endl; + } + } + else + // But in effort mode it means that we are sending 0 + // Therefore implements a default PD controller on the system. + if (control_mode_==EFFORT) + { + // ROS_INFO("Compute command for effort mode: %d %d",joints_.size(),effort_mode_pd_motors_.size()); + for(unsigned int idJoint=0;idJoint<joints_.size();idJoint++) + { + std::string joint_name = joints_name_[idJoint]; + std::map<std::string,EffortControlPDMotorControlData>::iterator + search_ecpd = effort_mode_pd_motors_.find(joint_name); + + if (search_ecpd!=effort_mode_pd_motors_.end()) + { + EffortControlPDMotorControlData & ecpdcdata = + search_ecpd->second; + double vel_err = 0 - joints_[idJoint].getVelocity(); + double err = ecpdcdata.des_pos - joints_[idJoint].getPosition(); + + ecpdcdata.integ_err +=err; + + double local_command = ecpdcdata.pid_controller.computeCommand(err,vel_err,period); + // Apply command + control_toolbox::Pid::Gains gains = ecpdcdata.pid_controller.getGains(); + //ROS_INFO("command: %d %s %f %f (%f %f %f)",idJoint, joints_name_[idJoint].c_str(), + //local_command, DataOneIter_.motor_angle[idJoint], + //gains.p_gain_,gains.d_gain_, gains.i_gain_); + joints_[idJoint].setCommand(local_command); + + // Update previous value. + ecpdcdata.prev = DataOneIter_.motor_angle[idJoint]; + } + } + } + } void RCSotController:: starting(const ros::Time &) @@ -668,10 +815,18 @@ namespace talos_sot_controller //return type_name_; if (control_mode_==POSITION) return hardware_interface::internal:: + #ifdef REAL_ROBOT demangledTypeName<hardware_interface::PositionJointInterface>(); + #else + demangledTypeName<talos_hardware_interface::PositionJointInterface>(); + #endif else if (control_mode_==EFFORT) return hardware_interface::internal:: + #ifdef REAL_ROBOT demangledTypeName<hardware_interface::EffortJointInterface>(); + #else + demangledTypeName<talos_hardware_interface::EffortJointInterface>(); + #endif std::string voidstring(""); return voidstring; } diff --git a/talos_roscontrol_sot/src/roscontrol-sot-controller.hh b/talos_roscontrol_sot/src/roscontrol-sot-controller.hh index 0280d88..fee2eac 100644 --- a/talos_roscontrol_sot/src/roscontrol-sot-controller.hh +++ b/talos_roscontrol_sot/src/roscontrol-sot-controller.hh @@ -35,13 +35,23 @@ #include <string> #include <map> +#ifdef REAL_ROBOT #include <controller_interface/controller.h> #include <hardware_interface/joint_command_interface.h> #include <hardware_interface/imu_sensor_interface.h> #include <hardware_interface/force_torque_sensor_interface.h> #include <pal_hardware_interfaces/actuator_temperature_interface.h> +#else +#include <talos_controller_interface/controller.h> +#include <talos_hardware_interface/joint_command_interface.h> +#include <talos_hardware_interface/imu_sensor_interface.h> +#include <talos_hardware_interface/force_torque_sensor_interface.h> +#include <talos_pal_hardware_interfaces/actuator_temperature_interface.h> +#endif #include <dynamic_graph_bridge/sot_loader_basic.hh> +#include <ros/ros.h> +#include <control_toolbox/pid.h> #include "log.hh" @@ -49,10 +59,39 @@ namespace talos_sot_controller { enum SotControlMode { POSITION, EFFORT}; + class XmlrpcHelperException : public ros::Exception + { + public: + XmlrpcHelperException(const std::string& what) + : ros::Exception(what) {} + }; + + + struct EffortControlPDMotorControlData + { + control_toolbox::Pid pid_controller; + + //double p_gain,d_gain,i_gain; + double prev; + double vel_prev; + double des_pos; + double integ_err; + + EffortControlPDMotorControlData(); + // void read_from_xmlrpc_value(XmlRpc::XmlRpcValue &aXRV); + void read_from_xmlrpc_value(const std::string &prefix); + }; + /** This class encapsulates the Stack of Tasks inside the ros-control infra-structure. */ +#ifdef REAL_ROBOT + namespace lhi = hardware_interface; +#else + namespace lhi = talos_hardware_interface; +#endif + class RCSotController : public controller_interface::ControllerBase, SotLoaderBasic { @@ -68,33 +107,33 @@ namespace talos_sot_controller /// @{ \name Ros-control related fields /// \brief Vector of joint handles. - std::vector<hardware_interface::JointHandle> joints_; + std::vector<lhi::JointHandle> joints_; std::vector<std::string> joints_name_; /// \brief Vector towards the IMU. - std::vector<hardware_interface::ImuSensorHandle> imu_sensor_; + std::vector<lhi::ImuSensorHandle> imu_sensor_; /// \brief Vector of 6D force sensor. - std::vector<hardware_interface::ForceTorqueSensorHandle> ft_sensors_; + std::vector<lhi::ForceTorqueSensorHandle> ft_sensors_; /// \brief Vector of temperature sensors for the actuators. - std::vector<hardware_interface::ActuatorTemperatureSensorHandle> + std::vector<lhi::ActuatorTemperatureSensorHandle> act_temp_sensors_; /// \brief Interface to the joints controlled in position. - hardware_interface::PositionJointInterface * pos_iface_; + lhi::PositionJointInterface * pos_iface_; /// \brief Interface to the joints controlled in force. - hardware_interface::EffortJointInterface * effort_iface_; + lhi::EffortJointInterface * effort_iface_; /// \brief Interface to the sensors (IMU). - hardware_interface::ImuSensorInterface* imu_iface_; + lhi::ImuSensorInterface* imu_iface_; /// \brief Interface to the sensors (Force). - hardware_interface::ForceTorqueSensorInterface* ft_iface_; + lhi::ForceTorqueSensorInterface* ft_iface_; /// \brief Interface to the actuator temperature sensor. - hardware_interface::ActuatorTemperatureSensorInterface * act_temp_iface_; + lhi::ActuatorTemperatureSensorInterface * act_temp_iface_; /// @} @@ -109,7 +148,12 @@ namespace talos_sot_controller /// \brief The robot can controlled in effort or position mode (default). SotControlMode control_mode_; - + + - + /// \brief Implement a PD controller for the robot when the dynamic graph + /// is not on. + std::map<std::string,EffortControlPDMotorControlData> effort_mode_pd_motors_; + /// \brief Map from ros-control quantities to robot device /// ros-control quantities are for the sensors: /// * motor-angles @@ -119,7 +163,7 @@ namespace talos_sot_controller /// ros-control quantities for control are: /// * joints /// * torques - std::map<std::string,std::string> mapFromRCToSotDevice; + std::map<std::string,std::string> mapFromRCToSotDevice_; public : @@ -127,7 +171,7 @@ namespace talos_sot_controller /// \brief Read the configuration files, /// claims the request to the robot and initialize the Stack-Of-Tasks. - bool initRequest (hardware_interface::RobotHW * robot_hw, + bool initRequest (lhi::RobotHW * robot_hw, ros::NodeHandle &robot_nh, ros::NodeHandle &controller_nh, std::set<std::string> & claimed_resources); @@ -150,7 +194,7 @@ namespace talos_sot_controller protected: /// Initialize the roscontrol interfaces - bool initInterfaces(hardware_interface::RobotHW * robot_hw, + bool initInterfaces(lhi::RobotHW * robot_hw, ros::NodeHandle &, ros::NodeHandle &, std::set<std::string> & claimed_resources); @@ -182,6 +226,9 @@ namespace talos_sot_controller /// \brief Read the control mode. bool readParamsControlMode(ros::NodeHandle & robot_nh); + /// \brief Read the PID information of the robot in effort mode. + bool readParamsEffortControlPDMotorControlData(ros::NodeHandle &robot_nh); + ///@} /// \brief Fill the SoT map structures -- GitLab