Skip to content

Commit

Permalink
Merge pull request #181 from cwruRobotics/livestream-gui-fix
Browse files Browse the repository at this point in the history
Add livestream gui
  • Loading branch information
InvincibleRMC authored May 27, 2024
2 parents 009df19 + c8d32e5 commit abe7b7f
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 40 deletions.
Binary file added src/surface/gui/gui/images/CWRUbotix Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
169 changes: 129 additions & 40 deletions src/surface/gui/gui/pilot_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,33 @@
from gui.widgets.flood_warning import FloodWarning
from gui.widgets.video_widget import (CameraDescription, CameraType,
SwitchableVideoWidget, VideoWidget)
from gui.widgets.livestream_header import LivestreamHeader

from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QHBoxLayout, QVBoxLayout
from PyQt6.QtGui import QScreen


FRONT_CAM_TOPIC = 'front_cam/image_raw'
BOTTOM_CAM_TOPIC = 'bottom_cam/image_raw'
DEPTH_CAM_TOPIC = 'depth_cam/image_raw'


def make_bottom_bar() -> QHBoxLayout:
bottom_screen_layout = QHBoxLayout()

timer = TimerDisplay()
bottom_screen_layout.addWidget(timer)

flood_widget = FloodWarning()
bottom_screen_layout.addWidget(flood_widget, alignment=Qt.AlignmentFlag.AlignHCenter |
Qt.AlignmentFlag.AlignBottom)

arm = Arm()
bottom_screen_layout.addWidget(arm, alignment=Qt.AlignmentFlag.AlignRight |
Qt.AlignmentFlag.AlignBottom)

return bottom_screen_layout


class PilotApp(App):
Expand All @@ -28,55 +53,119 @@ def __init__(self) -> None:
depth_cam_type = CameraType.DEPTH

if gui_param.value == 'pilot':
title = 'Pilot GUI - CWRUbotix ROV 2024'

video_layout: QHBoxLayout | QVBoxLayout = main_layout
front_cam_size = [1280, 720]
bottom_cam_size = front_cam_size
depth_cam_size = [640, 360]
else:
title = 'Debug GUI - CWRUbotix ROV 2024'
self.setWindowTitle('Pilot GUI - CWRUbotix ROV 2024')

front_cam_description = CameraDescription(
front_cam_type,
FRONT_CAM_TOPIC,
"Front Camera",
1280, 720
)
bottom_cam_description = CameraDescription(
bottom_cam_type,
BOTTOM_CAM_TOPIC,
"Bottom Camera",
1280, 720
)
depth_cam_description = CameraDescription(
depth_cam_type,
DEPTH_CAM_TOPIC,
"Depth Cam",
640, 360
)

main_layout.addWidget(VideoWidget(front_cam_description),
alignment=Qt.AlignmentFlag.AlignHCenter)
main_layout.addWidget(
SwitchableVideoWidget([bottom_cam_description, depth_cam_description]),
alignment=Qt.AlignmentFlag.AlignHCenter
)

main_layout.addLayout(make_bottom_bar())

self.show_on_monitor(1)

elif gui_param.value == 'livestream':
top_bar = QHBoxLayout()
top_bar.addWidget(LivestreamHeader())
top_bar.addWidget(TimerDisplay(), 2)
arm_widget = Arm()
arm_widget.setMaximumWidth(300)
top_bar.addWidget(arm_widget, 2)

main_layout.addLayout(top_bar)

self.setWindowTitle('Livestream GUI - CWRUbotix ROV 2024')

front_cam_description = CameraDescription(
front_cam_type,
FRONT_CAM_TOPIC,
"Forward Camera",
1280, 720
)
bottom_cam_description = CameraDescription(
bottom_cam_type,
BOTTOM_CAM_TOPIC,
"Down Camera",
1280, 720
)

video_layout = QHBoxLayout()
main_layout.addLayout(video_layout)
front_cam_size = [721, 541]
bottom_cam_size = front_cam_size
depth_cam_size = [640, 360]

# 1 big camera feed and 2 smaller ones
front_cam_description = CameraDescription(front_cam_type,
'front_cam/image_raw',
'Front Camera', *front_cam_size)

bottom_cam_description = CameraDescription(bottom_cam_type,
'bottom_cam/image_raw',
'Bottom Camera', *bottom_cam_size)
depth_cam_description = CameraDescription(depth_cam_type,
'depth_cam/image_raw',
'Depth Camera', *depth_cam_size)

main_video = VideoWidget(front_cam_description)
video_area = SwitchableVideoWidget([bottom_cam_description, depth_cam_description],
"camera_switch")
video_layout.addWidget(VideoWidget(front_cam_description),
alignment=Qt.AlignmentFlag.AlignHCenter)
video_layout.addWidget(VideoWidget(bottom_cam_description),
alignment=Qt.AlignmentFlag.AlignHCenter)

