第三章 ROS通信编程 课后作业

代码包

所有代码已上传至github网站:
github链接: https://github.com/YuemingBi/ros_practice/tree/master

课后作业

在这里插入图片描述

第一题

(1)vel_pose.cpp

#include "ros/ros.h"
#include "turtlesim/Pose.h"
#include "geometry_msgs/Twist.h"

void callback(const turtlesim::Pose::ConstPtr& pose){
    ROS_INFO("x: %f", pose->x);
    ROS_INFO("y: %f", pose->y);
    ROS_INFO("theta: %f", pose->theta);
    ROS_INFO("linear_velocity: %f", pose->linear_velocity);
    ROS_INFO("angular_velocity: %f", pose->angular_velocity);
    ROS_INFO("---");
}

int main(int argc, char ** argv){
    ros::init(argc, argv, "pose_subscriber");
    ros::NodeHandle n;
    ros::Publisher pub = n.advertise<geometry_msgs::Twist>("turtle1/cmd_vel", 1000);
    ros::Subscriber sub = n.subscribe("turtle1/pose", 1000, callback);
    ros::Rate loop_rate(10);

    while(ros::ok()){
        geometry_msgs::Twist msg;
        msg.linear.x = 0.5;
        msg.angular.z = 0.5;
        //ROS_INFO("vel_publish: linear.x=%.1f angular.z=%.1f", msg.linear.x, msg.angular.z);
        pub.publish(msg);
        loop_rate.sleep();
        ros::spinOnce();
    }

    return 0;
}

主要编程思想:将发布消息的函数pub.publish()和ros::spinOnce()都放在while循环里,这样就可保证发布一次消息后订阅一次消息进入回调函数,显示pose信息。

(2)运行结果

$ roscore
$ rosrun turtlesim turtlesim_node
$ rosrun test1 vel_pose

在这里插入图片描述

第二题

(1)spawn_client.cpp

#include "ros/ros.h"
#include "turtlesim/Spawn.h"
#include "ctime"
#include "sstream"

int main(int argc, char **argv){
    ros::init(argc, argv, "spawn_client");
    ros::NodeHandle n;
    ros::ServiceClient client = n.serviceClient<turtlesim::Spawn>("spawn");
    turtlesim::Spawn srv;

    int number[2];
    int count = 0;
    int input1 = 12;
    int input2 = 999999999;
    srand(time(0));
    number[0] = rand()%input1;
    number[1] = rand()%input1;
    number[2] = rand()%input1;
    count = rand()%input2;

    std::stringstream ss;
    ss << "turtle"<< count;

    srv.request.x = number[0];
    srv.request.y = number[1];
    srv.request.theta = number[2];
    srv.request.name = ss.str();
    client.call(srv);
    ROS_INFO("show result: %s", srv.response.name.c_str());

    return 0;
}

程序里面用到了随机数,随机位置、随机角度(这里对应了第三题的位置不重叠)。

(2)运行结果

$ roscore
$ rosrun turtlesim turtlesim_node
$ rosrun test2 spawn_client
...

在这里插入图片描述

第三题

第一问

(1)turtle_spawn.cpp
#include "ros/ros.h"
#include "turtlesim/Spawn.h"
#include "ctime"

int main(int argc, char** argv){
    ros::init(argc, argv, "turtle_spawn");
    ros::NodeHandle n;
    ros::ServiceClient client = n.serviceClient<turtlesim::Spawn>("spawn");
    turtlesim::Spawn srv;

    int input1 = 10;
    int number[2];
    srand(time(0));
    number[0] = rand()%input1;
    number[1] = rand()%input1;
    number[2] = rand()%input1;

    srv.request.x = number[0];
    srv.request.y = number[1];
    srv.request.theta = number[2];
    srv.request.name = argv[1];
    client.call(srv);
    ROS_INFO("show result: %s", srv.response.name.c_str());

    return 0;
}

注意:程序中的argv[1]代表命令行中输入的海龟的名字。

(2)运行结果
$ roscore
$ rosrun turtlesim turtlesim_node
$ rosrun test3 turtle_spawn turtle2
$ rosrun test3 turtle_spawn turtle3
$ rosrun test3 turtle_spawn turtle4
$ rosrun test3 turtle_spawn turtle5
$ rosrun test3 turtle_spawn turtle6
$ rosrun test3 turtle_spawn turtle7

在这里插入图片描述

第二问

第二问可以利用多个节点来完成此功能,利用circular_motion节点来接收命令行中的信息,包括海龟名字、运动还是停止、运动的速度,然后将判断结果传入motion_control服务当中,进行海龟的控制。这样就大大简化了问题。

(1)circular_motion.cpp
#include "ros/ros.h"
#include "test3/turtlesrv.h"
#include "sstream"

int main(int argc, char **argv){
    ros::init(argc, argv, "circular_motion");
    ros::NodeHandle n;
    std::stringstream ss;
    ss << argv[1] << "/cmd_vel";
    ros::ServiceClient client = n.serviceClient<test3::turtlesrv>("motion_control");
    test3::turtlesrv srv;
    srv.request.turtlename = ss.str();
    srv.request.x = atof(argv[3]);
    srv.request.z = atof(argv[4]);
    std::string name = argv[2];

    if(name=="begin"){
        srv.request.data = true;
        ROS_INFO("Start moving");
    }
    else if(name=="stop"){
        srv.request.data = false;
        ROS_INFO("Stop moving");
    }

    if(client.call(srv)){
        ROS_INFO("Start moving");
    }
    else{
        ROS_INFO("Stop moving");
    }

    return 0;
}

