sensors — Line Tension Sensing¶
The sensors package publishes /fishing_arm/tension as an
interfaces/FishingTension message. A single node — load_cell_node — serves
both hardware and simulation by switching its source parameter.
Source: software/src/sensors/sensors/load_cell_publisher.py
Python API: sensors
Config: config/sensor_params.yaml
Design principle: one node, two backends¶
The tension controller (control — Tension Controllers) always subscribes to /fishing_arm/tension.
It never needs to know whether tension came from a physical HX711 or a MuJoCo
simulation model. bringup sets the backend at launch:
source = 'sim_fts' if use_sim else 'hardware'
flowchart TB
LC["load_cell_node"]
LC -->|"always"| TOP["/fishing_arm/tension<br/>FishingTension"]
subgraph hw["source:=hardware"]
HX["HX711 ADC<br/>read_raw_adc()"]
CAL["calibration_offset · calibration_scale"]
HX --> CAL --> LC
end
subgraph sim["source:=sim_fts"]
TF["TF: rod_tip_link → fish_link<br/>line length L"]
STR["Hooke's law:<br/>k(L-L0) + c dL/dt"]
WRENCH["/tension_sensor_broadcaster/wrench<br/>(fallback)"]
TF --> STR --> LC
WRENCH -.->|"if TF unavailable"| LC
end
Node: load_cell_node¶
Parameters (from sensor_params.yaml)¶
Parameter |
Default |
Purpose |
|---|---|---|
|
|
HX711 zero-load ADC reading |
|
|
N per ADC bit |
|
|
Enable sliding-window smoothing |
|
|
Moving average length |
|
|
Timer rate (Hz) |
|
|
Log warning above this (N) |
|
|
Zero out sub-threshold readings |
|
|
Message header frame |
|
|
|
|
|
Must match MJCF tendon stiffness |
|
|
Rest length L₀ (m) |
|
|
Damping on stretch rate |
|
|
TF frame at rod tip |
|
|
TF frame at fish |
Hardware path (source:=hardware)¶
read_raw_adc()reads the HX711 (currently a placeholder with simulated sine disturbance for development).Apply
(raw - calibration_offset) * calibration_scale→ Newtons.Zero out below
noise_floor.Optional moving average over
window_sizesamples.Publish
FishingTension.
Warning
read_raw_adc() is still a stub. Replace with real SPI/serial HX711 driver
before trusting hardware tension values.
Simulation path (source:=sim_fts)¶
Primary method — stretch model matching the MJCF tendon:
Lookup TF transform
rod_tip_link→fish_link.Compute line length
L = ||translation||.Stretch
= max(L - sim_line_springlength, 0).Tension
= k * stretch + c * dL/dt(damping only on lengthening).Fallback: if TF unavailable, subscribe to
/tension_sensor_broadcaster/wrenchand use force magnitude.
The stretch model is preferred because it matches the controller’s physical expectation and is independent of the FTS frame orientation.
ROS 2 interfaces¶
Publications¶
Topic |
Type |
Rate |
|---|---|---|
|
|
|
Message fields:
tension_newtons— measured tension (primary signal for controllers)target_tension_newtons— reserved (currently always0.0; controllers use params instead)
Subscriptions (sim only)¶
Topic |
Type |
When |
|---|---|---|
|
|
|
TF (sim only)¶
Uses tf2_ros.Buffer + TransformListener to compute inter-frame distance.
Depends on robot_state_publisher publishing the tree that includes fish_link
(sim URDF only).
Signal processing pipeline¶
Each timer tick (timer_callback):
raw reading → noise floor → moving average → FishingTension publish
↓
threshold warning (log)
The moving average uses a fixed-length collections.deque — O(1) append and
bounded memory.
Interactions¶
Package / node |
Relationship |
|---|---|
Subscribes to |
|
Sets |
|
|
|
Defines |
|
|
Sim-only ros2_control broadcaster → wrench topic |
Defines |
Physical layer diagrams¶
Simulation chain: Simulation ROS 2 Graph (data flow section)
Hardware chain: Hardware ROS 2 Graph (data flow section)
Launch¶
# Normally launched by bringup; standalone:
ros2 launch sensors sensor.launch.py source:=hardware
ros2 launch sensors sensor.launch.py source:=sim_fts