Skip to content

Commit 38f6372

Browse files
authored
Merge pull request #169 from CWRUbotix/luxonis-stoppable-stream
Luxonis stoppable stream
2 parents d163c94 + 61027bf commit 38f6372

File tree

27 files changed

+875
-111
lines changed

27 files changed

+875
-111
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Luxonis cam
2+
.cache/
3+
14
# Python
25
__pycache__/
36
*.py[cod]

src/rov_msgs/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ find_package(std_msgs REQUIRED)
2727

2828
rosidl_generate_interfaces(${PROJECT_NAME}
2929
"msg/Manip.msg"
30-
"msg/CameraControllerSwitch.msg"
30+
"msg/VideoWidgetSwitch.msg"
3131
"msg/Flooding.msg"
3232
"msg/Temperature.msg"
3333
"msg/IPAddress.msg"

src/rov_msgs/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This is the package for all our msg, srv, and action definitions.
66

77
## Msg files
88

9-
[CameraControllerSwitch.msg](msg/CameraControllerSwitch.msg)
9+
[VideoWidgetSwitch.msg](msg/VideoWidgetSwitch.msg)
1010

1111
Used for toggling through camera feeds in the pilot gui.
1212

src/rov_msgs/msg/CameraControllerSwitch.msg

Lines changed: 0 additions & 2 deletions
This file was deleted.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# True interprets index as a relative change in cam index from the current index
2+
# False treats it as the absolute index of the new stream
3+
bool relative
4+
int8 index

src/rov_msgs/srv/CameraManage.srv

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
uint8 FRONT = 0
2-
uint8 DOWN = 1
3-
uint8 DUAL = 2
1+
uint8 FLIR_FRONT = 0
2+
uint8 FLIR_DOWN = 1
3+
4+
uint8 LUX_LEFT = 10
5+
uint8 LUX_RIGHT = 11
6+
7+
uint8 LUX_LEFT_RECT = 20
8+
uint8 LUX_RIGHT_RECT = 21
9+
uint8 LUX_DISPARITY = 22
10+
uint8 LUX_DEPTH = 23
411

512
bool on
613
uint8 cam

src/surface/flight_control/flight_control/mavlink_control_node.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from rclpy.node import Node
1010
from rclpy.qos import qos_profile_system_default
1111

12-
from rov_msgs.msg import Heartbeat, Manip, VehicleState
12+
from rov_msgs.msg import Heartbeat, Manip, VehicleState, VideoWidgetSwitch
1313
from rov_msgs.srv import VehicleArming
1414

1515
os.environ['MAVLINK20'] = '1' # Force mavlink 2.0 for pymavlink
@@ -159,6 +159,10 @@ def __init__(self) -> None:
159159
VehicleArming, 'arming', callback=self.arming_service_callback
160160
)
161161

162+
self.right_stream_switch_publisher = self.create_publisher(
163+
VideoWidgetSwitch, 'switch_right_stream', qos_profile_system_default
164+
)
165+
162166
self.invert_controls = False
163167

164168
# Unix timestamp of the last mavlink heartbeat from the pi
@@ -178,6 +182,7 @@ def controller_callback(self, joy_state: JoystickState) -> None:
178182
joy_state : JoystickState
179183
The current state of the joystick buttons and axes
180184
"""
185+
# MARK: CTRLR CALLBACK
181186
self.process_arming_buttons(joy_state)
182187
self.send_mavlink_control(joy_state)
183188
self.manip_callback(joy_state)
@@ -197,6 +202,7 @@ def joystick_map(raw: float) -> float:
197202
float
198203
The output of the mapping, between -1 and 1
199204
"""
205+
# MARK: JOY MAP
200206
return math.copysign(math.fabs(raw) ** JOY_MAP_STRENGTH, raw) * GLOBAL_THROTTLE
201207

202208
def send_mavlink_control(self, joy_state: JoystickState) -> None:
@@ -207,6 +213,7 @@ def send_mavlink_control(self, joy_state: JoystickState) -> None:
207213
joy_state : JoystickState
208214
The state of the joystick buttons and axes
209215
"""
216+
# MARK: SEND MAV CTRL
210217
axes = joy_state.axes
211218
buttons = joy_state.buttons
212219

@@ -242,6 +249,7 @@ def manip_callback(self, joy_state: JoystickState) -> None:
242249
joy_state : JoystickState
243250
The state of the joystick buttons and axes
244251
"""
252+
# MARK: MANIP CALLBACK
245253
buttons = joy_state.buttons
246254
for button_id, manip_button in self.manip_buttons.items():
247255
just_pressed = buttons[button_id] == PRESSED
@@ -261,6 +269,7 @@ def set_armed(self, *, arm: bool) -> None:
261269
arm : bool
262270
Whether the vehicle should be armed (True) or disarmed (False)
263271
"""
272+
# MARK: SET ARMED
264273
self.mavlink.mav.command_long_send(
265274
self.mavlink.target_system,
266275
self.mavlink.target_component,
@@ -292,6 +301,7 @@ def arming_service_callback(
292301
VehicleArming.Response
293302
The filled ROS service response
294303
"""
304+
# MARK: ARM CALLBACK
295305
self.set_armed(arm=request.arm)
296306

297307
response.message_sent = True
@@ -305,6 +315,7 @@ def process_arming_buttons(self, joy_state: JoystickState) -> None:
305315
joy_state : JoystickState
306316
The state of the joystick buttons and axes
307317
"""
318+
# MARK: PROC ARM BUTTONS
308319
buttons = joy_state.buttons
309320

310321
if buttons[self.profile.disarm_button] == PRESSED:
@@ -322,19 +333,21 @@ def process_camera_buttons(self, joy_state: JoystickState) -> None:
322333
joy_state : JoystickState
323334
The state of the joystick buttons and axess
324335
"""
336+
# MARK: PROC CAM BUTTONS
325337
# Camera switching uses the DPAD, currently not remapable with the controller profile system
326338
# because DPADs are presented as axes not buttons and using any other axis is non-sensible
327339
if joy_state.buttons[self.profile.cam_front_button]:
328-
# TODO: Message camera manager and gui to swap cameras
340+
self.right_stream_switch_publisher.publish(VideoWidgetSwitch(relative=False, index=0))
329341
self.invert_controls = False
330342
elif joy_state.buttons[self.profile.cam_back_button]:
331-
# TODO: Message camera manager and gui to swap cameras
343+
self.right_stream_switch_publisher.publish(VideoWidgetSwitch(relative=False, index=1))
332344
self.invert_controls = True
333345

334346
def poll_mavlink(self) -> None:
335347
"""Check for incoming mavlink messages from the vehicle and send state updates if
336348
the vehicle state has changed.
337349
"""
350+
# MARK: POLL MAVLINK
338351
new_state = self.poll_mavlink_for_new_state()
339352

340353
# Check pi timeeout
@@ -364,6 +377,7 @@ def poll_mavlink_for_new_state(self) -> VehicleState:
364377
VehicleState
365378
The updated state of the vehicle
366379
"""
380+
# MARK: POLL MAV NEW STATE
367381
new_state = VehicleState(
368382
pi_connected=self.vehicle_state.pi_connected,
369383
ardusub_connected=self.vehicle_state.ardusub_connected,
@@ -404,6 +418,7 @@ def pi_heartbeat_callback(self, _: Heartbeat) -> None:
404418
_ : Heartbeat
405419
The heartbeat message
406420
"""
421+
# MARK: PI HEARTBEAT
407422
self.last_pi_heartbeat = time.time()
408423

409424
if not self.vehicle_state.pi_connected:
@@ -415,6 +430,7 @@ def poll_subscribers(self) -> None:
415430
"""Check for ros subsribers to our vehicle state topic, and send a state update whenever
416431
a new one subscribes.
417432
"""
433+
# MARK: POLL SUBSCRIBERS
418434
# Whenever a node subscribes to vehicle state updates, send the current state
419435
subscriber_count = self.state_publisher.get_subscription_count()
420436
if subscriber_count > self.last_state_subscriber_count:
@@ -424,6 +440,7 @@ def poll_subscribers(self) -> None:
424440

425441
def handle_pygame_events(self) -> None:
426442
"""Poll pygame for joystick connection and disconnection events."""
443+
# MARK: HANDLE PYGAME
427444
for event in pygame.event.get():
428445
if event.type == pygame.JOYDEVICEADDED:
429446
new_joy = joystick.Joystick(event.device_index)
@@ -445,6 +462,7 @@ def handle_pygame_events(self) -> None:
445462

446463
def poll_joystick(self) -> None:
447464
"""Read the current state of the joystick and send a mavlink message."""
465+
# MARK: POLL JOYSTICK
448466
self.handle_pygame_events()
449467

450468
if self.current_joystick_id is not None:

src/surface/gui/gui/gui_node.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def __connect_to_service(self, client: Client, timeout: float) -> None:
121121
)
122122

123123
def send_request_multithreaded(
124-
self, client: Client, request: SrvTypeRequest, signal: pyqtBoundSignal
124+
self, client: Client, request: SrvTypeRequest, signal: pyqtBoundSignal | None = None
125125
) -> None:
126126
"""Send a request from the given client on a separate thread.
127127
Emit the result to the given signal.
@@ -137,7 +137,9 @@ def send_request_multithreaded(
137137
"""
138138

139139
def wrapper(request: SrvTypeRequest) -> None:
140-
signal.emit(client.call(request))
140+
response: SrvTypeRequest | None = client.call(request)
141+
if signal is not None:
142+
signal.emit(response)
141143

142144
Thread(
143145
target=wrapper,

src/surface/gui/gui/operator_app.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from gui.widgets.ip_widget import IPWidget
88
from gui.widgets.logger import Logger
99
from gui.widgets.tabs.general_debug_tab import GeneralDebugTab
10-
from gui.widgets.task_selector import TaskSelector
1110
from gui.widgets.temperature import TemperatureSensor
1211
from gui.widgets.timer import InteractiveTimer
1312

@@ -41,7 +40,6 @@ def __init__(self) -> None:
4140
right_pane.addWidget(TemperatureSensor())
4241
right_pane.addWidget(IPWidget())
4342
right_pane.addStretch()
44-
right_pane.addWidget(TaskSelector())
4543

4644
# Add tabs to root
4745
root_layout = QVBoxLayout()

0 commit comments

Comments
 (0)