From 8176f001a76a3f98f90347a3a157707dadcbb3a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Thu, 21 May 2026 21:16:55 +0200 Subject: [PATCH] Speed Max einstellbar --- ExoMy_Software-master/docker/entrypoint.sh | 2 + ExoMy_Software-master/gui/admin.html | 56 +++++++++++++++++++ .../scripts/exomy_admin_api.py | 49 ++++++++++++++++ .../src/joystick_parser_node.py | 19 ++++++- 4 files changed, 124 insertions(+), 2 deletions(-) diff --git a/ExoMy_Software-master/docker/entrypoint.sh b/ExoMy_Software-master/docker/entrypoint.sh index 493e931..9d52866 100644 --- a/ExoMy_Software-master/docker/entrypoint.sh +++ b/ExoMy_Software-master/docker/entrypoint.sh @@ -36,6 +36,8 @@ then rosparam set /controller logitech-F710 rosparam set /delay_seconds 0.0 echo 0.0 > /tmp/exomy_delay.txt + rosparam set /speed_limit_percent 100 + echo 100 > /tmp/exomy_speed_limit.txt /opt/ros/melodic/lib/rosbridge_server/rosbridge_websocket > /tmp/rosbridge.log 2>&1 & ROSBRIDGE_PID=$! diff --git a/ExoMy_Software-master/gui/admin.html b/ExoMy_Software-master/gui/admin.html index ec070ff..ce6d244 100644 --- a/ExoMy_Software-master/gui/admin.html +++ b/ExoMy_Software-master/gui/admin.html @@ -101,6 +101,33 @@ +
+
+

Geschwindigkeit

+
+ +
+

Systemstatus

@@ -304,6 +331,33 @@ if (sel) sel.value = String(seconds); } + async function fetchSpeedLimit() { + try { + var response = await fetch(adminApiBase + '/api/speed-limit'); + if (!response.ok) return; + var data = await response.json(); + var sel = document.getElementById('speed_limit_select'); + if (sel) sel.value = String(data.speed_limit_percent); + } catch (e) {} + } + + async function setSpeedLimit(percent) { + var statusEl = document.getElementById('speed_limit_status'); + if (statusEl) statusEl.textContent = 'Setze…'; + try { + var response = await fetch(adminApiBase + '/api/speed-limit', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({speed_limit_percent: percent}) + }); + var data = await response.json(); + if (statusEl) statusEl.textContent = data.status || 'Gesetzt'; + window.setTimeout(function() { if (statusEl) statusEl.textContent = ''; }, 2000); + } catch (e) { + if (statusEl) statusEl.textContent = 'Fehler'; + } + } + async function fetchDelay() { try { var response = await fetch(adminApiBase + '/api/delay'); @@ -351,8 +405,10 @@ fetchStatus(); fetchDelay(); + fetchSpeedLimit(); window.setInterval(fetchStatus, 10000); window.setInterval(fetchDelay, 5000); + window.setInterval(fetchSpeedLimit, 5000); }); diff --git a/ExoMy_Software-master/scripts/exomy_admin_api.py b/ExoMy_Software-master/scripts/exomy_admin_api.py index 5a176b2..1c33fe0 100644 --- a/ExoMy_Software-master/scripts/exomy_admin_api.py +++ b/ExoMy_Software-master/scripts/exomy_admin_api.py @@ -14,6 +14,7 @@ import time PORT = 8082 EXOMY_CONTAINER = 'exomy_autostart' DELAY_FILE = '/tmp/exomy_delay.txt' +SPEED_LIMIT_FILE = '/tmp/exomy_speed_limit.txt' MOTOR_TEST_LOCK = threading.Lock() @@ -251,6 +252,33 @@ def set_delay(seconds): return seconds +def get_speed_limit(): + try: + with open(SPEED_LIMIT_FILE) as f: + return max(10, min(100, int(f.read().strip()))) + except Exception: + return 100 + + +def set_speed_limit(percent): + percent = max(10, min(100, int(percent))) + data = str(percent).encode() + try: + fd = os.open(SPEED_LIMIT_FILE, os.O_WRONLY | os.O_TRUNC) + except FileNotFoundError: + fd = os.open(SPEED_LIMIT_FILE, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o666) + try: + os.write(fd, data) + finally: + os.close(fd) + subprocess.run( + ['docker', 'exec', EXOMY_CONTAINER, 'bash', '-c', + f'source /opt/ros/melodic/setup.bash && rosparam set /speed_limit_percent {percent}'], + capture_output=True, check=False + ) + return percent + + def rumble_controller(duration_ms=400): # Linux FF constants EV_FF = 0x15 @@ -539,6 +567,9 @@ class Handler(http.server.BaseHTTPRequestHandler): if self.path == '/api/delay': self.write_json(200, {'delay_seconds': get_delay()}) return + if self.path == '/api/speed-limit': + self.write_json(200, {'speed_limit_percent': get_speed_limit()}) + return if self.path == '/api/status': self.write_json(200, collect_status()) return @@ -577,6 +608,24 @@ class Handler(http.server.BaseHTTPRequestHandler): self.write_json(500, {'status': str(exc)}) return + if self.path == '/api/speed-limit': + 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 + try: + percent = set_speed_limit(payload.get('speed_limit_percent', 100)) + self.write_json(200, {'status': 'Geschwindigkeitslimit gesetzt', 'speed_limit_percent': percent}) + except Exception as exc: + self.write_json(500, {'status': str(exc)}) + return + if self.path == '/api/motor-test/drive-neutral/preview': try: content_length = int(self.headers.get('Content-Length', '0')) diff --git a/ExoMy_Software-master/src/joystick_parser_node.py b/ExoMy_Software-master/src/joystick_parser_node.py index 06605d0..dc1bff5 100644 --- a/ExoMy_Software-master/src/joystick_parser_node.py +++ b/ExoMy_Software-master/src/joystick_parser_node.py @@ -6,6 +6,7 @@ import math import os import struct import threading +import time import rospy from sensor_msgs.msg import Joy @@ -21,6 +22,8 @@ global last_locomotion_mode locomotion_mode = LocomotionMode.ACKERMANN.value last_locomotion_mode = locomotion_mode motors_enabled = True +_speed_limit = 100 +_speed_limit_last_read = 0.0 AXIS_DEADZONE = 0.1 last_start_button_pressed = False last_webgui_time = None @@ -72,6 +75,18 @@ CONTROLLER_FUNCTION_MAPS = { } +def get_speed_limit(): + global _speed_limit, _speed_limit_last_read + now = time.time() + if now - _speed_limit_last_read > 2.0: + try: + _speed_limit = int(rospy.get_param('/speed_limit_percent', 100)) + except Exception: + pass + _speed_limit_last_read = now + return _speed_limit + + def _rumble_thread(duration_ms): EV_FF = 0x15 FF_RUMBLE = 0x50 @@ -229,9 +244,9 @@ def callback(data): rover_cmd.motors_enabled = motors_enabled - # The velocity is decoded as value between 0...100 + # The velocity is decoded as value between 0...100, capped by speed limit stick_length = min(math.sqrt(x*x + y*y), 1.0) - rover_cmd.vel = int(100 * math.pow(stick_length, VELOCITY_EXPO)) + rover_cmd.vel = int(get_speed_limit() * math.pow(stick_length, VELOCITY_EXPO)) # The steering is described as an angle between -180...180 # Which describe the joystick position as follows: