ROS2 and AI Experiments - slgrobotics/articubot_one GitHub Wiki
See my notes on ROS2/Nav2 and AI integration here.
Contents:
- Components used
- Installation
- Running Rosbridge and MCP Server on Seggy
- Querying MCP Server for its capabilities as a ROS2 "tool"
- Querying HuskyLens 2 built-in MCP server
- Using HuskyLens 2 I2C interface
- Exploring examples
- robot Seggy, a general purpose wheeled base, Raspberry Pi 5, LIDAR, Nav2, custom behaviors
- HuskyLens 2 with WiFi adapter, capable of running its built-in MCP Server (over WiFi) and connected via I2C. It provides visual recognition by running VLMs
- ros-mcp-server by RobotMCP / Contoro is a broad ecosystem that connects LLMs (like Claude, ChatGPT, or Gemini) to any ROS/ROS 2 robot. It has built-in examples showing an AI agent executing high-level tasks like "Grab a Coke from the fridge and go to the living room" by stringing together Nav2 goals and MoveIt manipulation commands.
- LLM - ChatGPT Desktop. Runs on an Intel workstation with Nvidia 3060 video card, connects to the Cloud.
Here are some helpful facts about ChatGPT Desktop (AI assisted research)
Click here to expand
- What is ChatGPT Desktop and what does it do? answer
- Is there a way to run ChatGPT Desktop on Ubuntu? answer
- Can I restrict what ChatGPT Desktop can do on my computer? answer
- Does ChatGPT Desktop use online ChatGPT models, or can I restrict it to local models? answer
Other options - Claude, Gemini, Ollama
- Compare ChatGPT/Codex vs. Ollama + local models vs. Claude Code/Gemini CLI specifically for my Ubuntu ROS2 development machine. I intend to drive my Seggy robot which runs ros-mcp-server by RobotMCP / Contoro, while keeping LLM strategy functions on an Intel desktop with Nvidia Geforce RTX 3060 card. I don't mind using online models initially for experiments, but having models local may be beneficial for cost and latency. answer
So, the data flow is as follows:
βββββββββββββββββββββ
β Strategy API β
β model-agnostic β
βββββββββββ¬ββββββββββ
β
βββββββββββββββΌβββββββββββββββ
β β β
βΌ βΌ βΌ
GPT/Claude Ollama Gemini
cloud local cloud
RTX 3060
β β β
βββββββββββββββΌβββββββββββββββ
β
MCP
β
βββββββββββΌββββββββββ
β ros-mcp-server β
β Seggy β
βββββββββββ¬ββββββββββ
β
ROS2
β
ββββββββββββββββββββββΌβββββββββββββββββββββ
β β β
Nav2 perception behaviors
β β β
ββββββββββββββββββββββΌβββββββββββββββββββββ
β
robot hardware
- In my case perception is delegated to an MCP server running on a dedicated camera device - HuskyLens 2 with WiFi adapter, capable of running its built-in MCP Server (over WiFi) and connected via I2C. It provides visual recognition by running VLMs. How does it fit into my architecture? answer
AI SERVICES
β
βββββββββββββββΌββββββββββββββ
β β β
Strategy Vision Future AI
LLM VLM services
β β β
βββββββββββββββΌββββββββββββββ
β
MCP
β
ββββββββββββ΄βββββββββββ
β β
ROS-MCP Vision-MCP
β β
βΌ βΌ
ROS2 HuskyLens
β
βΌ
Seggy
- So, will the reasoning layer have to poll Vision-MCP often? How does it receive perceived info from Vision AI? answer
Note: you will run out of tokens really fast on a free tier. Be prepared to pay.
I've chosen to install ChatGPT Desktop on my Intel I7 Ubuntu 24.04 workstation. You can use Claude Code, Codex, Gemini etc.
I installed Rosbridge and MCP Server on Seggy.
-
ChatGPT Desktop for Linux installation on the Workstation:
- go to ChatGPT download page: https://chatgpt.com/download/ and download a
.debfile - Install it:
- go to ChatGPT download page: https://chatgpt.com/download/ and download a
cd ~/Downloads
sudo apt install ./chatgpt*.deb
# Some day you will need to upgrade it. Use package manager to install later updates:
sudo apt update
sudo apt install --only-upgrade chatgpt
- Seggy is described here. It needs Rosbridge installed to allow the MCP server to connect to ROS2 over a WebSocket interface.
- ros-mcp-server install on the workstation is described here. I built it from sources on Seggy instead. The new uv installer is used.
sudo apt install ros-${ROS_DISTRO}-rosbridge-server
# install uv - replaces pip:
curl -LsSf https://astral.sh/uv/install.sh | sh
# re-login or run env setup, this was added to ~/.bashrc:
. "$HOME/.local/bin/env"
# build MCP Server from sources:
mkdir -p ~/mcp_ws/src
cd ~/mcp_ws/src
git clone https://github.com/robotmcp/ros-mcp-server.git
cd ros-mcp-server/
uv sync
uv run server.py --help
ros2 launch rosbridge_server rosbridge_websocket_launch.xml
cd ~/mcp_ws/src/ros-mcp-server
# Note the "--host 0.0.0.0" part - it allows connections across LAN:
uv run server.py --transport streamable-http --host 0.0.0.0 --port 9000
Let's make Seggy execute commands issued in ChatGPT Desktop in human language.
Click here to expand
In ChatGPT Desktop type:
- Connect to the MCP server at http://seggy.local:9000/mcp and query its capabilities
Connected successfully. Itβs `ros-mcp-server` v2.13.0, with 31 tools for ROS/ROS 2 robot inspection and control.
You can:
- Discover connected robots, test ROSbridge connectivity, and detect the ROS version.
- Inspect ROS nodes, topics, services, actions, message types, and parameters.
- Read camera/image-topic data and retrieve saved images.
- Subscribe to topic messages once or over a time window.
- Inspect action state, send action goals, and cancel running goals.
- Call ROS services.
- Change or delete parameters.
- Publish individual messages or timed command sequencesβfor example, send velocity commands to `/cmd_vel`.
The server marks robot-affecting operations as destructive, including publishing commands,
action goals, service calls, and parameter changes.
Read-only discovery and monitoring tools are separately labeled.
- What ROS2 topics can you see?
The server currently sees four ROS 2 topics:
Topic | Message type
------------------ | ------------------------------------
/client_count | std_msgs/msg/Int32
/connected_clients | rosbridge_msgs/msg/ConnectedClients
/parameter_events | rcl_interfaces/msg/ParameterEvent
/rosout | rcl_interfaces/msg/Log
These are ROS/rosbridge system topics; no robot sensor or command topics are visible yet.
- query again (this time I ran Seggy's full stack on its RPi5)
Refresh succeeded: the ROS graph now exposes **133 topics**βa Nav2 mobile-robot stack is active.
Key topics include:
- Motion commands: `/cmd_vel`, `/cmd_vel_nav`, `/cmd_vel_teleop`, `/cmd_vel_smoothed`
- Localization/navigation: `/amcl_pose`, `/map`, `/scan`, `/goal_pose`, `/plan`, `/waypoints`
- Robot state: `/odometry/local`, `/odometry/global`, `/joint_states`, `/imu/data`, `/battery/battery_state`
- Navigation costmaps: `/global_costmap/*`, `/local_costmap/*`
- Transforms: `/tf`, `/tf_static`
- Vision/interaction: `/face_gesture_detections`, `/fgs/*`, `/joy`
- Docking and safety: `/dock_pose`, `/docking_trajectory`, `/collision_monitor_state`, `/geofence/*`
The change from four system topics means the robot/navigation system has since come online.
- Move the robot forward for 2 seconds
Moved forward at 0.1 m/s for 2 seconds, then sent a zero-velocity stop.
The ROS server confirmed 21 messages published to `/cmd_vel` with no errors.
- Plan and execute a path via Nav2. I want the robot move 1 meter forward. Use
/odometry/localfor position queries.
Nav2 planned a valid 40-pose path and began executing it.
The robot moved approximately **1.00 m** from its starting odometry position.
It stopped about 11 cm short of the exact Nav2 target while the original goal remained active,
so I cancelled that lingering goal. Nav2 confirms that original goal is now **aborted**.
See this "Getting Started" guide first. More info here.
Check out my ROS 2 package for HuskyLens 2 for device setup and other info.
Here is DFRobot's guide on MCP Server use.
In ChatGPT Desktop type:
-
I have a Huskylens 2 camera MCP server at
http://*.*.*.167:3000/sseQuery its capabilities (use actual IP address)
Repeated successfully. The HuskyLens MCP server is online as v1.0.1 and exposes the same capabilities:
- Real-time recognition results and image data
- Algorithm listing, switching, parameters, and multi-algorithm mode
- Object learning, naming, and forgetting
- Photo, screenshot, audio recording, and music playback
- Display overlays: draw/clear text and rectangles
- Device controls: backlight, flashlight, volume
- Knowledge-base load/save and scheduled camera tasks
If you haven't done it before, install uv (a pip replacement):
curl -LsSf https://astral.sh | sh
Re-login to enable environment variables
Create an environment and install libraries:
mkdir ~/husky2_project && cd ~/husky2_project
uv venv husky2_env
source husky2_env/bin/activate
uv pip install pyhuskylens smbus2
Click here to expand code
import time
from pyhuskylens import HuskyLens
from pyhuskylens import (
HuskyLens,
ALGORITHM_OBJECT_RECOGNITION,
ALGORITHM_OBJECT_CLASSIFICATION,
)
print("Initializing HuskyLens 2 on I2C...")
# Pass 1 for /dev/i2c-1. The library automatically looks for the 0x50 address.
try:
hl = HuskyLens(1)
print("Success! Connected to HuskyLens 2.")
except Exception as e:
print(f"Connection Failed: {e}")
print("Double check that your port light is BLUE and i2cdetect shows 0x50.")
exit()
print("IP: setting OBJECT_RECOGNITION algorithm...")
hl.set_alg(ALGORITHM_OBJECT_RECOGNITION)
# For "learned" objects:
# print("IP: setting ALGORITHM_OBJECT_CLASSIFICATION algorithm...")
# hl.set_alg(ALGORITHM_OBJECT_CLASSIFICATION)
print("Streaming object data... Press Ctrl+C to stop.")
try:
while True:
# Grab any active bounding boxes/blocks from the screen
blocks = hl.get_blocks()
if blocks:
for block in blocks:
# name β semantic class ("chair")
# ID β learned-object/category ID
# classID β classification class ID (where supported)
# confidence β model confidence, but not necessarily retrievable
print(f"Name: {getattr(block, 'name', None)} \t" \
f"Center: ({block.x}, {block.y}) " \
f"Size: {block.width} x {block.height} " \
f"Type: {getattr(block, 'type', None)} " \
f"ID: {getattr(block, 'ID', None)} " \
f"Learned: {getattr(block, 'learned', None)} " \
f"Confidence: {getattr(block, 'confidence', None)} " \
f"Content: {getattr(block, 'content', None)}")
# print("------------------------------")
time.sleep(0.2)
except KeyboardInterrupt:
print("\nExiting script.")
Place something (chair, keyboard, computer monitor) in front of the camera.
Note: HuskyLens 2 ALGORITHM_OBJECT_RECOGNITION recognizes exactly 80 built-in object categories.
DFRobot says the model is trained on MS COCO80, and its current documentation provides the complete list:
Click here to expand list
person
bicycle
car
motorcycle
airplane
bus
train
truck
boat
traffic light
fire hydrant
stop sign
parking meter
bench
bird
cat
dog
horse
sheep
cow
elephant
bear
zebra
giraffe
backpack
umbrella
handbag
tie
suitcase
frisbee
skis
snowboard
sports ball
kite
baseball bat
baseball glove
skateboard
surfboard
tennis racket
bottle
wine glass
cup
fork
knife
spoon
bowl
banana
apple
sandwich
orange
broccoli
carrot
hot dog
pizza
donut
cake
chair
couch
potted plant
bed
dining table
toilet
tv
laptop
mouse
remote
keyboard
cell phone
microwave
oven
toaster
sink
refrigerator
book
clock
vase
scissors
teddy bear
hair drier
toothbrush
Run the script. The script selects "Object Recognition" mode.
cd ~/husky2_project
source husky2_env/bin/activate
python3 ./test_husky2.py
Initializing HuskyLens 2 on I2C...
Success! Connected to HuskyLens 2.
Streaming object data... Press Ctrl+C to stop.
Name: tv Center: (503, 369) Size: 176 x 122 Type: BLOCK ID: 0 Learned: False Confidence: 2 Content:
Name: keyboard Center: (149, 365) Size: 298 x 130 Type: BLOCK ID: 0 Learned: False Confidence: 2 Content:
Name: chair Center: (143, 60) Size: 169 x 121 Type: BLOCK ID: 0 Learned: False Confidence: 2 Content:
Name: sports ball Center: (319, 327) Size: 51 x 52 Type: BLOCK ID: 0 Learned: False Confidence: 2 Content:
...
See this repository for more information and examples.
Examples are located in this folder of the repository.
To Be Continued
Back to the Top