reachymini

package module
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 5, 2026 License: MIT Imports: 23 Imported by: 0

README

reachy-mini-sdk-go

A Go SDK for piloting a Reachy Mini robot without writing any Python.

Pollen Robotics' official SDK is Python-only, but the robot runs a background daemon (a FastAPI service, pre-installed and auto-started) that exposes the entire control surface over plain HTTP REST + WebSocket JSON, plus a separate embedded WebRTC signalling server for the camera feed. This package is a from-scratch Go client for that daemon API, reverse-engineered from the daemon's live OpenAPI schema and, for the camera, the upstream GStreamer webrtcsink signalling protocol.

Install

go get github.com/nlm/reachy-mini-sdk-go

Requirements

  • Go 1.25+
  • ffmpeg on PATH, built with libopus (only needed for the WebRTC media features — StreamCameraFrames, StreamMicrophoneAudio, OpenAudioSession — where it decodes the camera's H.264/VP8 video and encodes/decodes Opus audio, since there are no production-quality pure-Go codecs for these)
  • Network access to the robot's daemon: port 8000 for the REST/WebSocket API, and 8443 for the WebRTC signalling server used for the camera, microphone and speaker streams.

Usage

import reachymini "github.com/nlm/reachy-mini-sdk-go"

client := reachymini.New("http://localhost:8000")

ctx := context.Background()
if err := client.EnsureMotorMode(ctx, reachymini.MotorModeEnabled); err != nil {
	log.Fatal(err)
}
if err := client.WakeUp(ctx); err != nil {
	log.Fatal(err)
}

See github.com/nlm/reachy-mini-sdk-go on pkg.go.dev for the full API, and github.com/nlm/reachy-mini-demos for runnable example programs built on this SDK.

SDK coverage

File Covers
state.go Robot state: full state (with FullStateOptions to opt into head/passive joints, DoA, IMU, matrix poses), present head pose / body yaw / antenna positions, direction-of-arrival, IMU, plus StreamFullState for the live WebSocket feed
move.go Movement: Goto (interpolated), SetTarget/StreamSetTarget (direct, low-latency), WakeUp/GotoSleep (canned animations), Stop, recorded move datasets
motors.go Motor control mode (enabled / disabled / gravity_compensation), plus EnsureMotorMode
media.go Sound playback: play/stop/list/upload/delete, clear incoming audio
tracking.go Daemon-side face tracking: enable (with blend weight) / disable, latest tracked face
wobbling.go Daemon-side audio-reactive head wobbling (the head moves while the robot speaks): enable / disable
audio.go Speaker/mic volume, low-level audio mixer parameters, test sound
daemon.go Daemon status, start/stop/restart, robot name, hardware ID, robot app-lock status
apps.go The Hugging Face Spaces app store: list/install/remove/update/start/stop apps, check for updates, the auto-start app
camera.go Camera specs (resolutions, intrinsics/distortion)
camera_stream.go + webrtc_signalling.go StreamCameraFrames — live decoded video frames over WebRTC
audio_stream.go StreamMicrophoneAudio — live decoded PCM audio from the robot's microphone, over the same WebRTC feed
audio_session.go + speaker_audio.go + ogg.go OpenAudioSession — stream PCM to the robot's speaker (and optionally receive its microphone) over one WebRTC session, with Clear/Buffered/Drain for barge-in and end-of-utterance
kinematics.go Kinematics info, URDF, STL mesh downloads
ws.go Shared WebSocket helper for the streaming state/target endpoints

All request/response types were derived from the daemon's live /openapi.json and cross-checked against a real robot and Pollen's own desktop simulator — see "Verified vs. inferred" below for the exceptions.

Known issues / caveats

  • Some calls need daemon 1.11 or newer: head tracking (tracking.go), GetIMU / FullStateOptions.IMU, GetRobotName / SetRobotName, GetStartupApp / SetStartupApp and StartAppNoEvict. Older daemons (e.g. the 1.8.x desktop app) answer 404, or simply leave the IMU and DaemonStatus.FaceTarget empty.

  • gravity_compensation motor mode returns HTTP 500 on daemon v1.8.1 (confirmed against real hardware). Prefer disabled, which works reliably.

  • Motor control mode does not survive a daemon restart. On real hardware it always came back disabled; the desktop simulator has come back either way. Nothing enforces this — any program that moves the robot should call EnsureMotorMode(ctx, MotorModeEnabled) first rather than assuming it's already enabled. It's also been observed to reset to disabled on its own between sessions, with no restart involved, so "check before you move" is the safe default, not just "check after a restart."

  • Movement commands don't validate hardware state. Goto, SetTarget, WakeUp, etc. all return 200 OK and a UUID even when motor control is disabled — they're silently no-ops. There's no error to catch; the only sign is that nothing physically moves.

  • A daemon restart puts motors in compliant/free-spinning mode for its duration. Anything resting on the antennas/head (or gravity) can leave them far from where they started. Re-enabling control doesn't re-home position.

  • Pose's AnyPose union (XYZRPYPose vs Matrix4x4Pose) is distinguished in UnmarshalJSON by the presence of an "m" field, since the daemon's Pydantic model doesn't use an explicit discriminator tag. Verified against live data using XYZRPYPose; Matrix4x4Pose round-tripping hasn't been separately exercised.

Camera / WebRTC
  • Every WebRTC stream is its own consumer session, and the daemon runs a separate camera encoder for each one, even for audio-only use. On the robot's Raspberry Pi that's real load: when you need both microphone and speaker, use one OpenAudioSession with Microphone: true rather than a separate StreamMicrophoneAudio.

  • Verified live end-to-end against Pollen's desktop simulator: signalling handshake, WebRTC/ICE negotiation, VP8 depacketization, IVF muxing, and ffmpeg decode all confirmed producing real, correctly-decoded frames.

  • The simulator negotiates VP8. Real hardware has been observed in the daemon's own source to use hardware H.264 on Raspberry Pi instead. Both codecs are handled in camera_stream.go (decoder choice is deferred until the negotiated codec is known), but only the VP8 path has actually been exercised against a live producer — H.264 is implemented from the same protocol understanding but unverified against real hardware.

  • TestFFmpegH264DecodePipeline and TestFFmpegVP8DecodePipeline (camera_stream_test.go) test the ffmpeg decode pipeline in isolation with synthetic streams, independent of the robot — run with go test ./....

  • The same WebRTC feed also carries an Opus audio track from the robot's microphone, alongside the video track (confirmed by cross-referencing the official Python SDK's ReachyMini(media_backend="webrtc") + mini.media.start_recording() path, which relies on the same daemon capability). StreamMicrophoneAudio (audio_stream.go) consumes it, muxing RTP packets into an Ogg/Opus container (pion/webrtc's oggwriter, no manual depacketization needed since one RTP packet is one Opus frame) and decoding via ffmpeg to raw PCM, the same subprocess pattern as the video path. It is tested end to end against an in-process fake producer, and the same microphone transport (via OpenAudioSession's Microphone option) has been verified against Pollen's desktop simulator, but not yet against real hardware.

  • Speaker audio (OpenAudioSession) goes the other way: the daemon offers every consumer a send-and-receive audio transceiver and plays what it receives through its speaker, feeding the head wobbler (EnableWobbling) and the barge-in flush (ClearIncomingAudio). The session encodes PCM to Opus with ffmpeg and paces it in real time, sending silence when idle. The daemon assumes a single client sends audio: with several, ClearIncomingAudio and its echo canceller follow only the most recently connected one. Tested end to end against an in-process fake producer (webrtc_fake_producer_test.go, real pion WebRTC over loopback) and verified live against Pollen's desktop simulator (daemons 1.8.4 and 1.11.0): audio plays, drives the wobbler, and stops on Clear + ClearIncomingAudio. Not yet run on real hardware; go test -tags live -run Live (see live_test.go) repeats those checks against any daemon.

