Visualize ROS2 node topology from Python and C++ source code with no robot required.
Point it at your ROS2 workspace and get an interactive graph showing how nodes, topics, services and message types connect. No ROS2 installation needed, no running system, no simulator.
Every existing ROS2 visualization tool requires a live running system. If you just cloned a repo, you are doing code review, or you are in CI none of those tools work.
ros2grapher reads your source files directly using static analysis and builds the graph without executing anything.
| ros2grapher | rqt_graph | ros_network_viz | |
|---|---|---|---|
| Requires ROS2 running | no | yes | yes |
| Works on cloned repos | yes | no | no |
| Works in CI/CD | yes | no | no |
| Supports C++ nodes | yes | yes | yes |
| No install needed | yes | no | no |
git clone https://github.com/Supull/ros2grapher.git
cd ros2grapher
pip install -e .
ros2grapher /path/to/your/ros2_ws
Then open http://localhost:8888 in your browser.
ros2grapher ./src # scan a specific folder
ros2grapher ./src --ai # use AI to resolve dynamic topics
ros2grapher ./src --port 9000 # use a different port
ros2grapher ./src --no-serve # just generate index.html
ros2grapher ./src --print # print graph to terminal
ros2grapher uses two layers of analysis:
Layer 1 — Static analysis (always runs)
Walks your workspace and parses every Python and C++ source file using Python AST parsing and regex pattern matching. It looks for:
- Python classes extending Node or C++ classes extending rclcpp::Node or rclcpp_lifecycle::LifecycleNode
- create_publisher calls to extract topic names and message types
- create_subscription calls to extract topic names and message types
- create_service calls to extract service names and types
- Cross-package topic matching. A publisher in one package connects to a subscriber in another if they share the same topic name
Hardcoded topic names are resolved with full certainty and shown in green. Topics that cannot be resolved statically are flagged as [dynamic].
Layer 2 — AI resolution (optional, requires --ai flag)
When a topic name is stored in a variable or comes from a parameter, static analysis cannot determine it. With --ai, ros2grapher sends the source file to Gemini AI with a structured prompt asking it to determine the topic name from context — for example by reading the default value passed to declare_parameter.
Each AI resolution comes with a confidence score:
- High — topic found directly in a declare_parameter default value
- Medium — inferred from variable names, class names, or context
- Low — best guess from surrounding code
AI resolved connections are shown in orange in the graph so you always know what is certain and what is inferred.
Requires a free Gemini API key from https://aistudio.google.com
export GEMINI_API_KEY=your_key_here
ros2grapher ./src --ai
- Blue circles — ROS2 nodes
- Green ellipses — topics (statically certain)
- Orange ellipses — topics (AI resolved)
- Red dashed ellipses — orphan topics (no publisher or no subscriber)
- Orange rectangles — services
- Dashed colored borders — package groups
- node to topic arrow — node publishes to that topic
- topic to node arrow — node subscribes to that topic
- Orange line — connection resolved by AI
Hover over any node or topic to see details. Drag to rearrange. Scroll to zoom. Drag a package border to move the whole group.
- ROS2 nodes — Python classes extending Node, C++ classes extending rclcpp::Node
- LifecycleNodes — rclcpp_lifecycle::LifecycleNode
- Publishers — create_publisher
- Subscribers — create_subscription
- Services — create_service
- Dynamic topic names — flagged as [dynamic] or resolved by AI with confidence score
- Orphan topics — published but never subscribed or vice versa
- Cross-language connections — C++ publisher to Python subscriber and vice versa
- Package grouping — nodes grouped visually by their ROS2 package
- Dynamic topic names cannot always be resolved statically
- C++ nodes with variable node names show as unknown_ClassName
- AI resolution requires a free Gemini API key
- AI resolution is slower on large workspaces due to API rate limits
Add ros2grapher to any ROS2 repo to automatically post node topology as a comment on every pull request.
Create .github/workflows/ros2grapher.yml in your ROS2 repo:
name: ros2grapher
on:
pull_request:
paths:
- '**.py'
- '**.cpp'
- '**.hpp'
jobs:
graph:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.10'
- run: pip install git+https://github.com/Supull/ros2grapher.git
- id: grapher
run: |
OUTPUT=$(ros2grapher . --print --no-serve 2>/dev/null)
echo "output<<EOF" >> $GITHUB_OUTPUT
echo "$OUTPUT" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '## ros2grapher\n```\n${{ steps.grapher.outputs.output }}\n```\n_static analysis, no robot required_'
});
- C++ node support
- AI-assisted dynamic topic resolution
- Services visualization
- Package grouping
- Cross-language topic matching
- GitHub Action for CI/CD
- Additional AI providers (Claude, GPT, Ollama)
MIT