Skip to content

Commit 5f01368

Browse files
committed
Add low battery check to the hcm
1 parent 6ea8d7c commit 5f01368

5 files changed

Lines changed: 77 additions & 88 deletions

File tree

src/bitbots_motion/bitbots_hcm/bitbots_hcm/hcm_dsd/decisions/check_hardware.py

Lines changed: 13 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
from typing import Optional
2+
3+
from rclpy.time import Time
4+
15
from bitbots_hcm.hcm_dsd.decisions import AbstractHCMDecisionElement
26
from bitbots_msgs.msg import RobotControlState
37

@@ -158,53 +162,24 @@ def get_reevaluate(self):
158162
return True
159163

160164

161-
class CheckPressureSensor(AbstractHCMDecisionElement):
165+
class CheckBattery(AbstractHCMDecisionElement):
162166
"""
163-
Checks connection to pressure sensors.
167+
Checks the battery level
164168
"""
165169

166170
def __init__(self, blackboard, dsd, parameters):
167171
super().__init__(blackboard, dsd, parameters)
168-
self.had_problem = False
172+
self.last_battery_high_time: Optional[Time] = None
169173

170174
def perform(self, reevaluate=False):
171-
if self.blackboard.visualization_active:
172-
# no pressure sensors is visualization, but thats okay
173-
return "OKAY"
174-
175-
if not self.blackboard.pressure_sensors_installed:
176-
# no pressure sensors installed, no check necessary
177-
return "OKAY"
178-
179-
# Check if we get no messages due to an error or always the exact same one (no connection)
180-
if (
181-
not self.blackboard.pressure_diag_error
182-
and not self.blackboard.previous_pressures == self.blackboard.pressures
183-
):
184-
self.blackboard.last_different_pressure_state_time = self.blackboard.node.get_clock().now()
175+
if self.blackboard.battery_voltage is None or self.blackboard.battery_voltage >= self.blackboard.battery_voltage_threshold:
176+
self.last_battery_high_time = self.blackboard.node.get_clock().now()
185177

