diff --git a/pixi.lock b/pixi.lock index f0d7877..36f23bd 100644 --- a/pixi.lock +++ b/pixi.lock @@ -382,7 +382,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h4a9d5aa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ninja-1.13.2-h171cf75_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.11.3-he02047a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlopt-2.11.0-np2py312h0f77346_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda @@ -461,6 +461,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/tiledb-2.30.1-h8f647a8_15.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tinyxml2-11.0.0-h3f2d84a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tomlplusplus-3.3.0-hcb278e6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tzcode-2026b-h280c20c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/uncrustify-0.83.0-h54a6638_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-17.0.1-py312h4c3975b_0.conda @@ -1498,7 +1499,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h4a9d5aa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ninja-1.13.2-h171cf75_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.11.3-he02047a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlopt-2.11.0-np2py312h0f77346_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda @@ -1577,6 +1578,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/tiledb-2.30.1-h8f647a8_15.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tinyxml2-11.0.0-h3f2d84a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tomlplusplus-3.3.0-hcb278e6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tzcode-2026b-h280c20c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/uncrustify-0.83.0-h54a6638_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-17.0.1-py312h4c3975b_0.conda @@ -2603,7 +2605,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/nanoflann-1.6.1-hff21bea_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h4a9d5aa_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.11.3-he02047a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlopt-2.11.0-np2py312h0f77346_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda @@ -2681,6 +2683,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/tiledb-2.30.1-h8f647a8_15.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tinyxml2-11.0.0-h3f2d84a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tomlplusplus-3.3.0-hcb278e6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tzcode-2026b-h280c20c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/uncrustify-0.83.0-h54a6638_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-17.0.1-py312h4c3975b_0.conda @@ -3787,7 +3790,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/nanoflann-1.6.1-hff21bea_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h4a9d5aa_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.11.3-he02047a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlopt-2.11.0-np2py312h0f77346_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda @@ -3865,6 +3868,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/tiledb-2.30.1-h8f647a8_15.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tinyxml2-11.0.0-h3f2d84a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tomlplusplus-3.3.0-hcb278e6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tzcode-2026b-h280c20c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/uncrustify-0.83.0-h54a6638_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-17.0.1-py312h4c3975b_0.conda @@ -4893,7 +4897,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h4a9d5aa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ninja-1.13.2-h171cf75_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.11.3-he02047a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlopt-2.11.0-np2py312h0f77346_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda @@ -4972,6 +4976,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/tiledb-2.30.1-h8f647a8_15.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tinyxml2-11.0.0-h3f2d84a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tomlplusplus-3.3.0-hcb278e6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tzcode-2026b-h280c20c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/uncrustify-0.83.0-h54a6638_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-17.0.1-py312h4c3975b_0.conda @@ -6001,7 +6006,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h4a9d5aa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ninja-1.13.2-h171cf75_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.11.3-he02047a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlopt-2.11.0-np2py312h0f77346_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda @@ -6080,6 +6085,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/tiledb-2.30.1-h8f647a8_15.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tinyxml2-11.0.0-h3f2d84a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tomlplusplus-3.3.0-hcb278e6_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tzcode-2026b-h280c20c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/uncrustify-0.83.0-h54a6638_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-17.0.1-py312h4c3975b_0.conda @@ -13456,16 +13462,18 @@ packages: run_exports: {} size: 186323 timestamp: 1763688260928 -- conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda - sha256: fd2cbd8dfc006c72f45843672664a8e4b99b2f8137654eaae8c3d46dca776f63 - md5: 16c2a0e9c4a166e53632cfca4f68d020 - constrains: - - nlohmann_json-abi ==3.12.0 +- conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.11.3-he02047a_1.conda + sha256: ce4bcced4f8eea71b7cac8bc3daac097abf7a5792f278cd811dedada199500c1 + md5: e46f7ac4917215b49df2ea09a694a3fa + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc-ng >=12 + - libstdcxx-ng >=12 license: MIT license_family: MIT run_exports: {} - size: 136216 - timestamp: 1758194284857 + size: 122743 + timestamp: 1723652407663 - conda: https://conda.anaconda.org/conda-forge/linux-64/nlopt-2.11.0-np2py312h0f77346_1.conda sha256: 1020e8c934aa3ccf12704e15c758b1629ed66079a44d6c6a00c524188ed56f49 md5: 4db67f3defb6b2f969b8631d6f732e6e @@ -15069,6 +15077,17 @@ packages: - tk >=8.6.13,<8.7.0a0 size: 3301196 timestamp: 1769460227866 +- conda: https://conda.anaconda.org/conda-forge/linux-64/tomlplusplus-3.3.0-hcb278e6_0.conda + sha256: c731301896e33e177f0a9fed1867fa620072fb2598196fce1a4f6776e80f0b5c + md5: 7889e87a703ca4dc0dc78aea89296410 + depends: + - libgcc-ng >=12 + - libstdcxx-ng >=12 + license: MIT + license_family: MIT + run_exports: {} + size: 100241 + timestamp: 1675026801832 - conda: https://conda.anaconda.org/conda-forge/linux-64/tzcode-2026b-h280c20c_0.conda sha256: 35da5b89561ed93629f751f111a092abcaaa9fdc516e09e9b4ab9880756a1871 md5: 5c5f9b9bad2a0852ffa38833ba2a1c7d diff --git a/pixi.toml b/pixi.toml index a7918cf..ff2c4ca 100644 --- a/pixi.toml +++ b/pixi.toml @@ -44,7 +44,8 @@ c-compiler = "*" cxx-compiler = "*" pkg-config = "*" qt-main = "*" -nlohmann_json = "*" +nlohmann_json = "3.11.3.*" +tomlplusplus = "3.3.0.*" rust = ">=1.96.0,<1.97" # ─── Workspace tasks ──────────────────────────────────────────────────────────── diff --git a/ros2_ws/src/mobile_manipulator_hmi/CMakeLists.txt b/ros2_ws/src/mobile_manipulator_hmi/CMakeLists.txt index 7fc8168..50385c9 100644 --- a/ros2_ws/src/mobile_manipulator_hmi/CMakeLists.txt +++ b/ros2_ws/src/mobile_manipulator_hmi/CMakeLists.txt @@ -69,20 +69,19 @@ find_package(rai_interfaces REQUIRED) # custom Utilization message # add source directory to include path include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -# --- nlohmann/json dependency --- -include(FetchContent) -FetchContent_Declare( - json - GIT_REPOSITORY https://github.com/nlohmann/json.git - GIT_TAG v3.11.3 # or latest -) -FetchContent_MakeAvailable(json) +# --- nlohmann/json dependency (from conda-forge) --- +find_package(nlohmann_json REQUIRED) + +# --- toml++ dependency (config.toml parsing, from conda-forge) --- +find_package(tomlplusplus REQUIRED) set(PROJECT_SOURCES main.cpp ZoomableGraphicsView.h ZoomableGraphicsView.cpp Config.h + ModelConfig.h + ModelConfig.cpp LogItemWidget.h LogItemWidget.cpp LogView.h @@ -127,6 +126,7 @@ target_link_libraries(MobileManipulatorHMI PRIVATE cv_bridge::cv_bridge ${OpenCV_LIBS} # OpenCV provides targets like OpenCV::Core, but ${OpenCV_LIBS} is usually set nlohmann_json::nlohmann_json + tomlplusplus::tomlplusplus ) # Install targets diff --git a/ros2_ws/src/mobile_manipulator_hmi/Config.h b/ros2_ws/src/mobile_manipulator_hmi/Config.h index 82431f8..c2ab8cf 100644 --- a/ros2_ws/src/mobile_manipulator_hmi/Config.h +++ b/ros2_ws/src/mobile_manipulator_hmi/Config.h @@ -52,8 +52,6 @@ namespace HardcodedConfig { const static char UserPromptTopic[] = "/user_tasks"; const static char OrchestratorHeartbeat[] = "/orchestrator/heartbeat"; // TODO: Get actual topic names // - const static QString SelectedLLMModel = "gpt-oss-20B"; - const static QString SelectedVLMModel = "LFM2-VL-3B | Gemma4-4B"; const static char VLMTopic[] = "/vlm_topic"; const static char EmergencyStopTopic[] = "/emergency_stop"; diff --git a/ros2_ws/src/mobile_manipulator_hmi/ModelConfig.cpp b/ros2_ws/src/mobile_manipulator_hmi/ModelConfig.cpp new file mode 100644 index 0000000..7afa445 --- /dev/null +++ b/ros2_ws/src/mobile_manipulator_hmi/ModelConfig.cpp @@ -0,0 +1,72 @@ +// Copyright (C) 2026 Advanced Micro Devices, Inc. +// Developed by Robotec.ai sp. z o.o. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "ModelConfig.h" + +#include +#include + +QString defaultModelConfigPath() +{ + const QString demoRoot = qEnvironmentVariable("DEMO_ROOT"); + if (!demoRoot.isEmpty()) { + return demoRoot + "/config.toml"; + } + return QStringLiteral("config.toml"); +} + +ModelNames loadModelNames(const QString &configPath) +{ + ModelNames names{QStringLiteral("unknown"), QStringLiteral("unknown")}; + + toml::table config; + try { + config = toml::parse_file(configPath.toStdString()); + } catch (const std::exception &) { + return names; + } + + const toml::table *endpoints = config["endpoints"].as_table(); + if (!endpoints) { + return names; + } + + // LLM: the endpoint referenced by [general].llm + if (auto llmRef = config["general"]["llm"].value()) { + if (auto model = (*endpoints)[*llmRef]["model"].value()) { + names.llm = QString::fromStdString(*model); + } + } + + // VLM: every distinct model served by an endpoint of type "vlm" + QStringList vlmModels; + for (const auto &[endpointName, node] : *endpoints) { + const toml::table *endpoint = node.as_table(); + if (!endpoint || (*endpoint)["type"].value_or(std::string{}) != "vlm") { + continue; + } + if (auto model = (*endpoint)["model"].value()) { + const QString modelName = QString::fromStdString(*model); + if (!vlmModels.contains(modelName)) { + vlmModels << modelName; + } + } + } + if (!vlmModels.isEmpty()) { + names.vlm = vlmModels.join(QStringLiteral(" | ")); + } + + return names; +} diff --git a/ros2_ws/src/mobile_manipulator_hmi/ModelConfig.h b/ros2_ws/src/mobile_manipulator_hmi/ModelConfig.h new file mode 100644 index 0000000..c0cbd06 --- /dev/null +++ b/ros2_ws/src/mobile_manipulator_hmi/ModelConfig.h @@ -0,0 +1,31 @@ +// Copyright (C) 2026 Advanced Micro Devices, Inc. +// Developed by Robotec.ai sp. z o.o. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +struct ModelNames { + QString llm; + QString vlm; +}; + +// $DEMO_ROOT/config.toml when DEMO_ROOT is set, otherwise ./config.toml +// (which may be a symlink placed next to the HMI's working directory). +QString defaultModelConfigPath(); + +// Reads the inference SSOT (config.toml) and returns the model names to +// display. Never throws: a missing or malformed file yields "unknown". +ModelNames loadModelNames(const QString &configPath); diff --git a/ros2_ws/src/mobile_manipulator_hmi/hmiWindow.cpp b/ros2_ws/src/mobile_manipulator_hmi/hmiWindow.cpp index 56cfdd2..2ade59e 100644 --- a/ros2_ws/src/mobile_manipulator_hmi/hmiWindow.cpp +++ b/ros2_ws/src/mobile_manipulator_hmi/hmiWindow.cpp @@ -26,6 +26,7 @@ #include #include #include "LogView.h" +#include "ModelConfig.h" #include "ParseRaiData.h" QString HRIMessageToString(const ParseRaiData::HRIMessage& msg) @@ -273,8 +274,9 @@ HMIWindow::HMIWindow(QWidget *parent) ui->graphicsViewMap->setDragMode(QGraphicsView::RubberBandDrag); ui->graphicsViewMap->setRenderHint(QPainter::Antialiasing); ui->graphicsViewMap->setTransformationAnchor(QGraphicsView::AnchorUnderMouse); - ui->llm_text_field->setText(HardcodedConfig::SelectedLLMModel); - ui->vlm_text_field->setText(HardcodedConfig::SelectedVLMModel); + const ModelNames models = loadModelNames(defaultModelConfigPath()); + ui->llm_text_field->setText(models.llm); + ui->vlm_text_field->setText(models.vlm); logView_ = new LogView(this); queueView_ = new LogView(this);