ros-controls / ros_controllers

Generic robotic controllers to accompany ros_control
http://wiki.ros.org/ros_control
BSD 3-Clause "New" or "Revised" License
561 stars 526 forks source link

hardware_interface_adapter design in joint_trajectory_controller #396

Open elton-choi opened 5 years ago

elton-choi commented 5 years ago

if we want to connect hardware_interface and joint_trajectory_controller, we can customize hardware_interface_adapter template class.

template <class HardwareInterface, class State>
class HardwareInterfaceAdapter
{
public:
  bool init(std::vector<typename HardwareInterface::ResourceHandleType>& /*joint_handles*/, ros::NodeHandle& /*controller_nh*/)
  {
    return false;
  }

  void starting(const ros::Time& /*time*/) {}
  void stopping(const ros::Time& /*time*/) {}

  void updateCommand(const ros::Time&     /*time*/,
                     const ros::Duration& /*period*/,
                     const State&         /*desired_state*/,
                     const State&         /*state_error*/) {}
};

In this class, the last input of updateCommand function is state_error. I think it should be just current_state. state_error argument is limited for pid controller. for example, if we're going to use gravity compensation + pid controller, we need current_state and state_error. state_error can be calculated from desired_state and current_state. In order to generalize hardware_interface_adapter for general controller, I think we should change the last argument from state_error to current_state.


[Modify] Actually, the above issue was not a big problem, because I can get current_state from joint handles. But, more serious problem is ,in hardware_interface_adapter.h, ClosedLoopHardwareInterfaceAdapter and class HardwareInterfaceAdapter<hardware_interface::EffortJointInterface, State> : public ClosedLoopHardwareInterfaceAdapter are limited for pid controller.

I want to implement other controllers such as gravity compensation controller, computed-torque controller, passivity-based controller which is necessary to control serial-chain arm through effort hardwareinterface. I tried to do this not by fixing hardware_interface_adapter.h directly, but writing custom-code outside joint-trajectory codes, but since effort hardware interface adapter inherited from ClosedLoopHardwareInterfaceAdapter is limited for pid controller, I failed.

Is there simple way that I can write custom controller code upon this joint-trajectory controller module? It was possible to write custom controller code referencing effort_controllers. (https://github.com/ros-controls/ros_control/wiki/controller_interface) But, with joint_trajectory_controller, I cannot find a way to write custom controller easily.

2b-t commented 4 months ago

I tried to do the very same and just wanted to document the solution here for reference...

The way that the joint trajectory controller works in ROS 1 is outlined here:

The controller is templated to work with multiple hardware interface types. Currently joints with position, velocity and effort interfaces are supported. For position-controlled joints, desired positions are simply forwarded to the joints; while for velocity (effort) joints, the position+velocity trajectory following error is mapped to velocity (effort) commands through a PID loop. Example controller configurations can be found here.

For example the effort_controllers::JointTrajectoryController is a short-hand notation for the fully specialized C++ template joint_trajectory_controller::JointTrajectoryController< trajectory_interface::QuinticSplineSegment<double>, hardware_interface::EffortJointInterface> (see here). At the very end of the update loop the set-point is mapped through the HwIfaceAdapter<HardwareInterface, Segment::State> to a point that matches the HardwareInterface. The partial specialization for effort can be found here and is basically just a ClosedLoopHardwareInterfaceAdapter<State> which performs a simple PID loop for mapping the position set-point to effort here.

Anyone wishing to implement a custom JointTrajectoryController can therefore re-use most of the ros_control infrastructure to do so. All they have to do is implement their own HardwareInterfaceAdapter. The main problem is integrating it into the rest of the code base as the following line hard codes the mapping for the known interfaces:

https://github.com/ros-controls/ros_controllers/blob/c2348e85abf35cf33cf654a84d61db206abe9a73/joint_trajectory_controller/include/joint_trajectory_controller/joint_trajectory_controller.h#L178

There are the following three options of implementation that come to my mind: