5.编写ROS程序

1. 发布者Publisher的编程实现

1.1. 创建功能包
catkin_create_pkg learning_topic roscpp rospy std_msgs geometry_msgs turtlesim

1.2. 创建发布者代码(C++)
#include <ros/ros.h>
#include <geometry_msgs/Twist.h>

int main(int argc,char **argv)
{
    //节点初始化
    ros::init(argc,argv,"velocity_publisher");

    //创建节点句柄
    ros::NodeHandle n;

    //创建一个Publisher,发布名为/turtle1/cmd_vel的topic,消息类型为geometry_msgs::Twist,队列长度10
    ros::Publisher turtle_vel_pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel",10);

    // 设置循环的频率
    ros::Rate loop_rate(10);

    int count = 0;
    while (ros::ok())
    {
        // 初始化geometry_msgs::Twist类型的消息
        geometry_msgs::Twist vel_msg;
        vel_msg.linear.x = 0.5;
        vel_msg.angular.z = 0.2;

        // 发布消息
        turtle_vel_pub.publish(vel_msg);
        ROS_INFO("Publish turtle velocity command[%0.2f m/s,%0.2f rad/s]",vel_msg.linear.x,vel_msg.angular.z);

        // 按照循环频率延时
        loop_rate.sleep();
    }

    return 0;
    
}
1.3. 配置发布者代码编译规则
add_executable(velocity_publisher src/velocity_publisher.cpp)
target_link_libraries(velocity_publisher ${catkin_LIBRARIES})
1.4. 编译并运行发布者
catkin_make

  1. 运行roscore
roscore
  1. 运行海龟仿真器
rosrun turtlesim turtlesim_node
  1. 设置环境变量
source devel/setup.bash
  1. 运行自己功能包定义
rosrun learning_topic velocity_publisher

2. 订阅者Subscriber的编程实现

2.1. 订阅代码
#include <ros/ros.h>
#include "turtlesim/Pose.h"

void poseCallback(const turtlesim::Pose::ConstPtr& msg)
{
    // 将接受到的消息打印出来
    ROS_INFO("Turtle pose: x:%0.6f,y:%0.6f",msg->x,msg->y);
}

int main(int argc, char **argv)
{
    // 初始化ROS节点
    ros::init(argc,argv,"pose_subscriber");

    // 创建节点句柄
    ros::NodeHandle n;

    // 创建一个Subsciber,订阅名为/turtle1/pose的topic,注册回调函数poseCallback
    ros::Subscriber pose_sub = n.subscribe("/turtle1/pose",10,poseCallback);

    // 循环等待回调函数
    ros::spin();

    return 0;
}
2.2. 配置订阅代码编译规则
add_executable(pose_subscriber src/pose_subscriber.cpp)
target_link_libraries(pose_subscriber ${catkin_LIBRARIES})
2.3. 编译代码
catkin_make

2.4. 运行代码
roscore
rosrun turtlesim turtlesim_node
source devel/setup.bash
rosrun pose_subscriber pose_subscriber
rosrun turtlesim turtle_teleop_key

3. 话题消息的定义与使用

3.1. 创建msg文件夹

3.2. 数据接口定义

创建Person.msg文件并写入内容

注意这里只能一个空格

string name
uint8 sex
uint8 age

uint8 unkown = 0
uint8 male   = 1
uint8 female = 2

3.3. 在package.xml中添加功能包依赖
  <build_export_depend>message_generation</build_export_depend>
  <exec_depend>message_runtime</exec_depend>

3.4. 在CMakeList.txt添加编译选项
  1. 添加依赖包

  1. 添加消息定义
add_message_file(FILES Person.msg)
generate_messages(DEPENDENCIES std_msgs)

  1. 添加运行依赖
CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs turtlesim message_runtime

  1. 完成编译

3.5. 创建发布者代码
#include <ros/ros.h>
#include "learning_topic/Person.h"

int main(int argc, char **argv)
{
    // ros节点初始化
    ros::init(argc,argv,"person_publisher");

    // 创建节点句柄
    ros::NodeHandle n;

    // 创建一个Publisher,发布名为/person_info的topic,消息类型为learning_topic::Person,队列长度为10
    ros::Publisher  person_info_pub = n.advertise<learning_topic::Person>("/person_info",10);

    // 设置循环频率
    ros::Rate loop_rate(1);

    int count = 0;

    while (ros::ok())
    {
        // 初始化learning_topic::Person类型的消息
    	learning_topic::Person person_msg;
		person_msg.name = "Tom";
		person_msg.age  = 18;
		person_msg.sex  = learning_topic::Person::male;

        // 发布消息
		person_info_pub.publish(person_msg);

       	ROS_INFO("Publish Person Info: name:%s  age:%d  sex:%d", 
				  person_msg.name.c_str(), person_msg.age, person_msg.sex);

        // 按照循环频率延时
        loop_rate.sleep();
    }

    return 0;

}
3.6. 订阅者代码
#include <ros/ros.h>
#include "learning_topic/Person.h"