Verified vs. inferred

Most of the SDK has been exercised against either real Reachy Mini hardware or Pollen's desktop simulator (state reads, movement, sounds, motors, daemon restart, volume, apps listing, kinematics, camera). A few corners haven't been:

  • InstallApp / RemoveApp / UpdateApp / StartApp / StopCurrentApp / ResetAppsCache — not run live, since they mutate persistent app installation state
  • GetKinematicsSTL — needs a real filename from GetURDF's content, not just guessed
  • ReadAudioParameter / ApplyAudioConfig — parameter names are undocumented and backend-specific
  • H.264 camera decoding (see above)
  • StreamMicrophoneAudio and OpenAudioSession on real hardware (both verified against the simulator, see "Camera / WebRTC" above)
  • Head tracking with a face actually in view (enable/disable/face queries are verified on the 1.11 simulator, which reported no face), and GetIMU returning a reading (the simulator has no IMU)
  • StartAppNoEvict — not run live, since it starts an installed app
  • StartDaemon / StopDaemon — not run live, since they take the robot backend down

These are implemented against the daemon's documented schema and follow the same patterns as the verified parts of the SDK, but treat them as a starting point to debug against real traffic rather than a guaranteed-working path.

Documentation

Overview

Package reachymini is a Go client for the Reachy Mini daemon's REST/WebSocket API (the same interface used by Pollen Robotics' own TypeScript SDK and desktop app), so the robot can be piloted without writing any Python.

Index

Examples

Constants

View Source
const AudioChannels = 1

AudioChannels is the channel count of the PCM chunks StreamMicrophoneAudio delivers. The decoder always downmixes to mono so callers don't need to discover the negotiated channel count asynchronously from inside OnTrack.

View Source
const AudioSampleRate = 48000

AudioSampleRate is the sample rate (Hz) of the PCM chunks StreamMicrophoneAudio delivers. Opus's RTP clock rate is fixed at 48000 by RFC 7587 regardless of the codec's actual internal audio bandwidth, so this is a constant rather than something negotiated per-track.

Variables

View Source
var ErrAudioSessionClosed = errors.New("reachymini: audio session closed")

ErrAudioSessionClosed is returned by AudioSession methods once the session has been closed.

Functions

This section is empty.

Types

type APIError

type APIError struct {
	// StatusCode is the HTTP status the daemon returned (e.g. 404, 500).
	StatusCode int
	// Body is the raw response body, usually a FastAPI JSON error detail.
	Body string
}

APIError is returned when the daemon responds with a non-2xx status.

func (*APIError) Error

func (e *APIError) Error() string

type AppInfo

type AppInfo struct {
	// Name is the app's unique identifier, used e.g. by StartApp/RemoveApp.
	Name string `json:"name"`
	// SourceKind is where this app comes from (see SourceKind).
	SourceKind SourceKind `json:"source_kind"`
	// Description is a human-readable summary, if the source provides one.
	Description string `json:"description,omitempty"`
	// URL points at the app's source (e.g. its Hugging Face Space page),
	// if applicable to SourceKind.
	URL *string `json:"url,omitempty"`
	// Extra carries source-specific metadata not otherwise modeled here.
	Extra map[string]any `json:"extra,omitempty"`
}

AppInfo describes an app available from the robot's app store or already installed.

type AppState

type AppState string

AppState is the runtime status of an app.

const (
	AppStateStarting AppState = "starting"
	AppStateRunning  AppState = "running"
	AppStateDone     AppState = "done"
	AppStateStopping AppState = "stopping"
	AppStateError    AppState = "error"
)

type AppStatus

type AppStatus struct {
	// Info identifies which app this status is for.
	Info AppInfo `json:"info"`
	// State is the app's current runtime status (see AppState).
	State AppState `json:"state"`
	// Error is set when State is AppStateError, describing what went wrong.
	Error *string `json:"error,omitempty"`
}

AppStatus is the status of a running (or just-started/stopped) app.

type AppUpdateStatus

type AppUpdateStatus struct {
	// AppName is the installed app's name, matching AppInfo.Name.
	AppName string `json:"app_name"`
	// SpaceID is the app's Hugging Face Space identifier.
	SpaceID string `json:"space_id"`
	// InstalledSHA is the commit SHA currently installed.
	InstalledSHA string `json:"installed_sha"`
	// LatestSHA is the commit SHA currently published upstream.
	LatestSHA string `json:"latest_sha"`
	// UpdateAvailable reports whether InstalledSHA differs from LatestSHA.
	UpdateAvailable bool `json:"update_available"`
	// LastModified is when the upstream Space was last modified, if known.
	LastModified *string `json:"last_modified,omitempty"`
}

AppUpdateStatus is the result of checking one installed app for updates.

type AppUpdatesResponse

type AppUpdatesResponse struct {
	// AppsWithUpdates lists only the installed apps that have an update
	// available (not every app that was checked).
	AppsWithUpdates []AppUpdateStatus `json:"apps_with_updates"`
	// AppsChecked is how many installed apps were checked for updates.
	AppsChecked int `json:"apps_checked"`
	// AppsSkipped is how many installed apps couldn't be checked (e.g. not
	// backed by a Hugging Face Space).
	AppsSkipped int `json:"apps_skipped"`
}

AppUpdatesResponse is the response of GET /api/apps/check-updates.

type AudioParamPair

type AudioParamPair struct {
	// Name is the mixer parameter's name (backend-specific; see
	// ReadAudioParameter's doc comment).
	Name string `json:"name"`
	// Values are the parameter's new value(s) -- some mixer parameters are
	// scalar (one value), others are per-channel (one value each).
	Values []float64 `json:"values"`
}

AudioParamPair is one (parameter name, values) pair in an audio config payload, as used by ApplyAudioConfig.

type AudioSession added in v1.3.0

type AudioSession struct {
	// contains filtered or unexported fields
}

AudioSession is a WebRTC session with the daemon that plays audio on the robot's speaker. Audio sent this way is what the daemon's head wobbling (EnableWobbling) reacts to, and what ClearIncomingAudio flushes.

The session streams continuously in real time: Write queues PCM, and the session encodes the queue as it falls due, or silence when the queue is empty, so queued audio plays back to back and gaps play as silence. Its methods are safe for concurrent use.

The daemon is built around a single client sending audio. With several (another AudioSession, the Python SDK, the phone app), ClearIncomingAudio and the echo canceller only follow the most recently connected one, and every sender's audio, silence included, feeds the same head wobbler.

func (*AudioSession) Buffered added in v1.3.0

func (s *AudioSession) Buffered() time.Duration

Buffered returns how much queued audio hasn't been sent yet.

func (*AudioSession) Clear added in v1.3.0

func (s *AudioSession) Clear()

Clear drops all queued audio that hasn't been sent yet, e.g. when the user interrupts the robot. Audio already sent is still in the daemon's playback buffer; call Client.ClearIncomingAudio to drop that too.

func (*AudioSession) Close added in v1.3.0

func (s *AudioSession) Close() error

Close ends the session, dropping any audio not yet played, and waits for it to release its resources. It returns Err, which is nil unless something else had already ended the session.

func (*AudioSession) Done added in v1.3.0

func (s *AudioSession) Done() <-chan struct{}

Done is closed when the session has ended and released its resources.

func (*AudioSession) Drain added in v1.3.0

func (s *AudioSession) Drain(ctx context.Context) error

Drain waits until all queued audio has been handed to the encoder. The robot finishes playing it about half a second later: the encoder, the network and the daemon's 300 ms jitter buffer all sit in between. Close drops whatever is still in flight, so to finish an utterance, wait that long after Drain before closing.

func (*AudioSession) Err added in v1.3.0

func (s *AudioSession) Err() error

