calibrate-suite 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- calibrate_suite-0.1.0.dist-info/METADATA +761 -0
- calibrate_suite-0.1.0.dist-info/RECORD +47 -0
- calibrate_suite-0.1.0.dist-info/WHEEL +5 -0
- calibrate_suite-0.1.0.dist-info/entry_points.txt +3 -0
- calibrate_suite-0.1.0.dist-info/licenses/LICENSE +201 -0
- calibrate_suite-0.1.0.dist-info/top_level.txt +4 -0
- fleet_server/__init__.py +32 -0
- fleet_server/app.py +377 -0
- fleet_server/config.py +91 -0
- fleet_server/templates/error.html +57 -0
- fleet_server/templates/index.html +137 -0
- fleet_server/templates/viewer.html +490 -0
- fleet_server/utils.py +178 -0
- gui/__init__.py +2 -0
- gui/assets/2d-or-3d-fleet-upload.png +0 -0
- gui/assets/2d_3d_overlay_output.jpg +0 -0
- gui/assets/3d-or-2d-overlay_page.png +0 -0
- gui/assets/3d-or-2d-record-page.png +0 -0
- gui/assets/3d_3d_overlay_output.png +0 -0
- gui/assets/3d_or_2d_calibrate-page.png +0 -0
- gui/assets/GUI_homepage.png +0 -0
- gui/assets/hardware_setup.jpeg +0 -0
- gui/assets/single_lidar_calibrate_page.png +0 -0
- gui/assets/single_lidar_output.png +0 -0
- gui/assets/single_lidar_record_page.png +0 -0
- gui/assets/virya.jpg +0 -0
- gui/main.py +23 -0
- gui/widgets/calibrator_widget.py +977 -0
- gui/widgets/extractor_widget.py +561 -0
- gui/widgets/home_widget.py +117 -0
- gui/widgets/recorder_widget.py +127 -0
- gui/widgets/single_lidar_widget.py +673 -0
- gui/widgets/three_d_calib_widget.py +87 -0
- gui/widgets/two_d_calib_widget.py +86 -0
- gui/widgets/uploader_widget.py +151 -0
- gui/widgets/validator_widget.py +614 -0
- gui/windows/main_window.py +56 -0
- gui/windows/main_window_ui.py +65 -0
- rviz_configs/2D-3D.rviz +183 -0
- rviz_configs/3D-3D.rviz +184 -0
- rviz_configs/default_calib.rviz +167 -0
- utils/__init__.py +13 -0
- utils/calibration_common.py +23 -0
- utils/cli_calibrate.py +53 -0
- utils/cli_fleet_server.py +64 -0
- utils/data_extractor_common.py +87 -0
- utils/gui_helpers.py +25 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
|
|
2
|
+
QLineEdit, QPushButton, QComboBox, QMessageBox,
|
|
3
|
+
QGroupBox, QCheckBox)
|
|
4
|
+
from PyQt5.QtCore import QProcess
|
|
5
|
+
import datetime
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
class RecorderWidget(QWidget):
|
|
9
|
+
def __init__(self):
|
|
10
|
+
super().__init__()
|
|
11
|
+
self.process = None
|
|
12
|
+
self.initUI()
|
|
13
|
+
|
|
14
|
+
def initUI(self):
|
|
15
|
+
layout = QVBoxLayout()
|
|
16
|
+
|
|
17
|
+
# Config
|
|
18
|
+
group = QGroupBox("Recording Configuration")
|
|
19
|
+
form = QVBoxLayout()
|
|
20
|
+
|
|
21
|
+
# Output Name
|
|
22
|
+
name_layout = QHBoxLayout()
|
|
23
|
+
self.name_input = QLineEdit()
|
|
24
|
+
self.name_input.setPlaceholderText("e.g. calibration_run_1")
|
|
25
|
+
name_layout.addWidget(QLabel("Session Name:"))
|
|
26
|
+
name_layout.addWidget(self.name_input)
|
|
27
|
+
form.addLayout(name_layout)
|
|
28
|
+
|
|
29
|
+
# Topics (Simplified for now)
|
|
30
|
+
self.topics = [
|
|
31
|
+
"/velodyne_points",
|
|
32
|
+
"/zed/zed_node/left/image_rect_color",
|
|
33
|
+
"/zed/zed_node/depth/depth_registered",
|
|
34
|
+
"/zed/zed_node/left/camera_info",
|
|
35
|
+
"/tf",
|
|
36
|
+
"/tf_static"
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
form.addWidget(QLabel("Recording Topics:"))
|
|
40
|
+
for topic in self.topics:
|
|
41
|
+
cb = QCheckBox(topic)
|
|
42
|
+
cb.setChecked(True)
|
|
43
|
+
cb.setEnabled(False) # Forcing these for now
|
|
44
|
+
form.addWidget(cb)
|
|
45
|
+
|
|
46
|
+
group.setLayout(form)
|
|
47
|
+
layout.addWidget(group)
|
|
48
|
+
|
|
49
|
+
# Controls
|
|
50
|
+
btn_layout = QHBoxLayout()
|
|
51
|
+
self.btn_rec = QPushButton("🟢 Start Recording")
|
|
52
|
+
self.btn_rec.clicked.connect(self.toggle_recording)
|
|
53
|
+
self.btn_rec.setStyleSheet("""
|
|
54
|
+
QPushButton { background-color: #d32f2f; color: white; font-size: 16px; padding: 15px; }
|
|
55
|
+
QPushButton:hover { background-color: #ef5350; }
|
|
56
|
+
""")
|
|
57
|
+
|
|
58
|
+
self.lbl_status = QLabel("Status: Idle")
|
|
59
|
+
self.lbl_status.setStyleSheet("color: #888; font-weight: bold;")
|
|
60
|
+
|
|
61
|
+
btn_layout.addWidget(self.btn_rec)
|
|
62
|
+
btn_layout.addWidget(self.lbl_status)
|
|
63
|
+
layout.addLayout(btn_layout)
|
|
64
|
+
|
|
65
|
+
layout.addStretch()
|
|
66
|
+
self.setLayout(layout)
|
|
67
|
+
|
|
68
|
+
def toggle_recording(self):
|
|
69
|
+
if self.process is None:
|
|
70
|
+
self.start_recording()
|
|
71
|
+
else:
|
|
72
|
+
self.stop_recording()
|
|
73
|
+
|
|
74
|
+
def start_recording(self):
|
|
75
|
+
name = self.name_input.text().strip()
|
|
76
|
+
if not name:
|
|
77
|
+
name = f"calib_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}"
|
|
78
|
+
|
|
79
|
+
# Setup Process
|
|
80
|
+
self.process = QProcess()
|
|
81
|
+
self.process.readyReadStandardError.connect(self.handle_stderr)
|
|
82
|
+
self.process.readyReadStandardOutput.connect(self.handle_stdout)
|
|
83
|
+
|
|
84
|
+
cmd = "ros2"
|
|
85
|
+
args = ["bag", "record", "-o", name] + self.topics
|
|
86
|
+
|
|
87
|
+
self.process.start(cmd, args)
|
|
88
|
+
self.process.waitForStarted()
|
|
89
|
+
|
|
90
|
+
if self.process.state() == QProcess.Running:
|
|
91
|
+
self.btn_rec.setText("🔴 Stop Recording")
|
|
92
|
+
self.btn_rec.setStyleSheet("""
|
|
93
|
+
QPushButton { background-color: #333; color: white; font-size: 16px; padding: 15px; }
|
|
94
|
+
QPushButton:hover { background-color: #555; }
|
|
95
|
+
""")
|
|
96
|
+
self.lbl_status.setText(f"Recording to: {name}...")
|
|
97
|
+
self.lbl_status.setStyleSheet("color: #4CAF50; font-weight: bold;")
|
|
98
|
+
self.name_input.setEnabled(False)
|
|
99
|
+
else:
|
|
100
|
+
QMessageBox.critical(self, "Error", "Failed to start recording process.")
|
|
101
|
+
self.process = None
|
|
102
|
+
|
|
103
|
+
def stop_recording(self):
|
|
104
|
+
if self.process:
|
|
105
|
+
# Send SIGINT (Ctrl+C)
|
|
106
|
+
self.process.terminate()
|
|
107
|
+
self.process.waitForFinished(2000)
|
|
108
|
+
if self.process.state() == QProcess.Running:
|
|
109
|
+
self.process.kill() # Force kill if stuck
|
|
110
|
+
|
|
111
|
+
self.process = None
|
|
112
|
+
self.btn_rec.setText("🟢 Start Recording")
|
|
113
|
+
self.btn_rec.setStyleSheet("""
|
|
114
|
+
QPushButton { background-color: #d32f2f; color: white; font-size: 16px; padding: 15px; }
|
|
115
|
+
QPushButton:hover { background-color: #ef5350; }
|
|
116
|
+
""")
|
|
117
|
+
self.lbl_status.setText("Status: Saved")
|
|
118
|
+
self.lbl_status.setStyleSheet("color: #2196F3; font-weight: bold;")
|
|
119
|
+
self.name_input.setEnabled(True)
|
|
120
|
+
|
|
121
|
+
def handle_stderr(self):
|
|
122
|
+
data = self.process.readAllStandardError()
|
|
123
|
+
print(f"[RECORDER STDERR] {data.data().decode()}")
|
|
124
|
+
|
|
125
|
+
def handle_stdout(self):
|
|
126
|
+
data = self.process.readAllStandardOutput()
|
|
127
|
+
print(f"[RECORDER STDOUT] {data.data().decode()}")
|