Robotics StackExchange | Archived questions

How to setup diff_drive_controller to make it work with ros_control's velocity_controllers?

Hello, I'm quite confused with how to setup ros_control's velocity/position PID controllers source in a differential drive robot with diff_drive_controller wiki.

Here are some ambiguities on conceptual level with some code snippets to make everything clearer. It is somehow related to #249435, but I think that these examples with some answers will greatly help other beginners to find some info on configuration diff_drive_controller package, because besides some very general examples I couldn't find much info how to set it up properly. Hence this question.

What I did so far

I've already passed 2 joints of my robot (defined in URDF) to diff_drive_controller. Controller takes cmd_vel commands quite well. The problem is that when I'm sending linear.x = 0.3 m/s, angular.z = 0.0 rad/s command, it doesn't drive exactly forward. Another thing is that when I send linear.x = 0.1 m/s it couldn't overcome friction and is standing still.

Here is a part of the controller_common.yaml (diff drive controller params) file content:

mobile_base_controller:
  enable_odom_tf: true
  odom_frame_id: odom
  publish_cmd: true
  type: diff_drive_controller/DiffDriveController
  left_wheel: wheel_0_joint
  right_wheel: wheel_1_joint
  # and so on, it works straight ahead so I won't paste whole file, params set are listed on wiki page

Here is control.yaml file's content - 2 velocity controllers I can't make working:

  joint_state_controller:
    type: joint_state_controller/JointStateController
    publish_rate: 50  

  left_wheel_velocity_controller:
    type: velocity_controllers/JointVelocityController
    joint: wheel_0_joint  # base_to_0_wheel
    pid: {p: 00.1, i: 0.00001, d: 0.0001}

  right_wheel_velocity_controller:
    type: velocity_controllers/JointVelocityController
    joint: wheel_1_joint  # base_to_1_wheel
    pid: {p: 100.0, i: 0.1, d: 10.0}

and here is .launch file's content:

<rosparam command="load" file="$(find diff_drive_mapping_robot)/config/control.yaml" /> 
<rosparam command="load" file="$(find diff_drive_mapping_robot)/config/controller_common.yaml" /> 

<node name="base_controller_spawner"  pkg="controller_manager"  type="spawner"  output="screen"  args="mobile_base_controller" />

<node name="joint_controllers_spawner" pkg="controller_manager" type="spawner" respawn="false"
  output="screen"  args="joint_state_controller
                         left_wheel_velocity_controller
                         right_wheel_velocity_controller" >

</node> 

<node name="controller_manager_node"  pkg="diff_drive_mapping_robot" type="controller_manager_node"  output="screen" />

My robot's hardware_interfaces are defined and registered exactly as shown here

I also updated my robot_description (stored on Parameter Server) to extend joint description with hardware_interface

 <!-- =============== WHEEL_LEFT ===============-->
 <link name="wheel_0_joint">
    <visual>
      <geometry>
        <cylinder length="0.027" radius="0.03315"/>
      </geometry>
      <origin rpy="0 0 0" xyz="0 0 0"/>
      <material name="black">
        <color rgba="0 0 0 1"/>
      </material>
    </visual>
  </link>
  <joint name="base_to_0_wheel" type="fixed">
    <parent link="base_link"/>
    <child link="wheel_0_joint"/>
    <origin xyz="0 0.0955 0.03315" rpy="1.5708 0 0"/>
    <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface> <!-- please notice -->
  </joint>


  <!-- =============== WHEEL_RIGHT ===============-->
   <link name="wheel_1_joint">
    <visual>
      <geometry>
        <cylinder length="0.027" radius="0.03315"/>
      </geometry>
      <origin rpy="0 0 0" xyz="0 0 0"/>
      <material name="black">
        <color rgba="0 0 0 1"/>
      </material>
    </visual>
  </link>
  <joint name="base_to_1_wheel" type="fixed">
    <parent link="base_link"/>
    <child link="wheel_1_joint"/>
    <origin xyz="0 -0.0955 0.03315" rpy="1.5708 0 0"/>
    <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface> <!-- please notice -->
  </joint>

