Understanding the effort_controller/JointTrajectoryController

Hello,
I am having trouble understanding how the effort_controller/JointTrajectoryController works in control terms. I understand how to use it and what it does, however I am having trouble grasping how it performs its calculations. I understand that it takes a joint trajectory as input, and outputs effort with the effort interface.

  1. However, how does it implement the PID controller? Does it implment a PID controller for both the desired position and velocity, or just for the desired position?
  2. And does it use a feedforward controller for the desired velocity?
  3. Also, how does it determine the desired velocity from the trajectory and how can this be specified?

I hope you can help me gain a better understanding. Thank you.

Kind regards,
Anders

Hello @volvo2,
as you correctly said the effort_controller/JointTrajectoryController executes joint trajectories on a set of joints and sends commands to an effort interface.

The nice thing about the JointTrajectoryController is that you can provide just a few waypoints and the controller will interpolate new points and will send smooth control command updates to the robot.

From the documentation the trajectory_msgs/JointTrajectory message is as follows:

std_msgs/Header header
  uint32 seq
  time stamp
  string frame_id
string[] joint_names
trajectory_msgs/JointTrajectoryPoint[] points
  float64[] positions
  float64[] velocities
  float64[] accelerations
  duration time_from_start

In this message you must provide at least positions and you can optionally also provide velocities. Internally, when the trajectory is sampled, the position+velocity trajectory following error is mapped to effort commands through a PID loop. I am not an expert of each controller internals, but this is what I noticed when examining the source code that is in the official ros_controllers repository.

For instance by inspecting this file here:

In fact as you can see the command is computed adding feedforward+feedback control:

  • Feedforward term: Desired velocity, as computed by the joint trajectory controller.
  • Feedback: PID that compensates drift from the desired position.

This was also taken form that source code file:

The following is an example configuration of a controller that uses this adapter.
Notice the parameters gains and velocity_ff :

  head_controller:
    type: "effort_controllers/JointTrajectoryController"
    joints:
      - head_1_joint
      - head_2_joint
    gains:
      head_1_joint: {p: 200, d: 1, i: 5, i_clamp: 1}
      head_2_joint: {p: 200, d: 1, i: 5, i_clamp: 1}
    velocity_ff:
      head_1_joint: 1.0
      head_2_joint: 1.0
    constraints:
      goal_time: 0.6
      stopped_velocity_tolerance: 0.02
      head_1_joint: {trajectory: 0.05, goal: 0.02}
      head_2_joint: {trajectory: 0.05, goal: 0.02}
    stop_trajectory_duration: 0.5
    state_publish_rate:  25

Hope I could help a little bit, I definitely recommend diving deeper into the source code of the controller to get all the details about its implementation.

Best,

Roberto

Hello Roberto @rzegers ,
Thank you very much for the answer.
Understanding the JointTrajectory message helped a lot.

Am I correct in understanding that Moveit uses this message with the follow_joint_trajectory action?
So, in other words Moveit! plans a path using one of its planning algorithms, and then uses this for the follow_joint_trajectory action?
Does Moveit! provide the planned path as a set of waypoints which the controller then interpolates between?

Thank you for the patience- I am trying to gain a greater understanding of how the different mechanisms work.

Kind regards,
Anders

Hello @volvo2,

your understanding is correct, that is how MoveIt send commands to robotic arm joints. It works as you have described it.

Regards,

Roberto