ROS基础——服务与应答(2)

上工了,上工了(
我们使用rosservice list命令来查看我们当前系统中的服务列表。列表里显示我们有好多服务。

(base) warmtree@warmtree-HP-Pavilion-Laptop-15-cc5xx:~/ros$ rosservice list
/move_left_arm/get_loggers
/move_left_arm/set_logger_level
/robot/get_loggers
/robot/set_logger_level
/robot_state_publisher/get_loggers
/robot_state_publisher/set_logger_level
/rosout/get_loggers
/rosout/set_logger_level
/rviz/get_loggers
/rviz/reload_shaders
/rviz/set_logger_level
/rviz_1588660343341296029/get_loggers
/rviz_1588660343341296029/reload_shaders
/rviz_1588660343341296029/set_logger_level
/tf_br/get_loggers
/tf_br/set_logger_level
/tracker/get_loggers
/tracker/set_logger_level

服务中的Server和Client

服务是节点之间同步通信的一种方式,允许客户端节点发布请求(request),由服务端节点处理后反馈应答。
我们在这里还是先从自定义服务数据类型说起。和我们之前了解到的话题消息用msg文件夹里.msg 文件定义一样,我们这里是在srv文件夹里面定义.srv 文件。

geometry_msgs/PointStamped goal
---
sensor_msgs/JointState[] solutions

srv文件的格式如上, — 是分割线,
上面相当于 客户端节点发布的请求’goal’,下面相当于 服务端节点反馈的应答’solution’。

如上例,“问”的部分为 左边机械臂的末端执行器的位置,“答”的部分为关节传感器检测到的有效结果。

服务节点的创建

创建服务端Server节点的代码实现是在right_arm_IK_service.cpp里面。

我们已经有一个right_arm_IK_service文件了,初次见面先来了解一下新同学。
这是一个计算机械臂IGM的服务,我们希望在得知右末端执行器到达的位置(这个位置是我们来通过tf监听器得到的目标点)后把机器人的各个关节状态得到。
我们消息的类型是自定义的消息类型DualArmIK在使用自定义消息类型的时候要加上相应的.h头文件,这个文件是我们在创建服务数据类型的描述文件时自动生成的。我们有一个回调函数right_arm_IK_service是布尔类型的。我们有请求和应答两个参数变量,输入为ik_request和输出为ik_response

bool right_arm_IK_service(
        dual_planar_arm_msgs::DualArmIK::Request &ik_request,
        dual_planar_arm_msgs::DualArmIK::Response &ik_response )

有关回调函数的具体功能实现可以简略浏览,但是这其实是我们我们服务端设计的重点。

我们开始到主函数里面看看服务端节点的实现过程。其中节点初始化和创建NodeHandle是常规操作。
重点是下面这句话。我们要创建一个名字是right_arm_IK的服务端,注册回调函数right_arm_IK_service

    // Declare you publishers and service servers
    ros::ServiceServer service = nh_glob.advertiseService("right_arm_IK", right_arm_IK_service);

通过注释提示,我们得知我们的服务没有发布,只有一个订阅消息。

客户的创建

现在一个问题出现了,我们的客户是谁?是谁在使用我们的服务端?我们最初假设tf_listener是我们的Client。啊啊啊啊, 但是实际上我们的文件里面已经有我们的Client文件初始版本了,名字叫做track_left_arm.cpp.所以我们才不用更正CMakeLists等文件,也不用自己去重新新建.cpp文件。
废弃代码完全缺少对知识点的认识(,那也舍不得扔掉,那就存储在公共网络资源里面吧。

//ROS
#include "ros/ros.h"
#include  /******************include the header.file***/
int main (int argc, char** argv)
{

	//ROS Initialization
    ros::init(argc, argv, "my_tf_listener");
	//we create a TransformListener object
    tf::TransformListener listener; 
	// Define your node handles: YOU NEED AT LEAST ONE !
    ros::NodeHandle nh_glo, nh_loc("~") ;
	//Check the existence of the service with “exists” method in the initialization part of the code.
	//Alternatively, using“waitForService” is possible.
    ros::service::waitForService("/right_arm_IK_service");
	if( ! ros::ServiceClient::exists( )){
		ROS_ERROR(“Call to service failed”);
	}else{
    // Do what you have to do...
		
	}
    

    ros::Rate rate(50);   // Or other rate.
    while (ros::ok()){
        ros::spinOnce();

        // Your code here.
		tf::StampedTransform transform;
		//The listener is typically used within a try...catch structure.
        try{
			listener.lookupTransform("/r_arm_base", "/goal",ros::Time(0), transform);
		}catch(tf::TransformException ex){
			ROS_ERROR("%s",ex.what());
		}
		
        rate.sleep();
    }
}

我们所有的代码都要添加在创建NodeHandle之后,否则会出现错误。
我们开始验证新一轮自己写的监听器二代有什么不对的地方。
ROS基础——服务与应答(2)_第1张图片我们出现了今天的第一个bug,真的刺激,那么我们要如何解决?
[ERROR] [1588665775.499889412]: “r_arm_base” passed to lookupTransform argument target_frame does not exist.
[ERROR] [1588665775.519896645]: Could not find a connection between ‘r_arm_base’ and ‘goal’ because they are not part of the same tree.Tf has two or more unconnected trees.

这里有一个更正说明,给系统一定时间反映反映,错误确实少了一个,但是 “right_arm_base” passed to lookupTransform argument source_frame does not exist. 错误依然存在。

首先,我们要创建一个Client,请求服务right_arm_IK。服务的消息类型是DualArmIK,使用时为dual_planar_arm_msgs::DualArmIK

ros::ServiceClient client = nh_glob.serviceClient<dual_planar_arm_msgs::DualArmIK>("right_arm_IK");

在这里隐隐感觉到那么一丝丝不对劲的地方。我们的请求参数呢?
不要慌张,在下面我们要创建一个dual_planar_arm_msgs::DualArmIK 类型的服务srv,在srv.request里面就是我们的请求了。

dual_planar_arm_msgs::DualArmIK srv;

现在,我们的关键问题是如何把tf监听器得到的结果写道请求里面。

left_arm.cpp:33:
/opt/ros/melodic/include/geometry_msgs/PointStamped.h:24:8: note: candidate: geometry_msgs::PointStamped_<std::allocator<void> >& geometry_msgs::PointStamped_<std::allocator<void> >::operator=(const geometry_msgs::PointStamped_<std::allocator<void> >&)
 struct PointStamped_
        ^~~~~~~~~~~~~
/opt/ros/melodic/include/geometry_msgs/PointStamped.h:24:8: note:   no known conversion for argument 1 from ‘tf::StampedTransform’ to ‘const geometry_msgs::PointStamped_<std::allocator<void> >&/opt/ros/melodic/include/geometry_msgs/PointStamped.h:24:8: note: candidate: geometry_msgs::PointStamped_<std::allocator<void> >& geometry_msgs::PointStamped_<std::allocator<void> >::operator=(geometry_msgs::PointStamped_<std::allocator<void> >&&)
/opt/ros/melodic/include/geometry_msgs/PointStamped.h:24:8: note:   no known conversion for argument 1 from ‘tf::StampedTransform’ to ‘geometry_msgs::PointStamped_<std::allocator<void> >&&’
make[2]: *** [CMakeFiles/track_left_arm.dir/src/track_left_arm.cpp.o] Error 1
make[1]: *** [CMakeFiles/track_left_arm.dir/all] Error 2

geometry_msgs::PointStamped相关的解释。当然,我们也要了解一下sensor_msgs/JointState[],这个是我们服务端最后给客户端的应答。

ROS基础——服务与应答(2)_第2张图片
今日背景音乐星辰变《随心》,啊啊啊啊啊啊啊,新的一季开始了。
不被期待的人也能成为英雄 )

微风拂面走走停停
这里是否有你想要的
想要的风景
跌跌撞撞会忘曾经
那是的你充满了
寻找一片天地
那里充满自由那里有你想要飞翔的憧憬
继续走吧 追寻
梦不会停息
我在天空里
被阳光包围的心情
很静

你可能感兴趣的:(ROS基础)