ROS学习笔记五:创建library

本文介绍如何使用ROS (Robot Operating System) 创建自定义库(library),包括创建库的步骤、使用catkin_simple简化流程的方法,以及如何在其他项目中调用这些库。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ROS学习笔记五:创建library

很多时候都是调用系统编辑好的library或者别人做好的,自己编辑自己要用的library的时候比较少,不过了解之后,觉得还是很有用处,暂时的麻烦,可以为以后的编程提供很多便利,特别是自己项目要用到的,多几步操作,把一些有用的函数封装起来,以后调用只要加几行代码就可以了。


一.创建一个library

①先创建一个package存放相关文件
cs_create_pkg creating_a_ros_library roscpp std_msgs std_srvs

以下内容说明catkin_simple的好处,已get的忽略


在这里不用catkin_create_pkg创建包,上述指令中的cs的意思是catkin_simple ,可以规范catkin package以及简化CMakeLists文件,很多依赖项在package.xml文件中列出后就不需要在CMakeLists文件中再次列出,例如:
part 1 这是catkin_make package 的CMakeLists文件

cmake_minimum_required(VERSION 2.8.3)
project(example_service)

find_package(catkin REQUIRED COMPONENTS roscpp rospy message_generation std_msgs std_srvs)

 add_service_files(
   FILES
   ExampleServiceMsg.srv
 )

 generate_messages(
   DEPENDENCIES
   std_msgs
 )

catkin_package(

CATKIN_DEPENDS message_runtime

)

#在生成了service messages头文件之后再添加以下的信息
add_executable(example_service src/example_service.cpp)
target_link_libraries(example_service ${catkin_LIBRARIES})
#add_dependencies(example_service example_service_generate_messages_cpp)


add_executable(example_client src/example_client.cpp)
target_link_libraries(example_client ${catkin_LIBRARIES})
#add_dependencies(example_client example_client_generate_messages_cpp)

part 2 这是catkin_simple package 的CMakeLists文件

cmake_minimum_required(VERSION 2.8.3)
project(creating_a_ros_library)

find_package(catkin_simple REQUIRED)

catkin_simple()

cs_add_library(example_ros_library src/example_ros_class.cpp)   


cs_add_executable(ros_library_test_main src/example_ros_class_test_main.cpp)

target_link_libraries(ros_library_test_main example_ros_library)

cs_install()
cs_export()

对比以上两part可以发现用catkin_simple创建package确实比较好用,但是要转变习惯,毕竟习惯用catkin_make创建package。


回归正题
完成创建package后,可以发现生成了src和include文件夹,以及CMakeLists.txt、package.xml和README.md文件,catkin_make package是不会生成readme file的。

②然后借用上一章完成的class练习的代码并做一些修改,将example_ros_class.cpp复制到src文件夹中。
注意去掉example_ros_class.cpp中的main函数部分
如下:

#include "example_ros_class.h" //我们自定义类(class)的头文件

// 不得不通过节点句柄指针进入构造函数再有构造函数去构建subscriber
ExampleRosClass::ExampleRosClass(ros::NodeHandle* nodehandle):nh_(*nodehandle) // 构造函数
{ 
    ROS_INFO("in class constructor of ExampleRosClass");
    initializeSubscribers(); // 需要通过成员协助函数帮助构建subscriber,在构造函数中做初始化的工作
    initializePublishers();
    initializeServices();

    val_to_remember_=0.0; //初始化储存数据的变量的值
}


//以下是一个成员协助函数,帮助构建subscriber
void ExampleRosClass::initializeSubscribers()
{
    ROS_INFO("Initializing Subscribers");
    minimal_subscriber_ = nh_.subscribe("example_class_input_topic", 1, &ExampleRosClass::subscriberCallback,this);  
    //订阅了名称为"example_class_input_topic"的topic
    //&ExampleRosClass::subscriberCallback 是一个指向成员函数“ExampleRosClass”的指针
    // “this”的用意是指向当前实例(ExampleRosClass)
}

//与上相同
void ExampleRosClass::initializeServices()
{
    ROS_INFO("Initializing Services");
    minimal_service_ = nh_.advertiseService("example_minimal_service",
                                                   &ExampleRosClass::serviceCallback,
                                                   this);  

}

//与上相同
void ExampleRosClass::initializePublishers()
{
    ROS_INFO("Initializing Publishers");
    minimal_publisher_ = nh_.advertise<std_msgs::Float32>("example_class_output_topic", 1, true); 
}

//以下内容与之前在构建publishers/subscribers通信时,编写的publishers和subscribers节点相似
//大部分的工作都是在回调函数中完成的
void ExampleRosClass::subscriberCallback(const std_msgs::Float32& message_holder) {

    val_from_subscriber_ = message_holder.data; // 用成员变量储存回调的数据
    ROS_INFO("myCallback activated: received value %f",val_from_subscriber_);
    std_msgs::Float32 output_msg;
    val_to_remember_ += val_from_subscriber_; //储存每次调用的数据
    output_msg.data= val_to_remember_;

    minimal_publisher_.publish(output_msg); //在这里之所以可以使用publishers的功能,是因为在类中publishers也是其他一个成员函数,所以可以被调用
}


