Streaming Control of a Rotary Joint
Joint control with one Elevate neuron per controller, reciprocal inhibition and excitatory sensory feedback in ROS2 Humble.
Abstract
Two single-neuron Elevate controllers drive opposing muscles on a rotary joint with a 2 g tip mass under gravity. Motor spikes activate muscles and inhibit the peer; angle feedback excites each controller. Three ROS2 Humble nodes exchange 1 ms spike windows in Docker on separate CPUs.
Results
The recording covers 30 s of model time over 30.00 s of wall time. All three nodes completed 30,000 updates each; mechanical stop hits: 0. Timing verdict: fail.
Control Approach
The current tuning came from an empirical parameter scan: we varied the neurons’ background excitation, sensory feedback strength and muscle response per spike, then selected a combination that produced stable, repeatable oscillation without hitting the joint limits. The retired recordings were reported at about 0.57 Hz with a 63° peak-to-peak excursion; those measurements are no longer available for inspection here.
To formalise this, we could add an online adaptive controller that measures each cycle’s frequency and amplitude, compares them with the desired values, and gradually adjusts the parameters to reduce both errors. Small parameter perturbations could reveal their effects during operation, allowing adaptation to account for their coupling. Updates would need bounds and a slower timescale than the oscillation to preserve stability; achievable targets and convergence would require validation.
Timings Summary
| Quantity | Value | Meaning |
|---|---|---|
| Internal integration step | 0.025 ms | Integrates neuron equations and detects upward voltage crossings. |
| External simulation step | 1 ms model time | 40 internal steps; fixed input conductances. |
| Exported spike flag | 0 or 1 per neuron per 1 ms | Any upward crossing sets the flag; multiple crossings collapse to one. Finer spike times are discarded. |
| Mechanical step | 1 ms model time | Updates muscle activation, velocity and angle. |
| Model window | 1 ms model time | Model time advanced per callback. |
| Callback | One node update | Advances the model, publishes outputs and records diagnostics. |
| Callback duration | Variable wall time | Execution time, excluding input waiting. |
| Control period | 1 ms wall time | Interval between scheduled releases. |
| Deadline | Scheduled release + 1 ms | Required finish time, even after a late start. |
| Logical transport delay | 1 ms model time | Window 's spikes enter window . |
Mean callback duration (95th percentile): flexor/extensor 0.534 ms (0.702 ms); joint 0.046 ms (0.073 ms).
Of 30,000 callbacks per node, deadline misses were 2,154 flexor (7.18%), 2,183 extensor (7.28%) and 1,480 joint (4.93%). Callbacks over 1 ms: 195 flexor, 218 extensor, 0 joint. Short callbacks can miss deadlines through late starts.
Neuron model
Elevate is a phenomenological model with sodium, potassium, calcium, slow potassium and leak currents:
denote voltage, time, capacitance and applied current. Excitatory and inhibitory conductances have reversals ; intrinsic conductance has reversal . Units are mV, ms, nF, µS and nA; no cell-area calibration is assumed.
For gates ,
is filtered voltage (mV), its timescale (ms), a dimensionless gate, the slope (mV), the midpoint (mV), and the dimensionless sigmoid argument. In that order, slopes are and midpoints mV:
is maximum conductance. Both potassium currents use . KCa depends on filtered voltage, with no calcium-concentration state. All six states, and the five , start at mV.
Numerical update and spike output
Each 1 ms step uses 40 split substeps of ms with fixed input conductances. First update the filters using the old voltage:
The superscript denotes an updated value. Evaluate gates and conductances from , then update the membrane with conductances frozen:
is total conductance (µS), the equilibrium voltage (mV), and indexes the five intrinsic currents. Each frozen sub-update is exact; their composition approximates the coupled dynamics. A crossing mV sets the window’s spike flag without resetting state.
Synaptic and local drive
Let denote flexor or extensor, its peer, and the control window. Synapses decay, then receive spike increments:
and are sensory AMPA and peer GABA conductances (µS). and count the preceding window’s sensory and peer motor spikes. With ms, decay times are ms and per-spike weights are µS. Initial conductances and input counts are zero; increments are added in full, without timestep scaling.
Unfiltered local excitation switches from starting to tonic drive:
is model time from startup, ms, µS and µS. At , the membrane inputs are
and are total excitatory and inhibitory conductances. Recorded settings appear in the parameter table.
Joint dynamics model
Two muscles drive a spring-damped joint. Zero points downward; positive angles point right. Only the tip mass contributes gravity:
is angle (rad); dots denote derivatives in seconds. is base inertia (kg m), tip mass (kg), arm length (m), gravity (m/s), spring rest angle (rad), damping (N m s/rad), and stiffness (N m/rad). are flexor/extensor activations; is maximum muscle torque (N m).
At mechanical step , muscle updates as
Here s, is activation decay time (s), the dimensionless spike increment, and the preceding window’s motor spike count per neuron. Updated activations set torque. Semi-implicit Euler updates velocity, then angle; stops at rad clamp angle and zero velocity.
The joint starts at (90°), with zero velocity and activation. Total inertia is kg m; initial gravity torque is N m. Flexor raises the mass against gravity; extensor lowers it.
Before each update, sensory spikes excite flexor for and extensor for . The sensory centre is , threshold rad, and minimum interspike interval 10 ms. Each channel repeats while beyond threshold.
Learning rule
The separate native adaptation protocol uses bounded coordinate search to adjust tonic excitation and sensory synaptic strength , symmetrically across flexor and extensor. Reciprocal inhibition and mechanics remain fixed. This is a model-specific application of derivative-free direct search, using global movement errors:
is dimensionless loss. Frequency (Hz) is the reciprocal of mean cycle period; excursion (rad) is the mean peak-to-peak angle across measured cycles. Positive targets default to 0.65 Hz and rad (60° peak-to-peak). The two relative errors receive equal weight.
Alternate between the two conductances. For the selected coordinate , test both proposals
is the current conductance and a proposal, both in µS; chooses decrease or increase, is that coordinate’s fractional probe size, and bounds conductance to 0.01–0.10 µS. Keep the baseline unless an eligible proposal lowers by more than ; choose the better eligible proposal. Probe sizes start at 10% and halve after an unsuccessful comparison, down to 1.25%.
Each baseline or probe lasts at least 26 s of model time. Discard the first 15 s and measure the final five complete cycles, delimited by upward crossings of . Eligibility requires no stop hits and all cycle-repeatability errors below 1%: maximum relative period and turning-point errors, and worst-cycle normalized root-mean-square errors for angle and velocity. Period errors use the median period; turning-point and angle errors use median excursion, and velocity errors use the median waveform’s velocity range. Unsettled segments extend in 5 s increments up to 60 s. Unsettled probes are excluded; an unsettled baseline skips its update without shrinking the probe size.
Neural, synaptic, muscle and pending spike states continue between probes. After 16 coordinate attempts, freeze the parameters and validate for 60 s both continuously and from a fresh reset, assessing the final ten complete cycles after settling. Local repeatability alone does not guarantee target acquisition or repeatability after reset.
Architecture Pseudocode
Each node retains state. These Python-like helpers summarize execution.
Setup
dt = 1 * ms
controllers = paired_controllers(neuron="Elevate")
joint = loaded_joint(initial_angle=90 * degrees)
warm_up_then_reset(controllers)
start_together(*controllers, joint)
Warm-up resets controller states, inputs and model clocks before execution.
Each control window
Each node waits for its release and both preceding input windows, servicing messages and enforcing its lag limit. Startup inputs are empty; silence is published explicitly.
def run(node):
for window in fixed_schedule(period=dt):
inputs = receive_previous_window(window)
outputs = node.update(inputs)
publish_window(window, outputs) # Include windows with no spikes.
record_timing(deadline=window.release + dt)
Late nodes catch up without dropping windows or shifting deadlines.
Controller and joint updates
Controllers share this update but receive different starting excitation.
def update_controller(controller, sensory_spikes, peer_spikes, time):
drive = starting_drive(controller) if time < 20 * ms else tonic_drive
controller.excite(local_drive=drive, sensory_spikes=sensory_spikes)
controller.inhibit(peer_spikes)
return controller.advance(dt).spikes
def update_joint(joint, motor_spikes, time):
sensory_spikes = sense_angle(joint, time)
activation = decay_then_activate(joint.muscles, motor_spikes)
torque = opposing_muscle_torque(activation)
advance_mechanics(joint, torque, dt)
return sensory_spikes
Network diagram
Parameters
Values come from the selected recording’s native snapshot and configuration.
| Parameter | Recorded value |
|---|---|
| Network | |
| Motor cells per controller | 1 |
| Controller populations | motor |
| Neuron model | elevate |
| Ionic membrane dynamics | |
| Capacitance (nF) | 1 |
| Sodium conductance (µS) | 100 |
| Potassium conductance (µS) | 65 |
| Calcium conductance (µS) | 2 |
| Slow potassium conductance (µS) | 10 |
| Leak conductance (µS) | 2 |
| Sodium reversal (mV) | 40 |
| Potassium reversal (mV) | -90 |
| Calcium reversal (mV) | 120 |
| Leak reversal (mV) | -50 |
| Excitation reversal (mV) | 0 |
| Inhibition reversal (mV) | -80 |
| Initial voltage (mV) | -60 |
| Constant applied current (nA) | -5 |
| Sodium activation filter (ms) | 0.1 |
| Sodium inactivation filter (ms) | 1 |
| Potassium activation filter (ms) | 1 |
| Calcium activation filter (ms) | 1 |
| Slow potassium activation filter (ms) | 75 |
| Maximum internal step (ms) | 0.025 |
| Synaptic decay (ms) | |
| local_bias | Direct conductance |
| peer_inhibition | 50 |
| sensory_drive | 10 |
| Synapses and weights | |
| local_bias | 1 |
| peer_inhibition | 0.2 |
| sensory_drive | 0.035 |
| Input and simulation | |
| Duration (s) | 30 |
| Numerical timestep (ms) | 1 |
| Control period (ms) | 1 |
| Seed | 0 |
| Controller warm-up simulated duration (ms) | 1000 |
| Starting pulse duration (ms) | 20 |
| Starting flexor / extensor drive (µS) | 0.5 / 0 |
| Ongoing tonic drive (µS) | 0.04 |
| Spike transport | logical |
| SNNLab execution | default |
| Lag stop / delivery budget (ms) | 8000 / 5 |
| Analysis | |
| Seed count | 1 (selected acquisition) |
| Assessed complete cycles | 10 |
| Cycle burn-in (s) | 5 |
| Cycle relative tolerance | 0.01 |
| Phase samples per cycle | 128 |
| Joint mechanics | |
| Activation increment per normalized spike | 0.003 |
| Activation decay (s) | 0.08 |
| Angle convention | zero_downward_positive_right |
| Arm length (m) | 0.2 |
| Damping (N m s/rad) | 0.02 |
| Gravity (m/s²) | 9.81 |
| Hard stop relative to centre (rad) | 1 |
| Base inertia (kg m²) | 0.005 |
| Initial angle (rad) | 1.5707963267948966 |
| Maximum muscle torque (N m) | 0.8 |
| Sensory and stop centre (rad) | 1.5707963267948966 |
| Minimum sensory interval (s) | 0.01 |
| Sensory threshold relative to centre (rad) | 0.25 |
| Spring rest angle (rad) | 1.5707963267948966 |
| Stiffness (N m/rad) | 0.02 |
| Tip point mass (kg) | 0.002 |
| Total inertia including tip mass (kg m²) | 0.00508 |
Dataset
Upstream: —
Downstream: —
| Run | Date | Duration | Size | Evidence | Storage | Ran on | Verification |
|---|---|---|---|---|---|---|---|
| exp152-r116-present | 1s | 19.4 MB | Current | R2 | Local | Local: absent; R2: catalog-verified | |
| exp152-r115-analyse | <1s | 4.8 MB | Current | R2 | Local | Local: absent; R2: catalog-verified | |
| exp152-r114-compute | 41s | 68.4 MB | Current | R2 | Local | Local: absent; R2: catalog-verified | |
| exp152-r113-analyse | <1s | 127.9 KB | Current | R2 | Local | Local: absent; R2: catalog-verified | |
| exp152-r112-compute | 36s | 1.9 MB | Current | R2 | Local | Local: absent; R2: catalog-verified |