ROS 基础知识(一)

ROS基础目录

工作空间

src 代码空间

build 编译空间

devel 开发空间

install 安装控件

创建工作空间

创建工作空间是在src目录下进行catkin_init_workspace

mkdir -p ~/catkin_ws/src 	// 创建目录  -p 一次行创建多级目录
cd ~/catkin_ws/src			// 切换到 ~/catkin_ws/src	 目录下
catkin_init_workspace		// 初始化工作空间

编译工作空间

编译工作空间要在根目录下

cd ~/catkin_ws/				// 切换到工作空间根目录
catkin_make					// 编译

设置环境变量

仅在当前terminal中有效的设置方法

source devdl/setup.bash		// 这一步是在根目录下执行

确定当前环境变量是否设置成功

echo $ROS_PACKAGE_PATH

输出

/home/luo/ws/catkin_ws/src:/opt/ros/melodic/share

环境变量通过 : 进行分割 如果自己的目录在环境变量中,既是设置成功,可以发现后加入的环境变量在前面。

永久有效的方法

前面的方法在新开的terminal中,刚刚设置的环境变量还是不存在的。如果想在新打开的terminal中依然存在刚设置的环境变量,需要修改~目录下的.bashrc。方法如下

nano ~/.bashrc

在.bashrc 最后加入

source ~/ws/catkin_ws/devel/setup.bash
source ~/.bashrc				// 更新环境变量

验证 环境变量 是否成功设置,新开一个terminal,

echo $ROS_PACKAGE_PATH

查看输出的路径中是否有刚刚自己添加的路径。

在环境变量中 筛选有用信息

env |grep ROS_PACKAGE_PATH

查看环境变量中和ROS_PACKAGE_PATH相关的信息

创建功能包

创建功能包要在src下面

catkin_create_pkg learning_communication std_msgs rospy roscpp

其中catkin_create_pkg是指令

learning_communication功能包的名字

std_msgs rospy roscpp 是依赖环境 正常都要带上

编译功能包

返回到根目录

cd ..

编译

catkin_make

注意事项:同一个工作空间下,不可以存在相同的功能包

​ 不同的工作空间下,可以存在相同的功能包

查找功能包

rospack find roscpp_tutorials

返回的是功能包的路径

ROS通信机制

1、话题编程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RjiF89gD-1640778615234)(D:\笔记文件夹\ROS基础(2).assets\image-20211229105628607-16407466072741.png)]

  1. 创建发布者

  2. 创建订阅者

  3. 添加编译选项

  4. 运行可执行程序

创建发布者

/**
 * 该例程将发布chatter话题,消息类型String
 */
 
#include <sstream>
#include "ros/ros.h"
#include "std_msgs/String.h"

int main(int argc, char **argv)
{
  // ROS节点初始化
  ros::init(argc, argv, "talker");
  
  // 创建节点句柄
  ros::NodeHandle n;
  
  // 创建一个Publisher,发布名为chatter的topic,消息类型为std_msgs::String
  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

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

  int count = 0;
  while (ros::ok())
  {
	// 初始化std_msgs::String类型的消息
    std_msgs::String msg;
    std::stringstream ss;
    ss << "hello world " << count;
    msg.data = ss.str();

	// 发布消息
    ROS_INFO("%s", msg.data.c_str());
    chatter_pub.publish(msg);

	// 循环等待回调函数
    ros::spinOnce();
	
	// 按照循环频率延时
    loop_rate.sleep();
    ++count;
  }

  return 0;
}

CMakeLists.txt 中文件修改

生产可执行文件 talker 生成到 devel/lib/node名称下/talker,之后通过rosrun 对其进行执行

add_executable(talker src/talker.cpp)

如果cpp中用到第三方插件,需要在这里进行target_link 链接到第三方库文件,现在链接的库是catkin的基础库

 target_link_libraries(talker  ${catkin_LIBRARIES} )

创建接收者

自己写的程序

#include "ros/ros.h"
#include "std_msgs/String.h"


void  chatterCallback(const std_msgs::String::ConstPtr& msg)
{
    ROS_INFO("I heard : %s",msg->data.c_str());
}


int main(int argc, char **argv)
{
   ros::init(argc,argv,"lensener");
   ros::NodeHandle n;

   ros::Subscriber sub = n.subscribe("chatter1",1000,chatterCallback);

    ros::spin();


    return 0;
}

程序历程

/**
 * 该例程将订阅chatter话题,消息类型String
 */
 
#include "ros/ros.h"
#include "std_msgs/String.h"

// 接收到订阅的消息后,会进入消息回调函数
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  // 将接收到的消息打印出来
  ROS_INFO("I heard: [%s]", msg->data.c_str());
}

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

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

  // 创建一个Subscriber,订阅名为chatter的topic,注册回调函数chatterCallback
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

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

  return 0;
}

CMakeLists.txt 中文件修改

生产可执行文件 talker 生成到 devel/lib/node名称下/talker,之后通过rosrun 对其进行执行

add_executable(lensener src/lensener.cpp)

如果cpp中用到第三方插件,需要在这里进行target_link 链接到第三方库文件,现在链接的库是catkin的基础库

 target_link_libraries(lensener  ${catkin_LIBRARIES} )

此处出现的问题:

当先开启 subscribe,再启动Publisher 时, 发布的前两包信息会被丢弃 这个是什么原因?

  1. 定义msg文件
  2. 再package.xml中添加功能包依赖
  3. 再CMakeList.txt中添加编译

