Place the robot
So far, a robot model was created from scratch, sensors were added to it to visualize its surroundings, and a package was developed to start the robot in a simulated environment. This is a real achievement!
But without placing the robot in a specific environment, let's place it in a built world.
Add World file
Paste myworld.world ( https://github.com/jeffnd/Robotics-Software-Engineer/blob/master/Project1-BuildMyWorld/world/World4 ) into the world directory of my_robot. In the worlds directory, there are now two files - empty.world and myworld.world, feel free to delete the empty.world file, we don't need it anymore.
start the world
Edit the world.launch file and add a reference to myworld.world. Open the world.launch file and edit this line:
<arg name="world_file"default="$(findmy_robot)/worlds/empty.world"/>
replace it with:
<arg name="world_file"default="$(findmy_robot)/worlds/myworld.world"/>
start up!
Now that the world file has been added to the my_robot package, start and visualize the robot:
$ cd /home/workspace/catkin_ws/
$ source devel/setup.bash
$ roslaunch my_robot world.launch
Initialize the position and orientation of the robot
The initial position of the robot can be achieved by editing the world.launch file:
<!-- Robot pose -->
<argname="x"default="0"/>
<argname="y"default="0"/>
<argname="z"default="0"/>
<argname="roll"default="0"/>
<argname="pitch"default="0"/>
<argname="yaw"default="0"/>
The best way to find out these numbers is to change the robot's position and orientation in Gazebo, record its pose, and then update the launch file.
Summary: Follow the steps below to place a robot in an environment:
![](https://img-blog.csdnimg.cn/img_convert/dee9c7a45441801ee11a760df2228db5.png)
11. Set the ball_chaser
The second main task in this project is to create the ball_chaser ROS package. In this package, the images captured by the camera are analyzed to determine the position of the white ball, and then drive the robot towards the direction of the ball. The nodes in ball_chaser establish communication with the my_robot package by subscribing to the data from the robot's camera sensor and publishing it to the robot's wheel joints.
package node
The ball_chaser package has two c++ nodes: drive_bot and process_image
drive_bot : This server node will provide a ball_chaser/command_robot service to drive the robot by controlling its linear x and angular z velocity. The service will publish a message containing the velocity to the wheel joint.
process_image : This client node will subscribe to the robot's camera images and analyze each image to determine the position of the white ball. Once the position of the ball is determined, the client node will request a service to drive the robot left, right or forward.
Now, follow the steps to setup ball_chaser .
Create the ball_chaser package
1) Navigate to the src directory of catkin_ws and create the ball_chaser package:
Write node in c++, since we already know that this package will contain c++ sources and messages, let's create the package with these dependencies:
$ cd /home/workspace/catkin_ws/src/
$ catkin_create_pkg ball_chaser roscpp std_msgs message_generation
2) Next, create a srv and a launch folder, which will further define the structure of the package:
$ cd /home/workspace/catkin_ws/src/ball_chaser/
$ mkdir srv
$ mkdir launch
Remember, srv is the directory where service files are stored, and launch is the directory where startup files are stored. The src directory for storing c++ programs is created by default.
build pack
$ cd /home/workspace/catkin_ws/
$ catkin_make
Summary: Follow the steps below to setup the ball_chaser package:
![](https://img-blog.csdnimg.cn/img_convert/554905aea5ed9bf58c096b637a6c397b.png)
12. ROS node: drive_bot
This server node provides a ball_chaser/command_robot service to drive the robot by setting its linear x and angular z velocity. The service server publishes messages containing the wheel joint velocities.
After writing this node, you will be able to request the ball_chaser/command_robot service from a terminal or client node to drive the robot by controlling its linear x and angular z velocity.
ROS service file
1) Write DriveToTarget.srv file
In the srv directory of ball_chaser, create a DriveToTarget.srv file. Then, define the DriveToTarget.srv file as follows:
Require:
linear_x type float64
angular_z type float64
response:
msg_feedback type string
2) Test DriveToTarget.srv
After writing the service file, test it with ROS. Open a new terminal and execute the following command:
$ cd /home/workspace/catkin_ws/
$ source devel/setup.bash
$ rossrv show DriveToTarget
Received the following reply:
[ball_chaser/DriveToTarget]:
float64 linear_x
float64 angular_z
---
string msg_feedback
drive_bot.cpp node
Create scripts in the src directory of the ball_chaser package. Attached below is a program that will continuously publish to the robot/cmd_vel topic, this code will drive the robot forward:
#include"ros/ros.h"
#include"geometry_msgs/Twist.h"
//TODO: Include the ball_chaser "DriveToTarget" header file
// ROS::Publisher motor commands;
ros::Publisher motor_command_publisher;
// TODO: Create a handle_drive_request callback function that executes whenever a drive_bot service is requested
// This function should publish the requested linear x and angular velocities to the robot wheel joints
// After publishing the requested velocities, a message feedback should be returned with the requested wheel velocities
int main(int argc, char** argv)
{
// Initialize a ROS node
ros::init(argc, argv, "drive_bot");
// Create a ROS NodeHandle object
ros::NodeHandle n;
// Inform ROS master that we will be publishing a message of type geometry_msgs::Twist on the robot actuation topic with a publishing queue size of 10
motor_command_publisher = n.advertise<geometry_msgs::Twist>("/cmd_vel", 10);
// TODO: Define a drive /ball_chaser/command_robot service with a handle_drive_request callback function
// TODO: Delete the loop, move the code to the inside of the callback function and make the necessary changes to publish the requested velocities instead of constant values
while (ros::ok()) {
// Create a motor_command object of type geometry_msgs::Twist
geometry_msgs::Twist motor_command;
// Set wheel velocities, forward [0.5, 0.0]
motor_command.linear.x = 0.5;
motor_command.angular.z = 0.0;
// Publish angles to drive the robot
motor_command_publisher.publish(motor_command);
}
// TODO: Handle ROS communication events
//ros::spin();
return0;
}
Take a look at the program and try to understand what's going on. Then, copy it to drive_bot.cpp and make the necessary changes to define a ball_chaser/command_robot service.
The reference code is as follows ---
#include"ros/ros.h"
#include"geometry_msgs/Twist.h"
//TODO: Include the ball_chaser "DriveToTarget" header file
#include "ball_chaser/DriveToTarget.h"
using namespace std;
// ROS::Publisher motor commands;
ros::Publisher motor_command_publisher;
// TODO: Create a handle_drive_request callback function that executes whenever a drive_bot service is requested
// This function should publish the requested linear x and angular velocities to the robot wheel joints
// After publishing the requested velocities, a message feedback should be returned with the requested wheel velocities
bool handle_drive_request(ball_chaser::DriveToTarget::Request& req, ball_chaser::DriveToTarget::Response& res)
{
ROS_INFO("DriveToTargetRequest received - linear_x: %.2f, angular_z: %.2f", req.linear_x, req.angular_z);
// Create a motor_command object of type geometry_msgs::Twist
geometry_msgs::Twist motor_command;
// Set wheel velocities
motor_command.linear.x = req.linear_x;
motor_command.angular.z = req.angular_z;
// Publish data to drive the robot
motor_command_publisher.publish(motor_command);
// Return a response message
res.msg_feedback = "Motor Command is: linear_x: " + to_string(motor_command.linear.x) + ", angular_z: " + to_string(motor_command.angular.z);
ROS_INFO_STREAM(res.msg_feedback);
return true;
}
int main(int argc, char** argv)
{
// Initialize a ROS node
ros::init(argc, argv, "drive_bot");
// Create a ROS NodeHandle object
ros::NodeHandle n;
// Inform ROS master that we will be publishing a message of type geometry_msgs::Twist on the robot actuation topic with a publishing queue size of 10
motor_command_publisher = n.advertise<geometry_msgs::Twist>("/cmd_vel", 10);
// TODO: Define a drive /ball_chaser/command_robot service with a handle_drive_request callback function
ros::ServiceServer service = n.advertiseService("/ball_chaser/command_robot", handle_drive_request);
// TODO: Delete the loop, move the code to the inside of the callback function and make the necessary changes to publish the requested velocities instead of constant values
/*while (ros::ok()) {
// Create a motor_command object of type geometry_msgs::Twist
geometry_msgs::Twist motor_command;
// Set wheel velocities, forward [0.5, 0.0]
motor_command.linear.x = 0.5;
motor_command.angular.z = 0.0;
// Publish angles to drive the robot
motor_command_publisher.publish(motor_command);
}*/
// TODO: Handle ROS communication events
ros::spin();
return0;
}
Edit CMakeLists.txt
After writing a server node in c++, the following dependencies must be added:
Add add_compile_options for c++11 dependencies, this step is optional, depends on your code
Add add_service_files dependency which defines DriveToTarget.srv file
Add generate_messages dependency
Add include_directories dependency
Add add_executable, target_link_libraries and add_dependencies dependencies for drive_bot.cppscript
build pack
Now that you have included specific instructions for the drive_bot.cpp code in the CMakeLists.txt file, compile it with the following command:
$ cd /home/workspace/catkin_ws/
$ catkin_make
test-drive_bot.cpp
To test that the written service is working, first start the bot. Then call the /ball_chaser/command_robot service to drive the robot forward, left, then right.
1) Start the robot
$ cd /home/workspace/catkin_ws/
$ source devel/setup.bash
$ roslaunch my_robot world.launch
2) Run the drive_bot node
$ cd /home/workspace/catkin_ws/
$ source devel/setup.bash
$ rosrun ball_chaser drive_bot
3) Request ball_chaser/command_robot service
Test the service by requesting different speed sets from the terminal. Open a new terminal with all nodes running and type:
$ cd /home/workspace/catkin_ws/
$ source devel/setup.bash
$ rosservice call /ball_chaser/command_robot "linear_x: 0.5
angular_z: 0.0"# This request should drive your robot forward
$ rosservice call /ball_chaser/command_robot "linear_x: 0.0
angular_z: 0.5"# This request should drive your robot left
$ rosservice call /ball_chaser/command_robot "linear_x: 0.0
angular_z: -0.5"# This request should drive your robot right
$ rosservice call /ball_chaser/command_robot "linear_x: 0.0
angular_z: 0.0"# This request should bring your robot to a complete stop
startup file
Add the drive_bot node to a startup file. Create a ball_chaser.launch in the Launch directory of your ball_chaser package, and copy the following code into it:
<launch>
<!-- The drive_bot node -->
<node name="drive_bot" type="drive_bot" pkg="ball_chaser" output="screen">
</node>
</launch>
This code will start the drive_bot node, which is included in the ball_chaser package. The server node outputs all logs to the terminal window.
Follow the steps below to create a drive_bot node:
![](https://img-blog.csdnimg.cn/img_convert/d5d9c20694b4a7d1a9bcbdb1bfcb4b63.png)