Skip to content

Commit ff56026

Browse files
Add MOLA on MRPT 3 (#117)
Closes #106, porting RoboStack/ros-lyrical#30: adds mola (MOLA 3.x on MRPT 3) to the shared selection, on all platforms (humble, jazzy, lyrical, rolling). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent e4b09b7 commit ff56026

23 files changed

Lines changed: 732 additions & 0 deletions

‎distros/humble/patch/dependencies.yaml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ mimick_vendor:
6262
add_build: ["vcstool"]
6363
moveit_visual_tools:
6464
add_host: ["${{ 'libgl-devel' if linux }}", "${{ 'libopengl-devel' if linux }}"]
65+
mrpt_gui:
66+
# Overrides shared/: this distribution maps Qt to qt-main 5.15, whose builds need
67+
# gstreamer <1.27, while the pinned wxwidgets (3.3.3) needs gstreamer 1.28. A version
68+
# spec bypasses that pin, so the solver picks a wxwidgets that coexists with qt-main.
69+
add_host: ["wxwidgets >=3.2", "${{ 'glad' if win }}"] # glad: as in shared/
6570
nav2_constrained_smoother:
6671
add_host: ["${{ 'openblas' if win }}"]
6772
nav2_util:

‎distros/jazzy/patch/dependencies.yaml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ mimick_vendor:
101101
add_host: ["setuptools <81"]
102102
moveit_visual_tools:
103103
add_host: ["${{ 'libgl-devel' if linux }}", "${{ 'libopengl-devel' if linux }}"]
104+
mrpt_gui:
105+
# Overrides shared/: this distribution maps Qt to qt-main 5.15, whose builds need
106+
# gstreamer <1.27, while the pinned wxwidgets (3.3.3) needs gstreamer 1.28. A version
107+
# spec bypasses that pin, so the solver picks a wxwidgets that coexists with qt-main.
108+
add_host: ["wxwidgets >=3.2", "${{ 'glad' if win }}"] # glad: as in shared/
104109
nav2_constrained_smoother:
105110
add_host: ["${{ 'openblas' if win }}"]
106111
nav2_mppi_controller:

‎shared/patch/dependencies.yaml‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,29 @@ moveit_setup_framework:
7878
add_host: ["${{ 'libgl-devel' if linux }}", "${{ 'libopengl-devel' if linux }}"]
7979
moveit_setup_srdf_plugins:
8080
add_host: ["${{ 'libgl-devel' if linux }}", "${{ 'libopengl-devel' if linux }}"]
81+
mrpt_common:
82+
# CMakeLists.txt calls find_package(ament_cmake) when ROS_VERSION=2 (set by ros_environment),
83+
# but package.xml (build_type cmake) does not declare it
84+
add_host: ["ros2-ament-cmake"]
85+
mrpt_gui:
86+
# links libwx_*; the wxwidgets/wx-common keys map to wxpython, so wxwidgets is only a
87+
# transitive host dep and its (weak) run_exports never reach the run requirements
88+
# Windows: nanogui links conda-forge's glad instead of its bundled copy (ros2-mrpt-gui.win.patch)
89+
add_host: ["wxwidgets", "${{ 'glad' if win }}"]
90+
mrpt_imgui:
91+
# Windows: links conda-forge's GLEW like mrpt_opengl, also for its users (ros2-mrpt-imgui.win.patch)
92+
add_host: ["${{ 'glew' if win }}"]
93+
add_run: ["${{ 'glew' if win }}"]
94+
mrpt_math:
95+
# its public headers include Eigen, and its exported CMake targets (and mrpt_poses') carry
96+
# the eigen3 include directory: users need the headers (eigen-abi-devel's run_exports only
97+
# add eigen-abi), or dependents without their own eigen dependency fail to configure
98+
add_run: ["eigen"]
99+
mrpt_opengl:
100+
# Windows: the release source has no bundled GLEW (ros2-mrpt-opengl.win.patch); users of
101+
# opengl_api.h need GL/glew.h too
102+
add_host: ["${{ 'glew' if win }}"]
103+
add_run: ["${{ 'glew' if win }}"]
81104
mujoco_ros2_control_plugins:
82105
add_host:
83106
- if: linux
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
diff --git a/CMakeLists.txt b/CMakeLists.txt
2+
index 1002ccf..fc37b9a 100644
3+
--- a/CMakeLists.txt
4+
+++ b/CMakeLists.txt
5+
@@ -85,6 +85,10 @@ mola_add_library(
6+
# Same for mrpt_libros_bridge
7+
mola_version_to_hexadecimal(mrpt_libros_bridge_VERSION_HEX ${mrpt_libros_bridge_VERSION})
8+
target_compile_definitions(${PROJECT_NAME} PRIVATE MRPT_ROS2_BRIDGE_VERSION=${mrpt_libros_bridge_VERSION_HEX})
9+
+if(MSVC)
10+
+ # error C1128: number of sections exceeded object file format limit
11+
+ target_compile_options(${PROJECT_NAME} PRIVATE /bigobj)
12+
+endif()
13+
message(STATUS "Found: mrpt_libros_bridge_VERSION: ${mrpt_libros_bridge_VERSION} (${mrpt_libros_bridge_VERSION_HEX})")
14+
15+
if (gps_msgs_FOUND)
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
diff --git a/include/mola_kernel/interfaces/DiagnosticsProvider.h b/include/mola_kernel/interfaces/DiagnosticsProvider.h
2+
index 9ee9be8..fb7423d 100644
3+
--- a/include/mola_kernel/interfaces/DiagnosticsProvider.h
4+
+++ b/include/mola_kernel/interfaces/DiagnosticsProvider.h
5+
@@ -22,6 +22,12 @@
6+
#include <string>
7+
#include <vector>
8+
9+
+// windows.h (wingdi.h) defines ERROR, which breaks DiagnosticLevel::ERROR below
10+
+// (the generated diagnostic_msgs headers do the same)
11+
+#if defined(_WIN32) && defined(ERROR)
12+
+#undef ERROR
13+
+#endif
14+
+
15+
namespace mola
16+
{
17+
/** \addtogroup mola_kernel_interfaces_grp
18+
diff --git a/include/mola_kernel/interfaces/VizInterface.h b/include/mola_kernel/interfaces/VizInterface.h
19+
index e86f489..1d67359 100644
20+
--- a/include/mola_kernel/interfaces/VizInterface.h
21+
+++ b/include/mola_kernel/interfaces/VizInterface.h
22+
@@ -147,10 +147,12 @@ class VizInterface
23+
[[nodiscard]] virtual const std::string& gui_backend() const noexcept = 0;
24+
25+
/// Canonical backend name returned by MolaViz (nanogui).
26+
- static const std::string BACKEND_NANOGUI; // defined in VizInterface.cpp as "nanogui"
27+
+ // RoboStack: inline, so Windows DLLs using it need no exported data symbol
28+
+ static inline const std::string BACKEND_NANOGUI = "nanogui";
29+
30+
/// Canonical backend name returned by MolaVizImGui (Dear ImGui).
31+
- static const std::string BACKEND_IMGUI; // defined in VizInterface.cpp as "imgui"
32+
+ // RoboStack: inline, so Windows DLLs using it need no exported data symbol
33+
+ static inline const std::string BACKEND_IMGUI = "imgui";
34+
35+
/**
36+
* \brief Installs or replaces the menu bar of a parent window.
37+
diff --git a/src/interfaces/VizInterface.cpp b/src/interfaces/VizInterface.cpp
38+
index 8b207c8..1caa66f 100644
39+
--- a/src/interfaces/VizInterface.cpp
40+
+++ b/src/interfaces/VizInterface.cpp
41+
@@ -24,7 +24,5 @@ namespace mola
42+
43+
VizInterface::~VizInterface() = default;
44+
45+
-const std::string VizInterface::BACKEND_NANOGUI = "nanogui";
46+
-const std::string VizInterface::BACKEND_IMGUI = "imgui";
47+
48+
} // namespace mola
49+
\ No newline at end of file
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
diff --git a/src/MolaDLL_Loader.cpp b/src/MolaDLL_Loader.cpp
2+
--- a/src/MolaDLL_Loader.cpp
3+
+++ b/src/MolaDLL_Loader.cpp
4+
@@ -24,7 +24,7 @@
5+
6+
#include <map>
7+
8+
-#if defined(__unix__)
9+
+#if defined(__unix__) || defined(__APPLE__)
10+
#include <dlfcn.h>
11+
#endif
12+
13+
@@ -39,7 +39,9 @@
14+
{
15+
MRPT_TRY_START
16+
17+
-#if defined(__unix__)
18+
+#if defined(__APPLE__)
19+
+#define DLL_EXT "dylib"
20+
+#elif defined(__unix__)
21+
#define DLL_EXT "so"
22+
#else
23+
#define DLL_EXT "dll"
24+
@@ -59,11 +61,14 @@
25+
for (const auto& lib : lst)
26+
{
27+
if (lib.name.find("mola") == std::string::npos) continue; // skip
28+
+ // ROS interface libraries (e.g. mola_msgs) are never MOLA modules, and the
29+
+ // Python ones cannot be dlopen()ed from a non-Python process:
30+
+ if (lib.name.find("__rosidl_") != std::string::npos) continue; // skip
31+
32+
// Already loaded?
33+
if (loaded_lib_handled.count(lib.name) != 0) continue; // skip
34+
35+
-#if defined(__unix__)
36+
+#if defined(__unix__) || defined(__APPLE__)
37+
// Check if already loaded?
38+
{
39+
void* handle = dlopen(lib.wholePath.c_str(), RTLD_NOLOAD);
40+
@@ -109,7 +114,7 @@
41+
{
42+
// printf("[mola-launcher] Unloading: %s\n",
43+
// lib.second.lib_path.c_str());
44+
-#if defined(__unix__)
45+
+#if defined(__unix__) || defined(__APPLE__)
46+
dlclose(lib.second.handle);
47+
#else
48+
FreeLibrary(lib.second.handle);
49+
diff --git a/src/MolaLauncherApp.cpp b/src/MolaLauncherApp.cpp
50+
--- a/src/MolaLauncherApp.cpp
51+
+++ b/src/MolaLauncherApp.cpp
52+
@@ -119,6 +119,18 @@
53+
// do not filter these ones by *directory* name, since *filenames* will be
54+
// filtered later on:
55+
from_env_var_to_list("LD_LIBRARY_PATH", lib_search_paths_);
56+
+
57+
+ // conda/RoboStack environments do not set LD_LIBRARY_PATH: also search
58+
+ // <prefix>/lib (<prefix>/bin for Windows DLLs) for every prefix in AMENT_PREFIX_PATH.
59+
+ {
60+
+ std::vector<std::string> prefixes;
61+
+ from_env_var_to_list("AMENT_PREFIX_PATH", prefixes);
62+
+#if defined(_WIN32)
63+
+ for (const auto& prefix : prefixes) safe_add_to_list(prefix + "/bin", lib_search_paths_);
64+
+#else
65+
+ for (const auto& prefix : prefixes) safe_add_to_list(prefix + "/lib", lib_search_paths_);
66+
+#endif
67+
+ }
68+
}
69+
70+
MolaLauncherApp::~MolaLauncherApp()
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
diff --git a/apps/mola-cli.cpp b/apps/mola-cli.cpp
2+
index 2bd97ff..d77ceda 100644
3+
--- a/apps/mola-cli.cpp
4+
+++ b/apps/mola-cli.cpp
5+
@@ -23,7 +23,11 @@
6+
#include <mrpt/core/exceptions.h>
7+
#include <mrpt/rtti/CObject.h>
8+
#include <mrpt/system/filesystem.h>
9+
+#if defined(_WIN32)
10+
+#include <io.h> // _write()
11+
+#else
12+
#include <unistd.h> // write()
13+
+#endif
14+
15+
#include <CLI/CLI.hpp>
16+
#include <atomic>
17+
@@ -48,7 +52,11 @@ void mola_signal_handler([[maybe_unused]] int s)
18+
// raw write() to stderr. The actual shutdown (which logs, sleeps and joins
19+
// threads) is done by the main thread as soon as spin() returns.
20+
static const char msg[] = "\nTermination signal caught. Shutting down...\n";
21+
+#if defined(_WIN32)
22+
+ [[maybe_unused]] const auto n = ::_write(2, msg, sizeof(msg) - 1);
23+
+#else
24+
[[maybe_unused]] const auto n = ::write(STDERR_FILENO, msg, sizeof(msg) - 1);
25+
+#endif
26+
27+
if (auto* app = theApp.load())
28+
{
29+
@@ -58,6 +66,11 @@ void mola_signal_handler([[maybe_unused]] int s)
30+
31+
void mola_install_signal_handler()
32+
{
33+
+#if defined(_WIN32)
34+
+ // No sigaction() on Windows:
35+
+ std::signal(SIGINT, &mola_signal_handler);
36+
+ std::signal(SIGTERM, &mola_signal_handler);
37+
+#else
38+
struct sigaction sigIntHandler;
39+
40+
sigIntHandler.sa_handler = &mola_signal_handler;
41+
@@ -71,6 +84,7 @@ void mola_install_signal_handler()
42+
// the main MOLA loop keeps running, so the process never exits and lingers
43+
// with its ROS 2 endpoints still advertised but no longer served.
44+
sigaction(SIGTERM, &sigIntHandler, nullptr);
45+
+#endif
46+
}
47+
48+
// Default task for mola-cli: launching a SLAM system
49+
diff --git a/src/MolaDLL_Loader.cpp b/src/MolaDLL_Loader.cpp
50+
index ec376eb..6dcee68 100644
51+
--- a/src/MolaDLL_Loader.cpp
52+
+++ b/src/MolaDLL_Loader.cpp
53+
@@ -26,6 +26,11 @@
54+
55+
#if defined(__unix__) || defined(__APPLE__)
56+
#include <dlfcn.h>
57+
+#elif defined(_WIN32)
58+
+#ifndef NOMINMAX
59+
+#define NOMINMAX
60+
+#endif
61+
+#include <windows.h> // LoadLibraryA(), FreeLibrary()
62+
#endif
63+
64+
/** From internal_load_lib_modules() */
65+
@@ -81,11 +86,17 @@ void internal_load_lib_modules(
66+
67+
void* handle = dlopen(lib.wholePath.c_str(), RTLD_LAZY);
68+
#else
69+
- HMODULE handle = LoadLibrary(lib.wholePath.c_str());
70+
+ void* handle = LoadLibraryA(lib.wholePath.c_str());
71+
#endif
72+
if (handle == nullptr)
73+
{
74+
+#if defined(_WIN32)
75+
+ const std::string err_str =
76+
+ mrpt::format("LoadLibrary() error code %lu", static_cast<unsigned long>(GetLastError()));
77+
+ const char* err = err_str.c_str();
78+
+#else
79+
const char* err = dlerror();
80+
+#endif
81+
if (!err) err = "(error calling dlerror())";
82+
THROW_EXCEPTION(mrpt::format(
83+
"Error loading module: `%s`\ndlerror(): `%s`", lib.wholePath.c_str(), err));
84+
@@ -117,7 +128,7 @@ void internal_unload_lib_modules()
85+
#if defined(__unix__) || defined(__APPLE__)
86+
dlclose(lib.second.handle);
87+
#else
88+
- FreeLibrary(lib.second.handle);
89+
+ FreeLibrary(static_cast<HMODULE>(lib.second.handle));
90+
#endif
91+
}
92+
loaded_lib_handled.clear();
93+
diff --git a/src/MolaLauncherApp.cpp b/src/MolaLauncherApp.cpp
94+
index d939bfe..37be9fc 100644
95+
--- a/src/MolaLauncherApp.cpp
96+
+++ b/src/MolaLauncherApp.cpp
97+
@@ -99,7 +99,7 @@ std::string relative_to_abs_path(
98+
if (f.is_relative())
99+
{
100+
f = fs::path(*basePath) / f;
101+
- return f;
102+
+ return f.string(); // no implicit conversion on Windows (wchar_t paths)
103+
}
104+
else
105+
return path;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
diff --git a/CMakeLists.txt b/CMakeLists.txt
2+
index 775a066..073a5f8 100644
3+
--- a/CMakeLists.txt
4+
+++ b/CMakeLists.txt
5+
@@ -187,7 +187,8 @@ add_subdirectory(apps)
6+
# -----------------------
7+
# define tests:
8+
enable_testing()
9+
-add_subdirectory(tests)
10+
+# RoboStack: not on Windows, the tests use POSIX setenv()/unsetenv()
11+
+# add_subdirectory(tests)
12+
13+
# -----------------------------------------------------------------------------
14+
# ROS2
15+
diff --git a/src/KeyframePointCloudMap.cpp b/src/KeyframePointCloudMap.cpp
16+
index 74b2701..1a38249 100644
17+
--- a/src/KeyframePointCloudMap.cpp
18+
+++ b/src/KeyframePointCloudMap.cpp
19+
@@ -1864,7 +1864,8 @@ namespace
20+
/// axis with a large centering offset, covering ~ +/-1e6 voxels per axis.
21+
inline int64_t voxelKey(float x, float y, float z, double inv_voxel)
22+
{
23+
- constexpr int64_t kOffset = 1 << 20; // center the range around 0
24+
+ // RoboStack: static, so the lambda below needn't capture it (MSVC requires that, C3493)
25+
+ static constexpr int64_t kOffset = 1 << 20; // center the range around 0
26+
const auto q = [inv_voxel](float c)
27+
{ return static_cast<int64_t>(std::floor(static_cast<double>(c) * inv_voxel)) + kOffset; };
28+
const int64_t ix = q(x);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
diff --git a/include/mola_yaml/macro_helpers.h b/include/mola_yaml/macro_helpers.h
2+
index 0f76953..cb7c4a4 100644
3+
--- a/include/mola_yaml/macro_helpers.h
4+
+++ b/include/mola_yaml/macro_helpers.h
5+
@@ -48,7 +48,10 @@
6+
// which corresponds to the actual argument count (up to 10 args supported).
7+
// ---------------------------------------------------------------------------
8+
#define MOLA_NARG(...) MOLA_NARG_I_(__VA_ARGS__, MOLA_RSEQ_N())
9+
-#define MOLA_NARG_I_(...) MOLA_ARG_N(__VA_ARGS__)
10+
+// MSVC's traditional preprocessor passes __VA_ARGS__ on as one argument unless
11+
+// it is rescanned through another macro:
12+
+#define MOLA_EXPAND_(x) x
13+
+#define MOLA_NARG_I_(...) MOLA_EXPAND_(MOLA_ARG_N(__VA_ARGS__))
14+
15+
/** Picks the 11th argument - used internally by MOLA_NARG. */
16+
#define MOLA_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
17+
@@ -80,4 +83,4 @@
18+
* @param func Base name of the macro family (without trailing digit).
19+
* @param ... Arguments forwarded verbatim to the selected overload.
20+
*/
21+
-#define VFUNC(func, ...) MOLA_VFUNC(func, MOLA_NARG(__VA_ARGS__))(__VA_ARGS__)
22+
+#define VFUNC(func, ...) MOLA_EXPAND_(MOLA_VFUNC(func, MOLA_NARG(__VA_ARGS__))(__VA_ARGS__))

0 commit comments

Comments
 (0)