186-
# Check if we get no messages for a while
187-
if (
188-
self.blackboard.last_different_pressure_state_time is None
189-
or self.blackboard.node.get_clock().now().nanoseconds
190-
- self.blackboard.last_different_pressure_state_time.nanoseconds
191-
> 0.1 * 1e9
178+
if self.last_battery_high_time is None or (
179+
self.blackboard.node.get_clock().now().nanoseconds - self.last_battery_high_time.nanoseconds
180+
> self.blackboard.battery_debounce_time * 1e9
192181
):
193-
# Check if we are in the startup phase (not too long tho)
194-
if (
195-
self.blackboard.current_state == RobotControlState.STARTUP
196-
and self.blackboard.node.get_clock().now().nanoseconds - self.blackboard.start_time.nanoseconds
197-
< 10 * 1e9
198-
):
199-
# wait for the pressure sensors to start
200-
return "PRESSURE_NOT_STARTED"
201-
else:
202-
return "PROBLEM"
203-
204-
if self.had_problem:
205-
# had problem before, just tell that this is solved now
206-
self.blackboard.node.get_logger().info("Pressure sensors are now connected. Will resume.")
207-
self.had_problem = False
182+
return "LOW"
208183

209184
return "OKAY"
210185

src/bitbots_motion/bitbots_hcm/bitbots_hcm/hcm_dsd/hcm.dsd

Lines changed: 47 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -9,48 +9,50 @@ $StartHCM
99
START_UP --> $Simulation
1010
YES --> @RobotStateStartup, @PlayAnimationInit, @PlayAnimationWalkReady
1111
NO --> #INIT_PATTERN
12-
RUNNING --> $CheckMotors
13-
MOTORS_NOT_STARTED --> @RobotStateStartup, @Wait
14-
OVERLOAD --> #EMERGENCY_FALL
15-
OVERHEAT --> #EMERGENCY_FALL
16-
PROBLEM --> @RobotStateHardwareProblem, @WaitForMotors
17-
TURN_ON --> #INIT_PATTERN
18-
OKAY --> $RecordAnimation
19-
RECORD_ACTIVE --> @RobotStateRecord, @Wait
20-
FREE --> $TeachingMode
21-
TEACH --> @RobotStateRecord, @SetTorque + stiff:false, @Wait
22-
HOLD --> @SetTorque + stiff:true, @Wait
23-
FINISHED --> @SetTorque + stiff:true + r:false, @RobotStateControllable, @PlayAnimationWalkReady
24-
OFF --> $Stop
25-
STOPPED --> @RobotStatePenalty, @CancelGoals, @StopWalking, @PlayAnimationWalkReady, @Wait
26-
FREE -->$CheckIMU
27-
IMU_NOT_STARTED --> @RobotStateStartup, @WaitForIMUStartup
28-
PROBLEM --> @RobotStateHardwareProblem, @WaitForIMU
29-
OKAY --> $Fallen
30-
FALLEN_FRONT --> $GameControllerStop
31-
STOPPED --> @RobotStateFallen, @CancelGoals, @StopWalking, @Wait
32-
FREE --> @RobotStateFallen, @CancelGoals, @StopWalking, @RobotStateGettingUp, @PlayAnimationStandupFront, @SetSquat + squat:true
33-
FALLEN_BACK --> $GameControllerStop
34-
STOPPED --> @RobotStateFallen, @CancelGoals, @StopWalking, @Wait
35-
FREE --> @RobotStateFallen, @CancelGoals, @StopWalking, @RobotStateGettingUp, @SetFootZero, @PlayAnimationFallingBack, @PlayAnimationStandupBack, @SetSquat + squat:true
36-
FALLEN_RIGHT --> $GameControllerStop
37-
STOPPED --> @RobotStateFallen, @CancelGoals, @StopWalking, @Wait
38-
FREE --> @RobotStateFallen, @CancelGoals, @StopWalking, @PlayAnimationTurningFrontRight
39-
FALLEN_LEFT --> $GameControllerStop
40-
STOPPED --> @RobotStateFallen, @CancelGoals, @StopWalking, @Wait
41-
FREE --> @RobotStateFallen, @CancelGoals, @StopWalking, @PlayAnimationTurningFrontLeft
42-
NOT_FALLEN --> $Falling
43-
FALLING_LEFT --> @RobotStateFalling, @CancelGoals, @StopWalking, @PlayAnimationFallingLeft, @Wait
44-
FALLING_RIGHT --> @RobotStateFalling, @CancelGoals, @StopWalking, @PlayAnimationFallingRight, @Wait
45-
FALLING_FRONT --> @RobotStateFalling, @CancelGoals, @StopWalking, @PlayAnimationFallingFront, @Wait
46-
FALLING_BACK --> @RobotStateFalling, @CancelGoals, @StopWalking, @PlayAnimationFallingBack, @Wait
47-
NOT_FALLING --> $InSquat
48-
YES --> @RobotStateGettingUp, @Complain, @PlayAnimationRise, @SetSquat + squat:false
49-
NO --> $PlayingExternalAnimation
50-
ANIMATION_RUNNING --> @StopWalking, @RobotStateAnimationRunning, @Wait
51-
ANIMATION_SERVER_TIMEOUT --> @CancelAnimation
52-
FREE --> $RecentWalkingGoals
53-
STAY_WALKING --> @RobotStateWalking, @Wait
54-
NOT_WALKING --> $RecentKickGoals
55-
KICKING --> @RobotStateKicking, @Wait
56-
NOT_KICKING --> @RobotStateControllable, @Wait
12+
RUNNING --> $CheckBattery
13+
LOW --> @CancelGoals, @StopWalking, @Speak + text:Battery_low_so_please_power_me_off_gracefully, @Wait + time:10 + r:false
14+
OKAY --> $CheckMotors
15+
MOTORS_NOT_STARTED --> @RobotStateStartup, @Wait
16+
OVERLOAD --> #EMERGENCY_FALL
17+
OVERHEAT --> #EMERGENCY_FALL
18+
PROBLEM --> @RobotStateHardwareProblem, @WaitForMotors
19+
TURN_ON --> #INIT_PATTERN
20+
OKAY --> $RecordAnimation
21+
RECORD_ACTIVE --> @RobotStateRecord, @Wait
22+
FREE --> $TeachingMode
23+
TEACH --> @RobotStateRecord, @SetTorque + stiff:false, @Wait
24+
HOLD --> @SetTorque + stiff:true, @Wait
25+
FINISHED --> @SetTorque + stiff:true + r:false, @RobotStateControllable, @PlayAnimationWalkReady
26+
OFF --> $Stop
27+
STOPPED --> @RobotStatePenalty, @CancelGoals, @StopWalking, @PlayAnimationWalkReady, @Wait
28+
FREE -->$CheckIMU
29+
IMU_NOT_STARTED --> @RobotStateStartup, @WaitForIMUStartup
30+
PROBLEM --> @RobotStateHardwareProblem, @WaitForIMU
31+
OKAY --> $Fallen
32+
FALLEN_FRONT --> $GameControllerStop
33+
STOPPED --> @RobotStateFallen, @CancelGoals, @StopWalking, @Wait
34+
FREE --> @RobotStateFallen, @CancelGoals, @StopWalking, @RobotStateGettingUp, @PlayAnimationStandupFront, @SetSquat + squat:true
35+
FALLEN_BACK --> $GameControllerStop
36+
STOPPED --> @RobotStateFallen, @CancelGoals, @StopWalking, @Wait
37+
FREE --> @RobotStateFallen, @CancelGoals, @StopWalking, @RobotStateGettingUp, @SetFootZero, @PlayAnimationFallingBack, @PlayAnimationStandupBack, @SetSquat + squat:true
38+
FALLEN_RIGHT --> $GameControllerStop
39+
STOPPED --> @RobotStateFallen, @CancelGoals, @StopWalking, @Wait
40+
FREE --> @RobotStateFallen, @CancelGoals, @StopWalking, @PlayAnimationTurningFrontRight
41+
FALLEN_LEFT --> $GameControllerStop
42+
STOPPED --> @RobotStateFallen, @CancelGoals, @StopWalking, @Wait
43+
FREE --> @RobotStateFallen, @CancelGoals, @StopWalking, @PlayAnimationTurningFrontLeft
44+
NOT_FALLEN --> $Falling
45+
FALLING_LEFT --> @RobotStateFalling, @CancelGoals, @StopWalking, @PlayAnimationFallingLeft, @Wait
46+
FALLING_RIGHT --> @RobotStateFalling, @CancelGoals, @StopWalking, @PlayAnimationFallingRight, @Wait
47+
FALLING_FRONT --> @RobotStateFalling, @CancelGoals, @StopWalking, @PlayAnimationFallingFront, @Wait
48+
FALLING_BACK --> @RobotStateFalling, @CancelGoals, @StopWalking, @PlayAnimationFallingBack, @Wait
49+
NOT_FALLING --> $InSquat
50+
YES --> @RobotStateGettingUp, @Complain, @PlayAnimationRise, @SetSquat + squat:false
51+
NO --> $PlayingExternalAnimation
52+
ANIMATION_RUNNING --> @StopWalking, @RobotStateAnimationRunning, @Wait
53+
ANIMATION_SERVER_TIMEOUT --> @CancelAnimation
54+
FREE --> $RecentWalkingGoals
55+
STAY_WALKING --> @RobotStateWalking, @Wait
56+
NOT_WALKING --> $RecentKickGoals
57+
KICKING --> @RobotStateKicking, @Wait
58+
NOT_KICKING --> @RobotStateControllable, @Wait

src/bitbots_motion/bitbots_hcm/bitbots_hcm/hcm_dsd/hcm_blackboard.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def __init__(self, node: Node):
8989
self.current_joint_state: Optional[JointState] = None
9090
self.previous_joint_state: Optional[JointState] = None
9191
self.last_different_joint_state_time: Optional[Time] = None
92-
self.is_power_on: bool = False
92+
self.is_power_on: bool = True
9393

9494
# Motor Parameters
9595
self.motor_timeout_duration: float = self.node.get_parameter("motor_timeout_duration").value
@@ -114,6 +114,11 @@ def __init__(self, node: Node):
114114
self.previous_imu_msg: Optional[Imu] = None
115115
self.last_different_imu_state_time: Optional[Time] = None
116116

117+
# Battery state
118+
self.battery_voltage_threshold: float = self.node.get_parameter("battery_voltage_threshold").value
119+
self.battery_debounce_time: float = self.node.get_parameter("battery_debounce_time").value
120+
self.battery_voltage: Optional[float] = None
121+
117122
# Diagnostics state
118123
self.servo_diag_error: bool = False
119124
self.servo_overload: bool = False

src/bitbots_motion/bitbots_hcm/bitbots_hcm/humanoid_control_module.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from sensor_msgs.msg import Imu, JointState
2222
from std_msgs.msg import Bool
2323
from std_srvs.srv import SetBool
24+
from livelybot_msg.msg import PowerDetect
2425

2526
from bitbots_hcm import hcm_dsd
2627
from bitbots_hcm.hcm_dsd.hcm_blackboard import HcmBlackboard
@@ -77,7 +78,7 @@ def __init__(self, use_sim_time, simulation_active, visualization_active):
7778
self.hcm_deactivated = False
7879

7980
# Create subscribers
80-
self.node.create_subscription(Bool, "core/power_switch_status", self.power_cb, 1)
81+
self.node.create_subscription(PowerDetect, "power_detect_state", self.power_detect_cb, 1)
8182
self.node.create_subscription(Bool, "hcm_deactivate", self.deactivate_cb, 1)
8283
self.node.create_subscription(DiagnosticArray, "diagnostics_agg", self.diag_cb, 1)
8384
self.node.create_subscription(Bool, "game_controller/stop_msg", self.stop_cb, 1)
@@ -141,9 +142,9 @@ def set_manual_penalize_mode_callback(self, req: ManualPenalize.Request, resp: M
141142
resp.success = True
142143
return resp
143144

144-
def power_cb(self, msg: Bool):
145-
"""Updates the power state."""
146-
self.blackboard.is_power_on = msg.data
145+
def power_detect_cb(self, msg: PowerDetect):
146+
"""Recives data send by the battery management system."""
147+
self.blackboard.battery_voltage = msg.voltage
147148

148149
def diag_cb(self, msg: DiagnosticArray):
149150
"""Updates the diagnostic state."""

src/bitbots_motion/bitbots_hcm/config/hcm_wolfgang.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,9 @@
4444

4545
# Pick up
4646
pick_up_accel_threshold: 7.0
47+
48+
# Battery
49+
battery:
50+
voltage_threshold: 18.0 # Voltage under which the battery is considered low
51+
debounce_time: 5.0 # Time the battery has to be under the threshold to be considered low [s]
52+

0 commit comments

Comments
 (0)