0
$\begingroup$

Rosanswers logo

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:

image description

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/273947/moving-joints-in-gazebo-simple-example/) 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.

Thanks in advance.


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 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.


Edit #2

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

Yes you are right. I'm a bit verbose.

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

I followed this answer: https://answers.ros.org/question/273947/moving-joints-in-gazebo-simple-example/ where sample code had the two lines I mentioned in those files. You can see the yaml and urdf files here: https://github.com/Toronto-Robotics-club/Toronto-Robotics-club-ros_control_and_gazebo_simple_position_controller

Could you clarify what sort of behavior you are looking for exactly?

First off, thank you very much. You have helped me so much over the past while and I really appreciate your help. I put together a quick drawing for what I am trying to do in Gazebo (which is already implemented on the physical robot):

  • The red lines show the sweeping arc that the lidar should perform given the Twist data.
  • Issue #1 - the current answer does not allow me to give a "do a single revolution command". This will be needed in both directions (1 revolution right, 1 revolution left).
  • Issue #2 - say the lidar is located on the green line (pointing in that direction). The lidar now needs to sweep the area in the red lines. The shortest path to a full sweep is to go CCW, but that is not what will happen.

image description

I have a feeling the best solution is to use a velocity control on the joint, and monitor the position of the joint. Then when the joint is in position, send a stop command. What do you think?


Originally posted by BuilderMike on ROS Answers with karma: 247 on 2020-02-12

Post score: 0

$\endgroup$

1 Answer 1

0
$\begingroup$

Rosanswers logo

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 an opposite direction. Is it possible to configure the direction of motion somehow?

Unfortunately I don't believe this is configurable. See here for the code which determines the shortest distance. For the average case this behaviour makes sense I would say.

Could you clarify what sort of behaviour you are looking for exactly?

Your lidar is mounted on a single joint (a continuous one?), which you want to sweep along an arc (ie: part of the circle described by a full rotation), with the "center" of the arc aligned with the direction in which the vehicle is moving. Is that correct?


Edit 2:

I have a feeling the best solution is to use a velocity control on the joint, and monitor the position of the joint. Then when the joint is in position, send a stop command. What do you think?

Yes, that does sound like a good approach.

I'd implement this in a separate node, which takes in the current heading of the vehicle, the incoming Twist and then calculates the desired arc lengths to achieve the sweep. A velocity controller would indeed be a good thing to have. To make sure it's actually closed-loop (and not a forwarding controller), be sure to give your Gazebo vehicle an effort interface for that joint.

If you want to make things nice, you could implement a custom ros_control controller. It could take in the same data and interact (ie: command) your joint directly, instead of via topics.


Originally posted by gvdhoorn with karma: 86574 on 2020-02-12

This answer was ACCEPTED on the original site

Post score: 1


Original comments

Comment by BuilderMike on 2020-02-12:
@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?

Comment by BuilderMike on 2020-02-13:
@gvdhoorn could you please have a look at Edit #2? Thanks so much for all your help!

$\endgroup$

Your Answer

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