安置机器人
到目前为止,从头创建了一个机器人模型,向其添加传感器以可视化其周围环境,并开发了一个包来在模拟环境中启动机器人。这是一个真正的成就!
但是还没有把机器人放在一个特定的环境中,让我们把它安置在一个建造的世界中。
添加World文件
把myworld. world(https://github.com/jeffnd/Robotics-Software-Engineer/blob/master/Project1-BuildMyWorld/world/World4)粘贴到my_robot的world目录中。在worlds目录中,现在有两个文件-empty. world和myworld. world,可随时删除empty. world文件,我们不再需要它了。
启动the World
编辑world.launch文件,添加对myworld. world的引用。打开world. launch文件并编辑这一行:
<arg name="world_file"default="$(findmy_robot)/worlds/empty.world"/>
把它替换成:
<arg name="world_file"default="$(findmy_robot)/worlds/myworld.world"/>
启动!
现在,已经将world文件添加到my_robot包中,启动并可视化机器人:
$ cd /home/workspace/catkin_ws/
$ source devel/setup.bash
$ roslaunch my_robot world.launch
初始化机器人的位置和方向
机器人的初始位置,可以通过编辑world. launch文件来实现:
<!-- 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"/>
找出这些数字的最好方法是改变机器人在Gazebo中的位置和方向,记录它的姿势,然后更新launch文件。
总结:按照以下步骤,安置机器人在某个环境中:
11.设置ball_chaser
这个项目中的第二个主要任务是创建ball_chaser ROS包。在这个包中,分析相机捕获的图像,以确定白球的位置,然后驱动机器人开向球的方向。ball_chaser中的节点与my_robot包建立通信,通过订阅机器人相机传感器的数据并发布到机器人的车轮关节来实现。
包节点
ball_chaser包有两个c++节点:drive_bot和process_image
drive_bot: 这个服务器节点将提供一个ball_chaser/command_robot服务,通过控制机器人的线性x和角z速度来驱动机器人。该服务将向车轮关节发布一条包含速度的消息。
process_image: 这个客户端节点将订阅机器人的摄像头图像,并分析每张图像以确定白球的位置。一旦确定了球的位置,客户端节点将请求一个服务来驱动机器人向左、向右或向前。
现在,按照步骤设置ball_chaser。
创建ball_chaser包
1)导航到catkin_ws的src目录,创建ball_chaser包:
用c++编写节点,因为我们已经知道这个包将包含c++源代码和消息,让我们创建带有这些依赖项的包:
$ cd /home/workspace/catkin_ws/src/
$ catkin_create_pkg ball_chaser roscpp std_msgs message_generation
2)接下来,创建一个srv和一个launch文件夹,这将进一步定义包的结构:
$ cd /home/workspace/catkin_ws/src/ball_chaser/
$ mkdir srv
$ mkdir launch
记住,srv是存储服务文件的目录,而launch是存储启动文件的目录。存储c++程序的src目录是默认创建的。
构建包
$ cd /home/workspace/catkin_ws/
$ catkin_make
总结:按照以下步骤设置ball_chaser包:
12.ROS节点:drive_bot
这个服务器节点提供了一个ball_chaser/command_robot服务,通过设置机器人的线性x和角z速度来驱动机器人。service服务器发布包含车轮关节速度的消息。
写完这个节点后,将能够从终端或客户端节点请求ball_chaser/command_robot服务,通过控制机器人的线性x和角z速度来驱动机器人。
ROS服务文件
1)写入DriveToTarget. srv文件
在ball_chaser的srv目录下,创建一个DriveToTarget. srv文件。然后,定义DriveToTarget. srv文件如下:
要求:
linear_x type float64
angular_z type float64
响应:
msg_feedback type string
2)测试DriveToTarget.srv
在编写服务文件之后,使用ROS对其进行测试。打开一个新终端,执行以下命令:
$ cd /home/workspace/catkin_ws/
$ source devel/setup.bash
$ rossrv show DriveToTarget
收到以下回复:
[ball_chaser/DriveToTarget]:
float64 linear_x
float64 angular_z
---
string msg_feedback
drive_bot.cpp节点
在ball_chaser包的src目录下创建脚本。下面附上的是一个程序,它将不断地发布到robot /cmd_vel主题,这段代码将驱动机器人前行:
#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;
}
看一看这个程序,试着理解发生了什么。然后,将其复制到drive_bot.cpp,并进行必要的更改以定义一个ball_chaser/command_robot服务。
参考代码如下---
#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;
}
编辑CMakeLists.txt
c++编写服务器节点之后,必须添加以下依赖项:
为c++ 11依赖项添加add_compile_options,这一步是可选的,取决于你的代码
添加add_service_files依赖项,它定义了DriveToTarget. srv 文件
添加generate_messages依赖项
添加include_directories依赖项
为drive_bot.cppscript添加add_executable、target_link_libraries和add_dependencies依赖项
构建包
现在已经在CMakeLists.txt文件中包含了drive_bot.cpp代码的特定指令,使用以下命令编译它:
$ cd /home/workspace/catkin_ws/
$ catkin_make
测试drive_bot.cpp
要测试编写的服务是否正在工作,首先启动机器人。然后调用/ball_chaser/command_robot服务来驱动机器人前进,向左,然后向右。
1)启动机器人
$ cd /home/workspace/catkin_ws/
$ source devel/setup.bash
$ roslaunch my_robot world.launch
2)运行drive_bot节点
$ cd /home/workspace/catkin_ws/
$ source devel/setup.bash
$ rosrun ball_chaser drive_bot
3)请求ball_chaser/command_robot服务
通过从终端请求不同的速度集来测试服务。在所有节点运行时打开一个新终端,输入:
$ 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
启动文件
将drive_bot节点添加到一个启动文件中。创建一个ball_chaser. launch在你的ball_chaser包的Launch目录下,然后复制以下代码到其中:
<launch>
<!-- The drive_bot node -->
<node name="drive_bot" type="drive_bot" pkg="ball_chaser" output="screen">
</node>
</launch>
这段代码将启动drive_bot节点,该节点包含在ball_chaser包中。服务器节点将所有日志输出到终端窗口。
按照以下步骤创建drive_bot节点: