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
fleet_server/config.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Fleet Server Configuration Management
|
|
2
|
+
|
|
3
|
+
Loads environment variables from .env file and provides defaults.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
# Try to import dotenv, fallback if not available
|
|
10
|
+
try:
|
|
11
|
+
from dotenv import load_dotenv
|
|
12
|
+
DOTENV_AVAILABLE = True
|
|
13
|
+
except ImportError:
|
|
14
|
+
DOTENV_AVAILABLE = False
|
|
15
|
+
|
|
16
|
+
# Load .env file from fleet_server directory if dotenv is available
|
|
17
|
+
FLEET_SERVER_DIR = Path(__file__).parent.absolute()
|
|
18
|
+
ENV_FILE = FLEET_SERVER_DIR / '.env'
|
|
19
|
+
if DOTENV_AVAILABLE and ENV_FILE.exists():
|
|
20
|
+
load_dotenv(ENV_FILE)
|
|
21
|
+
|
|
22
|
+
class Config:
|
|
23
|
+
"""Base configuration"""
|
|
24
|
+
# Server Settings
|
|
25
|
+
FLASK_HOST = os.getenv('FLASK_HOST', '0.0.0.0')
|
|
26
|
+
FLASK_PORT = int(os.getenv('FLASK_PORT', 5000))
|
|
27
|
+
FLASK_ENV = os.getenv('FLASK_ENV', 'development')
|
|
28
|
+
FLASK_DEBUG = os.getenv('FLASK_DEBUG', 'False').lower() == 'true'
|
|
29
|
+
|
|
30
|
+
# Database Path (use absolute path)
|
|
31
|
+
DATABASE_PATH = os.getenv(
|
|
32
|
+
'DATABASE_PATH',
|
|
33
|
+
str(FLEET_SERVER_DIR / 'fleet.db')
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# Upload Directory (use absolute path)
|
|
37
|
+
UPLOAD_FOLDER = os.getenv(
|
|
38
|
+
'UPLOAD_FOLDER',
|
|
39
|
+
str(FLEET_SERVER_DIR / 'uploads')
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Logs Directory
|
|
43
|
+
LOGS_FOLDER = str(FLEET_SERVER_DIR / 'logs')
|
|
44
|
+
LOG_FILE = os.getenv(
|
|
45
|
+
'LOG_FILE',
|
|
46
|
+
str(FLEET_SERVER_DIR / 'logs' / 'fleet_server.log')
|
|
47
|
+
)
|
|
48
|
+
LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO')
|
|
49
|
+
|
|
50
|
+
# Security Settings
|
|
51
|
+
MAX_UPLOAD_SIZE = int(os.getenv('MAX_UPLOAD_SIZE', 104857600)) # 100MB default
|
|
52
|
+
ALLOWED_EXTENSIONS = set(os.getenv('ALLOWED_EXTENSIONS', 'yaml,yml,pcd,zip').split(','))
|
|
53
|
+
|
|
54
|
+
# API Settings
|
|
55
|
+
API_KEY_ENABLED = os.getenv('API_KEY_ENABLED', 'False').lower() == 'true'
|
|
56
|
+
API_KEY = os.getenv('API_KEY', 'your_secret_key_here')
|
|
57
|
+
|
|
58
|
+
@classmethod
|
|
59
|
+
def ensure_directories(cls):
|
|
60
|
+
"""Create required directories if they don't exist"""
|
|
61
|
+
Path(cls.UPLOAD_FOLDER).mkdir(parents=True, exist_ok=True)
|
|
62
|
+
Path(cls.LOGS_FOLDER).mkdir(parents=True, exist_ok=True)
|
|
63
|
+
|
|
64
|
+
# Development Configuration
|
|
65
|
+
class DevelopmentConfig(Config):
|
|
66
|
+
FLASK_ENV = 'development'
|
|
67
|
+
FLASK_DEBUG = True
|
|
68
|
+
|
|
69
|
+
# Production Configuration
|
|
70
|
+
class ProductionConfig(Config):
|
|
71
|
+
FLASK_ENV = 'production'
|
|
72
|
+
FLASK_DEBUG = False
|
|
73
|
+
|
|
74
|
+
# Testing Configuration
|
|
75
|
+
class TestingConfig(Config):
|
|
76
|
+
TESTING = True
|
|
77
|
+
FLASK_DEBUG = True
|
|
78
|
+
DATABASE_PATH = str(FLEET_SERVER_DIR / 'test_fleet.db')
|
|
79
|
+
|
|
80
|
+
# Select configuration based on environment
|
|
81
|
+
config = {
|
|
82
|
+
'development': DevelopmentConfig,
|
|
83
|
+
'production': ProductionConfig,
|
|
84
|
+
'testing': TestingConfig,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
def get_config(env=None):
|
|
88
|
+
"""Get configuration object based on environment"""
|
|
89
|
+
if env is None:
|
|
90
|
+
env = os.getenv('FLASK_ENV', 'development')
|
|
91
|
+
return config.get(env, DevelopmentConfig)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Error - Fleet Server</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--bg-color: #121212;
|
|
10
|
+
--card-bg: #1e1e1e;
|
|
11
|
+
--text-primary: #e0e0e0;
|
|
12
|
+
--error: #f44336;
|
|
13
|
+
}
|
|
14
|
+
body {
|
|
15
|
+
background-color: var(--bg-color);
|
|
16
|
+
color: var(--text-primary);
|
|
17
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
18
|
+
margin: 0;
|
|
19
|
+
padding: 20px;
|
|
20
|
+
}
|
|
21
|
+
.error-container {
|
|
22
|
+
max-width: 600px;
|
|
23
|
+
margin: 50px auto;
|
|
24
|
+
background-color: var(--card-bg);
|
|
25
|
+
padding: 30px;
|
|
26
|
+
border-radius: 8px;
|
|
27
|
+
border-left: 5px solid var(--error);
|
|
28
|
+
}
|
|
29
|
+
h1 {
|
|
30
|
+
color: var(--error);
|
|
31
|
+
}
|
|
32
|
+
.error-message {
|
|
33
|
+
background-color: #1a1a1a;
|
|
34
|
+
padding: 15px;
|
|
35
|
+
border-radius: 4px;
|
|
36
|
+
margin: 20px 0;
|
|
37
|
+
font-family: monospace;
|
|
38
|
+
white-space: pre-wrap;
|
|
39
|
+
}
|
|
40
|
+
a {
|
|
41
|
+
color: #2196F3;
|
|
42
|
+
text-decoration: none;
|
|
43
|
+
}
|
|
44
|
+
a:hover {
|
|
45
|
+
text-decoration: underline;
|
|
46
|
+
}
|
|
47
|
+
</style>
|
|
48
|
+
</head>
|
|
49
|
+
<body>
|
|
50
|
+
<div class="error-container">
|
|
51
|
+
<h1>⚠️ Error</h1>
|
|
52
|
+
<p>An error occurred while processing your request:</p>
|
|
53
|
+
<div class="error-message">{{ error }}</div>
|
|
54
|
+
<p><a href="/">← Back to Dashboard</a></p>
|
|
55
|
+
</div>
|
|
56
|
+
</body>
|
|
57
|
+
</html>
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>Fleet Calibration Manager</title>
|
|
8
|
+
<style>
|
|
9
|
+
:root {
|
|
10
|
+
--bg-color: #121212;
|
|
11
|
+
--card-bg: #1e1e1e;
|
|
12
|
+
--text-primary: #e0e0e0;
|
|
13
|
+
--accent: #2196F3;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
body {
|
|
17
|
+
background-color: var(--bg-color);
|
|
18
|
+
color: var(--text-primary);
|
|
19
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
20
|
+
margin: 0;
|
|
21
|
+
padding: 20px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
h1,
|
|
25
|
+
h2 {
|
|
26
|
+
color: var(--accent);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.grid {
|
|
30
|
+
display: grid;
|
|
31
|
+
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
32
|
+
gap: 20px;
|
|
33
|
+
margin-bottom: 40px;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.card {
|
|
37
|
+
background-color: var(--card-bg);
|
|
38
|
+
padding: 20px;
|
|
39
|
+
border-radius: 8px;
|
|
40
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
|
|
41
|
+
transition: transform 0.2s;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.card:hover {
|
|
45
|
+
transform: translateY(-5px);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.status {
|
|
49
|
+
display: inline-block;
|
|
50
|
+
padding: 4px 8px;
|
|
51
|
+
border-radius: 4px;
|
|
52
|
+
font-size: 0.8em;
|
|
53
|
+
background: #4CAF50;
|
|
54
|
+
color: white;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
table {
|
|
58
|
+
width: 100%;
|
|
59
|
+
border-collapse: collapse;
|
|
60
|
+
background: var(--card-bg);
|
|
61
|
+
border-radius: 8px;
|
|
62
|
+
overflow: hidden;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
th,
|
|
66
|
+
td {
|
|
67
|
+
padding: 12px;
|
|
68
|
+
text-align: left;
|
|
69
|
+
border-bottom: 1px solid #333;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
th {
|
|
73
|
+
background-color: #333;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.btn {
|
|
77
|
+
text-decoration: none;
|
|
78
|
+
padding: 5px 10px;
|
|
79
|
+
border-radius: 4px;
|
|
80
|
+
margin-right: 5px;
|
|
81
|
+
font-size: 0.9em;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.view {
|
|
85
|
+
background-color: #2196F3;
|
|
86
|
+
color: white;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.down {
|
|
90
|
+
background-color: #555;
|
|
91
|
+
color: white;
|
|
92
|
+
}
|
|
93
|
+
</style>
|
|
94
|
+
</head>
|
|
95
|
+
|
|
96
|
+
<body>
|
|
97
|
+
<h1>🚀 Fleet Calibration Status</h1>
|
|
98
|
+
|
|
99
|
+
<h2>Active Robots</h2>
|
|
100
|
+
<div class="grid">
|
|
101
|
+
{% for robot in robots %}
|
|
102
|
+
<div class="card">
|
|
103
|
+
<h3>{{ robot['name'] }}</h3>
|
|
104
|
+
<p>Model: {{ robot['model'] }}</p>
|
|
105
|
+
<p>Last Calib: {{ robot['last_calib_date'] | format_timestamp }}</p>
|
|
106
|
+
<span class="status">Active</span>
|
|
107
|
+
</div>
|
|
108
|
+
{% endfor %}
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<h2>Recent Calibrations</h2>
|
|
112
|
+
<table>
|
|
113
|
+
<thead>
|
|
114
|
+
<tr>
|
|
115
|
+
<th>Time</th>
|
|
116
|
+
<th>Robot ID</th>
|
|
117
|
+
<th>Score (RMSE)</th>
|
|
118
|
+
<th>Actions</th>
|
|
119
|
+
</tr>
|
|
120
|
+
</thead>
|
|
121
|
+
<tbody>
|
|
122
|
+
{% for cal in recent %}
|
|
123
|
+
<tr>
|
|
124
|
+
<td>{{ cal['timestamp'] | format_timestamp }}</td>
|
|
125
|
+
<td>{{ cal['robot_id'] }}</td>
|
|
126
|
+
<td>{{ cal['score'] }} m</td>
|
|
127
|
+
<td>
|
|
128
|
+
<a href="/view/{{ cal['id'] }}" class="btn view">👁️ View 3D</a>
|
|
129
|
+
<a href="/files/{{ cal['artifacts_path'] | basename }}" class="btn down">⬇️ DL</a>
|
|
130
|
+
</td>
|
|
131
|
+
</tr>
|
|
132
|
+
{% endfor %}
|
|
133
|
+
</tbody>
|
|
134
|
+
</table>
|
|
135
|
+
</body>
|
|
136
|
+
|
|
137
|
+
</html>
|