BatteryState
Battery health and charge state for any battery-powered robot. Reports voltage, current draw, temperature, individual cell voltages, and charge percentage.
When to Use
Use BatteryState when your robot runs on batteries and you need to monitor power levels, trigger low-battery warnings, or initiate safe shutdown. Essential for mobile robots, drones, and any untethered system.
ROS2 Equivalent
sensor_msgs/BatteryState — similar structure (voltage, current, charge, capacity, temperature, cell voltages).
Rust Example
// simplified
use horus::prelude::*;
let battery = BatteryState {
voltage: 12.6,
current: -2.5, // negative = discharging
charge: f32::NAN, // NaN if unknown
capacity: f32::NAN,
percentage: 85.0, // 85% charge
power_supply_status: 2, // discharging
temperature: 32.0, // Celsius
cell_voltages: [0.0; 16],
cell_count: 0,
timestamp_ns: 0,
};
let topic: Topic<BatteryState> = Topic::new("battery.state")?;
topic.send(battery);
Python Example
import horus
battery = horus.BatteryState(
voltage=12.6,
current=-2.5,
percentage=85.0,
temperature=32.0,
)
Fields
| Field | Type | Unit | Description |
|---|---|---|---|
voltage | f32 | V | Total pack voltage |
current | f32 | A | Current draw (negative = discharging) |
charge | f32 | Ah | Remaining charge (NaN if unknown) |
capacity | f32 | Ah | Full capacity (NaN if unknown) |
percentage | f32 | % | State of charge (0–100) |
power_supply_status | u8 | — | 0=unknown, 1=charging, 2=discharging, 3=full |
temperature | f32 | °C | Pack temperature |
cell_voltages | [f32; 16] | V | Per-cell voltages (if available) |
cell_count | u8 | — | Number of valid cell readings |
timestamp_ns | u64 | ns | Timestamp |
Common Patterns
Low Battery Warning
// simplified
fn tick(&mut self) {
// IMPORTANT: always recv() every tick
if let Some(battery) = self.battery_sub.recv() {
if battery.percentage < 20.0 {
hlog!(warn, "Low battery: {:.0}% ({:.1}V)", battery.percentage, battery.voltage);
}
if battery.percentage < 5.0 {
// SAFETY: trigger safe shutdown
hlog!(error, "Critical battery: {:.0}% — shutting down", battery.percentage);
self.cmd_pub.send(CmdVel { linear: 0.0, angular: 0.0, timestamp_ns: 0 });
}
}
}
Quick Reference
| Method / Field | Type | Description |
|---|---|---|
voltage | f32 | Total pack voltage (V) |
current | f32 | Current draw, negative = discharging (A) |
percentage | f32 | State of charge 0--100 (%) |
temperature | f32 | Pack temperature (C) |
power_supply_status | u8 | 0=unknown, 1=charging, 2=discharging, 3=full |
cell_voltages | [f32; 16] | Per-cell voltages, valid up to cell_count |
cell_count | u8 | Number of valid cell readings |
charge | f32 | Remaining charge in Ah (NaN if unknown) |
capacity | f32 | Full capacity in Ah (NaN if unknown) |
Design Decisions
Why NaN for unknown charge/capacity instead of Option or sentinel values? BatteryState is a fixed-size Pod type for zero-copy transport. Option<f32> is not Pod-compatible. IEEE 754 NaN is universally recognized as "not available" and works in both Rust and Python without extra wrapping.
Why negative current for discharging? Sign convention matches physics and electrical engineering standards: positive current flows into the battery (charging), negative flows out (discharging). This lets you compute power with voltage * current directly -- negative power means the battery is supplying energy.
Why 16 cell slots instead of variable-length? Fixed-size arrays enable zero-copy transport. 16 cells cover common battery configurations: 3S/4S/6S LiPo (drones), 4S-14S (ground robots), and most industrial packs. For larger packs, publish multiple BatteryState messages per pack segment.
Why no built-in state-of-health or cycle count? Battery health estimation algorithms vary widely by chemistry (LiPo, LiFePO4, NiMH) and require calibration data. HORUS provides the raw measurements; health estimation belongs in a domain-specific node that publishes DiagnosticStatus.
Related Types
- EmergencyStop — Triggered by critical battery
- DiagnosticStatus — General health reporting
- ResourceUsage — CPU, memory, and system stats
See Also
- Sensor Messages (Rust) — Full Rust API
- Diagnostics Messages — System health reporting
- SafetyStatus — System-wide safety state