//与构建services/clients通信时相似
bool ExampleRosClass::serviceCallback(std_srvs::TriggerRequest& request, std_srvs::TriggerResponse& response) {
    ROS_INFO("service callback activated");
    response.success = true; // Trigger的消息类型是bool和string,对应的数据类型就是success和message
    response.message = "here is a response string";
    return true;
}

③然后到include文件夹中创建一个也叫“creating_a_ros_library”的文件夹,在里面复制上一章中创建的”example_ros_class.h“头文件

④修改“example_ros_class.cpp”文件中包含类的头文件的地址,如下

#include <creating_a_ros_library/example_ros_class.h>

要注意这个格式,如果头文件和.cpp是在同一目录下的,就可以省略前面的packageName,若不是,就要加上头文件所在的packageName

⑤在CMakeLists.txt中添加创建新的library的指令

cs_add_library(example_ros_library src/example_ros_class.cpp)   

注意example_ros_library是这个新建的library的名称,生产这个library的源代码是example_ros_class.cpp

⑥这时候就可以编译catkin_make生成新的library了,生成的位置
~/ros_ws/devel/lib,名称为“libexample_ros_library.so”,这是在我们设定的新建library名称前加上了lib,但其实我们如果要调用这个新建的library,并不需要知道这个.so文件的名称,只需要知道它所在的packageName就行了,然后在package.xml中添加相应的依赖,如下:

<build_depend>creating_a_ros_library</build_depend>
<run_depend>creating_a_ros_library</run_depend>

非常方便。


二.在其他的包中调用新建的library

只要建好library,要调用就很简单了
①同样,用catkin_simple package再创建一个package
cs_create_pkg using_a_ros_library roscpp std_msgs std_srvs creating_a_ros_library
注意上述指令,最后添加了“creating_a_ros_library”,这会使生成的”package.xml”中添加该package为一个依赖项,这是一个小技巧,等同于手动在“package.xml”文件中依赖项

②在src文件夹中添加上一章class练习中的“example_ros_class.cpp”文件
注意只保留main函数部分及头文件声明部分,其他去掉
头文件所在的package是creating_a_ros_library
代码如下:

int main(int argc, char** argv) 
{
    // ROS set-ups:
    ros::init(argc, argv, "exampleRosClass"); //节点名

    ros::NodeHandle nh; // 必须在main函数中创建一个节点句柄给构造函数使用,并且需要把它传递到构造函数中

    ROS_INFO("main: instantiating an object of type ExampleRosClass");
    ExampleRosClass exampleRosClass(&nh);  //实例化一个ExampleRosClass对象并将指针传递给nodehandle以供构造函数使用

    ROS_INFO("main: going into spin; let the callbacks do all the work");
    ros::spin();
    return 0;
} 

③最后,只需要在”CMakeLists.txt文件中添加生成执行文件的指令就可以了,不需要添加新建library的依赖声明,因为我们使用的是catkin_simple package,并且在package.xml文件中已经做出了声明。

cs_add_executable(ros_library_external_test_main src/example_ros_class_test_main.cpp)

其中ros_library_external_test_main是可执行程序名称,后面跟着的是源代码。

然后编译完成后就可以运行测试了
catkin_make
rosrun using_a_ros_library ros_library_external_test_main

至此就完成了调用新建library的操作。

### ROS2 C++ Topic Communication Learning Materials and Tutorials For those interested in exploring how to use topics for communication within the ROS2 framework using C++, several resources provide comprehensive guidance on this subject. The official documentation of ROS 2 offers an extensive tutorial that covers setting up publishers and subscribers with detailed explanations and code examples written in C++. This resource is invaluable as it not only explains the theory but also provides practical steps necessary to establish topic-based communications between nodes[^1]. Additionally, a popular choice among developers includes tutorials available from Robot Ignite Academy which presents step-by-step instructions alongside video demonstrations specifically tailored towards understanding message passing through topics via C++ interfaces in ROS2 environments. These sessions are designed to cater both beginners who need foundational knowledge about ROS concepts along with more advanced users looking into optimizing their applications' performance when dealing with real-time data exchange over networks. Another noteworthy mention goes out to Open Robotics’ own set of educational materials where one can find well-documented samples illustrating various aspects related to working with messages across different programming languages including C++; these documents often include best practices recommendations ensuring efficient utilization while adhering closely to community standards established around ROS ecosystem development processes. ```cpp // Example Code Snippet Demonstrating Basic Publisher Node Implementation Using rclcpp Library In C++ #include "rclcpp/rclcpp.hpp" using namespace std::chrono_literals; int main(int argc, char * argv[]) { rclcpp::init(argc, argv); auto node = rclcpp::Node::make_shared("example_publisher"); auto publisher = node->create_publisher<std_msgs::msg::String>("topic", 10); auto msg = std_msgs::msg::String(); msg.data = "Hello, world!"; rclcpp::WallRate loop_rate(1s); // Publish every second while (rclcpp::ok()) { RCLCPP_INFO(node->get_logger(), "Publishing: '%s'", msg.data.c_str()); publisher->publish(msg); rclcpp::spin_some(node); loop_rate.sleep(); } rclcpp::shutdown(); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值