自定义消息结构

  1. 在功能包下新建 msg文件夹

    新建文件Person.msg

    string name
    uint8 sex
    uint8 age
    
    uint8 unknown = 0
    uint8 male =1
    uint8 female =2
    
  2. 在package.xml 中加入

      <build_depend> message_generation</build_depend>
      <exec_depend>message_runtime</exec_depend>
    
  3. CMakeList中加入

    1. find_package(catkin REQUIRED COMPONENTS
        roscpp
        rospy
        std_msgs
        message_generation
      )
      
    2. ## Generate messages in the 'msg' folder
      add_message_files(
        FILES
        Person.msg
        # Message2.msg
      )
      
    3. ## Generate added messages and services with any dependencies listed here
      generate_messages(
        DEPENDENCIES
        std_msgs
      )
      
    4. catkin_package(
      #  INCLUDE_DIRS include
      #  LIBRARIES learning_communication
       CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
      #  DEPENDS system_lib
      )
      

      在创建完成后,编译 可以通过

      rosmsg show Person 来验证创建的是否正确
      

2、服务编程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0t52qGJO-1640778615236)(D:\笔记文件夹\ROS基础 (2).assets\image-20211229153801254-16407634850601.png)]

  1. 创建服务器
  2. 创建客户端
  3. 添加编译选项
  4. 运行可执行程序

定义srv文件

  1. 定义srv文件

  2. 在package.xml中添加功能包依赖

      <build_depend> message_generation</build_depend>
      <exec_depend>message_runtime</exec_depend>
    
  3. 在CMakeList.txt中修改 和自定义添加编译依赖 1、2 相同 3 是特有的

  4. find_package(catkin REQUIRED COMPONENTS
      roscpp
      rospy
      std_msgs
      message_generation
    )
    
  5. catkin_package(
    #  INCLUDE_DIRS include
    #  LIBRARIES learning_communication
     CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
    #  DEPENDS system_lib
    )
    
  6. ## Generate services in the 'srv' folder
    add_service_files(
      FILES
      AddTwo.srv
      # Service2.srv
    )
    
  7. 生成可支持 文件

    add_executable(server src/server.cpp)
    
  8. 测试生成文件是否可用

    启动 roscore rosrun

注意

在vscode中编程为了在编程过程中能够讲新建的srv文件引入,需要在 src/.vscode/c_cpp_properties.json 文件下 includePath 下面加入

    "includePath": [
        "/opt/ros/melodic/include/**",
        "/home/luo/ws/catkin_ws/src/learning_communication/include/**",
        "/usr/include/**",
        "/home/luo/ws/catkin_ws/devel/include/learning_communication**"				// 这行是新加入的,包含的新生成的srv文件
      ],

创建一个服务器

  1. 初始化ROS节点
  2. 创建Server实例
  3. 循环等到服务请求,进入回调函数
  4. 在回调函数中完成服务功能的处理,并反馈应答数据
#include "ros/ros.h"
#include "learning_communication/AddTwo.h"

// service回调函数,输入参数req,输出参数res
bool add(learning_communication::AddTwo::Request  &req,
         learning_communication::AddTwo::Response &res)
{
  // 将输入参数中的请求数据相加,结果放到应答变量中
  res.sum = req.a + req.b;
  ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
  ROS_INFO("sending back response: [%ld]", (long int)res.sum);
  
  return true;
}

int main(int argc, char **argv)
{
  	// ROS节点初始化
    ros::init(argc,argv,"add_two_inis_server");
    
	// 创建节点句柄
    ros::NodeHandle n;
	
	// 创建一个名为add_two_ints的server,注册回调函数add()
    ros::ServiceServer service = n.advertiseService("add_two_inis",add);
	
	// 循环等待回调函数
    ROS_INFO("Ready to add two ints.");
    ros::spin();

    return 0;
}

客户端程序

#include "learning_communication/AddTwo.h"
#include "ros/ros.h"
#include <cstdlib>

int main(int argc, char **argv)
{
    // ROS节点初始化
    ros::init(argc,argv,"add_two_ints_client");
    
    // 从终端命令行获取两个加数
    if (argc !=3)
    {
        ROS_INFO("usage :add two ints client X Y");
        return 1;
    }
    
    // 创建节点句柄
    ros::NodeHandle n;
    
	// 创建一个client,请求add_two_int service,service消息类型是learning_communication::AddTwoInts
    ros::ServiceClient client = n.serviceClient<learning_communication::AddTwo>("add_two_inis_server");
	
	// 创建learning_communication::AddTwoInts类型的service消息
    learning_communication::AddTwo srv;
    srv.request.a = atoll(argv[1]);
    srv.request.b = atoll(argv[2]);

	// 发布service请求,等待加法运算的应答结果
    if(client.call(srv))
    {
        ROS_INFO("Sum: %ld",(long int)srv.response.sum);
    }
    else
    {
        ROS_INFO("Failed to call service add_ two_ints");
        return 1;
    }
    return 0;
}

编译代码

add_executable(server src/server.cpp)						// 编译代码生成可执行文件
target_link_libraries(server  ${catkin_LIBRARIES} )			// 设置链接库
add_dependencies(server ${PROJECT_NAME}_gencpp)				// server  需要多加的一句  设置依赖

add_executable(client src/client.cpp)
target_link_libraries(client  ${catkin_LIBRARIES} )
add_dependencies(client ${PROJECT_NAME}_gencpp)				
上一篇:「全民k歌」有什么秘密?网站数据分析之数据获取


下一篇:CS61A HW 03 Church Numerals