argv[1]为海龟名字,argv[2]为运动状态(begin或stop),argv[3]为线速度,argv[4]为角速度。

(2)motion_server.cpp
#include "ros/ros.h"
#include "test3/turtlesrv.h"
#include "geometry_msgs/Twist.h"

bool control(test3::turtlesrv::Request &req, test3::turtlesrv::Response &res){
    if(req.data){
        ros::NodeHandle n;
        ros::Publisher pub = n.advertise<geometry_msgs::Twist>(req.turtlename, 1000);
        ros::Rate loop_rate(10);
        while(ros::ok()){
            geometry_msgs::Twist msg;
            msg.linear.x = req.x;
            msg.angular.z = req.z;
            ROS_INFO("vel_publish: linear.x=%.1f angular.z=%.1f", msg.linear.x, msg.angular.z);
            pub.publish(msg);
            loop_rate.sleep();
            ros::spinOnce();
        }

        return true;
    }
    else{
        ros::NodeHandle n;
        ros::Publisher pub = n.advertise<geometry_msgs::Twist>(req.turtlename, 1000);
        ros::Rate loop_rate(10);
        while(ros::ok()){
            geometry_msgs::Twist msg;
            msg.linear.x = 0;
            msg.angular.z = 0;
            ROS_INFO("vel_publish: linear.x=%.1f angular.z=%.1f", msg.linear.x, msg.angular.z);
            pub.publish(msg);
            loop_rate.sleep();
            ros::spinOnce();
        }
    }

      return false;
}

int main(int argc, char **argv){
    ros::init(argc, argv, "motion_server");
    ros::NodeHandle n;
    ros::ServiceServer service = n.advertiseService("motion_control", control);
    ros::spin();

    return 0;
}

从程序当中可以看出,如果motion_server接收的消息为True(即circular_motion接收到命令行的消息为begin),则会发布运动指令。同理如果motion_server接收的消息为False(即circular_motion接收到命令行的消息为stop),则会发布停止指令。其中的turtlesrv.h如下。

bool data
string turtlename
float64 x
float64 z
---
bool success
(3)运行结果

指定运动海龟为turtle5,begin(开始运动),线速度和角速度分别为0.5和0.5。

$ roscore
$ rosrun turtlesim turtlesim_node
$ rosrun test3 turtle_spawn turtle2
$ rosrun test3 turtle_spawn turtle3
$ rosrun test3 turtle_spawn turtle4
$ rosrun test3 turtle_spawn turtle5
$ rosrun test3 turtle_spawn turtle6
$ rosrun test3 turtle_spawn turtle7
$ rosrun test3 motion_server
$ rosrun test3 circular_motion turtle5 begin 0.5 0.5

在这里插入图片描述
stop(停止运动)

$ rosrun test3 circular_motion turtle5 stop 0 0

在这里插入图片描述

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
在Ubuntu 18.04上进行ROS通信编程,需要先安装ROS Melodic版本。安装完成后,可以使用ROS提供的通信机制,如话题(Topic)和服务(Service)等。 话题是一种发布/订阅(Publish/Subscribe)模式的通信机制,可以实现多个节点之间的异步通信。在ROS,话题的数据类型是消息(Message),可以自定义消息类型。节点可以发布消息到话题,也可以订阅话题接收消息。 服务是一种请求/响应(Request/Response)模式的通信机制,可以实现节点之间的同步通信。在ROS,服务的数据类型也是消息,但是服务消息包含请求消息和响应消息两部分。节点可以提供服务,也可以请求服务。 下面是一个简单的ROS话题通信示例: 1. 创建一个ROS工作空间 ``` mkdir -p ~/catkin_ws/src cd ~/catkin_ws/ catkin_make ``` 2. 创建一个ROS包 ``` cd ~/catkin_ws/src catkin_create_pkg my_package rospy ``` 3. 在my_package创建一个发布者节点 ``` cd ~/catkin_ws/src/my_package mkdir scripts cd scripts touch talker.py chmod +x talker.py ``` 将以下代码复制到talker.py文件: ```python #!/usr/bin/env python import rospy from std_msgs.msg import String def talker(): pub = rospy.Publisher('chatter', String, queue_size=10) rospy.init_node('talker', anonymous=True) rate = rospy.Rate(10) # 10hz while not rospy.is_shutdown(): hello_str = "hello world %s" % rospy.get_time() rospy.loginfo(hello_str) pub.publish(hello_str) rate.sleep() if __name__ == '__main__': try: talker() except rospy.ROSInterruptException: pass ``` 4. 在my_package创建一个订阅者节点 ``` cd ~/catkin_ws/src/my_package/scripts touch listener.py chmod +x listener.py ``` 将以下代码复制到listener.py文件: ```python #!/usr/bin/env python import rospy from std_msgs.msg import String def callback(data): rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data) def listener(): rospy.init_node('listener', anonymous=True) rospy.Subscriber('chatter', String, callback) rospy.spin() if __name__ == '__main__': listener() ``` 5. 编译ROS包 ``` cd ~/catkin_ws/ catkin_make ``` 6. 运行ROS节点 在一个终端运行发布者节点: ``` source ~/catkin_ws/devel/setup.bash rosrun my_package talker.py ``` 在另一个终端运行订阅者节点: ``` source ~/catkin_ws/devel/setup.bash rosrun my_package listener.py ``` 你可以看到,发布者节点会不断地发布消息到话题“chatter”,而订阅者节点会接收到这些消息并打印出来。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

*昨夜星辰*

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值