Err returns why the session ended: nil while it's running or if Close ended it, ctx's error if its context ended it, or the failure that ended it.

func (*AudioSession) Microphone added in v1.3.0

func (s *AudioSession) Microphone() <-chan []byte

Microphone returns the robot microphone's audio as signed 16-bit little-endian mono PCM at AudioSampleRate, if opts.Microphone was set (nil otherwise). The channel is closed when the session ends, or just before if a microphone failure is what ends it. Keep reading it: if it isn't drained, incoming audio backs up and is eventually dropped.

func (*AudioSession) Write added in v1.3.0

func (s *AudioSession) Write(pcm []byte) (int, error)

Write queues pcm (signed 16-bit little-endian, in the session's SampleRate and Channels) to play after any audio already queued. It accepts all of pcm without waiting for playback; once the session has ended it returns why (waiting for shutdown to finish if it's underway).

type AudioSessionOptions added in v1.3.0

type AudioSessionOptions struct {
	// SignallingURL is the WebRTC signalling server's WebSocket URL, as
	// in AudioStreamOptions. Defaults to Client's BaseURL host on port
	// 8443.
	SignallingURL string

	// ProducerName optionally selects a producer by its advertised meta
	// name, as in AudioStreamOptions.
	ProducerName string

	// FFmpegPath overrides the ffmpeg binary used to encode speaker audio
	// to Opus. Defaults to "ffmpeg" (resolved via PATH).
	FFmpegPath string

	// SampleRate is the sample rate, in Hz, of the PCM passed to Write.
	// Defaults to AudioSampleRate. Any rate works: ffmpeg resamples.
	SampleRate int

	// Channels is the channel count of the (interleaved) PCM passed to
	// Write. Defaults to 1. The robot plays it downmixed to mono.
	Channels int

	// Microphone also decodes the robot's microphone, delivered on
	// AudioSession.Microphone in the same format as
	// StreamMicrophoneAudio. A microphone failure (e.g. its decoder
	// dying) ends the whole session. Prefer this to a separate
	// StreamMicrophoneAudio when you need both directions: each WebRTC
	// session costs the robot a camera encoder.
	Microphone bool
}

AudioSessionOptions configures OpenAudioSession.

type AudioStreamOptions added in v1.1.0

type AudioStreamOptions struct {
	// SignallingURL is the WebRTC signalling server's WebSocket URL, e.g.
	// "ws://localhost:8443". Same signalling server as CameraStreamOptions
	// (see camera_stream.go) -- defaults to Client's BaseURL host on port
	// 8443 if empty. Opening this alongside a concurrent StreamCameraFrames
	// call is fine: the daemon's webrtcsink producer supports multiple
	// simultaneous consumer sessions.
	SignallingURL string

	// ProducerName optionally selects a specific producer by its
	// advertised meta name, if the signalling server lists more than one.
	// If empty, the first available producer is used.
	ProducerName string

	// FFmpegPath overrides the ffmpeg binary used to decode Opus to raw
	// PCM. Defaults to "ffmpeg" (resolved via PATH).
	FFmpegPath string
}

AudioStreamOptions configures StreamMicrophoneAudio.

type BackendStatus

type BackendStatus struct {
	// Ready is the backend's self-reported readiness (unreliable -- see
	// the type-level comment above).
	Ready bool `json:"ready"`
	// MotorControlMode is the current motor control mode (see
	// MotorControlMode), mirroring GetMotorStatus.
	MotorControlMode MotorControlMode `json:"motor_control_mode"`
	// LastAlive is a backend-specific liveness timestamp/marker with no
	// fixed schema in the daemon's OpenAPI spec.
	LastAlive any `json:"last_alive"`
	// ControlLoopStats is nil if the backend hasn't reported stats yet.
	ControlLoopStats *ControlLoopStats `json:"control_loop_stats"`
	// Error is a backend-specific error payload with no fixed schema,
	// non-nil if the backend is in an error state.
	Error any `json:"error"`
}

BackendStatus reports the motor/hardware backend's health. Ready has been observed false even during normal operation, so don't gate on it; State on the enclosing DaemonStatus is the more reliable liveness signal.

type CameraSpecs

type CameraSpecs struct {
	// Name identifies the camera module/model the daemon detected.
	Name string `json:"name"`
	// AvailableResolutions lists every resolution/FPS mode this camera
	// supports.
	AvailableResolutions []ResolutionInfo `json:"available_resolutions"`
	// DefaultResolution is the mode StreamCameraFrames requests frames at.
	DefaultResolution ResolutionInfo `json:"default_resolution"`
	// K is the 3x3 intrinsic camera matrix (focal lengths and principal
	// point), row-major, for DefaultResolution's dimensions.
	K [][]float64 `json:"K"`
	// D is the lens distortion coefficients, in OpenCV's order
	// (k1, k2, p1, p2, k3, ...).
	D []float64 `json:"D"`
}

CameraSpecs is the response of GET /api/camera/specs: full camera specifications as detected by the daemon, including the intrinsic matrix K and distortion coefficients D (standard OpenCV pinhole camera model).

type CameraStreamOptions

type CameraStreamOptions struct {
	// SignallingURL is the WebRTC signalling server's WebSocket URL, e.g.
	// "ws://localhost:8443". This is a *separate* connection from the
	// daemon's REST API -- see webrtc_signalling.go. Defaults to Client's
	// BaseURL host on port 8443 if empty.
	SignallingURL string

	// ProducerName optionally selects a specific producer by its
	// advertised meta name, if the signalling server lists more than one.
	// If empty, the first available producer is used.
	ProducerName string

	// FFmpegPath overrides the ffmpeg binary used to decode video to raw
	// RGB frames. Defaults to "ffmpeg" (resolved via PATH). This is a
	// runtime dependency of the calling machine, not a Go dependency --
	// there is no production-quality pure-Go decoder for either codec the
	// daemon may negotiate (see below).
	FFmpegPath string
}

CameraStreamOptions configures StreamCameraFrames.

type Client

type Client struct {
	// BaseURL is the daemon's REST API root, with no trailing slash (e.g.
	// "http://localhost:8000"). Also used to derive the WebSocket URLs for
	// StreamFullState/StreamSetTarget, and, unless overridden, the WebRTC
	// signalling server URL for StreamCameraFrames.
	BaseURL string
	// HTTPClient issues all REST requests. Defaults to a client with a 10s
	// timeout (see New); replace it to change timeouts, add TLS config, etc.
	HTTPClient *http.Client
}

Client talks to a Reachy Mini daemon reachable at BaseURL (e.g. "http://localhost:8000" or "http://<robot-host>:8000").

func New

func New(baseURL string) *Client

New returns a Client pointed at baseURL, e.g. "http://localhost:8000".

func (*Client) ApplyAudioConfig

func (c *Client) ApplyAudioConfig(ctx context.Context, config []AudioParamPair, verify bool) (bool, error)

