mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
puj
This commit is contained in:
@@ -56,7 +56,7 @@ cd ~/MultiRoombaRover
|
|||||||
sudo ./pi/install_roverd.sh --mediamtx
|
sudo ./pi/install_roverd.sh --mediamtx
|
||||||
```
|
```
|
||||||
|
|
||||||
Then point each rover's `/etc/roverd.yaml` at `ws://<server>:8080/rover`, set `name` to the rover’s ID, and make sure the Pi’s mediaMTX is reachable at `http://<pi-ip>:8889/whep/rovercam` (the default). Each rover advertises that WHEP URL in its `hello` frame, and the server’s media bridge automatically creates a matching pull path so mediaMTX on 192.168.0.86 fans the stream out to drivers/spectators—browsers never talk to the Pi directly.
|
Then point each rover's `/etc/roverd.yaml` at `ws://<server>:8080/rover`, set `name` to the rover’s ID, and make sure the Pi’s mediaMTX is reachable at `http://<pi-ip>:8889/rovercam/whep` (the default). Each rover advertises that WHEP URL in its `hello` frame, and the server’s media bridge automatically creates a matching pull path so mediaMTX on 192.168.0.86 fans the stream out to drivers/spectators—browsers never talk to the Pi directly.
|
||||||
Use the “Restart Camera” button if you enable media management so roverd can bounce the mediamtx service remotely.
|
Use the “Restart Camera” button if you enable media management so roverd can bounce the mediamtx service remotely.
|
||||||
Heads-up: the BRC pulser now uses libgpiod; make sure the `roverd` service account is in the `gpio` group (or otherwise allowed to access `/dev/gpiochip*`) and set `brc.gpioChip` if your hardware exposes a different chip name.
|
Heads-up: the BRC pulser now uses libgpiod; make sure the `roverd` service account is in the `gpio` group (or otherwise allowed to access `/dev/gpiochip*`) and set `brc.gpioChip` if your hardware exposes a different chip name.
|
||||||
|
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
@@ -55,7 +55,7 @@ Flags:
|
|||||||
| `--mediamtx` | download/install mediaMTX plus the provided config + unit |
|
| `--mediamtx` | download/install mediaMTX plus the provided config + unit |
|
||||||
| `--mediamtx-version X.Y.Z` | override the mediaMTX release tag (default `1.15.3`) |
|
| `--mediamtx-version X.Y.Z` | override the mediaMTX release tag (default `1.15.3`) |
|
||||||
|
|
||||||
If the script installs the sample config, it will remind you to edit `/etc/roverd.yaml` before manually restarting the service: set `name`, `serverUrl`, serial device, BRC pin, battery thresholds, and optionally override `media.whepUrl`. When left blank, roverd automatically uses the Pi’s primary IPv4 plus `:8889/whep/rovercam`.
|
If the script installs the sample config, it will remind you to edit `/etc/roverd.yaml` before manually restarting the service: set `name`, `serverUrl`, serial device, BRC pin, battery thresholds, and optionally override `media.whepUrl`. When left blank, roverd automatically uses the Pi’s primary IPv4 plus `:8889/rovercam/whep`.
|
||||||
|
|
||||||
## Manual installation
|
## Manual installation
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ If the script installs the sample config, it will remind you to edit `/etc/rover
|
|||||||
sudo install -o roverd -g roverd -m 0755 dist/roverd /usr/local/bin/roverd
|
sudo install -o roverd -g roverd -m 0755 dist/roverd /usr/local/bin/roverd
|
||||||
sudo install -o roverd -g roverd -m 0640 pi/roverd/roverd.sample.yaml /etc/roverd.yaml
|
sudo install -o roverd -g roverd -m 0640 pi/roverd/roverd.sample.yaml /etc/roverd.yaml
|
||||||
```
|
```
|
||||||
Adjust `/etc/roverd.yaml` for each rover: `name`, `serverUrl` (e.g. `ws://control-server:8080/rover`), serial port path, battery thresholds, GPIO pin for BRC, and (if needed) the media `whepUrl` override. Otherwise, roverd fills in `http://<pi-ip>:8889/whep/rovercam` based on the DHCP-assigned address.
|
Adjust `/etc/roverd.yaml` for each rover: `name`, `serverUrl` (e.g. `ws://control-server:8080/rover`), serial port path, battery thresholds, GPIO pin for BRC, and (if needed) the media `whepUrl` override. Otherwise, roverd fills in `http://<pi-ip>:8889/rovercam/whep` based on the DHCP-assigned address.
|
||||||
|
|
||||||
2. Install the systemd unit:
|
2. Install the systemd unit:
|
||||||
```bash
|
```bash
|
||||||
@@ -92,7 +92,7 @@ If you set `media.manage: true` in `/etc/roverd.yaml`, make sure the `roverd` se
|
|||||||
sudo systemctl enable --now mediamtx.service
|
sudo systemctl enable --now mediamtx.service
|
||||||
```
|
```
|
||||||
|
|
||||||
The sample config uses the Raspberry Pi camera module as the source, enables the local mediaMTX HTTP API so `roverd` can health-check the service, and serves WebRTC playback at `http://<pi-ip>:8889/whep/rovercam`. Keep that URL reachable from the control server—`roverd` advertises it automatically and the central media bridge pulls each rover’s feed over WHEP.
|
The sample config uses the Raspberry Pi camera module as the source, enables the local mediaMTX HTTP API so `roverd` can health-check the service, and serves WebRTC playback at `http://<pi-ip>:8889/rovercam/whep`. Keep that URL reachable from the control server—`roverd` advertises it automatically and the central media bridge pulls each rover’s feed over WHEP.
|
||||||
Expose the mediaMTX HTTP API locally (default `http://127.0.0.1:9997`) and set `media.healthUrl` so `roverd` can monitor the pipeline; `media.service` should match the systemd unit name (default `mediamtx.service`).
|
Expose the mediaMTX HTTP API locally (default `http://127.0.0.1:9997`) and set `media.healthUrl` so `roverd` can monitor the pipeline; `media.service` should match the systemd unit name (default `mediamtx.service`).
|
||||||
With that in place, the Pi only talks to the server over the trusted LAN while the server-side mediaMTX distributes video to every driver and spectator.
|
With that in place, the Pi only talks to the server over the trusted LAN while the server-side mediaMTX distributes video to every driver and spectator.
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -94,7 +94,7 @@ func LoadConfig(path string) (*Config, error) {
|
|||||||
},
|
},
|
||||||
Media: MediaConfig{
|
Media: MediaConfig{
|
||||||
WhepPort: 8889,
|
WhepPort: 8889,
|
||||||
WhepPath: "/whep/rovercam",
|
WhepPath: "/rovercam/whep",
|
||||||
HealthInterval: Duration{Duration: 30 * time.Second},
|
HealthInterval: Duration{Duration: 30 * time.Second},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -135,7 +135,7 @@ func LoadConfig(path string) (*Config, error) {
|
|||||||
}
|
}
|
||||||
path := cfg.Media.WhepPath
|
path := cfg.Media.WhepPath
|
||||||
if path == "" {
|
if path == "" {
|
||||||
path = "/whep/rovercam"
|
path = "/rovercam/whep"
|
||||||
}
|
}
|
||||||
path = ensureLeadingSlash(path)
|
path = ensureLeadingSlash(path)
|
||||||
scheme := "http"
|
scheme := "http"
|
||||||
|
|||||||
@@ -93,23 +93,50 @@ function normalizeSource(raw) {
|
|||||||
if (!raw) return null;
|
if (!raw) return null;
|
||||||
const trimmed = String(raw).trim();
|
const trimmed = String(raw).trim();
|
||||||
if (!trimmed) return null;
|
if (!trimmed) return null;
|
||||||
if (/^wheps?:\/\//i.test(trimmed)) {
|
|
||||||
return trimmed;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
const parsed = new URL(trimmed);
|
const parsed = new URL(trimmed);
|
||||||
const protocol = parsed.protocol === 'https:' ? 'wheps' : 'whep';
|
let protocol = parsed.protocol;
|
||||||
let pathname = parsed.pathname || '/';
|
if (!protocol || protocol === 'http:') {
|
||||||
if (!pathname.startsWith('/')) {
|
protocol = 'whep:';
|
||||||
pathname = `/${pathname}`;
|
} else if (protocol === 'https:') {
|
||||||
|
protocol = 'wheps:';
|
||||||
|
} else if (protocol !== 'whep:' && protocol !== 'wheps:') {
|
||||||
|
throw new Error('unsupported protocol');
|
||||||
}
|
}
|
||||||
return `${protocol}://${parsed.host}${pathname}${parsed.search || ''}`;
|
const host = parsed.host;
|
||||||
|
if (!host) {
|
||||||
|
throw new Error('missing host');
|
||||||
|
}
|
||||||
|
let pathname = parsed.pathname || '/';
|
||||||
|
pathname = normalizeWhepPath(pathname);
|
||||||
|
return `${protocol.slice(0, -1)}://${host}${pathname}${parsed.search || ''}`;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.warn('invalid WHEP URL provided by rover (%s): %s', raw, err.message);
|
logger.warn('invalid WHEP URL provided by rover (%s): %s', raw, err.message);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeWhepPath(pathname) {
|
||||||
|
let result = pathname || '/';
|
||||||
|
if (!result.startsWith('/')) {
|
||||||
|
result = `/${result}`;
|
||||||
|
}
|
||||||
|
result = result.replace(/\/+/g, '/');
|
||||||
|
result = result.replace(/\/+$/, '');
|
||||||
|
if (result.startsWith('/whep/')) {
|
||||||
|
result = `/${result.slice(6)}`;
|
||||||
|
} else if (result === '/whep') {
|
||||||
|
result = '/rovercam';
|
||||||
|
}
|
||||||
|
if (!result || result === '/') {
|
||||||
|
result = '/rovercam';
|
||||||
|
}
|
||||||
|
if (!result.endsWith('/whep')) {
|
||||||
|
result = `${result}/whep`;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
async function callApi(method, path, body) {
|
async function callApi(method, path, body) {
|
||||||
const url = `${apiBase}${path}`;
|
const url = `${apiBase}${path}`;
|
||||||
const res = await fetch(url, {
|
const res = await fetch(url, {
|
||||||
|
|||||||
Reference in New Issue
Block a user