// 接受订阅的消息后,会进入消息回调函数
void personInfoCallback(const learning_topic::Person::ConstPtr& msg)
{
    // 将接受到的消息打印出来
    ROS_INFO("Subcribe Person Info: name:%s age:%d sex:%d", msg->name.c_str(), msg->age, msg->sex);
}

int main(int argc, char **argv)
{
     // 初始化ROS节点
    ros::init(argc, argv, "person_subscriber");

    // 创建节点句柄
    ros::NodeHandle n;

     // 创建一个Subscriber,订阅名为/person_info的topic,注册回调函数personInfoCallback
    ros::Subscriber person_info_sub = n.subscribe("/person_info", 10, personInfoCallback);

    // 循环等待回调函数
    ros::spin();

    return 0;
}
3.7. 添加编译规则
add_executable(person_publisher src/person_publisher.cpp)
target_link_libraries(person_publisher ${catkin_LIBRARIES})
add_dependencies(person_publisher ${PROJECT_NAME}_generate_messages_cpp)

add_executable(person_subscriber src/person_subscriber.cpp)
target_link_libraries(person_subscriber ${catkin_LIBRARIES})
add_dependencies(person_subscriber ${PROJECT_NAME}_generate_messages_cpp)

3.8. 运行代码
rosrun learning_topic person_subscriber
rosrun learning_topic person_publisher

4. 客户端Client的编程实现

实现客户端的流程:

  1. 初始化ROS节点;
  2. 创建一个Client实例
  3. 发布服务请求数据;
  4. 等待Server处理之后的应答结果;
4.1. 创建功能包
catkin_create_pkg learning_service roscpp rospy std_msgs geometry_msgs turtlesim

4.2. 编写代码
#include <ros/ros.h>
#include <turtlesim/Spawn.h>

int main(int argc, char** argv)
{
    // 初始化ROS节点
    ros::init(argc,argv,"turtle_spawn");

    // 创建节点句柄
    ros::NodeHandle node;

    // 发现/spawn服务后,创建一个服务客户端,连接名为/spawn的service
    ros::service::waitForService("/spawn");
    ros::ServiceClient add_turtle = node.serviceClient<turtlesim::Spawn>("/spawn");

    // 初始化turtlesim::Spawn的请求数据
    turtlesim::Spawn srv;
    srv.request.x = 2.0;
    srv.request.y = 2.0;
    srv.request.name = "turtle2";

    // 请求服务调用
    ROS_INFO("Call service to spwan turtle[x:%0.6f,y:%0.6f,name:%s]",
            srv.request.x, srv.request.y, srv.request.name.c_str());

    add_turtle.call(srv);

    // 显示服务调用结果
    ROS_INFO("Spwan turtle successfully [name:%s]", srv.response.name.c_str());

    return 0;
}
4.3. 配置编译规则
add_executable(turtle_spawn src/turtle_spawn.cpp)
target_link_libraries(turtle_spawn ${catkin_LIBRARIES})

4.4. 编译代码

4.5. 程序运行
roscore
rosrun turtlesim turtlesim_node
rosrun learning_service turtle_spawn 

5. 服务端Service编程实现

5.1. 编写代码
#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <std_srvs/Trigger.h>

ros::Publisher  turtle_vel_pub;
bool pubCommand = false;

// service回调函数,输入参数req,输出参数res
bool commandCallback(std_srvs::Trigger::Request &req,
                     std_srvs::Trigger::Response &res)
{
    pubCommand = !pubCommand;

    // 显示请求数据
    ROS_INFO("Publish turtle velocity commadn [%s]", pubCommand==true?"Yes":"No");

    // 设置反馈数据
    res.success = true;
    res.message = "Change turtle command state!";

    return true;
}

int main(int argc, char** argv)
{
    // ROS节点初始化
    ros::init(argc,argv,"turtle_command_server");

    // 创建节点句柄
    ros::NodeHandle node;

    // 创建一个名为/turtle_command的server,注册回调函数commandCallback
    ros::ServiceServer command_service = node.advertiseService("/turtle_command",commandCallback);

    // 创建一个Publisher,发布名为/turtle1/cmd_vel的topic,消息类型为geometry_msgs::Twist,队列长度为10
    turtle_vel_pub = node.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel",10);

    // 循环等待回调函数
    ROS_INFO("Ready to receive turtle command.");

    // 设置循环的频率
    ros::Rate loop_rate(10);

    while (ros::ok())
    {
        // 查看一次回调函数队列
        ros::spinOnce();

        // 如果标志为true,则发布速度指令
        if (pubCommand)
        {
            geometry_msgs::Twist vel_msg;
            vel_msg.linear.x = 0.5;
            vel_msg.angular.z = 0.2;
            turtle_vel_pub.publish(vel_msg);
        }

        // 按照循环频率延时
        loop_rate.sleep();
    }
    
    return 0;

}
5.2. 配置编译规则
add_executable(turtle_command_server src/turtle_command_server.cpp)
target_link_libraries(turtle_command_server ${catkin_LIBRARIES})
5.3. 编译代码

5.4. 程序运行
roscore
rosrun turtlesim turtlesim_node
rosrun learning_service turtle_command_server
rosservice call /turle_command "{}"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值