ApplyAudioConfig applies low-level audio mixer parameters. If verify is true (the daemon's own default), it reads each parameter back after writing to confirm it took effect.

func (*Client) CheckAppUpdates

func (c *Client) CheckAppUpdates(ctx context.Context, force bool) (AppUpdatesResponse, error)

CheckAppUpdates checks installed apps for available updates. Set force to bypass any cached result.

func (*Client) ClearIncomingAudio

func (c *Client) ClearIncomingAudio(ctx context.Context) (map[string]string, error)

ClearIncomingAudio discards any buffered incoming audio (e.g. from the microphone/direction-of-arrival pipeline).

func (*Client) DeleteSound

func (c *Client) DeleteSound(ctx context.Context, filename string) error

DeleteSound removes a sound file from the robot.

func (*Client) DisableHeadTracking added in v1.2.0

func (c *Client) DisableHeadTracking(ctx context.Context) error

DisableHeadTracking stops the daemon's face detector.

Requires daemon 1.11+ (older daemons answer 404).

func (*Client) DisableWobbling added in v1.3.0

func (c *Client) DisableWobbling(ctx context.Context) error

DisableWobbling turns off audio-reactive head wobbling and resets the head offsets it applied back to zero.

func (*Client) EnableHeadTracking added in v1.2.0

func (c *Client) EnableHeadTracking(ctx context.Context, weight float64) (bool, error)

EnableHeadTracking turns on the daemon's face detector and blends its aim into the head pose by weight (0..1). The detector only runs while weight > 0; at weight >= 1 the daemon ignores other head targets. It reports false when the daemon can't track (e.g. no camera).

Requires daemon 1.11+ (older daemons answer 404).

func (*Client) EnableWobbling added in v1.3.0

func (c *Client) EnableWobbling(ctx context.Context) error

EnableWobbling turns on the daemon's audio-reactive head wobbling: audio played on the robot (PlaySound, incoming WebRTC audio) is analysed and converted into subtle head movements layered on top of the head target. The daemon still reports success when it has no media server (e.g. started with no media), in which case nothing wobbles.

func (*Client) EnsureMotorMode

func (c *Client) EnsureMotorMode(ctx context.Context, mode MotorControlMode) (changed bool, err error)

EnsureMotorMode sets the robot's motor control mode to mode if it isn't already there, and reports whether a change was made. Movement commands (Goto, SetTarget, WakeUp, GotoSleep, ...) are accepted by the daemon and silently no-op if the robot isn't actually in MotorModeEnabled, so this is meant to be called at the top of anything that's about to move the robot.

func (*Client) GetCameraSpecs

func (c *Client) GetCameraSpecs(ctx context.Context) (CameraSpecs, error)

GetCameraSpecs returns the robot's camera specifications.

func (*Client) GetCurrentAppStatus

func (c *Client) GetCurrentAppStatus(ctx context.Context) (*AppStatus, error)

GetCurrentAppStatus returns the currently running app's status, or nil if no app is running.

func (*Client) GetDaemonStatus

func (c *Client) GetDaemonStatus(ctx context.Context) (DaemonStatus, error)

GetDaemonStatus returns the daemon's current status, including hardware backend health and motor control mode.

func (*Client) GetDoA

func (c *Client) GetDoA(ctx context.Context) (DoAInfo, error)

GetDoA returns the current direction-of-arrival (sound source) estimate.

func (*Client) GetFullState

func (c *Client) GetFullState(ctx context.Context) (FullState, error)

GetFullState returns the robot's complete current state, with the daemon's default fields (see FullStateOptions).

func (*Client) GetFullStateWithOptions added in v1.3.0

func (c *Client) GetFullStateWithOptions(ctx context.Context, opts FullStateOptions) (FullState, error)

GetFullStateWithOptions returns the robot's current state with the fields selected by opts.

func (*Client) GetHardwareID added in v1.3.0

func (c *Client) GetHardwareID(ctx context.Context) (string, error)

GetHardwareID returns the robot's unique hardware ID, an opaque 16-hex-char value derived from its audio device's USB serial, stable across reboots and OS reinstalls. It is "" when no robot is attached, e.g. a daemon running on a developer machine.

func (*Client) GetIMU added in v1.3.0

func (c *Client) GetIMU(ctx context.Context) (*ImuData, error)

GetIMU returns the latest IMU reading, or nil when there is none: the Lite and simulation have no IMU, and the daemon drops stale readings.

Requires daemon 1.11+ (older daemons answer 404).

func (*Client) GetJobStatus

func (c *Client) GetJobStatus(ctx context.Context, jobID string) (JobInfo, error)

GetJobStatus returns the status of a background job: an install/update started by InstallApp, InstallPrivateSpace, or UpdateApp, or a daemon start/stop/restart (StartDaemon, StopDaemon, RestartDaemon).

func (*Client) GetKinematicsInfo

func (c *Client) GetKinematicsInfo(ctx context.Context) (map[string]any, error)

GetKinematicsInfo returns the daemon's kinematics configuration as a free-form map -- the daemon's OpenAPI spec declares this endpoint's response as an open object with no fixed schema.

func (*Client) GetKinematicsSTL

func (c *Client) GetKinematicsSTL(ctx context.Context, filename string) ([]byte, error)

GetKinematicsSTL downloads the raw STL mesh file named filename (as referenced by GetURDF/GetKinematicsInfo) and returns its bytes.

func (*Client) GetMicrophoneVolume

func (c *Client) GetMicrophoneVolume(ctx context.Context) (VolumeInfo, error)

GetMicrophoneVolume returns the current microphone volume.

func (*Client) GetMotorStatus

func (c *Client) GetMotorStatus(ctx context.Context) (MotorStatus, error)

GetMotorStatus returns the robot's current motor control mode.

func (*Client) GetPresentAntennaPositions

func (c *Client) GetPresentAntennaPositions(ctx context.Context) ([2]float64, error)

GetPresentAntennaPositions returns the [left, right] antenna joint positions.

func (*Client) GetPresentBodyYaw

func (c *Client) GetPresentBodyYaw(ctx context.Context) (float64, error)

GetPresentBodyYaw returns the body's current yaw.

func (*Client) GetPresentHeadPose

func (c *Client) GetPresentHeadPose(ctx context.Context) (Pose, error)

GetPresentHeadPose returns the head's current pose.

func (*Client) GetRobotAppLockStatus added in v1.3.0

func (c *Client) GetRobotAppLockStatus(ctx context.Context) (RobotAppLockStatus, error)

GetRobotAppLockStatus reports which managed app, if any, holds the robot. Clients talking to the daemon directly, like this SDK, bypass the lock, so it only reflects daemon-launched apps and remote sessions.

func (*Client) GetRobotName added in v1.3.0

func (c *Client) GetRobotName(ctx context.Context) (string, error)

GetRobotName returns the robot's display name: the name it was last renamed to, else the daemon's configured default. It is "" only when neither exists.

Requires daemon 1.11+ (older daemons answer 404).

func (*Client) GetStartupApp added in v1.3.0

func (c *Client) GetStartupApp(ctx context.Context) (string, error)

GetStartupApp returns the app the daemon starts automatically, or "" if none is set. The daemon starts it when the robot first wakes up, and when a touch on the antennas wakes an idle robot. It never evicts a remote WebRTC session to do so.

Requires daemon 1.11+ (older daemons answer 404).

func (*Client) GetTrackedFace added in v1.2.0

func (c *Client) GetTrackedFace(ctx context.Context) (FaceTarget, error)

GetTrackedFace returns the latest face the daemon's detector observed.

Requires daemon 1.11+ (older daemons answer 404).

func (*Client) GetURDF

func (c *Client) GetURDF(ctx context.Context) (map[string]string, error)

GetURDF returns the robot's URDF description as a set of named file contents (e.g. a "urdf" key holding the XML).

func (*Client) GetVolume

func (c *Client) GetVolume(ctx context.Context) (VolumeInfo, error)

GetVolume returns the current speaker volume.

func (*Client) Goto

func (c *Client) Goto(ctx context.Context, req GotoRequest) (MoveUUID, error)

Goto smoothly interpolates to the given target pose(s) over req.Duration.

Example

ExampleClient_Goto smoothly moves the head to a target pose over one second, using min-jerk interpolation for a natural-looking motion.

package main

import (
	"context"
	"log"

	reachymini "github.com/nlm/reachy-mini-sdk-go"
)

func main() {
	client := reachymini.New("http://localhost:8000")
	ctx := context.Background()

	_, err := client.Goto(ctx, reachymini.GotoRequest{
		HeadPose:      reachymini.NewXYZRPYPose(0, 0, 0, 0, 0.2, 0),
		Duration:      1.0,
		Interpolation: reachymini.InterpolationMinJerk,
	})
	if err != nil {
		log.Fatal(err)
	}
}

func (*Client) GotoSleep

func (c *Client) GotoSleep(ctx context.Context) (MoveUUID, error)

GotoSleep plays the robot's built-in sleep move.

func (*Client) InstallApp

func (c *Client) InstallApp(ctx context.Context, app AppInfo) (map[string]string, error)

InstallApp installs app and returns the daemon's raw install job response (the daemon's OpenAPI spec declares no fixed schema for it beyond string-to-string). Poll GetJobStatus to track progress.

