This English section was translated with GPT-5.4. It may contain minor inaccuracies compared with the Japanese section below.
CANweeb is a Rust-based multi-path mesh communication daemon for robotics. It is designed as a communication backbone between microcontrollers, Raspberry Pi systems, and Ubuntu Server nodes.
- Transport-independent — As long as TCP can pass through the link, CANweeb can use it: wired LAN, standard Wi-Fi LAN, Wi-Fi AP, or USB Ethernet.
- QoS separation —
control,telemetry, andstreamtraffic are handled on separate paths and queues. - No sensor data written to disk by default — High-frequency sensor and image data stay in memory so SD and eMMC storage are not worn out.
- Automatic fallback — If a wired path goes down, unacknowledged
controltraffic can be resent automatically over another transport.
CANweeb is the runtime and mesh layer in this repository.
- CmdLib provides Raspberry Pi-oriented hardware control utilities such as GPIO access, PWM output, rotary encoder handling, ultrasonic sensing, Device Tree Overlay helpers, and child-side helper processes.
- PiHub is a related project focused on sending a PC screen to a Raspberry Pi over a direct LAN connection, displaying it on HDMI, and exposing it on the web.
CANweeb can use any path that supports TCP. In most cases, the easiest setup is to place the parent and child nodes on the same router or the same LAN hub.
| Path | Typical use | Setting |
|---|---|---|
| Wired LAN | Normal deployment under the same router or hub | network_addr |
| Standard Wi-Fi LAN / AP | Devices connected to the same LAN | network_addr |
USB gadget Ethernet (192.168.7.x) |
Additional independent transport | usb_addr |
Easiest setup: Connect both parent and child to the same router or LAN hub with wired Ethernet, keep discovery.enabled = true, and start the service. In most cases you do not need a fixed network_addr.
Within the same LAN, peers can be detected and connected automatically through UDP broadcast discovery.
- Enable it with
discovery.enabled = true - Each node announces its
node_id,network_listenport, andwebport toannounce_addr - The receiving side automatically generates
network_addrfrom the sender IP and announced port - If
[[peers]]contains onlynode_id, connection can still be established without fixed IPs - Even without an explicit
[[peers]]entry, discovered peers can appear in status and connect dynamically
In addition to ordinary LAN discovery, the wifi section can be used for automatic parent AP creation and automatic child connection to known APs.
This is an optional feature. It is not enabled by default in the initial setup.
-
First, verify connectivity using only discovery on the same LAN
-
Set
wifi.auto_manage = trueonly when you want Wi-Fi fallback -
The sample configuration keeps the
CANweeb-Parentexample, but it does not start automatically by default -
Parent node:
wifi.desired_mode = "parent"- Creates an AP with
nmcli device wifi hotspot
- Creates an AP with
-
Child node:
wifi.desired_mode = "child"- Tries to connect to
wifi.fallback_networksin priority order
- Tries to connect to
-
The parent UI can switch modes, start the AP, connect manually, and disconnect
-
The parent UI can also change each peer's
relationshipandpreferred_transport_order -
The parent UI can monitor child power, uptime, queues, inbox, RTT, and connection quality
-
Child mode
- On startup, it tries to connect to the highest-priority SSID among the visible entries in
wifi.fallback_networks - Even if it is already connected to another Wi-Fi network, it switches to a configured SSID with higher priority when that SSID is visible
- If none of the configured candidates are visible, it does not repeatedly disconnect itself just to keep searching for an SSID that is not there
- On startup, it tries to connect to the highest-priority SSID among the visible entries in
-
Parent mode
- On startup,
wifi.interfaceis used for AP operation - If that same wireless interface was already being used for an existing Wi-Fi client connection, that connection will be replaced
- In other words, if you build a parent AP using only
wlan0, the original home Wi-Fi connection may not be preserved
- On startup,
-
Parent and child join an existing LAN / existing Wi-Fi / LAN hub
- If that LAN has Internet access, both parent and child can also access the Internet normally
-
Parent creates an AP on
wlan0- That
wlan0is used for parent-child communication - The existing Internet connection over the same
wlan0is usually not preserved - If the parent also needs Internet access, use wired LAN / USB Ethernet / a separate Wi-Fi interface
- That
- If
network_listen = "0.0.0.0:7002"is up, LAN / Wi-Fi communication listening is ready - For initial setup, simply place both nodes on the same router or the same LAN hub
- If
wifi.auto_manage = false, the runtime does not depend onnmclior AP mode - The parent management UI can be exposed at
http://<bind_addr>:8080/parent-ui/ - If
/parent-ui/returns 404, it is often because an oldtarget/release/canweebbinary is still running, so rebuild withcargo build --releaseand restart
| Class | ACK | Persistence | Typical use |
|---|---|---|---|
control |
Yes | Disk | Emergency stop, mode switching, GPIO commands, state transitions |
telemetry |
No | Memory (latest value per topic) | IMU, odometry, battery, estimated pose |
stream |
No | Memory (ring buffer) | Camera, RGB-D, LiDAR, large binary payloads |
Important: Do not send sensor data or images above 100 Hz through
control. That causes SD / eMMC wear, retransmission overhead, and control latency.
- Dual TCP listeners/connectors for USB and network transports, and it works even if only one side is present
- Automatic peer discovery and connection on the same LAN via UDP broadcast discovery
- Configurable transport priority and automatic failover
- Separate
control_tx/bulk_txqueues per connection to keep large streams from blocking control traffic controlACK with hop-by-hop retransmission and failover across multiple paths- Latest-value cache per
telemetrytopic, kept in memory only, up to 4096 topics - Chunked
streamtransfer with automatic reassembly on the receiver side; packet loss is finalized withStreamClose - Stream ring buffer keeping the latest 8 completed entries in memory
- Real-time WebSocket push for topics and streams
- Message deduplication based on
message_id - Loop prevention with
ttl/hops - Delivery targets such as
broadcast,node:X, andnodes:A,B,C - Web UI for send tests, Topic / Stream monitoring, Inbox, and
wpa_cli - Frame size limit of 32 MiB
# Build
cargo build --release
# Run
./target/release/canweeb --config config/example.tomlWeb UI: http://<bind_addr>:8080
Parent UI: http://<bind_addr>:8080/parent-ui/
Copy config/example.toml and edit it per node.
[node]
node_id = "node-pi"
role = "child"
tags = ["robot", "sensor"]
[storage]
root = "../data" # only control messages are persisted
retention_seconds = 86400
[web]
bind = "0.0.0.0:8080"
[transport]
network_listen = "0.0.0.0:7002" # LAN / Wi-Fi listener (optional)
connect_interval_ms = 1500
heartbeat_interval_ms = 1000
ack_timeout_ms = 2500
max_hops = 4
[discovery]
enabled = true
bind = "0.0.0.0:7060"
announce_addr = "255.255.255.255:7060"
announce_interval_ms = 1500
peer_ttl_ms = 8000
[wifi]
interface = "wlan0"
auto_manage = false
desired_mode = "child"
hotspot_ssid = "CANweeb-Parent"
hotspot_password = "canweeb1234"
hotspot_connection_name = "CANweeb Hotspot"
status_interval_ms = 2000
[[wifi.fallback_networks]]
ssid = "CANweeb-Parent"
password = "canweeb1234"
priority = 100
[[peers]]
node_id = "node-main"
role = "parent"
relationship = "parent"
preferred_transport_order = ["network"]
# network_addr = "192.168.1.10:7002"
tags = ["strategy"]Minimal configuration:
# for both parent.toml and child.toml
[discovery]
enabled = true
[wifi]
auto_manage = false
[[peers]]
# only the other node_id is needed
node_id = "node-main"| Method | Path | Description |
|---|---|---|
| GET | /api/status |
Node state and peer list |
| GET | /api/wifi/status |
Current Wi-Fi state for this node |
| POST | /api/wifi/apply-mode |
Automatically apply parent / child / ap / client |
| POST | /api/wifi/hotspot/start |
Start an AP immediately |
| POST | /api/wifi/connect |
Connect to a specified SSID |
| POST | /api/wifi/disconnect |
Disconnect Wi-Fi |
| GET | /api/peer-policies |
Peer relationship and transport priority |
| POST | /api/peer-policies |
Update peer relationship and transport priority |
| GET | /api/inbox |
List control inbox entries |
| GET | /api/inbox/:id |
Inbox details + payload base64 |
| POST | /api/messages |
Send a message |
| GET | /api/topics |
List latest telemetry values |
| GET | /api/topic?name=<topic> |
Topic detail including names with / |
| GET | /api/streams |
List completed streams (ring buffer) |
| GET | /api/streams/:stream_id |
Get a stream payload as base64 |
| POST | /api/wifi-direct/run |
Run a wpa_cli command |
| Path | Description |
|---|---|
ws://.../ws/topics |
Real-time push of telemetry topic updates |
ws://.../ws/streams |
Real-time push when stream assembly completes, including payload |
{
"target": "broadcast",
"traffic_class": "telemetry",
"topic": "imu/accel",
"content_type": "application/json",
"text": "{\"x\":0.1,\"y\":0.0,\"z\":9.8}"
}{
"target": "node:node-main",
"traffic_class": "control",
"subject": "emergency_stop",
"content_type": "application/octet-stream",
"payload_base64": "AQ=="
}# DHCP is fine
# Example:
ip addr showIf you start CANweeb in this state, the nodes can discover each other through discovery.
Change wifi.auto_manage = true before using it. It is not enabled by default in the initial setup.
You can use it in combination by adding usb_listen / usb_addr, but it is not used in the default sample configuration.
The wpa_cli panel remains in the Web UI, but it is not required for normal operation under a LAN / router setup.
For a simple demo-oriented operation, use the management screen in examples/parent-ui/index.html.
interface: wlan0
args: p2p_find
| Path | Description |
|---|---|
src/main.rs |
Entry point |
src/config.rs |
Configuration structures |
src/protocol.rs |
Frame definitions, TrafficClass, and DeliveryTarget |
src/storage.rs |
Persistent queue, inbox, topic cache, and stream ring buffer |
src/mesh.rs |
Connection management, retransmission, ACK, topic pub/sub, and stream assembly |
src/web.rs |
Web UI, HTTP API, and WebSocket |
config/example.toml |
Sample configuration |
- Routing is flooding-based; path learning is not implemented
- Time synchronization is not guaranteed; PTP / NTP are needed separately
- Authentication and encryption are not implemented
- Discovery only works automatically within the same L2 / LAN segment; it does not cross subnets
- If a network blocks UDP broadcast, set
network_addrexplicitly - No systemd unit is included; create one yourself and point
ExecStartat this binary
Ubuntu Server (strategy / AI)
↕ same LAN / router via CANweeb
Raspberry Pi (sensor / GPIO / actuator)
↕ LAN / Wi-Fi / other TCP
Microcontroller / external device
原文を書いて、英語に訳してもらって、それを編集して、日本語にしてもらったので逆翻訳になってます。
※ファクトチェックは済
Rust 製のロボティクス向け多経路メッシュ通信デーモン。マイコン・Raspberry Pi・Ubuntu Server 間をつなぐ通信基盤として設計されています。
- トランスポート非依存 — 有線 LAN・通常 Wi-Fi LAN・Wi-Fi AP・USB Ethernet、どれでも TCP が通れば動く
- QoS 分離 —
control/telemetry/streamを完全に別経路・別キューで扱う - センサデータをディスクに落とさない — 高頻度センサや画像データは SD / eMMC 寿命を消費しない
- フォールバック自動化 — 有線が切れた場合、未 ACK の
controlは network 側へ自動再送
CANweeb は TCP が通る経路ならなんでも使えます。デフォルトでは 親子を同じルーター / 同じ LAN ハブ配下の既存 LAN に参加させる のがいちばん簡単です。
| 経路 | 典型的な用途 | 設定 |
|---|---|---|
| 有線 LAN | 同じルーター / LAN ハブ配下の通常運用 | network_addr |
| 通常 Wi-Fi LAN / AP | 同じ LAN にいる端末同士の接続 | network_addr |
USB gadget Ethernet (192.168.7.x) |
追加の別 transport が欲しい場合 | usb_addr |
いちばん簡単な構成: 親も子も同じルーターまたは同じ LAN ハブに有線接続し、discovery.enabled = true のまま起動してください。通常は network_addr の固定設定も不要です。
同一 LAN 内では UDP broadcast discovery により peer を自動検知・自動接続できます。
discovery.enabled = trueで有効- 各ノードが
announce_addrへ自分のnode_id/network_listen port/web portを通知 - 受信側は送信元 IP と通知 port から
network_addrを自動生成 [[peers]]にnode_idだけ書いておけば、IP 固定なしでも自動接続可能[[peers]]自体を書かなくても、検出された peer は status に現れ、動的接続される
通常の LAN discovery に加えて、wifi セクションで 親の自動 AP 化 と 子の既知 AP 自動接続 を行えます。
これは 追加機能 です。初期セットアップの既定値では使いません。
-
まずは 同じ LAN 内で discovery だけで接続確認 してください
-
Wi-Fi fallback を使いたい場合だけ
wifi.auto_manage = trueにしてください -
サンプル設定には
CANweeb-Parentの例を残していますが、デフォルトでは自動起動しません -
親ノード:
wifi.desired_mode = "parent"nmcli device wifi hotspotで AP を作成
-
子ノード:
wifi.desired_mode = "child"wifi.fallback_networksを priority 順で接続試行
-
親 UI から mode 切替 / AP 起動 / 手動接続 / 切断が可能
-
親 UI から peer の
relationshipとpreferred_transport_orderを変更可能 -
child の power / uptime / queue / inbox / RTT / 接続品質も親 UI で監視可能
-
child モード
- 起動時に
wifi.fallback_networksのうち、見えている SSID の中で priority が最も高いもの へ接続を試みます - すでに別の Wi-Fi に繋がっていても、より優先度の高い設定済み SSID が見えていればそちらへ切り替えます
- 逆に、設定済みの候補が見えていない場合は、見つからない SSID を探すために無意味に切断し続けることはしません
- 起動時に
-
parent モード
- 起動時に
wifi.interfaceを AP 用に使います - 同じ無線インターフェースを既存の Wi-Fi クライアント接続に使っていた場合、その接続は切り替わります
- つまり、
wlan01 本で親 AP を立てる構成では、元の家庭内 Wi-Fi 接続を維持できないことがあります
- 起動時に
-
親子が既存 LAN / 既存 Wi-Fi / LAN ハブに参加する構成
- その LAN 自体がインターネットへ出られるなら、親も子も通常どおりインターネット接続できます
-
親が
wlan0で AP を作る構成- その
wlan0は親子通信用に使われます - 同じ
wlan0経由の既存インターネット接続は通常維持されません - 親側でインターネットも維持したい場合は、有線 LAN / USB Ethernet / 別 Wi-Fi インターフェース を別途使ってください
- その
network_listen = "0.0.0.0:7002"が起動していれば、LAN / Wi-Fi 経由の通信待受はできています- 初期セットアップは 同じルーター / 同じ LAN ハブ配下に置くだけ にしてください
wifi.auto_manage = falseのままならnmcliや AP モードに依存しません- 親向け管理 UI は
http://<bind_addr>:8080/parent-ui/で外部公開できます /parent-ui/が 404 の場合は、古いtarget/release/canweebが動いている ことが多いのでcargo build --release後に再起動してください
| クラス | ACK | 永続化 | 用途例 |
|---|---|---|---|
control |
あり | ディスク | 非常停止・モード切替・GPIO 指令・状態遷移 |
telemetry |
なし | メモリ (topic 最新値) | IMU・オドメトリ・バッテリ・推定姿勢 |
stream |
なし | メモリ (ring buffer) | カメラ・RGB-D・LiDAR・大容量バイナリ |
重要: 100 Hz 超のセンサや画像を
controlに載せないでください。SD/eMMC 摩耗・再送コスト・制御遅延の原因になります。
- USB / network の 2 系統 TCP リスナー・コネクタ(片方のみでも動作)
- 同一 LAN 上の peer 自動検知・自動接続(UDP broadcast discovery)
- transport 優先順の設定と自動フェイルオーバー
- 接続ごとの
control_tx/bulk_tx二重キュー(大容量 stream で制御系を塞がない) controlの ACK + hop-by-hop 再送(複数経路で自動フェイルオーバー)telemetryの topic ごと最新値キャッシュ(メモリのみ、最大 4096 topic)streamの chunked 転送 + 受信側自動組み立て(パケロス時は StreamClose で強制完了)- stream ring buffer(最新 8 件をメモリ保持)
- topic / stream の WebSocket リアルタイム push
- メッセージ重複排除(
message_idベース) ttl/hopsによるループ防止broadcast/node:X/nodes:A,B,Cの配送ターゲット- WebUI(送信テスト・Topic/Stream モニタ・Inbox・wpa_cli)
- フレームサイズ上限(32 MiB)
# ビルド
cargo build --release
# 起動
./target/release/canweeb --config config/example.tomlWebUI: http://<bind_addr>:8080
Parent UI: http://<bind_addr>:8080/parent-ui/
config/example.toml をコピーしてノードごとに編集してください。
[node]
node_id = "node-pi"
role = "child"
tags = ["robot", "sensor"]
[storage]
root = "../data" # control メッセージのみ永続化
retention_seconds = 86400
[web]
bind = "0.0.0.0:8080"
[transport]
network_listen = "0.0.0.0:7002" # LAN / Wi-Fi リスナー(省略可)
connect_interval_ms = 1500
heartbeat_interval_ms = 1000
ack_timeout_ms = 2500
max_hops = 4
[discovery]
enabled = true
bind = "0.0.0.0:7060"
announce_addr = "255.255.255.255:7060"
announce_interval_ms = 1500
peer_ttl_ms = 8000
[wifi]
interface = "wlan0"
auto_manage = false
desired_mode = "child"
hotspot_ssid = "CANweeb-Parent"
hotspot_password = "canweeb1234"
hotspot_connection_name = "CANweeb Hotspot"
status_interval_ms = 2000
[[wifi.fallback_networks]]
ssid = "CANweeb-Parent"
password = "canweeb1234"
priority = 100
[[peers]]
node_id = "node-main"
role = "parent"
relationship = "parent"
preferred_transport_order = ["network"]
# network_addr = "192.168.1.10:7002"
tags = ["strategy"]最短構成:
# parent.toml / child.toml ともに
[discovery]
enabled = true
[wifi]
auto_manage = false
[[peers]]
# 相手の node_id だけ書く
node_id = "node-main"| Method | Path | 説明 |
|---|---|---|
| GET | /api/status |
ノード状態・ピア一覧 |
| GET | /api/wifi/status |
自ノードの Wi-Fi 状態 |
| POST | /api/wifi/apply-mode |
parent / child / ap / client の自動適用 |
| POST | /api/wifi/hotspot/start |
今すぐ AP を作成 |
| POST | /api/wifi/connect |
指定 SSID に接続 |
| POST | /api/wifi/disconnect |
Wi-Fi 切断 |
| GET | /api/peer-policies |
peer 関係と transport 優先順 |
| POST | /api/peer-policies |
peer 関係と transport 優先順を更新 |
| GET | /api/inbox |
control inbox 一覧 |
| GET | /api/inbox/:id |
inbox 詳細 + payload base64 |
| POST | /api/messages |
メッセージ送信 |
| GET | /api/topics |
telemetry 最新値一覧 |
| GET | /api/topic?name=<topic> |
topic 最新値詳細(/ を含む topic 名対応) |
| GET | /api/streams |
完成 stream 一覧(ring buffer) |
| GET | /api/streams/:stream_id |
stream payload base64 取得 |
| POST | /api/wifi-direct/run |
wpa_cli コマンド実行 |
| Path | 説明 |
|---|---|
ws://.../ws/topics |
telemetry topic 更新をリアルタイム push |
ws://.../ws/streams |
stream 組み立て完了をリアルタイム push(payload 含む) |
{
"target": "broadcast",
"traffic_class": "telemetry",
"topic": "imu/accel",
"content_type": "application/json",
"text": "{\"x\":0.1,\"y\":0.0,\"z\":9.8}"
}{
"target": "node:node-main",
"traffic_class": "control",
"subject": "emergency_stop",
"content_type": "application/octet-stream",
"payload_base64": "AQ=="
}# DHCP のままでよい
# 例:
ip addr showこの状態で CANweeb を起動すると、discovery により相互検出できます。
wifi.auto_manage = true に変更してから使ってください。初期セットアップの既定値ではありません。
usb_listen / usb_addr を追加すれば併用できますが、サンプルの既定値では使いません。
WebUI の wpa_cli パネルは残していますが、通常の LAN / ルーター配下運用では必須ではありません。
親子デモ向けの簡単な操作は examples/parent-ui/index.html の管理画面から行う想定です。
interface: wlan0
args: p2p_find
| パス | 内容 |
|---|---|
src/main.rs |
エントリポイント |
src/config.rs |
設定構造体 |
src/protocol.rs |
フレーム定義・TrafficClass・DeliveryTarget |
src/storage.rs |
永続キュー・inbox・topic cache・stream ring buffer |
src/mesh.rs |
接続管理・再送・ACK・topic pub/sub・stream 組み立て |
src/web.rs |
WebUI・HTTP API・WebSocket |
config/example.toml |
サンプル設定 |
- ルーティングはフラッディングです(経路学習は未実装)
- 時刻同期は担保しません(PTP/NTP は別途必要)
- 認証・暗号化は未実装です
- discovery は同一 L2/LAN セグメント内の自動発見です。サブネットを跨ぐ検出は行いません
- UDP broadcast を遮断するネットワークでは
network_addrを固定設定してください - systemd unit は同梱していません(
ExecStartに本バイナリを指定して自分で作成してください)
Ubuntu Server (strategy / AI)
↕ same LAN / router via CANweeb
Raspberry Pi (sensor / GPIO / actuator)
↕ LAN / Wi-Fi / その他 TCP
マイコン / 外部デバイス