From bda1e849ea142e15fab00b03ac9695d8f84af206 Mon Sep 17 00:00:00 2001
From: Olivier Stasse <ostasse@laas.fr>
Date: Thu, 4 Jan 2018 11:52:04 +0100
Subject: [PATCH] Make sure that the robot is not falling when switching to
 effort control mode.

---
 talos_roscontrol_sot/CMakeLists.txt           |   2 +-
 .../src/roscontrol-sot-controller.cpp         | 111 +++++++++++++++--
 .../src/roscontrol-sot-controller.hh          |  35 +++++-
 .../config/sot_talos_params_effort.yaml       | 113 ++++++++++++++++++
 .../sot_talos_controller_gazebo_effort.launch |   4 +-
 5 files changed, 252 insertions(+), 13 deletions(-)

diff --git a/talos_roscontrol_sot/CMakeLists.txt b/talos_roscontrol_sot/CMakeLists.txt
index 2e8f55e..6e96b51 100644
--- a/talos_roscontrol_sot/CMakeLists.txt
+++ b/talos_roscontrol_sot/CMakeLists.txt
@@ -24,7 +24,7 @@ include(cmake/ros.cmake)
 include(cmake/GNUInstallDirs.cmake)
 include(cmake/python.cmake)
 
-project(talos_roscontrol_sot)
+#project(talos_roscontrol_sot)
 
 find_package(PkgConfig REQUIRED)
 
diff --git a/talos_roscontrol_sot/src/roscontrol-sot-controller.cpp b/talos_roscontrol_sot/src/roscontrol-sot-controller.cpp
index f6f8faa..7f00db9 100644
--- a/talos_roscontrol_sot/src/roscontrol-sot-controller.cpp
+++ b/talos_roscontrol_sot/src/roscontrol-sot-controller.cpp
@@ -41,6 +41,18 @@ 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():
@@ -234,19 +246,61 @@ 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]);
+	  }
+	return true;
+      }
+    
+    ROS_ERROR("No parameter /sot_controller/effort_controler_pd_motor_init");
+    return false;
+  }
+  
   bool RCSotController::
   readParamsFromRCToSotDevice(ros::NodeHandle &robot_nh)
   {
     // 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 +401,9 @@ 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 +512,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 +665,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,10 +700,46 @@ namespace talos_sot_controller
   }
 
   void RCSotController::
-  update(const ros::Time&, const ros::Duration& )
+  update(const ros::Time&, const ros::Duration& period)
   {
+    // Do not send any control if the dynamic graph is not started
     if (!isDynamicGraphStopped())
       one_iteration();
+    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::
diff --git a/talos_roscontrol_sot/src/roscontrol-sot-controller.hh b/talos_roscontrol_sot/src/roscontrol-sot-controller.hh
index addf29e..e45c20a 100644
--- a/talos_roscontrol_sot/src/roscontrol-sot-controller.hh
+++ b/talos_roscontrol_sot/src/roscontrol-sot-controller.hh
@@ -44,11 +44,35 @@
 #include <dynamic_graph_bridge/sot_loader_basic.hh>
 
 #include "log.hh"
+#include <ros/ros.h>
+#include <control_toolbox/pid.h>
 
 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.
      
@@ -109,7 +133,11 @@ 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 +147,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 :
 
@@ -182,6 +210,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
diff --git a/talos_roscontrol_sot_talos/config/sot_talos_params_effort.yaml b/talos_roscontrol_sot_talos/config/sot_talos_params_effort.yaml
index 9bd89c7..a0396e0 100644
--- a/talos_roscontrol_sot_talos/config/sot_talos_params_effort.yaml
+++ b/talos_roscontrol_sot_talos/config/sot_talos_params_effort.yaml
@@ -9,4 +9,117 @@ sot_controller:
   map_rc_to_sot_device: { motor-angles: motor-angles ,
   joint-angles: joint-angles, velocities: velocities, forces: forces, currents: currents,
   torques: torques, cmd-joints: control, cmd-effort: control, accelerometer_0: accelerometer_0, gyrometer_0: gyrometer_0 }
+    effort_control_pd_motor_init:
+	- name: leg_left_1_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: leg_left_2_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: leg_left_3_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: leg_left_4_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: leg_left_5_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: leg_left_6_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0	  
+	- name: leg_right_1_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: leg_right_2_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: leg_right_3_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: leg_right_4_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: leg_right_5_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: leg_right_6_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0	  
+	- name: torso_1_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: torso_2_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: arm_left_1_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: arm_left_2_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: arm_left_3_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: arm_left_4_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: arm_left_5_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: arm_left_6_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: arm_left_7_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0	  
+	- name: arm_right_1_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: arm_right_2_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: arm_right_3_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: arm_right_4_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: arm_right_5_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0
+	- name: arm_right_6_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0	  
+	- name: arm_right_7_joint
+	  p_gain: 1000.0
+	  d_gain: 1000.0
+	  des_pos: 0.0	  
   control_mode: EFFORT 
diff --git a/talos_roscontrol_sot_talos/launch/sot_talos_controller_gazebo_effort.launch b/talos_roscontrol_sot_talos/launch/sot_talos_controller_gazebo_effort.launch
index 9f5f1f5..bb3cc97 100644
--- a/talos_roscontrol_sot_talos/launch/sot_talos_controller_gazebo_effort.launch
+++ b/talos_roscontrol_sot_talos/launch/sot_talos_controller_gazebo_effort.launch
@@ -2,10 +2,12 @@
 
   <!-- Sot Controller configuration -->
   <rosparam command="load" file="$(find talos_roscontrol_sot_talos)/config/sot_talos_params_gazebo_effort.yaml"/>
+  <rosparam command="load" ns="/sot_controller/effort_control_pd_motor_init" file="$(find talos_hardware_gazebo)/config/pids.yaml"/>
   <rosparam command="load" file="$(find talos_roscontrol_sot_talos)/config/sot_talos_controller.yaml" />
   
   <!-- Spawn walking controller -->
-  <node name="sot_controller_spawner"
+  <node launch-prefix="xterm -e python -m pdb"
+  	name="sot_controller_spawner"
         pkg="talos_controller_manager" type="spawner" output="screen"
         args="sot_controller" />
 
-- 
GitLab