self.setWindowTitle(title)
video_layout.addWidget(main_video, alignment=Qt.AlignmentFlag.AlignHCenter)
video_layout.addWidget(video_area, alignment=Qt.AlignmentFlag.AlignHCenter)
main_layout.addLayout(video_layout)
main_layout.addStretch()

bottom_screen_layout = QHBoxLayout()
self.show_on_monitor(2)

timer = TimerDisplay()
bottom_screen_layout.addWidget(timer)
else:
self.setWindowTitle('Debug GUI - CWRUbotix ROV 2024')

front_cam_description = CameraDescription(
front_cam_type,
FRONT_CAM_TOPIC,
"Front Camera",
721, 541
)
bottom_cam_description = CameraDescription(
bottom_cam_type,
BOTTOM_CAM_TOPIC,
"Bottom Camera",
721, 541
)
depth_cam_description = CameraDescription(
depth_cam_type,
DEPTH_CAM_TOPIC,
"Depth Cam",
640, 360
)

flood_widget = FloodWarning()
bottom_screen_layout.addWidget(flood_widget, alignment=Qt.AlignmentFlag.AlignHCenter |
Qt.AlignmentFlag.AlignBottom)
video_layout = QHBoxLayout()

arm = Arm()
bottom_screen_layout.addWidget(arm, alignment=Qt.AlignmentFlag.AlignRight |
Qt.AlignmentFlag.AlignBottom)
video_layout.addWidget(VideoWidget(front_cam_description),
alignment=Qt.AlignmentFlag.AlignHCenter)
video_layout.addWidget(
SwitchableVideoWidget([bottom_cam_description, depth_cam_description]),
alignment=Qt.AlignmentFlag.AlignHCenter
)

main_layout.addLayout(bottom_screen_layout)
main_layout.addLayout(video_layout)
main_layout.addLayout(make_bottom_bar())

def show_on_monitor(self, monitor_id: int) -> None:
screen = self.screen()
if screen is None:
return

monitors = QScreen.virtualSiblings(screen)
if len(monitors) > monitor_id:
monitor = monitors[monitor_id].availableGeometry()
self.move(monitor.left(), monitor.top())
self.showFullScreen()


def run_gui_pilot() -> None:
Expand Down
42 changes: 42 additions & 0 deletions src/surface/gui/gui/widgets/livestream_header.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QHBoxLayout, QLabel, QVBoxLayout, QWidget
from PyQt6.QtGui import QPixmap

from ament_index_python.packages import get_package_share_directory
import os


class LivestreamHeader(QWidget):
def __init__(self) -> None:
super().__init__()

root_layout = QHBoxLayout()
self.setLayout(root_layout)

logo_path = os.path.join(
get_package_share_directory("gui"), "images", "CWRUbotix Logo.png"
)

logo_pixmap = QPixmap(logo_path)

logo_label = QLabel()
logo_label.setPixmap(
logo_pixmap.scaled(100, 100, Qt.AspectRatioMode.KeepAspectRatio,
Qt.TransformationMode.SmoothTransformation)
)

root_layout.addWidget(logo_label)
root_layout.addSpacing(10)

text_vbox = QVBoxLayout()
title_label = QLabel("Explorer Team 25 - CWRUbotix")
title_label.setStyleSheet('QLabel { font-size: 35px; }')
title_label.setAlignment(Qt.AlignmentFlag.AlignAbsolute)
text_vbox.addWidget(title_label)

subtitle_label = QLabel("Case Western Reserve University - Cleveland, Ohio")
subtitle_label.setStyleSheet('QLabel { font-size: 20px; }')
subtitle_label.setAlignment(Qt.AlignmentFlag.AlignAbsolute)
text_vbox.addWidget(subtitle_label)

root_layout.addLayout(text_vbox)
3 changes: 3 additions & 0 deletions src/surface/gui/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
# Include all style files.
(os.path.join('share', PACKAGE_NAME, 'styles'),
glob('gui/styles/*.qss')),
# Include all images.
(os.path.join('share', PACKAGE_NAME, 'images'),
glob('gui/images/*')),
],
install_requires=['setuptools'],
zip_safe=True,
Expand Down
35 changes: 35 additions & 0 deletions src/surface/surface_main/launch/competition_launch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import os

from ament_index_python.packages import get_package_share_directory
from launch.launch_description import LaunchDescription
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource


def generate_launch_description() -> LaunchDescription:

surface_path = get_package_share_directory('surface_main')
gui_path = get_package_share_directory('gui')

all_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource([
os.path.join(
surface_path, 'launch', 'surface_all_nodes_launch.py'
)
]),
)

# Launches livestream gui
gui_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource([
os.path.join(
gui_path, 'launch', 'pilot_launch.py'
)
]),
launch_arguments=[('gui', 'livestream')]
)

return LaunchDescription([
all_launch,
gui_launch
])

0 comments on commit abe7b7f

Please sign in to comment.