0
$\begingroup$

Rosanswers logo

Development Environment:

  • OS: Ubuntu 18.04
  • ROS version: Melodic

Robot:

I have working on this for the 2 weeks or so, but I still haven't quite figured out how ros_control is meant to work outside of tutorials.

Specifically, I have a small robot that I want to control with the diff_drive_control package. Currently the robot has onboard a TREX motor control board with a built in Arduino. I have programmed the Arduino with rosserial so that it reads from a couple rostopics a value between -255 and 255 to control the speed of the wheels on each side of the robot.

Now that I have proven that to work, I would like to replace these rostopics with the output from a differential drive controller. Specifically, I am using the diff_drive_controller package, trying to integrate skid steer into my robot.

I have gone through the tutorials at RobotIgnite Academy, as well as this rather helpful tutorial at https://slaterobots.com/blog/5abd8a1ed4442a651de5cb5b/how-to-implement-ros_control-on-a-custom-robot , but am still stuck on getting the diff_drive_controller to work.

My question right now is: what is required to run diff_drive_controller? I currently have a launch file, a controllers.yaml file and a urdf file. Do I have to develop a hardware interface c++ class? I just want to treat the robot like it has two wheels (one velocity for each side), and that seems standard enough that I would think the .yaml file would take care of that.

The environment builds, but I get the following message upon using the launch file:

taylorwelker@anshul-omegainfinity:~/rubble_ws$ roslaunch rubble rubble_control.launch
... logging to /home/taylorwelker/.ros/log/bf391328-ab9a-11e8-b7d3-e03f49b1675a/roslaunch-anshul-omegainfinity-2245.log
Checking log directory for disk usage. This may take awhile.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.

started roslaunch server http://192.168.0.101:33097/

SUMMARY
========

PARAMETERS
 * /ekf_localization/base_link_frame: base_link
 * /ekf_localization/frequency: 50
 * /ekf_localization/imu0: imu/data
 * /ekf_localization/imu0_config: [False, False, Fa...
 * /ekf_localization/imu0_differential: True
 * /ekf_localization/imu0_queue_size: 10
 * /ekf_localization/imu0_remove_gravitational_acceleration: True
 * /ekf_localization/odom0: rubble_velocity_c...
 * /ekf_localization/odom0_config: [False, False, Fa...
 * /ekf_localization/odom0_differential: False
 * /ekf_localization/odom0_queue_size: 10
 * /ekf_localization/odom_frame: odom
 * /ekf_localization/two_d_mode: True
 * /ekf_localization/world_frame: odom
 * /rosdistro: melodic
 * /rosversion: 1.14.3
 * /rubble_joint_publisher/publish_rate: 50
 * /rubble_joint_publisher/type: joint_state_contr...
 * /rubble_velocity_controller/angular/z/has_acceleration_limits: True
 * /rubble_velocity_controller/angular/z/has_velocity_limits: True
 * /rubble_velocity_controller/angular/z/max_acceleration: 25.0
 * /rubble_velocity_controller/angular/z/max_velocity: 2.0
 * /rubble_velocity_controller/cmd_vel_timeout: 0.25
 * /rubble_velocity_controller/enable_odom_tf: False
 * /rubble_velocity_controller/left_wheel: wheel_left_joint
 * /rubble_velocity_controller/linear/x/has_acceleration_limits: True
 * /rubble_velocity_controller/linear/x/has_velocity_limits: True
 * /rubble_velocity_controller/linear/x/max_acceleration: 20.0
 * /rubble_velocity_controller/linear/x/max_velocity: 2.0
 * /rubble_velocity_controller/pose_covariance_diagonal: [0.001, 0.001, 10...
 * /rubble_velocity_controller/publish_rate: 50
 * /rubble_velocity_controller/right_wheel: wheel_right_joint
 * /rubble_velocity_controller/twist_covariance_diagonal: [0.001, 0.001, 0....
 * /rubble_velocity_controller/type: diff_drive_contro...
 * /rubble_velocity_controller/wheel_radius_multiplier: 1.0
 * /rubble_velocity_controller/wheel_separation_multiplier: 1.5

NODES
  /
    controller_spawner (controller_manager/spawner)
    ekf_localization (robot_localization/ekf_localization_node)

auto-starting new master
process[master]: started with pid [2256]
ROS_MASTER_URI=http://localhost:11311

setting /run_id to bf391328-ab9a-11e8-b7d3-e03f49b1675a
process[rosout-1]: started with pid [2268]
started core service [/rosout]
process[controller_spawner-2]: started with pid [2274]
process[ekf_localization-3]: started with pid [2276]
[INFO] [1535554176.965737]: Controller Spawner: Waiting for service controller_manager/load_controller
[WARN] [1535554207.140939]: Controller Spawner couldn't find the expected controller_manager ROS interface.
[controller_spawner-2] process has finished cleanly
log file: /home/taylorwelker/.ros/log/bf391328-ab9a-11e8-b7d3-e03f49b1675a/controller_spawner-2*.log

I can't upload files so I will copy and paste them here:

rubble_control.launch

<launch>

  <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen"  
    args="
      /rubble_joint_publisher /rubble_velocity_controller 
  "/>

  <rosparam file="$(find rubble)/config/rubble_control.yaml" command="load" />

  <node pkg="robot_localization" type="ekf_localization_node" name="ekf_localization">
    <rosparam command="load" file="$(find rubble)/config/localization.yaml" />
  </node>

</launch>

rubble_control.yaml

rubble_joint_publisher:
  type: "joint_state_controller/JointStateController"
  publish_rate: 50

rubble_velocity_controller:
  type: "diff_drive_controller/DiffDriveController"      
  left_wheel: 'wheel_left_joint'
  right_wheel: 'wheel_right_joint'
  publish_rate: 50
  pose_covariance_diagonal: [0.001, 0.001, 1000000.0, 1000000.0, 1000000.0, 0.03]
  twist_covariance_diagonal: [0.001, 0.001, 0.001, 1000000.0, 1000000.0, 0.03]
  cmd_vel_timeout: 0.25

  # Odometry fused with IMU is published by robot_localization, so 
  # no need to publish a TF based on encoders alone.
  enable_odom_tf: false

  # Wheel separation and radius multipliers
  wheel_separation_multiplier: 1.5 # default: 1.0
  wheel_radius_multiplier    : 1.0 # default: 1.0

  # Velocity and acceleration limits
  # Whenever a min_* is unspecified, default to -max_*
  linear:
    x:
      has_velocity_limits    : true
      max_velocity           : 2.0   # m/s
      has_acceleration_limits: true
      max_acceleration       : 20.0  # m/s^2
  angular:
    z:
      has_velocity_limits    : true
      max_velocity           : 2.0   # m/s
      has_acceleration_limits: true
      max_acceleration       : 25.0  # rad/s^2

localization.yaml

odom_frame: odom
base_link_frame: base_link
world_frame: odom

two_d_mode: true

frequency: 50

odom0: rubble_velocity_controller/odom
odom0_config: [false, false, false,
               false, false, false,
               true, true, true,
               false, false, true,
               false, false, false]
odom0_differential: false
odom0_queue_size: 10

imu0: imu/data
imu0_config: [false, false, false,
              true, true, true,
              false, false, false,
              true, true, true,
              false, false, false]

imu0_differential: true
imu0_queue_size: 10
imu0_remove_gravitational_acceleration: true

rubble.urdf

<transmission name="wheel_left_transmission">
  <type>transmission_interface/SimpleTransmission</type>
  <joint name="wheel_left_joint">
    <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
  </joint>
  <actuator name="wheel_left_actuator">
    <mechanicalReduction>7</mechanicalReduction>
    <hardwareInterface>VelocityJointInterface</hardwareInterface>
  </actuator>
</transmission>

<transmission name="wheel_right_transmission">
  <type>transmission_interface/SimpleTransmission</type>
  <joint name="wheel_right_joint">
    <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
  </joint>
  <actuator name="wheel_right_actuator">
    <mechanicalReduction>7</mechanicalReduction>
    <hardwareInterface>VelocityJoint_Interface</hardwareInterface>
  </actuator>
</transmission>

Any tips on what I am missing? Is it a hardware interface? Is my urdf insufficient? Do I need to first provide the feedback to a specific rostopic? Any help would be great!


Originally posted by twelker on ROS Answers with karma: 3 on 2018-08-29

Post score: 0

$\endgroup$

1 Answer 1

0
$\begingroup$

Rosanswers logo

does diff_drive_controller require a hardware interface?

Yes.

Do I have to develop a hardware interface c++ class?

Yes, probably.

I just want to treat the robot like it has two wheels (one velocity for each side), and that seems standard enough that I would think the .yaml file would take care of that.

The kinematics may seem standard enough -- and indeed they are, as that is exactly what diff_drive_controller takes care of for you -- but how would you imagine we could abstract away the specific details of how your robot interfaces with its motion controller / controller boards? There are so many different ways to do that (serial, wireless, gpio, ethernet, some real-time fieldbus, hardwired signals, etc, etc) it is virtually impossible to support all of that out of the box.

That is where the hardware_interface comes in: it provides a standardised API for ros_control to talk to your hardware (without knowing anything about "TREX Robot Controllers" or other specific electronics).

But it does require you -- as the only one with the knowledge of how your robot is put together -- to create such an implementation of the hardware_interface API.


Edit: what you could do however is spend some time trying to find a hardware_interface implementation for a "TREX Robot Controller" that some other user before you has written (and open-sourced).

If you can find such a thing, and it is compatible with the exact model you have, you might be lucky and avoid having to write one yourself.


Originally posted by gvdhoorn with karma: 86574 on 2018-08-29

This answer was ACCEPTED on the original site

Post score: 2


Original comments

Comment by twelker on 2018-08-29:
Thank you gvdhoorn! I was under the impression that ros controllers simply take in sensor data via rostopic, and output a new command to another rostopic. I already built an interface that takes a rostopic and executes it on them on the motor controller, but not in "hardware_interface" format.

Comment by twelker on 2018-08-29:
But I guess I will have to rebuild it to fit this required format. Can the interface (read() and write() functions be something as simple as "read from" or "write to" a rostopic? The Arduino should be able to handle it from there.

Comment by gvdhoorn on 2018-08-29:
It's definitely possible to use topics, although it's not often used for 'serious' things, as it makes it immediately impossible to do anything real-time (the real real-time, so deterministic).

But again: I would spend some time trying to find out whether someone has already created something.

Comment by gvdhoorn on 2018-08-29:
Btw:

I was under the impression that ros controllers simply take in sensor data via rostopic, and output a new command to another rostopic

the reason it doesn't do that is because of the real-time aspect again, but there is a good chance that a ROS2 version of ros_control will do ..

Comment by gvdhoorn on 2018-08-29:
.. exactly that (ie: use topics).

ROS2 has a few features that make this possible without sacrificing potential real-time capabilities.

Comment by gvdhoorn on 2018-08-29:
If you're not into ros_control, you could take a look at the differential_drive package. It's somewhat similar, but does use topics.

You won't be able to use any of the ros_control features with it, but perhaps you don't need them.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.