func (*Client) InstallPrivateSpace

func (c *Client) InstallPrivateSpace(ctx context.Context, spaceID string) (map[string]string, error)

InstallPrivateSpace installs a private Hugging Face Space by ID.

func (*Client) ListAvailableApps

func (c *Client) ListAvailableApps(ctx context.Context) ([]AppInfo, error)

ListAvailableApps lists all apps available to install, across all sources.

func (*Client) ListAvailableAppsBySource

func (c *Client) ListAvailableAppsBySource(ctx context.Context, source SourceKind) ([]AppInfo, error)

ListAvailableAppsBySource lists apps available from a single source.

func (*Client) ListRecordedMoveDatasets

func (c *Client) ListRecordedMoveDatasets(ctx context.Context, datasetName string) ([]string, error)

ListRecordedMoveDatasets lists the recorded moves available in datasetName.

func (*Client) ListRunningMoves

func (c *Client) ListRunningMoves(ctx context.Context) ([]MoveUUID, error)

ListRunningMoves returns the UUIDs of moves currently in progress.

func (*Client) ListSounds

func (c *Client) ListSounds(ctx context.Context) ([]string, error)

ListSounds lists the sound files available on the robot.

func (*Client) OpenAudioSession added in v1.3.0

func (c *Client) OpenAudioSession(ctx context.Context, opts AudioSessionOptions) (*AudioSession, error)

OpenAudioSession connects to the daemon's WebRTC feed and returns once the connection is up and audio written to the session will play on the robot's speaker. It runs until ctx is cancelled, Close is called, or the connection fails (see Done and Err). Requires an `ffmpeg` binary with libopus on PATH (or set opts.FFmpegPath).

Each session is a WebRTC consumer of the daemon, which runs its own camera encoder per consumer, so prefer one long-lived session over one per utterance.

func (*Client) PlayRecordedMoveDataset

func (c *Client) PlayRecordedMoveDataset(ctx context.Context, datasetName, moveName string) (MoveUUID, error)

PlayRecordedMoveDataset plays moveName from datasetName.

func (*Client) PlaySound

func (c *Client) PlaySound(ctx context.Context, file string) error

PlaySound plays a sound file already stored on the robot (see ListSounds).

Example

ExampleClient_PlaySound plays a sound file already uploaded to the robot (see Client.UploadSound and Client.ListSounds).

package main

import (
	"context"
	"log"

	reachymini "github.com/nlm/reachy-mini-sdk-go"
)

func main() {
	client := reachymini.New("http://localhost:8000")
	ctx := context.Background()

	if err := client.PlaySound(ctx, "boot_chime.wav"); err != nil {
		log.Fatal(err)
	}
}

func (*Client) ReadAudioParameter

func (c *Client) ReadAudioParameter(ctx context.Context, name string) (ReadAudioParameterResponse, error)

ReadAudioParameter reads a single low-level audio mixer parameter by name. Valid names are specific to the daemon's audio backend and aren't enumerated anywhere in the API itself.

func (*Client) RemoveApp

func (c *Client) RemoveApp(ctx context.Context, appName string) (map[string]string, error)

RemoveApp uninstalls appName.

func (*Client) ResetAppsCache

func (c *Client) ResetAppsCache(ctx context.Context) (map[string]string, error)

ResetAppsCache clears the daemon's cached app store listing. Note this endpoint is mounted at /cache/reset-apps, not under /api like everything else -- that's how the daemon itself exposes it.

func (*Client) RestartCurrentApp

func (c *Client) RestartCurrentApp(ctx context.Context) (AppStatus, error)

RestartCurrentApp restarts whichever app is currently running.

func (*Client) RestartDaemon

func (c *Client) RestartDaemon(ctx context.Context) (string, error)

RestartDaemon restarts the daemon process, which re-initializes its connection to the motor/hardware backend. Useful when a joint has silently dropped off the control loop (no error reported, motor mode still "enabled", but it stops responding to position commands) -- cycling motor mode alone does not fix that, but a daemon restart does. Returns the daemon's internal job ID for the restart operation; the restart is asynchronous and briefly interrupts connectivity, so poll GetDaemonStatus afterward rather than assuming it's done when this returns.

func (*Client) SetMicrophoneVolume

func (c *Client) SetMicrophoneVolume(ctx context.Context, volume int) (VolumeInfo, error)

SetMicrophoneVolume sets the microphone volume (0-100).

func (*Client) SetMotorMode

func (c *Client) SetMotorMode(ctx context.Context, mode MotorControlMode) error

SetMotorMode changes the robot's motor control mode (e.g. enabling/disabling torque).

func (*Client) SetRobotName added in v1.3.0

func (c *Client) SetRobotName(ctx context.Context, name string) (string, error)

SetRobotName renames the robot (1-64 characters) and returns the name as stored, with surrounding whitespace trimmed. It persists across restarts and takes effect immediately in the daemon status and the robot's mDNS advertisement. The daemon answers 422 for an invalid name (including a blank one) and when it fails to save the name.

Requires daemon 1.11+ (older daemons answer 404).

func (*Client) SetStartupApp added in v1.3.0

func (c *Client) SetStartupApp(ctx context.Context, appName string) error

SetStartupApp sets the app the daemon starts automatically (see GetStartupApp); "" clears it. The app must already be installed (HTTP 400 otherwise). The change applies without a daemon restart.

Requires daemon 1.11+ (older daemons answer 404).

func (*Client) SetTarget

func (c *Client) SetTarget(ctx context.Context, target FullBodyTarget) error

SetTarget directly commands a target pose with no interpolation (lower latency than Goto, useful for teleop). For continuous streaming control, use StreamSetTarget instead.

func (*Client) SetVolume

func (c *Client) SetVolume(ctx context.Context, volume int) (VolumeInfo, error)

SetVolume sets the speaker volume (0-100).

func (*Client) StartApp

func (c *Client) StartApp(ctx context.Context, appName string) (AppStatus, error)

StartApp starts appName. The daemon refuses (HTTP 400) if an app is already running, so call StopCurrentApp first. A remote WebRTC session holding the robot is evicted; use StartAppNoEvict to fail instead.

func (*Client) StartAppNoEvict added in v1.3.0

func (c *Client) StartAppNoEvict(ctx context.Context, appName string) (AppStatus, error)

StartAppNoEvict is StartApp, except that it fails (HTTP 400) rather than evicting a remote WebRTC session that holds the robot (see GetRobotAppLockStatus).

Requires daemon 1.11+ (older daemons answer 404).

func (*Client) StartDaemon added in v1.3.0

func (c *Client) StartDaemon(ctx context.Context, wakeUp bool) (string, error)

StartDaemon starts the daemon's robot backend, optionally playing the wake-up animation once it's up. It is asynchronous and returns the daemon's job ID: GetJobStatus reports when the job is done, and GetDaemonStatus whether the daemon actually ended up running (the job finishes "done" even if the backend failed to start, and starting a running daemon is a no-op). The daemon answers 409 when another start/stop/restart job is already running.

func (*Client) Stop

func (c *Client) Stop(ctx context.Context, uuid MoveUUID) error

Stop halts the move identified by uuid (as returned by Goto, WakeUp, GotoSleep, or PlayRecordedMoveDataset; see also ListRunningMoves).

