We don't want our robot to touch the wall at all because this may cause some damage, so instead of the contact sensor we can use the Lidar. Lidar is an acronym for "light detection and ranging". This sensor can help us detect obstacles around the robot. We will use it to measure the distance between our robot and the wall.
First let's create a frame to fix our lidar to. This should be added inside of the vehicle_blue
tag, since the lidar frame is attached to the robot's chassis
:
0.8 0 0.5 0 0 0
Then add this plugin under the
tag, to be able to use the lidar
sensor:
ogre2
Under the chassis
link we can add the lidar
sensor as follows:
"
0 0 0 0 0 0
lidar
10
640
1
-1.396263
1.396263
1
0.01
0
0
0.08
10.0
0.01
1
true
name
and type
of our sensor, then we defined its
relative to the lidar_frame
.
we define the topic on which the lidar data will be published.
is the frequency at which the lidar
data is generated, in our case 10 Hz
which is equal to 0.1 sec
.
and
tags we define the properties of the horizontal and vertical laser rays.
is the number of simulated lidar rays to generate per complete laser sweep cycle.
: this number is multiplied by samples to determine the number range data points.
and
are the angle range of the generated rays.
we define range properties of each simulated ray
and
define the minimum and maximum distance for each lidar ray.
tag here defines the linear resolution of each lidar ray.
: if true the sensor will always be updated according to the
.
: if true the sensor is visualized in the GUI.Now run the world and press the play button in the bottom-left corner:
gz sim sensor_tutorial.sdf
Look at the lidar messages on the /lidar
topic, specifically the ranges
data:
gz topic -e -t /lidar
The lidar message has the following attributes:
message LaserScan
{
Header header = 1;
string frame = 2;
Pose world_pose = 3;
double angle_min = 4;
double angle_max = 5;
double angle_step = 6;
double range_min = 7;
double range_max = 8;
uint32 count = 9;
double vertical_angle_min = 10;
double vertical_angle_max = 11;
double vertical_angle_step = 12;
uint32 vertical_count = 13;
repeated double ranges = 14;
repeated double intensities = 15;
}
Now as we have the lidar on our robot, we can use the ranges
data and make our robot avoid hitting the wall. To do that, we'll write a short C++ program that listens to the sensor data and sends velocity commands to the robot. This program is called a node. We will build a node that subscribes to the /lidar
topic and reads its data. Have a look at this tutorial to learn how to build a publisher
and a subscriber
node. You can download the finished node for this demo from here.
gz::transport::Node node;
std::string topic_pub = "/cmd_vel";
gz::msgs::Twist data;
auto pub = node.Advertise(topic_pub);
We declare a node
which will publish to cmd_vel
topic and defined the message type Twist
. Then advertise our node.
void cb(const gz::msgs::LaserScan &_msg)
{
bool allMore = true;
for (int i = 0; i < _msg.ranges_size(); i++)
{
if (_msg.ranges(i) < 1.0)
{
allMore = false;
break;
}
}
if (allMore) //if all bigger than one
{
data.mutable_linear()->set_x(0.5);
data.mutable_angular()->set_z(0.0);
}
else
{
data.mutable_linear()->set_x(0.0);
data.mutable_angular()->set_z(0.5);
}
pub.Publish(data);
}
Inside the callback function we check if the range of all rays are bigger than 1.0
. If so we publish a message to our car to move forward. Otherwise we make the robot rotate.
int main(int argc, char **argv)
{
std::string topic = "/lidar";
// Subscribe to a topic by registering a callback.
if (!node.Subscribe(topic, cb))
{
std::cerr << "Error subscribing to topic [" << topic << "]" << std::endl;
return -1;
}
// Zzzzzz.
gz::transport::waitForShutdown();
return 0;
}
Inside the main we subscribe to the lidar
topic, and wait until the node is shut down.
Download the CMakeLists.txt, and in the same folder of lidar_node
create build/
directory:
mkdir build
cd build
Run cmake and build the code:
cmake ..
make lidar_node
Run the node from terminal 1:
./build/lidar_node
Run the world from terminal 2:
gz sim sensor_tutorial.sdf
Now you can see the robot move forward and as it approaches the wall it starts to turn left until it's clear and moves forward again (be sure to press the play button in the bottom-left corner to make the robot start moving).
Instead of running two different tasks from two different terminals we can make a launch file which will run the sensor_world
and the lidar_node
at the same time. Open your text editor and add the following code.
gz sim sensor_tutorial.sdf
./build/lidar_node
The launch file is an XML file. We simply define what commands will run under the
tag. The first command is gz sim sensor_tutorial.sdf
which launches the world. And the second command is ./build/lidar_node
which runs the lidar_node
. Save the file as sensor_launch.gzlaunch
, and then run it using the following command:
gz launch sensor_launch.gzlaunch
Press the play button to start the simulation. Hurray! Our robot is now moving and avoiding the wall.
To add even more complexity to your simulation, learn how to add actors to a world in the next tutorial.
A video walk-through of this tutorial is available from our YouTube channel: Gazebo tutorials: Sensors
/
720
1
-1.570796
1.570796
0.10
30.0
0.01
gaussian
0.0
0.01
30
/rrbot/laser
~/out:=scan
sensor_msgs/LaserScan