如何编译和link回调class(针对ROS消息)
How to compile and link callback class (for ROS messages)
基本上我已经定义了一个 class 来处理我的回调,声明和定义在头文件和源文件之间分开。但是我在编译一个文件然后使用所述回调时遇到了麻烦(尽管我试图 link 回调的目标文件),特别是我得到一个 linker 错误:
[ 98%] Linking CXX executable /home/salih/documents/university/3/6001/code/devel/lib/sdr_ros/sdr_ros
/usr/bin/ld: CMakeFiles/sdr_ros.dir/src/sdr_ros.cpp.o: in function `main':
sdr_ros.cpp:(.text+0x41e): undefined reference to `sdr_ros::TravelInfoCallback::callback(boost::shared_ptr<sdr_ros::TravelInfo_<std::allocator<void> > const> const&)'
collect2: error: ld returned 1 exit status
包名为 sdr_ros
,它处理的消息名为 TravelInfo
,存储在 msg
目录中。
include/travel_info_callback.hpp(头文件):
#ifndef TRAVEL_INFO_CALLBACK_HPP
#define TRAVEL_INFO_CALLBACK_HPP
#pragma once
#include <tuple>
#include "sdr_ros/TravelInfo.h" // message itself
/**
* @brief This file contains declarations for callback functionality which processes TravelInfo ROS message
*/
namespace sdr_ros {
class TravelInfoCallback {
/**
* @brief TravelInfoCallback - class to store values returned by callback pertaining to distance / angles changes
*/
private:
float _delta_x, _delta_y, _delta_z ;
float _yaw, _pitch, _roll ;
public:
/**
* @brief TravelInfoCallback - constructor initialises class values
*/
TravelInfoCallback() noexcept ;
/**
* @brief distance - method returning tuple of distance travelled along x, y, z
* @return std::tuple<float, float, float> - value pertaining to distance travelled along x, y, z axis
*/
::std::tuple<float, float, float> distance() const noexcept ;
/**
* @brief heading - method returning tuple of euler angles yaw, pitch, roll
* @return std::tuple<float, float, float> - value pertaining to distance travelled around the (yaw) z, (pitch) y, (roll) x axis
*/
::std::tuple<float, float, float> heading() const noexcept ;
/**
* @brief callback - method extracting distance travelled and heading angle from ROS message
* @param const sdr_ros::TravelInfoConstPtr& - const reference to boost shared pointer to ROS message storing distance travelled and heading angle
*/
void callback(const TravelInfoConstPtr&) noexcept ;
// below are defaulted and deleted methods
TravelInfoCallback(const TravelInfoCallback&) = delete ;
TravelInfoCallback& operator=(const TravelInfoCallback&) = delete ;
TravelInfoCallback(TravelInfoCallback&&) = delete ;
TravelInfoCallback&& operator=(TravelInfoCallback&&) = delete ;
~TravelInfoCallback() noexcept = default ;
} ;
}
#endif // TRAVEL_INFO_HPP
src/travel_info.cpp
#include <tuple>
#include "sdr_ros/TravelInfo.h" // message itself
#include "travel_info_callback.hpp"
/**
* @brief This file contains defintions for callback functionality which processes travel_info ROS message
*/
sdr_ros::TravelInfoCallback::TravelInfoCallback() noexcept : _delta_x(0.f), _delta_y(0.f), _delta_z(0.f), _yaw(0.f), _pitch(0.f), _roll(0.f) {} ;
std::tuple<float, float, float> sdr_ros::TravelInfoCallback::distance() const noexcept
{
return std::tuple<float, float, float>{
this->_delta_x, this->_delta_y, this->_delta_z
} ;
}
std::tuple<float, float, float> sdr_ros::TravelInfoCallback::heading() const noexcept
{
return std::tuple<float, float, float>{
this->_yaw, this->_pitch, this->_roll
} ;
}
inline void sdr_ros::TravelInfoCallback::callback(const sdr_ros::TravelInfoConstPtr& travel_info) noexcept
{
this->_delta_x = travel_info->delta_x ;
this->_delta_y = travel_info->delta_y ;
this->_delta_z = travel_info->delta_z ;
this->_yaw = travel_info->yaw ;
this->_pitch = travel_info->pitch ;
this->_roll = travel_info->roll ;
}
src/sdr_ros(使用回调的源代码)
#include <ros/ros.h>
#include <ros/console.h>
#include <ros/callback_queue.h>
#include <string>
#include <cmath>
#include <geometry_msgs/Pose.h>
#include "sdr_ros/TravelInfo.h"
#include "preprocessing.hpp"
#include "pose.hpp"
#include "travel_info_callback.hpp"
/**
* @brief This file serves as the ROS node which reads from the network and calls relevant functionality to calculate and distribute pose information
*/
int main(int argc, char** argv)
{
/* Initialisation */
const std::string node_name = "sdr_ros" ;
ros::init(argc, argv, node_name); ROS_INFO_STREAM(node_name << " running") ; // initialise ROS node
ros::NodeHandle nh("~") ; // handle to ROS communications (topics, services)
sdr::Pose pose ;
std::string initial_pose_file ;
if(nh.getParam("initial_pose_file", initial_pose_file))
{
pose = sdr::extract_initial_pose(initial_pose_file) ;
}
sdr_ros::TravelInfoCallback cb ; // callback object with methods
ros::Subscriber sub = nh.subscribe<sdr_ros::TravelInfo>("/travel_info", 100, &sdr_ros::TravelInfoCallback::callback, &cb) ; // subscribe to topic distance_info
geometry_msgs::Pose pose_msg ;
ros::Publisher pub = nh.advertise<geometry_msgs::Pose>("/odometry", 1) ; // publishes information about where car as XYZ, orientation as quaternion
/* Main functionality */
while(ros::ok()) // while ROS is running - the actual useful computation
{
/* Get info */
if(ros::getGlobalCallbackQueue()->callOne() == ros::CallbackQueue::CallOneResult::Empty) continue ;
// ^ we can't simply use `ros::spinOnce` as there's no indication of an empty queue, meaning we'd be processing the same message multiple times, exponentially increasing predicted distance.
const auto [delta_x, delta_y, delta_z] = cb.distance() ;
if(!delta_x && !delta_y && !delta_z)
{
continue ; // no point processing odom when we haven't moved
}
const auto [yaw, pitch, roll] = cb.heading() ;
pose.update_position(delta_x, delta_y, delta_z) ;
pose.update_orientation(yaw, pitch, roll) ;
pose_msg.position.x = pose.position()(0,0) ;
pose_msg.position.y = pose.position()(0,1) ;
pose_msg.position.z = pose.position()(0,2) ;
pose_msg.orientation.x = pose.orientation().x() ;
pose_msg.orientation.y = pose.orientation().y() ;
pose_msg.orientation.z = pose.orientation().z() ;
pose_msg.orientation.w = pose.orientation().w() ;
ROS_INFO_STREAM("Current position: " << pose_msg.position) ;
ROS_INFO_STREAM("Current orientation: " << pose_msg.orientation << '\n') ;
/* Publish odometry */
pub.publish(pose_msg) ;
}
/* E(nd) O(f) P(rogram) */
return 0 ;
}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.2)
project(sdr_ros)
## Compile as C++20, supported in ROS Kinetic and newer
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_FLAGS "-Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_RELEASE "-O0")
find_package(Eigen3 REQUIRED)
################################################
## Find catkin macros and libraries ##
################################################
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
tf
nav_msgs
genmsg
message_generation
)
## System dependencies are found with CMake's conventions
# find_package(Boost REQUIRED COMPONENTS system)
################################################
## Declare ROS messages, services and actions ##
################################################
## Generate messages in the 'msg' folder
add_message_files(
DIRECTORY
msg
FILES
TravelInfo.msg
)
## Generate services in the 'srv' folder
#add_service_files(
# FILES
#)
## Generate added messages and services with any dependencies listed here
generate_messages(
DEPENDENCIES
std_msgs
geometry_msgs
)
###################################
## catkin specific configuration ##
###################################
## The catkin_package macro generates cmake config files for your package
## Declare things to be passed to dependent projects
## INCLUDE_DIRS: uncomment this if your package contains header files
## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
catkin_package(
# INCLUDE_DIRS
# include
# ${EIGEN3_INCLUDE_DIR}
# libraries/sdr/include/
CATKIN_DEPENDS
message_runtime
)
###########
## Build ##
###########
add_subdirectory(libraries/sdr)
## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(
include
libraries/sdr/include/
${EIGEN3_INCLUDE_DIR}
${catkin_INCLUDE_DIRS}
)
## Declare a C++ executable
add_library(travel_info_callback ${CMAKE_CURRENT_SOURCE_DIR}/src/travel_info_callback.cpp)
target_include_directories(travel_info_callback PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(travel_info_callback ${catkin_LIBRARIES})
add_dependencies(travel_info_callback sdr_ros_generate_messages_cpp)
add_executable(sdr_ros src/sdr_ros.cpp)
target_link_libraries(sdr_ros ${catkin_LIBRARIES} travel_info_callback detailed_exception.o preprocessing.o pose.o yaml-cpp)
add_dependencies(sdr_ros sdr_ros_generate_messages_cpp)
我希望我已经提供了足够的信息并且有人可以提供帮助。非常感谢
您的消息类型有误。在设置订阅者时,您将给它一个 sdr_ros::TravelInfo
类型,但是回调定义将 sdr_ros::TravelInfoConstPtr
作为参数。相反,在您的回调中,您希望消息生成 ConstPtr,因此将签名更改为
sdr_ros::TravelInfoCallback::callback(const sdr_ros::TravelInfo::ConstPtr& travel_info)
**inline** void sdr_ros::TravelInfoCallback::callback(const sdr_ros::TravelInfoConstPtr& travel_info) noexcept
我不小心在函数头中留下了 inline 关键字。删除它允许正确的函数声明解决了我所有的问题
基本上我已经定义了一个 class 来处理我的回调,声明和定义在头文件和源文件之间分开。但是我在编译一个文件然后使用所述回调时遇到了麻烦(尽管我试图 link 回调的目标文件),特别是我得到一个 linker 错误:
[ 98%] Linking CXX executable /home/salih/documents/university/3/6001/code/devel/lib/sdr_ros/sdr_ros
/usr/bin/ld: CMakeFiles/sdr_ros.dir/src/sdr_ros.cpp.o: in function `main':
sdr_ros.cpp:(.text+0x41e): undefined reference to `sdr_ros::TravelInfoCallback::callback(boost::shared_ptr<sdr_ros::TravelInfo_<std::allocator<void> > const> const&)'
collect2: error: ld returned 1 exit status
包名为 sdr_ros
,它处理的消息名为 TravelInfo
,存储在 msg
目录中。
include/travel_info_callback.hpp(头文件):
#ifndef TRAVEL_INFO_CALLBACK_HPP
#define TRAVEL_INFO_CALLBACK_HPP
#pragma once
#include <tuple>
#include "sdr_ros/TravelInfo.h" // message itself
/**
* @brief This file contains declarations for callback functionality which processes TravelInfo ROS message
*/
namespace sdr_ros {
class TravelInfoCallback {
/**
* @brief TravelInfoCallback - class to store values returned by callback pertaining to distance / angles changes
*/
private:
float _delta_x, _delta_y, _delta_z ;
float _yaw, _pitch, _roll ;
public:
/**
* @brief TravelInfoCallback - constructor initialises class values
*/
TravelInfoCallback() noexcept ;
/**
* @brief distance - method returning tuple of distance travelled along x, y, z
* @return std::tuple<float, float, float> - value pertaining to distance travelled along x, y, z axis
*/
::std::tuple<float, float, float> distance() const noexcept ;
/**
* @brief heading - method returning tuple of euler angles yaw, pitch, roll
* @return std::tuple<float, float, float> - value pertaining to distance travelled around the (yaw) z, (pitch) y, (roll) x axis
*/
::std::tuple<float, float, float> heading() const noexcept ;
/**
* @brief callback - method extracting distance travelled and heading angle from ROS message
* @param const sdr_ros::TravelInfoConstPtr& - const reference to boost shared pointer to ROS message storing distance travelled and heading angle
*/
void callback(const TravelInfoConstPtr&) noexcept ;
// below are defaulted and deleted methods
TravelInfoCallback(const TravelInfoCallback&) = delete ;
TravelInfoCallback& operator=(const TravelInfoCallback&) = delete ;
TravelInfoCallback(TravelInfoCallback&&) = delete ;
TravelInfoCallback&& operator=(TravelInfoCallback&&) = delete ;
~TravelInfoCallback() noexcept = default ;
} ;
}
#endif // TRAVEL_INFO_HPP
src/travel_info.cpp
#include <tuple>
#include "sdr_ros/TravelInfo.h" // message itself
#include "travel_info_callback.hpp"
/**
* @brief This file contains defintions for callback functionality which processes travel_info ROS message
*/
sdr_ros::TravelInfoCallback::TravelInfoCallback() noexcept : _delta_x(0.f), _delta_y(0.f), _delta_z(0.f), _yaw(0.f), _pitch(0.f), _roll(0.f) {} ;
std::tuple<float, float, float> sdr_ros::TravelInfoCallback::distance() const noexcept
{
return std::tuple<float, float, float>{
this->_delta_x, this->_delta_y, this->_delta_z
} ;
}
std::tuple<float, float, float> sdr_ros::TravelInfoCallback::heading() const noexcept
{
return std::tuple<float, float, float>{
this->_yaw, this->_pitch, this->_roll
} ;
}
inline void sdr_ros::TravelInfoCallback::callback(const sdr_ros::TravelInfoConstPtr& travel_info) noexcept
{
this->_delta_x = travel_info->delta_x ;
this->_delta_y = travel_info->delta_y ;
this->_delta_z = travel_info->delta_z ;
this->_yaw = travel_info->yaw ;
this->_pitch = travel_info->pitch ;
this->_roll = travel_info->roll ;
}
src/sdr_ros(使用回调的源代码)
#include <ros/ros.h>
#include <ros/console.h>
#include <ros/callback_queue.h>
#include <string>
#include <cmath>
#include <geometry_msgs/Pose.h>
#include "sdr_ros/TravelInfo.h"
#include "preprocessing.hpp"
#include "pose.hpp"
#include "travel_info_callback.hpp"
/**
* @brief This file serves as the ROS node which reads from the network and calls relevant functionality to calculate and distribute pose information
*/
int main(int argc, char** argv)
{
/* Initialisation */
const std::string node_name = "sdr_ros" ;
ros::init(argc, argv, node_name); ROS_INFO_STREAM(node_name << " running") ; // initialise ROS node
ros::NodeHandle nh("~") ; // handle to ROS communications (topics, services)
sdr::Pose pose ;
std::string initial_pose_file ;
if(nh.getParam("initial_pose_file", initial_pose_file))
{
pose = sdr::extract_initial_pose(initial_pose_file) ;
}
sdr_ros::TravelInfoCallback cb ; // callback object with methods
ros::Subscriber sub = nh.subscribe<sdr_ros::TravelInfo>("/travel_info", 100, &sdr_ros::TravelInfoCallback::callback, &cb) ; // subscribe to topic distance_info
geometry_msgs::Pose pose_msg ;
ros::Publisher pub = nh.advertise<geometry_msgs::Pose>("/odometry", 1) ; // publishes information about where car as XYZ, orientation as quaternion
/* Main functionality */
while(ros::ok()) // while ROS is running - the actual useful computation
{
/* Get info */
if(ros::getGlobalCallbackQueue()->callOne() == ros::CallbackQueue::CallOneResult::Empty) continue ;
// ^ we can't simply use `ros::spinOnce` as there's no indication of an empty queue, meaning we'd be processing the same message multiple times, exponentially increasing predicted distance.
const auto [delta_x, delta_y, delta_z] = cb.distance() ;
if(!delta_x && !delta_y && !delta_z)
{
continue ; // no point processing odom when we haven't moved
}
const auto [yaw, pitch, roll] = cb.heading() ;
pose.update_position(delta_x, delta_y, delta_z) ;
pose.update_orientation(yaw, pitch, roll) ;
pose_msg.position.x = pose.position()(0,0) ;
pose_msg.position.y = pose.position()(0,1) ;
pose_msg.position.z = pose.position()(0,2) ;
pose_msg.orientation.x = pose.orientation().x() ;
pose_msg.orientation.y = pose.orientation().y() ;
pose_msg.orientation.z = pose.orientation().z() ;
pose_msg.orientation.w = pose.orientation().w() ;
ROS_INFO_STREAM("Current position: " << pose_msg.position) ;
ROS_INFO_STREAM("Current orientation: " << pose_msg.orientation << '\n') ;
/* Publish odometry */
pub.publish(pose_msg) ;
}
/* E(nd) O(f) P(rogram) */
return 0 ;
}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.2)
project(sdr_ros)
## Compile as C++20, supported in ROS Kinetic and newer
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_FLAGS "-Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_RELEASE "-O0")
find_package(Eigen3 REQUIRED)
################################################
## Find catkin macros and libraries ##
################################################
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
tf
nav_msgs
genmsg
message_generation
)
## System dependencies are found with CMake's conventions
# find_package(Boost REQUIRED COMPONENTS system)
################################################
## Declare ROS messages, services and actions ##
################################################
## Generate messages in the 'msg' folder
add_message_files(
DIRECTORY
msg
FILES
TravelInfo.msg
)
## Generate services in the 'srv' folder
#add_service_files(
# FILES
#)
## Generate added messages and services with any dependencies listed here
generate_messages(
DEPENDENCIES
std_msgs
geometry_msgs
)
###################################
## catkin specific configuration ##
###################################
## The catkin_package macro generates cmake config files for your package
## Declare things to be passed to dependent projects
## INCLUDE_DIRS: uncomment this if your package contains header files
## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
catkin_package(
# INCLUDE_DIRS
# include
# ${EIGEN3_INCLUDE_DIR}
# libraries/sdr/include/
CATKIN_DEPENDS
message_runtime
)
###########
## Build ##
###########
add_subdirectory(libraries/sdr)
## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(
include
libraries/sdr/include/
${EIGEN3_INCLUDE_DIR}
${catkin_INCLUDE_DIRS}
)
## Declare a C++ executable
add_library(travel_info_callback ${CMAKE_CURRENT_SOURCE_DIR}/src/travel_info_callback.cpp)
target_include_directories(travel_info_callback PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(travel_info_callback ${catkin_LIBRARIES})
add_dependencies(travel_info_callback sdr_ros_generate_messages_cpp)
add_executable(sdr_ros src/sdr_ros.cpp)
target_link_libraries(sdr_ros ${catkin_LIBRARIES} travel_info_callback detailed_exception.o preprocessing.o pose.o yaml-cpp)
add_dependencies(sdr_ros sdr_ros_generate_messages_cpp)
我希望我已经提供了足够的信息并且有人可以提供帮助。非常感谢
您的消息类型有误。在设置订阅者时,您将给它一个 sdr_ros::TravelInfo
类型,但是回调定义将 sdr_ros::TravelInfoConstPtr
作为参数。相反,在您的回调中,您希望消息生成 ConstPtr,因此将签名更改为
sdr_ros::TravelInfoCallback::callback(const sdr_ros::TravelInfo::ConstPtr& travel_info)
**inline** void sdr_ros::TravelInfoCallback::callback(const sdr_ros::TravelInfoConstPtr& travel_info) noexcept
我不小心在函数头中留下了 inline 关键字。删除它允许正确的函数声明解决了我所有的问题