func (*Client) StopCurrentApp

func (c *Client) StopCurrentApp(ctx context.Context) error

StopCurrentApp stops whichever app is currently running.

func (*Client) StopDaemon added in v1.3.0

func (c *Client) StopDaemon(ctx context.Context, gotoSleep bool) (string, error)

StopDaemon stops the daemon's robot backend, optionally playing the go-to-sleep animation first. Asynchronous, like StartDaemon. The HTTP API stays reachable, so StartDaemon can bring the backend back, but endpoints that need the backend (movement, state, sounds...) answer 503 until then.

func (*Client) StopSound

func (c *Client) StopSound(ctx context.Context) error

StopSound stops whatever sound is currently playing.

func (*Client) StreamCameraFrames

func (c *Client) StreamCameraFrames(ctx context.Context, opts CameraStreamOptions) (<-chan Frame, <-chan error, error)

StreamCameraFrames connects to the daemon's WebRTC camera feed and decodes it to raw RGB frames, delivered on the returned channel until ctx is cancelled. Requires an `ffmpeg` binary on PATH (or set opts.FFmpegPath).

The returned channel is closed once the stream ends after ctx is cancelled (or when the daemon ends the track). Errors, including a WebRTC connection that fails, are reported on errs; the stream doesn't end by itself on error, so cancel ctx to release it. The ffmpeg decoder is reaped on cancel.

