Hi,
I am trying to implement something like this: https://pcl.readthedocs.io/en/latest/normal_distributions_transform.html#normal-distributions-transform using lidar output.
I'm getting linking errors when trying to compile this.
colcon build --symlink-install
Starting >>> cpp_tests
--- stderr: cpp_tests
** WARNING ** io features related to pcap will be disabled
/usr/bin/ld: CMakeFiles/ndt_test.dir/src/ndt_transform_calculator.cpp.o: in function `pcl::Registration<pcl::PointXYZ, pcl::PointXYZ, float>::align(pcl::PointCloud<pcl::PointXYZ>&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&)':
ndt_transform_calculator.cpp:(.text._ZN3pcl12RegistrationINS_8PointXYZES1_fE5alignERNS_10PointCloudIS1_EERKN5Eigen6MatrixIfLi4ELi4ELi0ELi4ELi4EEE[_ZN3pcl12RegistrationINS_8PointXYZES1_fE5alignERNS_10PointCloudIS1_EERKN5Eigen6MatrixIfLi4ELi4ELi0ELi4ELi4EEE]+0x242): undefined reference to `pcl::search::KdTree<pcl::PointXYZ, pcl::KdTreeFLANN<pcl::PointXYZ, flann::L2_Simple<float> > >::setPointRepresentation(std::shared_ptr<pcl::PointRepresentation<pcl::PointXYZ> const> const&)'
/usr/bin/ld: CMakeFiles/ndt_test.dir/src/ndt_transform_calculator.cpp.o: in function `pcl::Registration<pcl::PointXYZ, pcl::PointXYZ, float>::Registration()':
ndt_transform_calculator.cpp:(.text._ZN3pcl12RegistrationINS_8PointXYZES1_fEC2Ev[_ZN3pcl12RegistrationINS_8PointXYZES1_fEC5Ev]+0x69): undefined reference to `pcl::search::KdTree<pcl::PointXYZ, pcl::KdTreeFLANN<pcl::PointXYZ, flann::L2_Simple<float> > >::KdTree(bool)'
/usr/bin/ld: ndt_transform_calculator.cpp:(.text._ZN3pcl12RegistrationINS_8PointXYZES1_fEC2Ev[_ZN3pcl12RegistrationINS_8PointXYZES1_fEC5Ev]+0x98): undefined reference to `pcl::search::KdTree<pcl::PointXYZ, pcl::KdTreeFLANN<pcl::PointXYZ, flann::L2_Simple<float> > >::KdTree(bool)'
/usr/bin/ld: CMakeFiles/ndt_test.dir/src/ndt_transform_calculator.cpp.o: in function `pcl::VoxelGridCovariance<pcl::PointXYZ>::VoxelGridCovariance()':
ndt_transform_calculator.cpp:(.text._ZN3pcl19VoxelGridCovarianceINS_8PointXYZEEC2Ev[_ZN3pcl19VoxelGridCovarianceINS_8PointXYZEEC5Ev]+0xe7): undefined reference to `pcl::KdTreeFLANN<pcl::PointXYZ, flann::L2_Simple<float> >::KdTreeFLANN(bool)'
/usr/bin/ld: CMakeFiles/ndt_test.dir/src/ndt_transform_calculator.cpp.o: in function `pcl::KdTreeFLANN<pcl::PointXYZ, flann::L2_Simple<float> >::~KdTreeFLANN()':
ndt_transform_calculator.cpp:(.text._ZN3pcl11KdTreeFLANNINS_8PointXYZEN5flann9L2_SimpleIfEEED2Ev[_ZN3pcl11KdTreeFLANNINS_8PointXYZEN5flann9L2_SimpleIfEEED5Ev]+0x26): undefined reference to `pcl::KdTreeFLANN<pcl::PointXYZ, flann::L2_Simple<float> >::cleanup()'
/usr/bin/ld: CMakeFiles/ndt_test.dir/src/ndt_transform_calculator.cpp.o: in function `pcl::VoxelGridCovariance<pcl::PointXYZ>::filter(bool)':
ndt_transform_calculator.cpp:(.text._ZN3pcl19VoxelGridCovarianceINS_8PointXYZEE6filterEb[_ZN3pcl19VoxelGridCovarianceINS_8PointXYZEE6filterEb]+0x135): undefined reference to `pcl::KdTreeFLANN<pcl::PointXYZ, flann::L2_Simple<float> >::setInputCloud(std::shared_ptr<pcl::PointCloud<pcl::PointXYZ> const> const&, std::shared_ptr<std::vector<int, std::allocator<int> > const> const&)'
/usr/bin/ld: CMakeFiles/ndt_test.dir/src/ndt_transform_calculator.cpp.o:(.data.rel.ro._ZTVN3pcl19VoxelGridCovarianceINS_8PointXYZEEE[_ZTVN3pcl19VoxelGridCovarianceINS_8PointXYZEEE]+0x48): undefined reference to `pcl::VoxelGridCovariance<pcl::PointXYZ>::applyFilter(pcl::PointCloud<pcl::PointXYZ>&)'
/usr/bin/ld: CMakeFiles/ndt_test.dir/src/ndt_transform_calculator.cpp.o:(.data.rel.ro._ZTVN3pcl9VoxelGridINS_8PointXYZEEE[_ZTVN3pcl9VoxelGridINS_8PointXYZEEE]+0x48): undefined reference to `pcl::VoxelGrid<pcl::PointXYZ>::applyFilter(pcl::PointCloud<pcl::PointXYZ>&)'
/usr/bin/ld: CMakeFiles/ndt_test.dir/src/ndt_transform_calculator.cpp.o:(.data.rel.ro._ZTVN3pcl11KdTreeFLANNINS_8PointXYZEN5flann9L2_SimpleIfEEEE[_ZTVN3pcl11KdTreeFLANNINS_8PointXYZEN5flann9L2_SimpleIfEEEE]+0x10): undefined reference to `pcl::KdTreeFLANN<pcl::PointXYZ, flann::L2_Simple<float> >::setInputCloud(std::shared_ptr<pcl::PointCloud<pcl::PointXYZ> const> const&, std::shared_ptr<std::vector<int, std::allocator<int> > const> const&)'
/usr/bin/ld: CMakeFiles/ndt_test.dir/src/ndt_transform_calculator.cpp.o:(.data.rel.ro._ZTVN3pcl11KdTreeFLANNINS_8PointXYZEN5flann9L2_SimpleIfEEEE[_ZTVN3pcl11KdTreeFLANNINS_8PointXYZEN5flann9L2_SimpleIfEEEE]+0x28): undefined reference to `pcl::KdTreeFLANN<pcl::PointXYZ, flann::L2_Simple<float> >::nearestKSearch(pcl::PointXYZ const&, unsigned int, std::vector<int, std::allocator<int> >&, std::vector<float, std::allocator<float> >&) const'
/usr/bin/ld: CMakeFiles/ndt_test.dir/src/ndt_transform_calculator.cpp.o:(.data.rel.ro._ZTVN3pcl11KdTreeFLANNINS_8PointXYZEN5flann9L2_SimpleIfEEEE[_ZTVN3pcl11KdTreeFLANNINS_8PointXYZEN5flann9L2_SimpleIfEEEE]+0x40): undefined reference to `pcl::KdTreeFLANN<pcl::PointXYZ, flann::L2_Simple<float> >::radiusSearch(pcl::PointXYZ const&, double, std::vector<int, std::allocator<int> >&, std::vector<float, std::allocator<float> >&, unsigned int) const'
/usr/bin/ld: CMakeFiles/ndt_test.dir/src/ndt_transform_calculator.cpp.o:(.data.rel.ro._ZTVN3pcl11KdTreeFLANNINS_8PointXYZEN5flann9L2_SimpleIfEEEE[_ZTVN3pcl11KdTreeFLANNINS_8PointXYZEN5flann9L2_SimpleIfEEEE]+0x58): undefined reference to `pcl::KdTreeFLANN<pcl::PointXYZ, flann::L2_Simple<float> >::setEpsilon(float)'
/usr/bin/ld: CMakeFiles/ndt_test.dir/src/ndt_transform_calculator.cpp.o: in function `pcl::VoxelGridCovariance<pcl::PointXYZ>::radiusSearch(pcl::PointXYZ const&, double, std::vector<pcl::VoxelGridCovariance<pcl::PointXYZ>::Leaf const*, std::allocator<pcl::VoxelGridCovariance<pcl::PointXYZ>::Leaf const*> >&, std::vector<float, std::allocator<float> >&, unsigned int) const':
ndt_transform_calculator.cpp:(.text._ZNK3pcl19VoxelGridCovarianceINS_8PointXYZEE12radiusSearchERKS1_dRSt6vectorIPKNS2_4LeafESaIS8_EERS5_IfSaIfEEj[_ZNK3pcl19VoxelGridCovarianceINS_8PointXYZEE12radiusSearchERKS1_dRSt6vectorIPKNS2_4LeafESaIS8_EERS5_IfSaIfEEj]+0xdc): undefined reference to `pcl::KdTreeFLANN<pcl::PointXYZ, flann::L2_Simple<float> >::radiusSearch(pcl::PointXYZ const&, double, std::vector<int, std::allocator<int> >&, std::vector<float, std::allocator<float> >&, unsigned int) const'
collect2: error: ld returned 1 exit status
gmake[2]: *** [CMakeFiles/ndt_test.dir/build.make:189: ndt_test] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:252: CMakeFiles/ndt_test.dir/all] Error 2
gmake: *** [Makefile:149: all] Error 2
---
Failed <<< cpp_tests [2.47s, exited with code 2]
Summary: 0 packages finished [2.66s]
1 package failed: cpp_tests
1 package had stderr output: cpp_tests
As far as I can tell, this is triggered by the line
pcl::NormalDistributionsTransform<pcl::PointXYZ, pcl::PointXYZ> ndt;
(Basically it compiles if I remove all references to NDT but I obviously can't do what I want to do.
#include <pcl/registration/ndt.h>
causes no problems, neither does initializing point clouds).
My CMakeLists file:
cmake_minimum_required(VERSION 3.8)
project(cpp_tests)
#Default to C++14
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra) # -Wpedantic)
endif()
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
find_package(sensor_msgs REQUIRED)
find_package(nav_msgs REQUIRED)
find_package(PCL 1.12 REQUIRED)
find_package (Eigen3 3.4 REQUIRED NO_MODULE)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})
add_executable(talker src/publisher_member_function.cpp)
ament_target_dependencies(talker rclcpp std_msgs)
add_executable(listener src/subscriber_member_function.cpp)
ament_target_dependencies(listener rclcpp std_msgs)
add_executable(pubsub src/publisher_subscriber_function.cpp)
ament_target_dependencies(pubsub rclcpp std_msgs)
add_executable(icp_test src/icp_transform_calculator.cpp)
ament_target_dependencies(icp_test rclcpp std_msgs PCL sensor_msgs nav_msgs)
add_executable(ndt_test src/ndt_transform_calculator.cpp)
ament_target_dependencies(ndt_test rclcpp std_msgs PCL sensor_msgs nav_msgs)
target_link_libraries (icp_test ${PCL_LIBRARIES} Eigen3::Eigen)
install(TARGETS
talker
listener
pubsub
icp_test
ndt_test
DESTINATION lib/${PROJECT_NAME})
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# comment the line when a copyright and license is added to all source files
set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# comment the line when this package is in a git repo and when
# a copyright and license is added to all source files
set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
ament_package()
The strangest part is that I did the same thing with ICP and that compiles without any problems. However, if I copy the contents of icp_transform_calculator.cpp into ndt_transform_calculator.cpp, I get basically the same linking error at pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp; instead.
(icp_transform_calculator.cpp compiles no problem at the same time with the exact same code and same dependencies).
At this point, I can't think of any reason for this issue, which is why I am posting it here. Is there any way to solve this issue?
Thank you.
EDIT:
Solved it (?). Adding
target_link_libraries (ndt_test ${PCL_LIBRARIES} Eigen3::Eigen)
to cmake_lists solved the issue. I still don't know what the source of the problem is (basically, why not linking Eigen would cause problems with PCL).
Originally posted by ALNA_Perera on ROS Answers with karma: 33 on 2023-06-06
Post score: 0
Original comments
Comment by 130s on 2023-06-06:
@ALNA_Perera Glad you resolved by yourself and thanks for sharing your resolution by updating your post.. Would you mind posting that as an answer, then mark it as "Answer" so that others can tell the question is resolved, and easily find the answer?
Comment by ALNA_Perera on 2023-06-06:
I will do that. I'm still not sure why that worked though.