GR-Power
1. Overview
GR-Power is the DDS publishing module for robot power status. The runtime Fourierpower publishes power and battery status as DDS topics for upper-layer modules to subscribe to.
| Element | Value |
|---|---|
| Runtime name | Fourierpower |
| Domain ID | 123 |
| Main DDS topics | hal_battery_monitor_status, hal_bms_error_code |
2. DDS Interface
2.1 Published Topics
| Topic | Message Type | Description |
|---|---|---|
hal_battery_monitor_status | fourier_msgs/msg/BmsStatusMsg | Main and sub-battery status list. |
hal_bms_error_code | fourier_msgs/msg/ErrorCodes | Power / battery fault-code list. |
2.2 Subscribed Topics
This module currently has no subscription entry points.
3. Message Definitions
3.1 BmsStatusMsg
struct BmsStatus {
double voltage;
double current;
double temperature;
uint8 level;
uint8 level_cap;
double mos_temperature;
boolean failure;
boolean battery_comm;
boolean output_mos_open;
boolean input_mos_open;
};
struct BmsStatusMsg {
std_msgs::msg::Header header;
sequence<BmsStatus> bms_state_list;
};
bms_state_list[0] is the main battery. bms_state_list[1] is the sub-battery.
3.2 ErrorCodes
struct ErrorCode {
uint32 high32;
uint32 low32;
};
struct ErrorCodes {
std_msgs::msg::Header header;
uint8 source; // 4 = power / battery
sequence<ErrorCode> error_codes;
};
high32 is encoded by GR-Power as:
level = high32 & 0xF
code = (high32 >> 12) & 0xFFFF
type_flag = (high32 >> 28) & 0xF
| type_flag | Meaning |
|---|---|
0 | BMS1 battery fault |
1 | BMS2 battery fault |
4. Basic Examples
4.1 Python - Subscribe to Battery Status
import time
from fourierdds_py import DDSInterface, SubscriberQosProfile
import fourier_msgs.msg.BmsState as BmsState
dds = DDSInterface(domain_id=123)
def seq_items(seq):
size = seq.size() if hasattr(seq, "size") else len(seq)
return [seq[i] for i in range(size)]
def on_bms(msg):
states = seq_items(msg.bms_state_list())
if not states:
print("[bms] empty state list")
return
for index, state in enumerate(states):
name = "main" if index == 0 else f"sub{index}"
print(
f"[bms:{name}] "
f"level={state.level()}% "
f"voltage={state.voltage():.3f}V "
f"current={state.current():.3f}A "
f"temperature={state.temperature():.1f}C "
f"failure={state.failure()} "
f"comm={state.battery_comm()}"
)
dds.create_subscription(
BmsState.BmsStatusMsgPubSubType,
"hal_battery_monitor_status",
on_bms,
qos_profile=SubscriberQosProfile.default(),
)
while True:
time.sleep(0.1)
Run example:
python3 watch_grpower_status.py
If the runtime service is root-owned and callbacks are matched but not received, run while preserving the DDS environment:
sudo env "PYTHONPATH=$PYTHONPATH" "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" python3 -u watch_grpower_status.py
4.2 Python - Subscribe to Fault Codes
import time
from fourierdds_py import DDSInterface, SubscriberQosProfile
import fourier_msgs.msg.ErrorCodes as ErrorCodes
dds = DDSInterface(domain_id=123)
def seq_items(seq):
size = seq.size() if hasattr(seq, "size") else len(seq)
return [seq[i] for i in range(size)]
def decode_high32(high32):
return {
"level": high32 & 0xF,
"code": (high32 >> 12) & 0xFFFF,
"type_flag": (high32 >> 28) & 0xF,
}
def on_error(msg):
print(f"[power_error] source={msg.source()} count={len(seq_items(msg.error_codes()))}")
for index, item in enumerate(seq_items(msg.error_codes())):
decoded = decode_high32(item.high32())
print(
f" [{index}] "
f"type_flag={decoded['type_flag']} "
f"level={decoded['level']} "
f"code=0x{decoded['code']:04X} "
f"high32=0x{item.high32():08X} "
f"low32=0x{item.low32():08X}"
)
dds.create_subscription(
ErrorCodes.ErrorCodesPubSubType,
"hal_bms_error_code",
on_error,
qos_profile=SubscriberQosProfile.default(),
)
while True:
time.sleep(0.1)
4.3 C++ - Subscribe to Battery Status
#include <BmsState/BmsStatePubSubTypes.hpp>
#include "fourier_dds/dds_node.hpp"
#include "fourier_dds/dds_subscription.hpp"
#include <chrono>
#include <iostream>
#include <memory>
#include <thread>
int main() {
auto node = std::make_shared<fourier_dds::DdsNode>(123);
auto bms_sub = std::make_shared<
fourier_dds::DdsSubscription<fourier_msgs::msg::BmsStatusMsgPubSubType>>(
node,
"hal_battery_monitor_status",
[](const fourier_msgs::msg::BmsStatusMsg& msg) {
const auto& states = msg.bms_state_list();
for (size_t i = 0; i < states.size(); ++i) {
const auto& state = states[i];
std::cout << "[bms:" << i << "] "
<< "level=" << static_cast<int>(state.level()) << "% "
<< "voltage=" << state.voltage() << "V "
<< "current=" << state.current() << "A "
<< "failure=" << state.failure()
<< std::endl;
}
});
while (true) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
Build example:
g++ -std=c++17 watch_grpower_status.cpp -o watch_grpower_status \
-I/opt/fftai/include/fourier_dds \
-I/opt/fftai/fourier_dds_msgs/include/fourier_dds_msgs \
-L/opt/fftai/fourier_dds_msgs/lib \
-Wl,-rpath,/opt/fftai/fourier_dds_msgs/lib \
-lBmsState \
-lfastdds \
-lfastcdr \
-pthread
Run example:
sudo env "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" ./watch_grpower_status
5. Advanced - Runtime Workflow
5.1 Observe Battery Status
- Start
Fourierpoweron the robot. - Run the status subscriber:
Bashpython3 watch_grpower_status.py
- Confirm the subscriber receives
hal_battery_monitor_status, and verify that voltage, current, level, and communication state inbms_state_listare as expected.
5.2 Observe Fault Codes
- Start the fault-code subscriber:
Bashpython3 watch_grpower_errors.py
- Confirm the subscriber receives
hal_bms_error_codewithsource=4. - Use
type_flag,level,code, andlow32to interpret the fault source and bit fields.
6. Troubleshooting & Reminders
No battery status received
Confirm Fourierpower is running, DDS domain is 123, and the subscriber uses the topic name and message type listed above. If the subscriber is matched but no callback is received, check the DDS environment variables, runtime user, and dynamic library path first.
No fault codes received
Confirm the subscriber uses hal_bms_error_code and fourier_msgs/msg/ErrorCodes, and that the DDS domain matches Fourierpower. ErrorCodes updates only when GR-Power publishes a fault.
source=4 in ErrorCodes
GR-Power sets ErrorCodes.source to 4, meaning the fault came from the power / battery module.