Skip to content

Commit faefbf8

Browse files
LukasBaeckerJohannes-Thielpascalzauberzeug
authored
Basic robot status in mobile app (#238)
To see basic robot status infos in the app, a module, extending the [rosys app control](https://github.com/zauberzeug/rosys/blob/main/rosys/automation/app_controls_.py), was added. - [x] creating app_control module - [x] showing basic status info in app - [x] testing on a robot --------- Co-authored-by: Johannes-Thiel <[email protected]> Co-authored-by: Pascal Schade <[email protected]>
1 parent e20b5e5 commit faefbf8

File tree

2 files changed

+65
-14
lines changed

2 files changed

+65
-14
lines changed

field_friend/app_controls.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import rosys
2+
from rosys.automation import Automator
3+
from rosys.automation.app_controls_ import AppControls as RosysAppControls
4+
from rosys.hardware import RobotBrain
5+
6+
from .hardware.field_friend import FieldFriend
7+
8+
9+
class AppControls(RosysAppControls):
10+
11+
def __init__(self,
12+
robot_brain: RobotBrain,
13+
automator: Automator,
14+
field_friend: FieldFriend,
15+
) -> None:
16+
super().__init__(robot_brain, automator)
17+
self.field_friend = field_friend
18+
self.last_battery_percentage: float | None = self.field_friend.bms.state.percentage
19+
self.last_charging: bool | None = self.field_friend.bms.state.is_charging
20+
self.last_estops_pressed: list[int] = []
21+
self.last_estop_soft_active: bool = self.field_friend.estop.is_soft_estop_active
22+
self.last_bumpers_active: list[str] = []
23+
self.last_info: str = ''
24+
self.APP_CONNECTED.register(self.reset)
25+
rosys.on_repeat(self.check_status, 2.0)
26+
27+
async def check_status(self) -> None:
28+
estop_changed = self.field_friend.estop.pressed_estops != self.last_estops_pressed or self.field_friend.estop.is_soft_estop_active != self.last_estop_soft_active
29+
if estop_changed:
30+
self.last_estops_pressed = list(self.field_friend.estop.pressed_estops)
31+
self.last_estop_soft_active = self.field_friend.estop.is_soft_estop_active
32+
battery_changed = self.field_friend.bms.state.percentage != self.last_battery_percentage or self.field_friend.bms.state.is_charging != self.last_charging
33+
if battery_changed:
34+
self.last_battery_percentage = self.field_friend.bms.state.percentage
35+
self.last_charging = self.field_friend.bms.state.is_charging
36+
bumpers_changed = self.last_bumpers_active != self.field_friend.bumper.active_bumpers if self.field_friend.bumper else False
37+
if bumpers_changed:
38+
assert self.field_friend.bumper is not None
39+
self.last_bumpers_active = self.field_friend.bumper.active_bumpers
40+
if estop_changed or battery_changed or bumpers_changed:
41+
await self.sync()
42+
43+
async def sync(self) -> None:
44+
await super().sync()
45+
info = ''
46+
if self.field_friend.estop.active:
47+
info = 'E-Stop active. Please check the robot.'
48+
elif self.field_friend.estop.is_soft_estop_active:
49+
info = 'Software E-Stop active. Please check the robot.'
50+
elif self.field_friend.bumper and self.field_friend.bumper.active_bumpers:
51+
info = 'A bumper is active. Please check the robot.'
52+
elif self.field_friend.bms.state.percentage is not None:
53+
info = f'{self.field_friend.bms.state.percentage:.0f}%'
54+
if self.field_friend.bms.state.is_charging:
55+
info += ' is charging'
56+
if info != self.last_info:
57+
await self.set_info(info)
58+
self.last_info = info
59+
60+
def reset(self) -> None:
61+
self.last_info = 'loading'

field_friend/system.py

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import config.config_selection as config_selector
1111

1212
from . import localization
13+
from .app_controls import AppControls as app_controls
1314
from .automations import (
1415
AutomationWatcher,
1516
BatteryWatcher,
@@ -20,26 +21,15 @@
2021
PlantProvider,
2122
Puncher,
2223
)
23-
from .automations.implements import (
24-
ExternalMower,
25-
Implement,
26-
Recorder,
27-
Tornado,
28-
WeedingScrew,
29-
)
24+
from .automations.implements import ExternalMower, Implement, Recorder, Tornado, WeedingScrew
3025
from .automations.navigation import (
3126
CrossglideDemoNavigation,
3227
FieldNavigation,
3328
FollowCropsNavigation,
3429
Navigation,
3530
StraightLineNavigation,
3631
)
37-
from .hardware import (
38-
FieldFriend,
39-
FieldFriendHardware,
40-
FieldFriendSimulation,
41-
TeltonikaRouter,
42-
)
32+
from .hardware import FieldFriend, FieldFriendHardware, FieldFriendSimulation, TeltonikaRouter
4333
from .info import Info
4434
from .kpi_generator import generate_kpis
4535
from .localization.geo_point import GeoPoint
@@ -185,7 +175,7 @@ def watch_robot() -> None:
185175
assert isinstance(self.field_friend, FieldFriendHardware)
186176
if self.field_friend.battery_control:
187177
self.battery_watcher = BatteryWatcher(self.field_friend, self.automator)
188-
rosys.automation.app_controls(self.field_friend.robot_brain, self.automator)
178+
app_controls(self.field_friend.robot_brain, self.automator, self.field_friend)
189179
rosys.on_repeat(self.log_status, 60*5)
190180

191181
def restart(self) -> None:

0 commit comments

Comments
 (0)