Now, with the same joints (same names) for diff drive controller and listed velocity controllers I get this error after starting .launch file:

[ WARN] [1527380810.421256974]: Resource conflict on [wheel_0_joint].  Controllers = [left_wheel_velocity_controller, mobile_base_controller, ]
[ WARN] [1527380810.421355205]: Resource conflict on [wheel_1_joint].  Controllers = [mobile_base_controller, right_wheel_velocity_controller, ]
[ERROR] [1527380810.421450132]: Could not switch controllers, due to resource conflict
[INFO] [1527380810.422338]: Started controllers: mobile_base_controller

When I create 2 extra instances to register interfaces (in the same manner as here ) like this:

  for (unsigned int i = 0; i < NUM_JOINTS; ++i)
  {
    std::ostringstream os;
    os << "wheel_" << i << "_joint";

    std::ostringstream os_ctrl;
    os_ctrl << "base_to_" << i << "_wheel";

    hardware_interface::JointStateHandle state_handle(os.str(), &pos[i], &vel[i], &eff[i]);
    jnt_state_interface.registerHandle(state_handle);

    hardware_interface::JointStateHandle state_handle_urdf(os_ctrl.str(), &pos_ctrl[i], &vel_ctrl[i], &eff_ctrl[i]);
    jnt_state_interface.registerHandle(state_handle_urdf);

    hardware_interface::JointHandle vel_handle(jnt_state_interface.getHandle(os.str()), &cmd[i]);
    jnt_vel_interface.registerHandle(vel_handle);

    hardware_interface::JointHandle vel_handle_urdf(jnt_state_interface.getHandle(os_ctrl.str()), &cmd_ctrl[i]);
    jnt_vel_interface.registerHandle(vel_handle_urdf);

  }

  registerInterface(&jnt_state_interface);
  registerInterface(&jnt_vel_interface);

and change joint names in control.yaml to:

  left_wheel_velocity_controller:
    type: velocity_controllers/JointVelocityController
    joint: base_to_0_wheel
    pid: {p: 00.1, i: 0.00001, d: 0.0001}
  right_wheel_velocity_controller:
    type: velocity_controllers/JointVelocityController
    joint: base_to_1_wheel
    pid: {p: 100.0, i: 0.1, d: 10.0}

I still get the error saying:

[ERROR] [1527380218.473857467]: Exception thrown while initializing controller left_wheel_velocity_controller.
Could not find resource 'base_to_0_wheel' in 'hardware_interface::VelocityJointInterface'.
[ERROR] [1527380218.473907473]: Initializing controller 'left_wheel_velocity_controller' failed
[ERROR] [1527380219.474679]: Failed to load left_wheel_velocity_controller

and the same error for second controller.

Questions

Do I really need to create 2 excessive joints for separate PID velocity controllers (each for one wheel)? What is missing in my configuration?

I remember that when I've been messing with above things I managed to start controllers without errors but robot's behavior didn't change. Should I use some external PID (non ros_control's like this) and make separate node out of it?

Sorry for this long question, I've tried to explain my problem the best I could to simplify finding a solution. I will appreciate any help.

Asked by rayvburn on 2018-05-26 19:47:25 UTC

Comments

Hi there, I am stuck at the very same problem for about 2 weeks now, as there doesnt seem to be much documentation. Did you get any further?

Asked by stuggibo on 2018-11-26 10:16:33 UTC

Unfortunately I had no luck. Finally used this package pid and it worked perfectly. EDIT: I forgot to post a link to my project's code. You may find it a useful example - Github repository

Asked by rayvburn on 2018-11-27 16:04:53 UTC

thanks, this helped me a lot :) did you somehow filter your velocity estimate?

Asked by stuggibo on 2018-12-20 09:49:20 UTC

No, sorry, I didn't need velocity filtering. Anyway, I'm glad I could help you a little.

Asked by rayvburn on 2018-12-23 04:03:32 UTC

This comment is probably not relevant for you anymore and I don't know if it is required either but I think you need to define a transmission tag inside your urdf in case you didn't have it. This seems to be required in simulation and when working with real hardware.

Asked by fjp on 2020-03-18 06:53:31 UTC

Answers