The negotiated video codec isn't known until after WebRTC negotiation completes, so the decoder is started lazily from the OnTrack callback. Verified live end-to-end against Pollen's desktop simulator (signalling, WebRTC negotiation, VP8 depacketization, IVF muxing, and ffmpeg decode all confirmed producing real, correctly-decoded frames). Real hardware has been observed (in the daemon's own source) to use hardware H.264 on Raspberry Pi instead -- both codecs are handled here, but only the VP8 path has actually been exercised against a live producer so far.

func (*Client) StreamFullState

func (c *Client) StreamFullState(ctx context.Context) (<-chan FullState, <-chan error, error)

StreamFullState streams FullState frames from WS /api/state/ws/full until ctx is cancelled, with the daemon's default fields and rate (10 Hz). The returned channels are closed when the stream ends; drain errs (buffered, size 1) to see why.

Example

ExampleClient_StreamFullState prints the robot's head pose as it changes, until ctx is cancelled.

package main

import (
	"context"
	"fmt"
	"log"
	"time"

	reachymini "github.com/nlm/reachy-mini-sdk-go"
)

func main() {
	client := reachymini.New("http://localhost:8000")
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	states, errs, err := client.StreamFullState(ctx)
	if err != nil {
		log.Fatal(err)
	}
	for {
		select {
		case state, ok := <-states:
			if !ok {
				return
			}
			fmt.Println(state.HeadPose)
		case err := <-errs:
			log.Fatal(err)
		}
	}
}

func (*Client) StreamFullStateWithOptions added in v1.3.0

func (c *Client) StreamFullStateWithOptions(ctx context.Context, opts StreamFullStateOptions) (<-chan FullState, <-chan error, error)

StreamFullStateWithOptions is StreamFullState with the fields and rate selected by opts.

func (*Client) StreamMicrophoneAudio added in v1.1.0

func (c *Client) StreamMicrophoneAudio(ctx context.Context, opts AudioStreamOptions) (<-chan []byte, <-chan error, error)

StreamMicrophoneAudio connects to the daemon's WebRTC feed and decodes the robot microphone's Opus audio track to raw signed 16-bit little-endian PCM, delivered on the returned channel until ctx is cancelled. Requires an `ffmpeg` binary on PATH (or set opts.FFmpegPath).

The returned channel is closed once the stream ends after ctx is cancelled (or when the daemon ends the track). Errors, including a WebRTC connection that fails, are reported on errs; the stream doesn't end by itself on error, so cancel ctx to release it. The ffmpeg decoder is reaped on cancel.

The daemon's webrtcsink producer carries both a video track (see StreamCameraFrames) and this audio track in the same negotiated session; this function only consumes the audio one. Unlike H.264/VP8 depacketizing, Opus needs no reassembly across RTP packets (one packet is one Opus frame), so the incoming RTP stream is simply muxed into an Ogg/Opus container (github.com/pion/webrtc/v4/pkg/media/oggwriter) and piped into ffmpeg for decoding.

This mirrors the official Python SDK's ReachyMini(media_backend="webrtc") + mini.media.start_recording()/get_audio_sample() path (see examples/sound_record.py in pollen-robotics/reachy_mini), which relies on the same underlying daemon capability. It has been verified against Pollen's desktop simulator but not yet real hardware -- see the README.

func (*Client) StreamSetTarget

func (c *Client) StreamSetTarget(ctx context.Context) (chan<- FullBodyTarget, <-chan error, error)

StreamSetTarget opens WS /api/move/ws/set_target and forwards every FullBodyTarget sent on the returned channel to the robot, until ctx is cancelled or the channel is closed. Useful for continuous/teleop control (e.g. driving the head from a joystick loop) where the lower per-call latency of a persistent connection matters; for one-off commands use SetTarget instead.

func (*Client) TestSound

func (c *Client) TestSound(ctx context.Context) (TestSoundResult, error)

TestSound plays a short sound at the current volume -- useful for letting a user confirm audio is working after changing the volume.

func (*Client) UpdateApp

func (c *Client) UpdateApp(ctx context.Context, appName string) (map[string]string, error)

UpdateApp updates appName to its latest available version.

func (*Client) UploadSound

func (c *Client) UploadSound(ctx context.Context, localPath string) error

UploadSound uploads the local file at localPath to the robot's sound library.

func (*Client) WakeUp

func (c *Client) WakeUp(ctx context.Context) (MoveUUID, error)

WakeUp plays the robot's built-in wake-up move.

Example

ExampleClient_WakeUp shows the minimal sequence to move the robot at all: motor control must be explicitly enabled before any movement command has an effect (see EnsureMotorMode's doc comment).

package main

import (
	"context"
	"log"

	reachymini "github.com/nlm/reachy-mini-sdk-go"
)

func main() {
	client := reachymini.New("http://localhost:8000")
	ctx := context.Background()

	if _, err := client.EnsureMotorMode(ctx, reachymini.MotorModeEnabled); err != nil {
		log.Fatal(err)
	}
	if _, err := client.WakeUp(ctx); err != nil {
		log.Fatal(err)
	}
}

type ControlLoopStats

type ControlLoopStats struct {
	// MeanControlLoopFrequency is the average control loop rate, in Hz.
	MeanControlLoopFrequency float64 `json:"mean_control_loop_frequency"`
	// MaxControlLoopInterval is the longest gap observed between control
	// loop iterations, in seconds -- large values indicate the loop
	// stalled or was delayed.
	MaxControlLoopInterval float64 `json:"max_control_loop_interval"`
	// NbError is the cumulative count of control loop errors.
	NbError int `json:"nb_error"`
	// MotorController names the low-level motor driver/backend in use.
	MotorController string `json:"motor_controller"`
}

ControlLoopStats reports low-level motor control loop timing/health.

type DaemonStatus

type DaemonStatus struct {
	// Type identifies this status payload's shape/version.
	Type string `json:"type"`
	// RobotName is the robot's configured hostname/name.
	RobotName string `json:"robot_name"`
	// State is the daemon's own lifecycle state (e.g. "running") -- the
	// most reliable liveness signal, more so than BackendStatus.Ready.
	State string `json:"state"`
	// WirelessVersion reports whether this is the wireless hardware
	// variant of the robot.
	WirelessVersion bool `json:"wireless_version"`
	// DesktopAppDaemon reports whether this daemon is running embedded in
	// Pollen's desktop app rather than on real hardware.
	DesktopAppDaemon bool `json:"desktop_app_daemon"`
	// SimulationEnabled reports whether motor commands are being
	// simulated rather than sent to real hardware.
	SimulationEnabled bool `json:"simulation_enabled"`
	// MockupSimEnabled reports whether a lightweight mockup simulation
	// backend is in use (distinct from the full desktop simulator).
	MockupSimEnabled bool `json:"mockup_sim_enabled"`
	// NoMedia reports whether audio/video subsystems are disabled for
	// this daemon instance.
	NoMedia bool `json:"no_media"`
	// MediaReleased reports whether media devices have been released
	// (e.g. to let another process use the camera/mic).
	MediaReleased bool `json:"media_released"`
	// CameraSpecsName is the detected camera's name, matching
	// CameraSpecs.Name.
	CameraSpecsName string `json:"camera_specs_name"`
	// BackendStatus reports the motor/hardware backend's health.
	BackendStatus BackendStatus `json:"backend_status"`
	// Error is a daemon-level error payload with no fixed schema, non-nil
	// if the daemon itself is in an error state.
	Error any `json:"error"`
	// WlanIP is the robot's current WiFi IP address, if connected.
	WlanIP string `json:"wlan_ip"`
	// Version is the daemon software's version string.
	Version string `json:"version"`
	// HardwareID uniquely identifies this physical robot.
	HardwareID string `json:"hardware_id"`
	// FaceTarget is the latest face seen by the daemon's head tracking,
	// equivalent to GetTrackedFace. Always empty before daemon 1.11.
	FaceTarget FaceTarget `json:"face_target"`
}

DaemonStatus is the response of GET /api/daemon/status.

type DoAInfo

type DoAInfo struct {
	// Angle is the estimated direction to the sound source, in radians:
	// 0 is the robot's left, pi/2 straight ahead, pi its right.
	Angle float64 `json:"angle"`
	// SpeechDetected reports whether the sound was classified as speech.
	SpeechDetected bool `json:"speech_detected"`
}

DoAInfo is the robot's direction-of-arrival (sound source) estimate.

type FaceTarget added in v1.2.0

type FaceTarget struct {
	Detected bool     `json:"detected"`
	X        *float64 `json:"x"`
	Y        *float64 `json:"y"`
	Roll     *float64 `json:"roll"`
	TS       *float64 `json:"ts"`
}

FaceTarget is the latest face seen by the daemon's own head-tracking detector (GET /api/media/tracking/face). X/Y are normalized to [-1, 1] in the tracker's image: X < 0 is the robot's left, Y > 0 is down. Pointers are nil when no face is detected. TS is on the daemon's clock.

type Frame

type Frame struct {
	// Width, Height are the frame's dimensions in pixels.
	Width, Height int
	// RGB is the frame's pixel data: 8-bit RGB, row-major, Width*Height*3
	// bytes.
	RGB []byte
	// Timestamp is when this frame was decoded, client-side (not a
	// timestamp carried by the stream itself).
	Timestamp time.Time
}

Frame is one decoded video frame from StreamCameraFrames: 8-bit RGB, row-major, Width*Height*3 bytes.

type FullBodyTarget

type FullBodyTarget struct {
	// TargetHeadPose is the target head pose, if the head should move.
	TargetHeadPose *Pose `json:"target_head_pose,omitempty"`
	// TargetAntennas is the target [left, right] antenna joint positions,
	// if the antennas should move.
	TargetAntennas *[2]float64 `json:"target_antennas,omitempty"`
	// TargetBodyYaw is the target body yaw, if the body should rotate.
	TargetBodyYaw *float64 `json:"target_body_yaw,omitempty"`
	// Timestamp optionally tags when this target was computed
	// client-side, e.g. for latency diagnostics during teleop.
	Timestamp *time.Time `json:"timestamp,omitempty"`
}

FullBodyTarget is the body of POST /api/move/set_target and each frame of WS /api/move/ws/set_target. Unlike GotoRequest, there's no interpolation: whichever fields are set are commanded immediately as-is.

type FullState

type FullState struct {
	// ControlMode is the current motor control mode (see MotorControlMode).
	ControlMode *MotorControlMode `json:"control_mode,omitempty"`
	// HeadPose is the head's current pose, equivalent to GetPresentHeadPose.
	HeadPose *Pose `json:"head_pose,omitempty"`
	// HeadJoints are the head's raw actuator joint positions, in the
	// daemon/URDF's native joint order (not a semantic X/Y/Z/RPY breakdown
	// like HeadPose).
	HeadJoints []float64 `json:"head_joints,omitempty"`
	// BodyYaw is the body's current yaw, equivalent to GetPresentBodyYaw.
	BodyYaw *float64 `json:"body_yaw,omitempty"`
	// AntennasPosition is the current [left, right] antenna joint
	// positions, equivalent to GetPresentAntennaPositions.
	AntennasPosition []float64 `json:"antennas_position,omitempty"`
	// PassiveJoints are the positions of joints not under direct motor
	// control (e.g. any spring-loaded or unactuated linkages).
	PassiveJoints []float64 `json:"passive_joints,omitempty"`
	// DoA is the current direction-of-arrival estimate, equivalent to GetDoA.
	DoA *DoAInfo `json:"doa,omitempty"`
	// IMU is the latest IMU reading, equivalent to GetIMU.
	IMU *ImuData `json:"imu,omitempty"`
	// Timestamp is when the daemon captured this state snapshot.
	Timestamp *time.Time `json:"timestamp,omitempty"`
}

FullState is the response of GET /api/state/full and each frame of WS /api/state/ws/full. Fields are omitted by the daemon (left nil/empty) when they weren't requested (see FullStateOptions) or that subsystem isn't available (e.g. NoMedia mode for DoA, no IMU on the Lite).

type FullStateOptions added in v1.3.0

type FullStateOptions struct {
	// OmitControlMode drops ControlMode. Ignored when streaming: the
	// WebSocket always includes it.
	OmitControlMode bool
	// OmitHeadPose drops HeadPose.
	OmitHeadPose bool
	// OmitBodyYaw drops BodyYaw.
	OmitBodyYaw bool
	// OmitAntennas drops AntennasPosition.
	OmitAntennas bool
	// HeadJoints adds HeadJoints.
	HeadJoints bool
	// PassiveJoints adds PassiveJoints.
	PassiveJoints bool
	// DoA adds DoA.
	DoA bool
	// IMU adds IMU. Daemons before 1.11 ignore it and never report one.
	IMU bool
	// PoseMatrix returns HeadPose as a 4x4 matrix (Pose.Matrix) instead of
	// XYZ/RPY (Pose.XYZRPY).
	PoseMatrix bool
}

FullStateOptions selects which fields GetFullStateWithOptions and StreamFullStateWithOptions ask the daemon for. The zero value matches the daemon's defaults: control mode, head pose, body yaw and antenna positions.

type GotoRequest

type GotoRequest struct {
	// HeadPose is the target head pose, if the head should move.
	HeadPose *Pose `json:"head_pose,omitempty"`
	// Antennas is the target [left, right] antenna joint positions, if the
	// antennas should move.
	Antennas *[2]float64 `json:"antennas,omitempty"`
	// BodyYaw is the target body yaw, if the body should rotate.
	BodyYaw *float64 `json:"body_yaw,omitempty"`
	// Duration is how long the interpolation should take, in seconds.
	Duration float64 `json:"duration"`
	// Interpolation selects the blending curve between the current and
	// target pose (see InterpolationTechnique).
	Interpolation InterpolationTechnique `json:"interpolation"`
}

GotoRequest is the body of POST /api/move/goto. Only the non-nil target fields are commanded; the others are left at their current value.

type ImuData added in v1.3.0

type ImuData struct {
	// Accelerometer is the [x, y, z] linear acceleration, in m/s².
	Accelerometer [3]float64 `json:"accelerometer"`
	// Gyroscope is the [x, y, z] angular rate, in rad/s.
	Gyroscope [3]float64 `json:"gyroscope"`
	// Quaternion is the orientation as [w, x, y, z] (w first).
	Quaternion [4]float64 `json:"quaternion"`
	// Temperature is the IMU's temperature, in °C.
	Temperature float64 `json:"temperature"`
}

ImuData is a reading from the robot's IMU (wireless version only).

type InterpolationTechnique

type InterpolationTechnique string

InterpolationTechnique selects how `Goto` blends between the current and target pose. Verified against a live daemon's /openapi.json.

const (
	InterpolationLinear    InterpolationTechnique = "linear"
	InterpolationMinJerk   InterpolationTechnique = "minjerk"
	InterpolationEaseInOut InterpolationTechnique = "ease_in_out"
	InterpolationCartoon   InterpolationTechnique = "cartoon"
)

type JobInfo

type JobInfo struct {
	// Command is the shell command the daemon is running for this job.
	Command string `json:"command"`
	// Status is the job's current lifecycle state (see JobStatus).
	Status JobStatus `json:"status"`
	// Logs are the job's captured output lines so far.
	Logs []string `json:"logs"`
}

JobInfo is the status of an async app install/update job (see InstallApp, InstallPrivateSpace, UpdateApp).

type JobStatus

type JobStatus string

JobStatus is the status of an async install/update job.

const (
	JobStatusPending    JobStatus = "pending"
	JobStatusInProgress JobStatus = "in_progress"
	JobStatusDone       JobStatus = "done"
	JobStatusFailed     JobStatus = "failed"
)

type Matrix4x4Pose

type Matrix4x4Pose struct {
	// M holds the matrix in row-major order: M[4*row+col]. The last row is
	// implicitly [0 0 0 1] for a rigid transform, but the daemon still sends
	// and expects all 16 values.
	M [16]float64 `json:"m"`
}

Matrix4x4Pose is a raw row-major 4x4 homogeneous transform.

type MotorControlMode

type MotorControlMode string

MotorControlMode selects the robot's motor control mode. Verified against a live daemon's /openapi.json.

const (
	MotorModeEnabled             MotorControlMode = "enabled"
	MotorModeDisabled            MotorControlMode = "disabled"
	MotorModeGravityCompensation MotorControlMode = "gravity_compensation"
)

type MotorStatus

type MotorStatus struct {
	// Mode is the robot's current motor control mode.
	Mode MotorControlMode `json:"mode"`
}

MotorStatus is the response of GET /api/motors/status.

type MoveUUID

type MoveUUID struct {
	// UUID is the move's unique identifier, as assigned by the daemon.
	UUID string `json:"uuid"`
}

MoveUUID identifies a move started via Goto, WakeUp, GotoSleep, or PlayRecordedMoveDataset, for use with Stop/ws/updates.

type Pose

type Pose struct {
	XYZRPY *XYZRPYPose
	Matrix *Matrix4x4Pose
}

Pose mirrors the daemon's `AnyPose = XYZRPYPose | Matrix4x4Pose` union. Exactly one of XYZRPY or Matrix should be set.

func NewMatrixPose

func NewMatrixPose(m [16]float64) *Pose

NewMatrixPose builds a Pose from a raw 4x4 transform.

func NewXYZRPYPose

func NewXYZRPYPose(x, y, z, roll, pitch, yaw float64) *Pose

NewXYZRPYPose builds a Pose from Cartesian position and roll/pitch/yaw.

func (Pose) MarshalJSON

func (p Pose) MarshalJSON() ([]byte, error)

MarshalJSON emits whichever variant is set. The daemon's Pydantic model distinguishes the union by field shape rather than an explicit tag, so we match on the presence of the "m" field (verified against a live daemon's /openapi.json: XYZRPYPose has no "m" field, Matrix4x4Pose requires one).

func (*Pose) UnmarshalJSON

func (p *Pose) UnmarshalJSON(data []byte) error

type ReadAudioParameterResponse

type ReadAudioParameterResponse struct {
	// Name echoes back the parameter name that was requested.
	Name string `json:"name"`
	// Values are the parameter's current value(s).
	Values []float64 `json:"values"`
}

ReadAudioParameterResponse is the response of GET /api/audio/config/parameter/{name}.

type ResolutionInfo

type ResolutionInfo struct {
	// Name is a short label for this resolution mode (e.g. "1080p").
	Name string `json:"name"`
	// Width, Height are the frame dimensions in pixels.
	Width  int `json:"width"`
	Height int `json:"height"`
	// FPS is the frame rate this resolution is streamed at.
	FPS int `json:"fps"`
	// CropFactor is the sensor crop applied to reach this resolution
	// (1.0 = full sensor field of view; >1.0 = cropped/zoomed in).
	CropFactor float64 `json:"crop_factor"`
}

ResolutionInfo is a single camera resolution entry.

type RobotAppLockState added in v1.3.0

type RobotAppLockState string

RobotAppLockState says which managed app, if any, holds the robot.

const (
	// RobotAppLockFree means no managed app holds the robot.
	RobotAppLockFree RobotAppLockState = "free"
	// RobotAppLockLocalApp means an app started by the daemon (StartApp)
	// is running.
	RobotAppLockLocalApp RobotAppLockState = "local_app"
	// RobotAppLockRemoteSession means a remote WebRTC client is connected
	// through Pollen's central signalling relay.
	RobotAppLockRemoteSession RobotAppLockState = "remote_session"
)

type RobotAppLockStatus added in v1.3.0

type RobotAppLockStatus struct {
	// State says who holds the robot.
	State RobotAppLockState `json:"state"`
	// HolderName is the app name for RobotAppLockLocalApp, the generic
	// "remote" for RobotAppLockRemoteSession, and empty when free.
	HolderName string `json:"holder_name"`
}

RobotAppLockStatus is the response of GET /api/daemon/robot-app-lock-status.

type SourceKind

type SourceKind string

SourceKind is where an app comes from.

const (
	SourceKindHFSpace            SourceKind = "hf_space"
	SourceKindDashboardSelection SourceKind = "dashboard_selection"
	SourceKindLocal              SourceKind = "local"
	SourceKindInstalled          SourceKind = "installed"
)

type StreamFullStateOptions added in v1.3.0

type StreamFullStateOptions struct {
	FullStateOptions
	// Frequency is the frame rate, in Hz. Zero, negative or infinite keeps
	// the daemon's default (10 Hz).
	Frequency float64
}

StreamFullStateOptions configures StreamFullStateWithOptions.

type TestSoundResult

type TestSoundResult struct {
	// Status is a short machine-readable outcome (e.g. "ok").
	Status string `json:"status"`
	// Message is a human-readable description of the outcome.
	Message string `json:"message"`
}

TestSoundResult is the response of POST /api/volume/test-sound.

type VolumeInfo

type VolumeInfo struct {
	// Volume is the current level, 0-100.
	Volume int `json:"volume"`
	// Platform identifies the underlying audio backend/OS (e.g. "linux").
	Platform string `json:"platform"`
	// Device is the backend-specific name of the audio device this
	// volume applies to.
	Device string `json:"device"`
}

VolumeInfo reports the current volume level for a device.

type XYZRPYPose

type XYZRPYPose struct {
	// X, Y, Z are the position, in the daemon's native units (meters,
	// matching the robot's URDF -- see GetURDF).
	X float64 `json:"x"`
	Y float64 `json:"y"`
	Z float64 `json:"z"`
	// Roll, Pitch, Yaw are the orientation, in radians.
	Roll  float64 `json:"roll"`
	Pitch float64 `json:"pitch"`
	Yaw   float64 `json:"yaw"`
}

XYZRPYPose is a Cartesian position plus roll/pitch/yaw orientation.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL