码丁实验室,一站式儿童编程学习产品,寻地方代理合作共赢,微信联系:leon121393608。
1.8.1 ROS actions
尽管服务(service)对于简单的获取/设置交互(例如查询状态和管理配置)非常方便,但它们不适用于长时间运行的任务。例如,将机器人移动到较远的位置。ROS actions是实现长时间间隔、目标导向行为接口的最佳方法。类似于服务的请求和响应模式,actions使用目标来发起行为,并在行为完成后发送结果。该操作还可以使用反馈来提供有关行为向目标进展的最新信息,还可以取消目标。此外,actions是异步的(与服务相反)。
官方链接:http://wiki.ros.org/actionlib
(1)actions客户端-服务器交互

图1 Action Client-Server Interaction
(2)actions服务器状态转换

图2 Action Server State Transitions(1)

图2 Action Server State Transitions(2)
(3).action文件
action规范在.action文件中定义,这些文件位于软件包的”./action目录中,例如:

action文件中生成以下消息类型:
DoDishesAction.msg
DoDishesActiongoal.msg
DoDishesActionResult.msg
DoDishesActionFeedback.msg
DoDishesgoal.msg
DoDishesResult.msg
DoDishesFeedback.msg
然后,这些消息将由actionlib在内部使用,用于ActionClient和ActionServer之间的通信。
(4)简单的actions客户端
实现一个简单的客户端,仅支持一个目标。action客户端以action定义为模板,指定要与action服务器通信的消息类型。action客户端接受两个参数:要连接的服务器名称、自动旋转线程的布尔选项(如果您不想使用线程(并且希望actionlib在幕后进行”线程魔术”),那么这对您来说是一个不错的选择。代码如下所示:

1.8.2 由代码发送目标命令
(1)send_goals
接下来的C++代码是一个简单的示例,发送目标给移动机器人。此时,目标将是”PoseStamped”类型的消息,包含有关机器人应移动到世界的位置信息。
参考链接:http://wiki.ros.org/navigation/Tutorials/SendingSimpleGoals
首先创建一个名为send_goals的新包,此程序包依赖于于以下程序包:actionlibgeometry_msgsmove_base_msgs
命令如下:
cd ~/catkin_ws/srccatkin_create_pkg send_goals std_msgs rospy roscpp actionlib tf geometry_msgs move_base_msgs
在/send_goals/src子目录下,创建一个名为send_goals.cpp的新文件。
typedef actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> MoveBaseClient;int main(int argc, char** argv) {ros::init(argc, argv, "send_goals_node");// Get the goal's x, y and angle from the launch filedouble x, y, theta;ros::NodeHandle nh;nh.getParam("goal_x", x);nh.getParam("goal_y", y);nh.getParam("goal_theta", theta);// create the action clientMoveBaseClient ac("move_base", true);// Wait 60 seconds for the action server to become availableROS_INFO("Waiting for the move_base action server");ac.waitForServer(ros::Duration(60));ROS_INFO("Connected to move base server");// Send a goal to move_basemove_base_msgs::MoveBaseGoal goal;goal.target_pose.header.frame_id = "map";goal.target_pose.header.stamp = ros::Time::now();goal.target_pose.pose.position.x = x;goal.target_pose.pose.position.y = y;// Convert the Euler angle to quaterniondouble radians = theta * (M_PI/180);tf::Quaternion quaternion;quaternion = tf::createQuaternionFromYaw(radians);geometry_msgs::Quaternion qMsg;tf::quaternionTFToMsg(quaternion, qMsg);goal.target_pose.pose.orientation = qMsg;// Send the goal commandROS_INFO("Sending robot to: x = %f, y = %f, theta = %f", x, y, theta);ac.sendGoal(goal);// Wait for the action to returnac.waitForResult();if (ac.getState() == actionlib::SimpleClientGoalState::SUCCEEDED)ROS_INFO("You have reached the goal!");elseROS_INFO("The base failed for some reason");return 0;}
(2)将欧拉角转换为四元数
使用欧拉角而不是使用四元数来定义目标姿势更容易,以下代码将角度从弧度转换为四元数表示:
double theta = 90.0;double radians = theta * (M_PI/180);tf::Quaternion quaternion;quaternion = tf::createQuaternionFromYaw(radians);geometry_msgs::Quaternion qMsg;tf::quaternionTFToMsg(quaternion, qMsg);= qMsg;
(3)send_goals.launch文件
<launch><param name="goal_x" value="2" /><param name="goal_y" value="-2" /><param name="goal_theta" value="180" /><param name="/use_sim_time" value="true"/><!-- Launch turtle bot world --><include file="$(find turtlebot_gazebo)/launch/turtlebot_world.launch"/><!-- Launch navigation stack with amcl --><include file="$(find turtlebot_gazebo)/launch/amcl_demo.launch"/><!-- Launch rviz --><include file="$(find turtlebot_rviz_launchers)/launch/view_navigation.launch"/><!-- Launch send goals node --><node name="send_goals_node" pkg="send_goals" type="send_goals_node" output="screen"/></launch>
(4)send_goals Demo
启动send_goals.launch:
 roslaunch send_goals send_goals.launch
现在,您应该看到rviz打开,并且机器人从其初始位姿,移动到启动文件中定义的目标位姿。

图3 send_goals Demo(1)

图3 send_goals Demo(2)
(5)Nodes Graph

图4 Nodes Graph
1.8.3 导航规划
(1)make_plan service
允许外部用户从move_base询问到给定目标位姿的路线,无需实际移动机器人。参数:
起始位姿;
目标位姿;
目标容忍度;
返回类型为”nav_msgs / GetPlan”的消息。
定位是估计机器人相对于地图的位姿的问题。定位问题对物体的确切位置不是非常敏感,因此它可以处理物体位置的小变化。ROS使用”AMCL包”实现定位。
(2)make_plan节点
现在,在我们的send_goal包中,我们将创建一个make_plan,它将调用make_plan服务并打印计划的输出路径。添加一个名为make_plan.cpp的新C ++文件:
using std::string;double goalTolerance = 0.5;void fillPathRequest(nav_msgs::GetPlan::Request &req);void callPlanningService(ros::ServiceClient &serviceClient, nav_msgs::GetPlan &srv);int main(int argc, char** argv){ros::init(argc, argv, "make_plan_node");ros::NodeHandle nh;// Init service query for make planstring service_name = "move_base/make_plan";while (!ros::service::waitForService(service_name, ros::Duration(3.0))) {ROS_INFO("Waiting for service move_base/make_plan to become available");}ros::ServiceClient serviceClient = nh.serviceClient<nav_msgs::GetPlan>(service_name, true);if (!serviceClient) {ROS_FATAL("Could not initialize get plan service from %s", serviceClient.getService().c_str());return -1;}nav_msgs::GetPlan srv;fillPathRequest(srv.request);if (!serviceClient) {ROS_FATAL("Persistent service connection to %s failed", serviceClient.getService().c_str());return -1;}callPlanningService(serviceClient, srv);}void fillPathRequest(nav_msgs::GetPlan::Request &request){request.start.header.frame_id = "map";request.start.pose.position.x = 0;request.start.pose.position.y = 0;request.start.pose.orientation.w = 1.0;request.goal.header.frame_id = "map";request.goal.pose.position.x = 2.0;request.goal.pose.position.y = -2.0;request.goal.pose.orientation.w = 1.0;request.tolerance = goalTolerance;}void callPlanningService(ros::ServiceClient &serviceClient, nav_msgs::GetPlan &srv){// Perform the actual path planner callif (serviceClient.call(srv)) {if (!srv.response.plan.poses.empty()) {forEach(const geometry_msgs::PoseStamped &p, srv.response.plan.poses) {ROS_INFO("x = %f, y = %f", p.pose.position.x, p.pose.position.y);}}else {ROS_WARN("Got empty plan");}}else {ROS_ERROR("Failed to call service %s - is the robot moving?", serviceClient.getService().c_str());}}
(3)make_plan.launch
<launch><param name="goal_x" value="2" /><param name="goal_y" value="-2" /><param name="goal_theta" value="180" /><param name="/use_sim_time" value="true"/><!-- Launch turtle bot world --><include file="$(find turtlebot_gazebo)/launch/turtlebot_world.launch"/><!-- Launch navigation stack with amcl --><include file="$(find turtlebot_gazebo)/launch/amcl_demo.launch"/><!-- Launch send goals node --><node name="make_plan" pkg="send_goals" type="make_plan" output="screen"/></launch>
(4)运行make_plan节点
命令如下:
 roslaunch send_goals make_plan.launch

图5 运行make_plan节点
转自公众号:
Robot404

