# How to mimic an encoder-motor joint in Gazebo using ros_control?

Hello,

I am running Ubuntu 16.04, with Ros Kinetic and Gazebo7 ver 7.16.

At present my physical robot can be viewed as a mobile base, and a custom 3-d lidar. The mobile base is controlled via a diff_drive controller. The node responsible for moving the lidar subscribes to the Twist command the diff_drive is receiving and moves the lidar system across the path of the robot. A single revolution of the lidar is measured via radians, with the front of the robot being 0 degrees. Every twist command is associated with “sweeping” between two radian places. Hopefully this old image during construction helps you visualize what I mean:

Recently I have come to realize that simulation (Gazebo) is very important (I’m a late bloomer). So I have modified my URDF, launch files, and so on to work with Gazebo. In Gazebo the robot drives around (using a diff_drive), and provides lidar data just like the physical robot. However I am having a hard time getting the lidar joint to work like the real unit.

I have used this answer (https://answers.ros.org/question/2739...) to get a joint to move in Gazebo via ros_control. I am able to get a joint to move with a fixed velocity or get a joint to “snap” into place. I say snap as the joint jumps from one position to another, it does not rotate from one position to another. Based on these circumstances I have two questions:

(1) At present I can use a velocity controller, monitor the position, and then stop at some desired point/position to mimic my physical system. Is there some other way?

(2) How do I write code that can run on both my physical machine and the Gazebo simulation? Any tips? I not really a software guy, so any advice is appreciated.

EDIT #1

By encoder-motor joint I mean that the encoder data (current position) has a direct effect on the motion of the motor (the joint). In my case the motor behavior is defined inside the hardware (acceleration, speed of travel, etc...) so all my code has to do is figure out the current position (from encoder data) and where we need to go (new position based on Twist data), and give a single command to the motor controller (physical device) which then takes care of the motion (starting motion, direction, velocity, and stopping the motion). I was hoping to be able to use ros_control to do the same in Gazebo. Give the position to the joint, and have the joint move from where it is to the new position (which would allow the lidar to collect data during the motion).

Something to clear up for me now: you mention Twist, but then ask about a position controlled system. geometry_msgs/Twist encodes velocities, not positions. Could you clarify how this works in your system?

The Twist data is used for the diff_drive controller to drive the robot around. At ...

edit retag close merge delete

Sort by » oldest newest most voted

We're going to need to know what sort of hardwareInterface you've added to your transmission.

If you have (let's say) a velocity interface, and would like to layer a position controller on-top, you'd use the velocity_controllers/JointPositionController. This takes in position setpoints (ie: radians) and outputs velocities (ie: rad/s).

Similarly: if you'd have an effort interface in your transmission, you'd use the effort_controllers/JointPositionController (which, as you may have guessed: takes in a position and outputs an effort).

I believe this would result in what you describe as a "encoder-motor joint".

See velocity_controllers/velocity_controllers_plugins.xml for a (very) terse description of the various velocity outputting controllers in ros_control.

Something to clear up for me now: you mention Twist, but then ask about a position controlled system. geometry_msgs/Twist encodes velocities, not positions. Could you clarify how this works in your system?

Edit:

By encoder-motor joint I mean that the encoder data (current position) has a direct effect on the motion of the motor (the joint). [..] Give the position to the joint, and have the joint move from where it is to the new position (which would allow the lidar to collect data during the motion).

This sounds like a regular, closed-loop position controller.

The Twist data is used for the diff_drive controller to drive the robot around. At the same time one of my lidar nodes subscribes to the topic on which the Twist message arrives, and based on the type of motion (drive straight, slight turn, rotate on the spot) the code determines the motion of the lidar. If robot is going straight the lidar sweeps directly in front, if robot is turning the lidar sweeps a bit of the front and the side, if robot is rotating on the spot the lidar rotates. The purpose here is to use the lidar to get the data that is most useful (ex: don't sweep behind the robot when we drive straight). I am trying to replicate this behavior (that works in the physical robot) in Gazebo.

Is this already a separate node (ie: the algorithm that controls the lidar based on vehicle ego motion)? If so, provided you use the same control interfaces and datastreams with your Gazebo simulation, this should work (ignoring tuning things to accommodate the slightly different behaviour between Gazebo and the real world of course).

I put <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface> in the urdf, and type: velocity_controllers/JointPositionController in the xacro file and everything seems to work.

Do you mean "the .yaml controller configuration file"? Because you don't typically configure controllers via/with/in a .xacro.

The only issue is that you cannot specify the direction. Whether you give a positive or negative radian value it moves to that point from its current position in the shortest path around the joint,

Yes, that would be the way the (closed-loop) position controllers are implemented.

and this doesn't work for my application as sometimes I need to sweep in ...

more

@gvdhoorn Please have a look at the edit regarding the Twist. I put <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface> in the urdf, and type: velocity_controllers/JointPositionController in the xacro file and everything seems to work. The only issue is that you cannot specify the direction. Whether you give a positive or negative radian value it moves to that point from its current position in the shortest path around the joint, and this doesn't work for my application as sometimes I need to sweep in an opposite direction. Is it possible to configure the direction of motion somehow?

( 2020-02-12 15:40:20 -0500 )edit

@gvdhoorn could you please have a look at Edit #2? Thanks so much for all your help!

( 2020-02-13 08:16:11 -0500 )edit