@rainbow-robotics/muscat-plugin-kit 1.3.2 → 1.3.3-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/docker/Dockerfile.cpp +22 -5
- package/cli/docker/Dockerfile.dev +25 -5
- package/cli/docker/Dockerfile.python +19 -0
- package/cli/src/bridge.mjs +19 -2
- package/cli/src/build.mjs +31 -79
- package/cli/src/cpp.mjs +10 -6
- package/cli/src/dev.mjs +7 -2
- package/cli/src/devBack.mjs +39 -32
- package/cli/src/host_agent.py +143 -83
- package/cli/src/mcp.mjs +75 -16
- package/cli/src/new.mjs +5 -2
- package/cli/src/ports.mjs +21 -7
- package/cli/src/python.mjs +9 -17
- package/cli/src/ros2.mjs +13 -8
- package/cli/src/sdk.mjs +23 -21
- package/cli/src/templates-embedded.mjs +1 -1
- package/cli/src/type.mjs +42 -8
- package/cli/src/util.mjs +53 -5
- package/cli/storybook-dist/assets/{Color-YHDXOIA2-CRNvRzJD.js → Color-YHDXOIA2-DNIJVGRw.js} +1 -1
- package/cli/storybook-dist/assets/{Docs-80l_9VTs.js → Docs-CIT3omBi.js} +1 -1
- package/cli/storybook-dist/assets/{Docs-BgDx9SSn.js → Docs-CdX_ToEv.js} +1 -1
- package/cli/storybook-dist/assets/{Docs-BV0FgAF_.js → Docs-D9eMx0Cp.js} +1 -1
- package/cli/storybook-dist/assets/{Docs-C4S_Kfa9.js → Docs-RJox-ekp.js} +1 -1
- package/cli/storybook-dist/assets/{Docs-axk94PIl.js → Docs-wnrZBY76.js} +1 -1
- package/cli/storybook-dist/assets/{Docs-DurNQvJo.js → Docs-x99QNSvG.js} +1 -1
- package/cli/storybook-dist/assets/{DocsRenderer-CFRXHY34-CEdKXElc.js → DocsRenderer-CFRXHY34-CPuvjoGb.js} +1 -1
- package/cli/storybook-dist/assets/{NxAvatar.stories-CyZ4AE2b.js → NxAvatar.stories-B3OxXBgc.js} +1 -1
- package/cli/storybook-dist/assets/{NxButton.stories-Bx8UtGNd.js → NxButton.stories-UTqX8ZkA.js} +1 -1
- package/cli/storybook-dist/assets/{NxNumberInput.stories-skizAdd5.js → NxNumberInput.stories-GoLEe-uJ.js} +1 -1
- package/cli/storybook-dist/assets/{NxPagination.stories-gtIxt2u0.js → NxPagination.stories-Jj6dt6eG.js} +1 -1
- package/cli/storybook-dist/assets/{NxPointerHoldButton.stories-DSHMk3N5.js → NxPointerHoldButton.stories-tLN9u4nC.js} +1 -1
- package/cli/storybook-dist/assets/{NxRangeInput.stories-C1YtrFZ1.js → NxRangeInput.stories-C-MK73xb.js} +1 -1
- package/cli/storybook-dist/assets/{NxSelectBox.stories-DCySAtBp.js → NxSelectBox.stories-CBcFcOIX.js} +1 -1
- package/cli/storybook-dist/assets/{NxSlideRange.stories-gSaMOWo7.js → NxSlideRange.stories-oNQkoW66.js} +1 -1
- package/cli/storybook-dist/assets/{NxSwitch.stories-DF0DBiyG.js → NxSwitch.stories-CqBkO5GC.js} +1 -1
- package/cli/storybook-dist/assets/{NxTextArea.stories-Dill0M6z.js → NxTextArea.stories-DtysSyl4.js} +1 -1
- package/cli/storybook-dist/assets/{NxTextInput.stories-Bax14r48.js → NxTextInput.stories-BOLDbSgF.js} +1 -1
- package/cli/storybook-dist/assets/{RBAccordion.stories-CCwz_pIV.js → RBAccordion.stories-D9-wu9LY.js} +1 -1
- package/cli/storybook-dist/assets/{RBAccordionGroup.stories-BjDxxdPV.js → RBAccordionGroup.stories-BPfnIKm6.js} +1 -1
- package/cli/storybook-dist/assets/{RBAlert.stories-5z6GasgP.js → RBAlert.stories-CGn-c2ac.js} +1 -1
- package/cli/storybook-dist/assets/{RBBadge.stories-BwcM7i7w.js → RBBadge.stories-CBLmeoq1.js} +1 -1
- package/cli/storybook-dist/assets/{RBBattery.stories-DOeQH3rK.js → RBBattery.stories-oo47rbDh.js} +1 -1
- package/cli/storybook-dist/assets/{RBCard.stories-DcmiOXAV.js → RBCard.stories-SiD2VfQ4.js} +1 -1
- package/cli/storybook-dist/assets/{RBCheckBox.stories-BYru87fX.js → RBCheckBox.stories-sEEVrjSg.js} +1 -1
- package/cli/storybook-dist/assets/{RBCheckIconButton.stories-CXUjtR1a.js → RBCheckIconButton.stories-C5GQUjZf.js} +1 -1
- package/cli/storybook-dist/assets/{RBCheckLabelButton.stories-BSOQV7Du.js → RBCheckLabelButton.stories-DTaTqBvJ.js} +1 -1
- package/cli/storybook-dist/assets/{RBChipTab.stories-ByBmeukU.js → RBChipTab.stories-3AZr4kOz.js} +1 -1
- package/cli/storybook-dist/assets/{RBChipsBoxTab.stories-GtJ01RTr.js → RBChipsBoxTab.stories-hCJnBYQl.js} +1 -1
- package/cli/storybook-dist/assets/{RBColorIcons.stories-C9saET1u.js → RBColorIcons.stories-BX4RJygu.js} +1 -1
- package/cli/storybook-dist/assets/{RBCommand.stories-CcvnWlWZ.js → RBCommand.stories-BidZ4H8f.js} +1 -1
- package/cli/storybook-dist/assets/{RBConfirm.stories-hdBVSdBS.js → RBConfirm.stories-D3Txw1kT.js} +1 -1
- package/cli/storybook-dist/assets/{RBDateInput.stories-BE9JQl-E.js → RBDateInput.stories-CLxRaN6T.js} +1 -1
- package/cli/storybook-dist/assets/{RBDialog.stories-BaWuDgl_.js → RBDialog.stories-CEhmUGp-.js} +1 -1
- package/cli/storybook-dist/assets/{RBDivider.stories-D3INKm_Z.js → RBDivider.stories-peXP2KG9.js} +1 -1
- package/cli/storybook-dist/assets/{RBDrawer.stories-BZ8V0J6-.js → RBDrawer.stories-38iDf6uC.js} +1 -1
- package/cli/storybook-dist/assets/{RBDropdownMenu.stories-DxLi8HRw.js → RBDropdownMenu.stories-Dsi8tqSy.js} +1 -1
- package/cli/storybook-dist/assets/{RBEmptyView.stories-DQcvDt2S.js → RBEmptyView.stories-VMxWhzLP.js} +1 -1
- package/cli/storybook-dist/assets/{RBIconButton.stories-DJfuTpQ0.js → RBIconButton.stories-BPLhceGO.js} +1 -1
- package/cli/storybook-dist/assets/{RBIcons.stories-BSsyb0BK.js → RBIcons.stories-DuYdO951.js} +1 -1
- package/cli/storybook-dist/assets/{RBInlineLabelButton.stories-Di3th--x.js → RBInlineLabelButton.stories-CGNYhQyl.js} +1 -1
- package/cli/storybook-dist/assets/{RBJoyStick.stories-DfGazm4n.js → RBJoyStick.stories-CCmn-LMy.js} +1 -1
- package/cli/storybook-dist/assets/{RBLabelButton.stories-CLbxzW56.js → RBLabelButton.stories-IkKjthGk.js} +1 -1
- package/cli/storybook-dist/assets/{RBLight.stories-DeiuDm_P.js → RBLight.stories-eJFQOjPH.js} +1 -1
- package/cli/storybook-dist/assets/{RBMenubar.stories-BZQTV9e5.js → RBMenubar.stories-kg-xXGrW.js} +1 -1
- package/cli/storybook-dist/assets/{RBMultiRangeInput.stories-DDNmdi_n.js → RBMultiRangeInput.stories-Czr1r3gd.js} +1 -1
- package/cli/storybook-dist/assets/{RBPagination.stories-CLBCEyCU.js → RBPagination.stories-Dyu6Khnl.js} +1 -1
- package/cli/storybook-dist/assets/{RBPopover.stories-DRI5Kfa-.js → RBPopover.stories-CAM6hpf2.js} +1 -1
- package/cli/storybook-dist/assets/{RBPrompt.stories-DIAmypoJ.js → RBPrompt.stories-B4M-veaf.js} +1 -1
- package/cli/storybook-dist/assets/{RBRadioBox.stories-BS_N4aLf.js → RBRadioBox.stories-DeAOKvil.js} +1 -1
- package/cli/storybook-dist/assets/{RBRadioButton.stories-BTm8cYvm.js → RBRadioButton.stories-DjXwYXFy.js} +1 -1
- package/cli/storybook-dist/assets/{RBRangeDateInput.stories-D5hBsSyB.js → RBRangeDateInput.stories-9pzKhXGf.js} +1 -1
- package/cli/storybook-dist/assets/{RBResizable.stories-CxPEkbXQ.js → RBResizable.stories-B4Hi4DUD.js} +1 -1
- package/cli/storybook-dist/assets/{RBSelectBox.stories-FUQ7AcUi.js → RBSelectBox.stories-tVVv4c6z.js} +1 -1
- package/cli/storybook-dist/assets/{RBSheet.stories-mhVHH_71.js → RBSheet.stories-BwOCmaNN.js} +1 -1
- package/cli/storybook-dist/assets/{RBSideNumberInput.stories-5FMkLUim.js → RBSideNumberInput.stories-BbGOIitU.js} +1 -1
- package/cli/storybook-dist/assets/{RBSlider.stories-Bnhcp9pz.js → RBSlider.stories-yIDdawYQ.js} +1 -1
- package/cli/storybook-dist/assets/{RBSpinner.stories-Bf4416mP.js → RBSpinner.stories-CIJvpbgK.js} +1 -1
- package/cli/storybook-dist/assets/{RBSwitch.stories-BNhFjRaV.js → RBSwitch.stories-Bo8hrSiq.js} +1 -1
- package/cli/storybook-dist/assets/{RBTab.stories-Bsr7jlfb.js → RBTab.stories-Cq3N4Dgb.js} +1 -1
- package/cli/storybook-dist/assets/{RBTable.stories-BkA6pKzs.js → RBTable.stories-DDeZf-Wb.js} +1 -1
- package/cli/storybook-dist/assets/{RBTableRow.stories-D07Z7D5-.js → RBTableRow.stories-BeKVMSo3.js} +1 -1
- package/cli/storybook-dist/assets/{RBTabs.stories-DHnZiV21.js → RBTabs.stories-DovB7PPB.js} +1 -1
- package/cli/storybook-dist/assets/{RBTextArea.stories-CtLMLuV_.js → RBTextArea.stories-D7H4RvP8.js} +1 -1
- package/cli/storybook-dist/assets/{RBTextField.stories-Chz0i1-u.js → RBTextField.stories-CmkNXeEk.js} +1 -1
- package/cli/storybook-dist/assets/{RBTextInput.stories-Dk5cZfUF.js → RBTextInput.stories-hnxbQJsb.js} +1 -1
- package/cli/storybook-dist/assets/{RBToast.stories-tZxbjmr8.js → RBToast.stories-BklGGkNh.js} +1 -1
- package/cli/storybook-dist/assets/{RBToggle.stories-VTe7a4xZ.js → RBToggle.stories-C56AXyxq.js} +1 -1
- package/cli/storybook-dist/assets/{RBToggleGroup.stories-WiFnGGYx.js → RBToggleGroup.stories-CpLPdAF0.js} +1 -1
- package/cli/storybook-dist/assets/{RBTooltip.stories-B_L4W7Mn.js → RBTooltip.stories-BdOnCwGk.js} +1 -1
- package/cli/storybook-dist/assets/{SideNumberInput-os5wKKf7.js → SideNumberInput-DLmM2_Dy.js} +80 -80
- package/cli/storybook-dist/assets/{entry-preview-COJgWzHb.js → entry-preview-DqMcNOGI.js} +1 -1
- package/cli/storybook-dist/assets/{iframe-DQEjJuXA.js → iframe-C1kyDB-R.js} +2 -2
- package/cli/storybook-dist/assets/{index-DEgQqQ_-.js → index-CdVSDe2m.js} +3 -3
- package/cli/storybook-dist/assets/{preview-BZ5PpEp_.js → preview-C_JfiDjl.js} +2 -2
- package/cli/storybook-dist/assets/preview-DvwEjyb4.js +3 -0
- package/cli/storybook-dist/iframe.html +1 -1
- package/cli/storybook-dist/project.json +1 -1
- package/cli/templates/common/README.md +65 -4
- package/cli/templates/common/py/main.py +5 -1
- package/cli/templates/common/requirements.txt +3 -3
- package/cli/templates/cpp/cpp/CMakeLists.txt +1 -2
- package/cli/templates/cpp/cpp/main.cpp +48 -8
- package/cli/templates/readme-cpp/README.md +969 -0
- package/cli/templates/ros2-cpp/ros2_ws/src/__PLUGIN_SLUG__/CMakeLists.txt +1 -1
- package/package.json +3 -3
- package/cli/storybook-dist/assets/preview-CmCb8Xea.js +0 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"generatedAt":
|
|
1
|
+
{"generatedAt":1790728570661,"userSince":1750932757926,"hasCustomBabel":false,"hasCustomWebpack":false,"hasStaticDirs":false,"hasStorybookEslint":true,"refCount":0,"testPackages":{"@vitest/browser":"3.2.4","@vitest/coverage-v8":"3.2.4","playwright":"1.59.1","vitest":"3.2.4"},"hasRouterPackage":false,"monorepo":"Turborepo","packageManager":{"type":"yarn","version":"berry","agent":"yarn@berry"},"preview":{"usesGlobals":false},"framework":{"name":"@storybook/react-vite","options":{}},"builder":"@storybook/builder-vite","renderer":"@storybook/react","portableStoriesFileCount":0,"applicationFileCount":0,"storybookVersion":"8.6.18","storybookVersionSpecifier":"^8.6.4","language":"typescript","storybookPackages":{"@chromatic-com/storybook":{"version":"3.2.7"},"@storybook/addon-essentials":{"version":"8.6.18"},"@storybook/addon-links":{"version":"8.6.18"},"@storybook/addon-onboarding":{"version":"8.6.18"},"@storybook/addon-themes":{"version":"8.6.18"},"@storybook/blocks":{"version":"8.6.18"},"@storybook/experimental-addon-test":{"version":"8.6.18"},"@storybook/react":{"version":"8.6.18"},"@storybook/react-vite":{"version":"8.6.18"},"@storybook/test":{"version":"8.6.18"},"@storybook/theming":{"version":"8.6.18"},"eslint-plugin-storybook":{"version":"0.11.6"},"storybook":{"version":"8.6.18"},"storybook-addon-react-docgen":{"version":"1.2.44"}},"addons":{"$SNIP/node_modules/@storybook/addon-links":{"version":null},"$SNIP/node_modules/@storybook/addon-essentials":{"version":null},"$SNIP/node_modules/@chromatic-com/storybook":{"version":null},"$SNIP/node_modules/@storybook/addon-themes":{"version":null},"$SNIP/node_modules/@storybook/experimental-addon-test":{"version":null}}}
|
|
@@ -766,15 +766,15 @@ container (your own Ubuntu 24.04 machine, or the robot PC):
|
|
|
766
766
|
|
|
767
767
|
```bash
|
|
768
768
|
curl -fsSL https://rainbowrobotics.github.io/rb-sdk/rb-sdk-apt-repo.gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/rb-sdk-apt.gpg
|
|
769
|
-
echo 'deb [signed-by=/usr/share/keyrings/rb-sdk-apt.gpg] https://rainbowrobotics.github.io/rb-sdk
|
|
770
|
-
sudo apt update && sudo apt install rainbow-rb-sdk-dev
|
|
769
|
+
echo 'deb [signed-by=/usr/share/keyrings/rb-sdk-apt.gpg] https://rainbowrobotics.github.io/rb-sdk stable main' | sudo tee /etc/apt/sources.list.d/rb-sdk.list
|
|
770
|
+
sudo apt update && sudo apt install rainbow-rb-sdk-dev
|
|
771
771
|
```
|
|
772
772
|
|
|
773
773
|
- CMake: `find_package(rb_sdk REQUIRED)` + `target_link_libraries(<target> rb_sdk::rb_sdk)` (C++20). pkg-config: `rb_sdk`.
|
|
774
774
|
- Headers: `<rainbow/rb_sdk/manipulate/rb_manipulate_sdk.hpp>` (`RBManipulateSDK`),
|
|
775
775
|
`<rainbow/rb_sdk/program/plugin_program_context.hpp>` (`rb_plugin::PluginProgramContext`, for `program.panel` commands — the header's top comment has a full `main()` example).
|
|
776
|
-
- The binary is linked **dynamically
|
|
777
|
-
- UI ↔ backend messaging
|
|
776
|
+
- The binary is linked **dynamically**; `muscat-pk build` copies the matching `librb_sdk.so` into `dist/<arch>/lib/` (the robot has no SDK installed), so each plugin keeps the SDK version it was built with. Change the version with `MUSCAT_PK_RB_SDK_VERSION=<version> MUSCAT_PK_REBUILD_IMAGE=1 muscat-pk dev`.
|
|
777
|
+
- UI ↔ backend messaging works from C++ too: `rb_plugin::RBPluginCall` in `<rainbow/rb_sdk/plugin/rb_plugin.hpp>` (see the scaffolded `cpp/main.cpp`).
|
|
778
778
|
|
|
779
779
|
### ROS2 (rclpy)
|
|
780
780
|
|
|
@@ -815,6 +815,65 @@ public:
|
|
|
815
815
|
|
|
816
816
|
---
|
|
817
817
|
|
|
818
|
+
## Video streaming (MediaMTX)
|
|
819
|
+
|
|
820
|
+
Muscat runs a MediaMTX media server. The backend publishes a stream over RTSP and
|
|
821
|
+
the UI plays it over WebRTC. `muscat-pk dev` runs the same server (or uses a local
|
|
822
|
+
Muscat's), so the addresses are identical in dev and on the robot.
|
|
823
|
+
|
|
824
|
+
| | Address |
|
|
825
|
+
| --- | --- |
|
|
826
|
+
| Publish (backend) | `rtsp://127.0.0.1:8554/<plugin_id>/<name>` |
|
|
827
|
+
| Play (UI) | `http://<host>:8889/<plugin_id>/<name>/` |
|
|
828
|
+
|
|
829
|
+
- Prefix the path with your plugin id — paths are shared with robot cameras and other plugins.
|
|
830
|
+
- The robot runtime has no ffmpeg, GStreamer or OpenCV; bring your own encoder (below).
|
|
831
|
+
|
|
832
|
+
**Backend (Python)** — use PyAV: add `av` and `numpy` to `requirements.txt`. Its wheels
|
|
833
|
+
include FFmpeg, so they ship in the ZIP like any other dependency.
|
|
834
|
+
|
|
835
|
+
```python
|
|
836
|
+
import fractions, time
|
|
837
|
+
import av, numpy as np
|
|
838
|
+
|
|
839
|
+
out = av.open("rtsp://127.0.0.1:8554/__PLUGIN_ID__/cam", mode="w", format="rtsp",
|
|
840
|
+
options={"rtsp_transport": "tcp"})
|
|
841
|
+
stream = out.add_stream("libx264", rate=25, options={"preset": "ultrafast", "tune": "zerolatency"})
|
|
842
|
+
stream.width, stream.height, stream.pix_fmt = 640, 360, "yuv420p"
|
|
843
|
+
|
|
844
|
+
i = 0
|
|
845
|
+
while True:
|
|
846
|
+
img = np.zeros((360, 640, 3), dtype=np.uint8) # your RGB frame here
|
|
847
|
+
frame = av.VideoFrame.from_ndarray(img, format="rgb24")
|
|
848
|
+
frame.pts, frame.time_base = i, fractions.Fraction(1, 25)
|
|
849
|
+
for packet in stream.encode(frame):
|
|
850
|
+
out.mux(packet)
|
|
851
|
+
i += 1
|
|
852
|
+
time.sleep(1 / 25)
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
Run the encoder loop in a thread (or `asyncio.to_thread`) so it doesn't block the
|
|
856
|
+
`RBPluginCall` handlers.
|
|
857
|
+
|
|
858
|
+
**UI** — embed MediaMTX's WebRTC player. `location.hostname` is `localhost` in the
|
|
859
|
+
preview and the robot's address on the robot:
|
|
860
|
+
|
|
861
|
+
```tsx
|
|
862
|
+
const STREAM = "__PLUGIN_ID__/cam"; // the path the backend publishes
|
|
863
|
+
|
|
864
|
+
export default function Camera() {
|
|
865
|
+
return (
|
|
866
|
+
<iframe
|
|
867
|
+
src={`${location.protocol}//${location.hostname}:8889/${STREAM}/`}
|
|
868
|
+
allow="autoplay"
|
|
869
|
+
className="aspect-video w-full border-0"
|
|
870
|
+
/>
|
|
871
|
+
);
|
|
872
|
+
}
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
---
|
|
876
|
+
|
|
818
877
|
## manifest.json
|
|
819
878
|
|
|
820
879
|
```jsonc
|
|
@@ -1043,6 +1102,8 @@ muscat-pk type change --to python # → Python
|
|
|
1043
1102
|
|
|
1044
1103
|
> Existing backend dirs (`ros2_ws/`, `cpp/`) are not deleted when switching away. Remove them manually if no longer needed.
|
|
1045
1104
|
|
|
1105
|
+
> Switching between a Python and a C++ backend asks whether to replace this README with the matching one (the old file is kept as `README.md.bak`). Add `--readme` to answer yes without the prompt.
|
|
1106
|
+
|
|
1046
1107
|
---
|
|
1047
1108
|
|
|
1048
1109
|
## AI coding assistants (MCP)
|
|
@@ -24,6 +24,7 @@ import os
|
|
|
24
24
|
from typing import Any
|
|
25
25
|
|
|
26
26
|
from rainbow.rb_sdk import RBManipulateSDK, RBPluginCall
|
|
27
|
+
from rainbow.rb_sdk.rb_sdk_cpp import ConnectOptions
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
PLUGIN_NAME = "__PLUGIN_NAME__"
|
|
@@ -95,7 +96,10 @@ async def main():
|
|
|
95
96
|
# Remote dev: connect to the robot before registering any handlers.
|
|
96
97
|
# connect() closes and reopens the Zenoh session, so handlers registered
|
|
97
98
|
# before this call would be lost.
|
|
98
|
-
|
|
99
|
+
opts = ConnectOptions()
|
|
100
|
+
opts.token = robot_token
|
|
101
|
+
opts.host = robot_host
|
|
102
|
+
manipulate.connect(opts)
|
|
99
103
|
|
|
100
104
|
register_handlers()
|
|
101
105
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
rainbow-rb-sdk==0.1.
|
|
2
|
-
rainbow-rb-flat-buffers==0.1.
|
|
3
|
-
rainbow-rb-zenoh==0.1.
|
|
1
|
+
rainbow-rb-sdk==0.1.3
|
|
2
|
+
rainbow-rb-flat-buffers==0.1.3
|
|
3
|
+
rainbow-rb-zenoh==0.1.3
|
|
4
4
|
requests==2.34.2
|
|
@@ -5,8 +5,7 @@ set(CMAKE_CXX_STANDARD 20)
|
|
|
5
5
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
6
6
|
|
|
7
7
|
# Rainbow Robotics C++ SDK — provided by the apt package rainbow-rb-sdk-dev
|
|
8
|
-
# (pre-installed in the muscat-pk dev container).
|
|
9
|
-
# ships the matching librb_sdk.so, so do NOT bundle or static-link it.
|
|
8
|
+
# (pre-installed in the muscat-pk dev container).
|
|
10
9
|
find_package(rb_sdk REQUIRED)
|
|
11
10
|
|
|
12
11
|
# The executable name must match runtime.entry in manifest.json.
|
|
@@ -3,14 +3,17 @@
|
|
|
3
3
|
// The Rainbow Robotics C++ SDK (apt: rainbow-rb-sdk-dev) is installed in the
|
|
4
4
|
// dev container and linked via CMake (rb_sdk::rb_sdk). Headers live under
|
|
5
5
|
// <rainbow/rb_sdk/...>:
|
|
6
|
+
// - plugin/rb_plugin.hpp rb_plugin::RBPluginCall — plugin UI <-> backend
|
|
7
|
+
// (serve/subscribe/publish) and external endpoints (router)
|
|
6
8
|
// - manipulate/rb_manipulate_sdk.hpp RBManipulateSDK — control the robot
|
|
7
9
|
// - program/plugin_program_context.hpp rb_plugin::PluginProgramContext —
|
|
8
10
|
// program.panel commands (done/pause/stop,
|
|
9
|
-
// program variables)
|
|
10
|
-
// top comment for a full main() example
|
|
11
|
-
// UI <-> backend messaging (RBPluginCall pub/sub/serve) is Python-only for now.
|
|
11
|
+
// program variables)
|
|
12
12
|
|
|
13
13
|
#include <rainbow/rb_sdk/manipulate/rb_manipulate_sdk.hpp>
|
|
14
|
+
#include <rainbow/rb_sdk/plugin/rb_plugin.hpp>
|
|
15
|
+
|
|
16
|
+
#include <nlohmann/json.hpp>
|
|
14
17
|
|
|
15
18
|
#include <chrono>
|
|
16
19
|
#include <cstdlib>
|
|
@@ -18,13 +21,50 @@
|
|
|
18
21
|
#include <string>
|
|
19
22
|
#include <thread>
|
|
20
23
|
|
|
24
|
+
using nlohmann::json;
|
|
25
|
+
using rb_plugin::RBPluginCall;
|
|
26
|
+
|
|
21
27
|
int main() {
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
const std::string name = "__PLUGIN_NAME__";
|
|
29
|
+
|
|
30
|
+
// Remote dev: connect before registering handlers (connect() reopens the session).
|
|
31
|
+
RBManipulateSDK manipulate;
|
|
32
|
+
const char* host = std::getenv("MUSCAT_ROBOT_HOST");
|
|
33
|
+
const char* token = std::getenv("MUSCAT_ROBOT_TOKEN");
|
|
34
|
+
if (host && token) manipulate.connect({.token = token, .host = host});
|
|
35
|
+
|
|
36
|
+
// plugin id comes from RB_PLUGIN_ID.
|
|
37
|
+
auto plugin = RBPluginCall::get_instance(RBPluginCall::resolve_plugin_id(std::nullopt));
|
|
38
|
+
|
|
39
|
+
// --- Plugin UI <-> backend (not reachable from outside Muscat) ---
|
|
40
|
+
|
|
41
|
+
// UI: await rb.action("grip", { width })
|
|
42
|
+
plugin->serve("grip", [&](const json& payload) {
|
|
43
|
+
const int width = payload.is_object() ? payload.value("width", 20) : 20;
|
|
44
|
+
std::cout << "[" << name << "] grip requested: width=" << width << std::endl;
|
|
45
|
+
plugin->publish("state", {{"ready", true}, {"last_grip_width", width}}); // -> rb.sub("state")
|
|
46
|
+
return json{{"ok", true}, {"width", width}};
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// UI: rb.pub("event", ...)
|
|
50
|
+
auto event_sub = plugin->subscribe("event", [&](const std::string&, const json& payload) {
|
|
51
|
+
std::cout << "[" << name << "] event: " << payload.dump() << std::endl;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// --- External endpoints (REST / Socket.IO / TCP / MQTT / WebRTC) ---
|
|
55
|
+
// curl -X POST http://<robot>/common/plugin/<plugin_id>/hello -d '{"name":"kim"}'
|
|
56
|
+
plugin->router().on("/hello", [](const json& payload, const json& meta) {
|
|
57
|
+
const std::string who = payload.is_object() ? payload.value("name", std::string("there")) : "there";
|
|
58
|
+
return json{{"msg", "hi " + who}, {"via", meta.value("transport", std::string())}};
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Example: robot control (not called automatically — add safety checks first).
|
|
62
|
+
// IPC::MoveInput_TargetT t; t.tar_values = {0, 0, 0, 0, 0, 0};
|
|
63
|
+
// manipulate.move.call_move_j("C500920", t);
|
|
64
|
+
|
|
65
|
+
plugin->publish("state", {{"ready", true}, {"plugin", name}});
|
|
66
|
+
std::cout << "[" << name << "] backend ready" << std::endl;
|
|
26
67
|
|
|
27
|
-
// e.g. RBManipulateSDK manipulate; manipulate.move.call_move_j(...);
|
|
28
68
|
// Keep the process alive.
|
|
29
69
|
while (true) {
|
|
30
70
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|