berechnung Weg und geschwindigkeit
This commit is contained in:
@@ -15,6 +15,9 @@ PORT = 8082
|
||||
EXOMY_CONTAINER = 'exomy_autostart'
|
||||
DELAY_FILE = '/tmp/exomy_delay.txt'
|
||||
SPEED_LIMIT_FILE = '/tmp/exomy_speed_limit.txt'
|
||||
DRIVE_ESTIMATOR_CALIBRATION_FILE = os.path.join(
|
||||
os.path.dirname(__file__), '..', 'config', 'drive_estimator_calibration.json'
|
||||
)
|
||||
MOTOR_TEST_LOCK = threading.Lock()
|
||||
|
||||
|
||||
@@ -492,6 +495,136 @@ def get_drive_neutral_status():
|
||||
return 500, {'status': 'Fahr-Neutralwerte konnten nicht geladen werden'}
|
||||
|
||||
|
||||
def get_drive_estimator_config():
|
||||
from admin_motor_test import WHEELS, _load_config
|
||||
|
||||
try:
|
||||
config_dir = os.path.join(os.path.dirname(__file__), '..', 'config')
|
||||
config_candidates = [
|
||||
os.path.join(config_dir, 'exomy.yaml'),
|
||||
os.path.join(config_dir, 'exomy.remote.yaml'),
|
||||
os.path.join(config_dir, 'exomy.yaml.template'),
|
||||
]
|
||||
config_path = next((path for path in config_candidates if os.path.exists(path)), None)
|
||||
if config_path is None:
|
||||
raise FileNotFoundError('Konfigurationsdatei nicht gefunden')
|
||||
|
||||
config = _load_config(config_path)
|
||||
neutral_values = [
|
||||
int(config[f'drive_pwm_neutral_{wheel}'])
|
||||
for wheel in WHEELS
|
||||
]
|
||||
average_neutral = sum(neutral_values) / len(neutral_values)
|
||||
return 200, {
|
||||
'status': 'Bereit',
|
||||
'estimator': {
|
||||
'config_path': os.path.abspath(config_path),
|
||||
'drive_pwm_neutral_average': average_neutral,
|
||||
'drive_pwm_neutral_values': neutral_values,
|
||||
'drive_pwm_range': int(config['drive_pwm_range']),
|
||||
'pwm_frequency_hz': 50,
|
||||
'servo_max_rpm': 50.0,
|
||||
'servo_full_scale_pulse_delta_ms': 0.2,
|
||||
'wheel_diameter_m_default': 0.1,
|
||||
},
|
||||
}
|
||||
except FileNotFoundError:
|
||||
return 500, {'status': 'Motor-Konfiguration fehlt'}
|
||||
except Exception:
|
||||
return 500, {'status': 'Estimator-Konfiguration konnte nicht geladen werden'}
|
||||
|
||||
|
||||
def get_drive_estimator_calibration():
|
||||
default_points = [0, 20, 30, 40, 50, 60, 80, 100]
|
||||
data = {
|
||||
'points': [
|
||||
{'percent': point, 'speed_mps': 0.0}
|
||||
for point in default_points
|
||||
],
|
||||
'updated_at': None,
|
||||
'source': 'default',
|
||||
}
|
||||
|
||||
try:
|
||||
with open(DRIVE_ESTIMATOR_CALIBRATION_FILE, 'r', encoding='utf-8') as handle:
|
||||
payload = json.load(handle)
|
||||
points = payload.get('points')
|
||||
if isinstance(points, list):
|
||||
cleaned_points = []
|
||||
for item in points:
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
percent = int(item.get('percent', 0))
|
||||
speed_mps = float(item.get('speed_mps', 0.0))
|
||||
cleaned_points.append({
|
||||
'percent': max(0, min(100, percent)),
|
||||
'speed_mps': max(0.0, speed_mps),
|
||||
})
|
||||
if cleaned_points:
|
||||
cleaned_points.sort(key=lambda item: item['percent'])
|
||||
data = {
|
||||
'points': cleaned_points,
|
||||
'updated_at': payload.get('updated_at'),
|
||||
'source': 'saved',
|
||||
}
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except (OSError, ValueError, TypeError, json.JSONDecodeError):
|
||||
return 500, {'status': 'Kalibrierung konnte nicht geladen werden'}
|
||||
|
||||
return 200, {
|
||||
'status': 'Bereit',
|
||||
'calibration': data,
|
||||
}
|
||||
|
||||
|
||||
def save_drive_estimator_calibration(points):
|
||||
if not isinstance(points, list) or not points:
|
||||
return 400, {'status': 'Kalibrierpunkte fehlen'}
|
||||
|
||||
cleaned_points = []
|
||||
seen_percents = set()
|
||||
for item in points:
|
||||
if not isinstance(item, dict):
|
||||
return 400, {'status': 'Kalibrierpunkte sind ungültig'}
|
||||
try:
|
||||
percent = int(item.get('percent', 0))
|
||||
speed_mps = float(item.get('speed_mps', 0.0))
|
||||
except (TypeError, ValueError):
|
||||
return 400, {'status': 'Kalibrierwerte sind ungültig'}
|
||||
percent = max(0, min(100, percent))
|
||||
speed_mps = max(0.0, speed_mps)
|
||||
if percent in seen_percents:
|
||||
return 400, {'status': 'Jede Stufe darf nur einmal vorkommen'}
|
||||
seen_percents.add(percent)
|
||||
cleaned_points.append({
|
||||
'percent': percent,
|
||||
'speed_mps': speed_mps,
|
||||
})
|
||||
|
||||
cleaned_points.sort(key=lambda item: item['percent'])
|
||||
os.makedirs(os.path.dirname(DRIVE_ESTIMATOR_CALIBRATION_FILE), exist_ok=True)
|
||||
payload = {
|
||||
'updated_at': time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'points': cleaned_points,
|
||||
}
|
||||
try:
|
||||
with open(DRIVE_ESTIMATOR_CALIBRATION_FILE, 'w', encoding='utf-8') as handle:
|
||||
json.dump(payload, handle, ensure_ascii=False, indent=2)
|
||||
handle.write('\n')
|
||||
except OSError:
|
||||
return 500, {'status': 'Kalibrierung konnte nicht gespeichert werden'}
|
||||
|
||||
return 200, {
|
||||
'status': 'Kalibrierung gespeichert',
|
||||
'calibration': {
|
||||
'points': cleaned_points,
|
||||
'updated_at': payload['updated_at'],
|
||||
'source': 'saved',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def preview_drive_neutral_action(values):
|
||||
from admin_motor_test import preview_drive_neutral_value
|
||||
|
||||
@@ -587,6 +720,14 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
||||
status_code, response = get_drive_neutral_status()
|
||||
self.write_json(status_code, response)
|
||||
return
|
||||
if self.path == '/api/drive-estimator/config':
|
||||
status_code, response = get_drive_estimator_config()
|
||||
self.write_json(status_code, response)
|
||||
return
|
||||
if self.path == '/api/drive-estimator/calibration':
|
||||
status_code, response = get_drive_estimator_calibration()
|
||||
self.write_json(status_code, response)
|
||||
return
|
||||
self.write_json(404, {'status': 'Unbekannt'})
|
||||
|
||||
def do_POST(self):
|
||||
@@ -626,6 +767,21 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
||||
self.write_json(500, {'status': str(exc)})
|
||||
return
|
||||
|
||||
if self.path == '/api/drive-estimator/calibration':
|
||||
try:
|
||||
content_length = int(self.headers.get('Content-Length', '0'))
|
||||
except ValueError:
|
||||
content_length = 0
|
||||
raw_body = self.rfile.read(content_length) if content_length > 0 else b'{}'
|
||||
try:
|
||||
payload = json.loads(raw_body.decode('utf-8'))
|
||||
except (UnicodeDecodeError, json.JSONDecodeError):
|
||||
self.write_json(400, {'status': 'Ungültige Anfrage'})
|
||||
return
|
||||
status_code, response = save_drive_estimator_calibration(payload.get('points'))
|
||||
self.write_json(status_code, response)
|
||||
return
|
||||
|
||||
if self.path == '/api/motor-test/drive-neutral/preview':
|
||||
try:
|
||||
content_length = int(self.headers.get('Content-Length', '0'))
|
||||
|
||||
Reference in New Issue
Block a user