小鱼 ROS 2 新书上线!点击链接查看, 新书配套视频点击链接查看。
提问前必看的发帖注意事项—— 提问前必看!不符合要求的问题拒绝回答!!
社区使用指南—如何添加标签修改密码
编译cmakelist报错找不到依赖库
-
编译cmakelist报错找不到依赖库/usr/bin/ld: CMakeFiles/pid_position_follow.dir/src/pid_position_follow.cpp.o: in function
TransformPose(std::shared_ptr<tf2_ros::Buffer> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, geometry_msgs::msg::PoseStamped_<std::allocator<void> > const&, geometry_msgs::msg::TransformStamped_<std::allocator<void> >&)': pid_position_follow.cpp:(.text+0xa21): undefined reference to
void tf2::fromMsg<geometry_msgs::msg::Pose_<std::allocator<void> >, geometry_msgs::msg::Transform_<std::allocator<void> > >(geometry_msgs::msg::Pose_<std::allocator<void> > const&, geometry_msgs::msg::Transform_<std::allocator<void> >&)'
/usr/bin/ld: pid_position_follow.cpp:(.text+0xaa2): undefined reference to `void tf2::fromMsg<geometry_msgs::msg::Pose_<std::allocator<void> >, geometry_msgs::msg::Transform_<std::allocator<void> > >(geometry_msgs::msg::Pose_<std::allocator<void> > const&, geometry_msgs::msg::Transform_<std::allocator<void> >&)'
collect2: error: ld returned 1 exit status
gmake[2]: *** [CMakeFiles/pid_position_follow.dir/build.make:243:pid_position_follow] 错误 1
gmake[1]: *** [CMakeFiles/Makefile2:137:CMakeFiles/pid_position_follow.dir/all] 错误 2
gmake: *** [Makefile:146:all] 错误 2
但是我加上链接后报错--- stderr: pid_position_follow
/usr/bin/ld: 找不到 -ltf2: 没有那个文件或目录
/usr/bin/ld: 找不到 -ltf2_ros: 没有那个文件或目录
/usr/bin/ld: 找不到 -ltf2_geometry_msgs: 没有那个文件或目录
collect2: error: ld returned 1 exit status
很抽象 -
这个错误表明你的项目在链接阶段找不到必要的
tf2
及其相关 ROS 库的库文件。这通常是因为这些库没有被正确安装或者它们的安装位置没有被添加到链接器的搜索路径中。以下是一些解决步骤:-
确认库是否已安装:
确保tf2
及其相关的 ROS 库(如tf2_ros
,tf2_geometry_msgs
)已经正确安装在你的系统上。如果你使用的是 ROS,你可以通过 ROS 的包管理器来安装这些库。例如,在 Ubuntu 上使用 ROS Noetic,你可以通过以下命令安装:sudo apt-get install ros-noetic-tf2 ros-noetic-tf2-ros ros-noetic-tf2-geometry-msgs
根据你的 ROS 版本(如 Kinetic, Melodic 等),替换
noetic
为对应的版本名称。 -
检查库文件的位置:
如果库已经安装,检查这些库文件(通常是.so
文件)位于哪个目录。你可以使用dpkg -L
命令来查看已安装包的文件列表。例如:dpkg -L ros-noetic-tf2 dpkg -L ros-noetic-tf2-ros dpkg -L ros-noetic-tf2-geometry-msgs
查找输出中
.so
文件的路径,通常这些文件位于/usr/lib/x86_64-linux-gnu/ros-<version>/
或/opt/ros/<version>/lib/
下。 -
设置链接器的搜索路径:
如果库文件存在但不在链接器的默认搜索路径中,你可以通过以下几种方式添加搜索路径:-
修改 CMakeLists.txt:在你的
CMakeLists.txt
文件中添加链接库的路径。使用link_directories()
函数:link_directories(/usr/lib/x86_64-linux-gnu/ros-noetic)
替换为实际库文件所在的路径。
-
设置环境变量:在运行
cmake
或make
之前,设置LD_LIBRARY_PATH
环境变量,包括库文件的路径:export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/ros-noetic:$LD_LIBRARY_PATH
然后再次运行
cmake
和make
。
-
-
清理并重新构建:
在做了上述更改后,确保清理旧的构建文件,然后重新运行cmake
和make
:cd your_project_directory make clean cmake . make
-
检查 ROS 环境:
确保你的 ROS 环境已经正确设置。这通常涉及到设置ROS_MASTER_URI
和ROS_PACKAGE_PATH
环境变量,以及在你的 shell 中 source 正确的setup.bash
文件。
如果以上步骤仍然无法解决问题,可能需要检查你的 ROS 安装是否完整或考虑重新安装 ROS 和相关库。
以上为生成回答,仅供参考~
-
-
@小伊 cmake_minimum_required(VERSION 3.10)
project(pid_position_follow)Use C++14
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)By adding -Wall and -Werror, the compiler does not ignore warnings anymore,
enforcing cleaner code.
add_definitions(-Wall -Werror)
Export compile commands for clangd
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
#######################
Find dependencies
#######################
find_package(ament_cmake_auto REQUIRED)
ament_auto_find_build_dependencies()添加包含目录
include_directories(
include/cubic_spline
include/pid_position_follow
)###########
Build
###########
ament_auto_add_executable(${PROJECT_NAME}
src/pid_position_follow.cpp
)确保链接 tf2 库
find_package(tf2 REQUIRED)
find_package(tf2_ros REQUIRED)
find_package(tf2_geometry_msgs REQUIRED)ament_target_dependencies(${PROJECT_NAME}
tf2
tf2_ros
tf2_geometry_msgs
)#############
Install
#############
ament_auto_package(
INSTALL_TO_SHARE
launch
include
)这个是我的cmakelist -
您的
CMakeLists.txt
文件主要用于配置一个使用 C++14 标准、包含特定编译器标志、依赖项和安装指令的 ROS 2 项目。不过,有几个小问题和改进点需要注意:-
语法错误和拼写错误:
Use C++14
应该是一个命令,但 CMake 中没有这样的命令。您已经正确地使用了set(CMAKE_CXX_STANDARD 14)
和set(CMAKE_CXX_STANDARD_REQUIRED ON)
来设置 C++ 标准。add_definitions(-Wall -Werror)
应该是add_compile_definitions(-Wall -Werror)
。add_definitions
不是一个 CMake 命令,而add_compile_definitions
用于添加预处理器定义。find_package
应该是find_package(PACKAGE_NAME [version] [REQUIRED|OPTIONAL])
,但您已经正确使用了它,只是写成了两行(可能是为了解释)。
-
改进点:
- 使用
ament_index_has_component
来检查依赖是否已安装(可选,但有助于调试)。 - 确保所有路径都是相对于项目根目录的,特别是
include_directories
中的路径。 - 注释和文档:增加更多的注释来说明每个部分的作用,特别是对于那些可能不熟悉的 CMake 或 ROS 2 的用户。
- 使用
下面是修改后的
CMakeLists.txt
文件:cmake_minimum_required(VERSION 3.10) project(pid_position_follow) # 设置 C++14 标准 set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 添加编译器标志 add_compile_definitions(-Wall -Werror) # 导出编译命令供 clangd 使用 set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # 查找依赖项 find_package(ament_cmake_auto REQUIRED) ament_auto_find_build_dependencies() # 添加包含目录 include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/include/cubic_spline ${CMAKE_CURRENT_SOURCE_DIR}/include/pid_position_follow ) # 构建可执行文件 ament_auto_add_executable(${PROJECT_NAME} src/pid_position_follow.cpp ) # 查找 tf2 相关的包 find_package(tf2 REQUIRED) find_package(tf2_ros REQUIRED) find_package(tf2_geometry_msgs REQUIRED) # 添加目标依赖 ament_target_dependencies(${PROJECT_NAME} tf2 tf2_ros tf2_geometry_msgs ) # 安装 ament_auto_package( INSTALL_TO_SHARE launch include )
确保您的项目结构正确,特别是
include
和src
目录的位置,以及CMakeLists.txt
文件位于项目的根目录。此外,如果您使用的是 ROS 2,确保您的环境已经正确设置,包括source
了正确的setup.bash
文件。
以上为生成回答,仅供参考~
-
-
@小伊 yzh@yzh:~/PID_Trajectory_Tracking$ colcon build
Starting >>> rm_decision_interfaces
Finished <<< rm_decision_interfaces [0.71s]
Starting >>> pid_position_follow
--- stderr: pid_position_follow
/usr/bin/ld: CMakeFiles/pid_position_follow.dir/src/pid_position_follow.cpp.o: in functionTransformPose(std::shared_ptr<tf2_ros::Buffer> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, geometry_msgs::msg::PoseStamped_<std::allocator<void> > const&, geometry_msgs::msg::TransformStamped_<std::allocator<void> >&)': pid_position_follow.cpp:(.text+0xa21): undefined reference to
void tf2::fromMsg<geometry_msgs::msg::Pose_<std::allocator<void> >, geometry_msgs::msg::Transform_<std::allocator<void> > >(geometry_msgs::msg::Pose_<std::allocator<void> > const&, geometry_msgs::msg::Transform_<std::allocator<void> >&)'
/usr/bin/ld: pid_position_follow.cpp:(.text+0xaa2): undefined reference to `void tf2::fromMsg<geometry_msgs::msg::Pose_<std::allocator<void> >, geometry_msgs::msg::Transform_<std::allocator<void> > >(geometry_msgs::msg::Pose_<std::allocator<void> > const&, geometry_msgs::msg::Transform_<std::allocator<void> >&)'
collect2: error: ld returned 1 exit status
gmake[2]: *** [CMakeFiles/pid_position_follow.dir/build.make:243:pid_position_follow] 错误 1
gmake[1]: *** [CMakeFiles/Makefile2:137:CMakeFiles/pid_position_follow.dir/all] 错误 2
gmake: *** [Makefile:146:all] 错误 2Failed <<< pid_position_follow [15.5s, exited with code 2]
Summary: 1 package finished [16.4s]
1 package failed: pid_position_follow
1 package had stderr output: pid_position_follow
还是报错 你看看我的这个#ifndef ROBOMASTER_UTILITY_H
#define ROBOMASTER_UTILITY_H#include <tf2/utils.h>
#include <tf2_ros/buffer.h>
#include <tf2_ros/transform_listener.h>
#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>#include <geometry_msgs/msg/pose_stamped.hpp>
#include <geometry_msgs/msg/quaternion.hpp>
#include <geometry_msgs/msg/transform_stamped.hpp>#include <rclcpp/rclcpp.hpp>
double GetYawFromOrientation(const geometry_msgs::msg::Quaternion &orientation) {
tf2::Quaternion q;
tf2::fromMsg(orientation, q);
tf2::Matrix3x3 m(q);
double roll, pitch, yaw;
m.getRPY(roll, pitch, yaw);
return yaw;
}double GetEuclideanDistance(const geometry_msgs::msg::PoseStamped &pose_1,
const geometry_msgs::msg::PoseStamped &pose_2) {
return hypot(pose_1.pose.position.x - pose_2.pose.position.x,
pose_1.pose.position.y - pose_2.pose.position.y);
}bool GetGlobalRobotPose(const std::shared_ptr<tf2_ros::Buffer> &tf_buffer,
const std::string &target_frame,
geometry_msgs::msg::PoseStamped &robot_global_pose) {
geometry_msgs::msg::PoseStamped robot_pose;
robot_pose.header.frame_id = "base_link";
robot_pose.header.stamp = tf2_ros::toMsg(tf2::TimePointZero);
robot_pose.pose.orientation.w = 1.0;try { tf_buffer->transform(robot_pose, robot_global_pose, target_frame); } catch (tf2::TransformException &ex) { RCLCPP_ERROR(rclcpp::get_logger("utility"), "Failed to transform robot pose: %s", ex.what()); return false; } return true;
}
bool TransformPose(const std::shared_ptr<tf2_ros::Buffer> &tf_buffer,
const std::string &target_frame,
const geometry_msgs::msg::PoseStamped &input_pose,
geometry_msgs::msg::PoseStamped &output_pose) {
if (target_frame == input_pose.header.frame_id) {
output_pose = input_pose;
return true;
}try { tf_buffer->transform(input_pose, output_pose, target_frame); } catch (tf2::TransformException &ex) { RCLCPP_ERROR(rclcpp::get_logger("utility"), "Failed to transform pose: %s", ex.what()); return false; } return true;
}
bool TransformPose(const std::shared_ptr<tf2_ros::Buffer> &tf_buffer,
const std::string &target_frame,
const geometry_msgs::msg::PoseStamped &input_pose,
geometry_msgs::msg::TransformStamped &output_pose_tf) {
if (target_frame == input_pose.header.frame_id) {
tf2::fromMsg(input_pose.pose, output_pose_tf.transform);
output_pose_tf.header = input_pose.header;
return true;
}geometry_msgs::msg::PoseStamped output_pose; if (!TransformPose(tf_buffer, target_frame, input_pose, output_pose)) { return false; } tf2::fromMsg(output_pose.pose, output_pose_tf.transform); output_pose_tf.header = output_pose.header; return true;
}
void TransformPose(const geometry_msgs::msg::TransformStamped &transform,
const geometry_msgs::msg::PoseStamped &input_pose,
geometry_msgs::msg::PoseStamped &output_pose) {
tf2::Transform input_pose_tf;
tf2::fromMsg(input_pose.pose, input_pose_tf);
tf2::Transform transform_tf;
tf2::fromMsg(transform.transform, transform_tf);
tf2::Transform output_pose_tf = transform_tf * input_pose_tf;
// Convert tf2::Transform to geometry_msgs::msg::Pose
geometry_msgs::msg::Pose output_pose_msg;
tf2::toMsg(output_pose_tf, output_pose_msg);
output_pose.pose = output_pose_msg;
output_pose.header.stamp = transform.header.stamp;
output_pose.header.frame_id = transform.header.frame_id;
}bool UpdateTransform(const std::shared_ptr<tf2_ros::Buffer> &tf_buffer,
const std::string &target_frame,
const std::string &source_frame,
const rclcpp::Time &source_time,
geometry_msgs::msg::TransformStamped &target_to_source_transform) {
try {
target_to_source_transform = tf_buffer->lookupTransform(target_frame, source_time, source_frame, source_time, source_frame);
} catch (tf2::TransformException &ex) {
RCLCPP_ERROR(rclcpp::get_logger("utility"), "Failed to update transform: %s", ex.what());
return false;
}return true;
}
#endif // ROBOMASTER_UTILITY_H这个代码有没有问题 改进一下
-
从你提供的错误信息来看,链接器在编译
pid_position_follow
包时未能找到tf2::fromMsg
函数的定义。这通常意味着链接时缺少了某些库文件,或者你的项目中没有正确包含所有需要的头文件。首先,确保你的项目中正确链接了
tf2
和tf2_geometry_msgs
库。这通常在 CMakeLists.txt 文件中设置。以下是一个基本的 CMakeLists.txt 示例,展示了如何链接这些库:cmake_minimum_required(VERSION 3.5) project(pid_position_follow) # Find dependencies find_package(REQUIRED COMPONENTS rclcpp std_msgs geometry_msgs tf2 tf2_geometry_msgs tf2_ros ) # Add executable add_executable(pid_position_follow src/pid_position_follow.cpp) # Link libraries target_link_libraries(pid_position_follow PRIVATE ${catkin_LIBRARIES})
注意,
target_link_libraries
需要包含所有必要的库。这里${catkin_LIBRARIES}
会自动包含通过find_package
找到的依赖库。接下来,关于你的头文件
ROBOMASTER_UTILITY_H
,有几个小问题和改进建议:-
头文件包含:确保你包含了所有需要的头文件,特别是与
tf2
和geometry_msgs
相关的。 -
命名空间:在函数定义中明确使用
tf2
命名空间可能更清晰,尽管在头文件中已经包含了tf2/utils.h
和其他相关头文件。 -
代码风格:代码整体风格良好,但建议使用
auto
关键字来自动推导变量类型,特别是复杂的类型,如std::shared_ptr<tf2_ros::Buffer>
。 -
错误处理:你的错误处理逻辑已经很好,使用了
try-catch
来捕获tf2::TransformException
。 -
代码冗余:在
TransformPose
函数中,你重复了tf2::fromMsg
的调用。考虑是否可以通过重构来减少重复代码。 -
使用 C++ 标准库:对于计算欧几里得距离,你已经使用了
hypot
,这是正确的。但也可以考虑使用 C++ 标准库中的其他函数,如std::sqrt
和std::pow
,尽管hypot
通常是处理这种情况的更好选择。 -
宏定义保护:你的头文件使用了
#ifndef
,#define
,#endif
来防止重复包含,这是良好的实践。
根据你的错误信息,问题很可能出在 CMakeLists.txt 文件中没有正确链接
tf2
或tf2_geometry_msgs
。请检查并确保这些库被正确链接。如果问题仍然存在,请检查是否有其他库或依赖项缺失。
以上为生成回答,仅供参考~
-
-
@小伊 如果我加上target_link_libraries(pid_position_follow PRIVATE ${catkin_LIBRARIES})就会报错/usr/bin/ld: 找不到 -ltf2: 没有那个文件或目录
/usr/bin/ld: 找不到 -ltf2_ros: 没有那个文件或目录 -
错误信息
/usr/bin/ld: 找不到 -ltf2: 没有那个文件或目录
和/usr/bin/ld: 找不到 -ltf2_ros: 没有那个文件或目录
表明链接器(ld)在尝试链接你的程序时找不到tf2
和tf2_ros
这两个库。这通常意味着这些库没有被正确安装在你的系统上,或者它们的安装路径没有被添加到链接器的搜索路径中。解决步骤
-
确认库的安装:
- 确保你已经安装了
tf2
和tf2_ros
库。这些库通常是通过 ROS(Robot Operating System)安装的。 - 如果你使用的是 ROS 1,你可以通过以下命令安装这些库(如果它们还未安装):
其中sudo apt-get install ros-<distro>-tf2 ros-<distro>-tf2-ros
<distro>
应该替换为你使用的 ROS 发行版,如melodic
、noetic
等。
- 确保你已经安装了
-
检查库文件:
- 安装完成后,你可以使用
find
命令来查找这些库文件(通常是.so
文件)。例如:sudo find / -name "libtf2*.so*" sudo find / -name "libtf2_ros*.so*"
- 这将帮助你确认库文件是否存在于你的系统中,以及它们的位置。
- 安装完成后,你可以使用
-
设置环境变量:
- 如果库文件存在但不在标准路径下,你可能需要设置
LD_LIBRARY_PATH
环境变量来包含这些库的路径。例如:export LD_LIBRARY_PATH=/path/to/your/libs:$LD_LIBRARY_PATH
- 替换
/path/to/your/libs
为实际库文件所在的目录。
- 如果库文件存在但不在标准路径下,你可能需要设置
-
CMakeLists.txt 修改:
- 确保你的
CMakeLists.txt
文件正确链接了这些库。你已经在使用target_link_libraries
,这是正确的。但确认库名是否正确,有时需要指定完整的库名(包括前缀lib
和后缀.so
的版本号,但通常只写基本名即可)。 - 确保
find_package
指令包含了tf2
和tf2_ros
(如果它们是独立的 ROS 包)。
- 确保你的
-
重新编译:
- 清理你的构建目录(通常是
catkin_ws/build
和catkin_ws/devel
),然后重新编译整个工作空间:cd ~/catkin_ws catkin_make clean catkin_make
- 清理你的构建目录(通常是
-
检查 ROS 环境:
- 确保你的 ROS 环境已经正确设置。运行
source ~/catkin_ws/devel/setup.bash
(或你的工作空间对应的路径)来设置环境变量。
- 确保你的 ROS 环境已经正确设置。运行
如果以上步骤仍然不能解决问题,可能需要检查你的 ROS 安装是否完整或考虑重新安装 ROS 和相关库。
以上为生成回答,仅供参考~
-