V2
This commit is contained in:
+29
-6
@@ -71,6 +71,11 @@ class MavlinkWorker:
|
||||
self.axes = Axes()
|
||||
self.output_axes = Axes()
|
||||
self.last_control_at = 0.0
|
||||
# Enabled by the web bridge only; the legacy Tk frontend is unchanged.
|
||||
self.require_input_lease = False
|
||||
self.last_input_at = 0.0
|
||||
self.last_input_sequence = -1
|
||||
self.input_timeout = 1.0
|
||||
# Smooth ESC commands without adding a perceptible one-second lag.
|
||||
# At 20 Hz this produces five small steps from neutral to full command.
|
||||
self.ramp_seconds = 0.25
|
||||
@@ -200,6 +205,10 @@ class MavlinkWorker:
|
||||
payload = str(msg)
|
||||
self.log("RX", payload)
|
||||
if msg_type == "HEARTBEAT" and getattr(msg, "type", 0) != mavutil.mavlink.MAV_TYPE_GCS:
|
||||
if getattr(msg, "autopilot", mavutil.mavlink.MAV_AUTOPILOT_INVALID) == mavutil.mavlink.MAV_AUTOPILOT_INVALID:
|
||||
return
|
||||
if self.target_system and (msg.get_srcSystem(), msg.get_srcComponent()) != (self.target_system, self.target_component):
|
||||
return
|
||||
first = not self.target_system
|
||||
self.target_system = msg.get_srcSystem()
|
||||
self.target_component = msg.get_srcComponent()
|
||||
@@ -213,15 +222,17 @@ class MavlinkWorker:
|
||||
mode = str(msg.custom_mode)
|
||||
autopilot = mavutil.mavlink.enums["MAV_AUTOPILOT"].get(msg.autopilot)
|
||||
ap_name = autopilot.name if autopilot else str(msg.autopilot)
|
||||
self.events.put(("heartbeat", self.target_system, ap_name, mode, armed))
|
||||
self.events.put(("heartbeat", self.target_system, ap_name, mode, armed, self.last_heartbeat))
|
||||
if first:
|
||||
self.events.put(("status", "Heartbeat received; controls are neutral."))
|
||||
self._configure_low_bandwidth_streams()
|
||||
self._start_servo_scan()
|
||||
elif msg_type == "COMMAND_ACK":
|
||||
if (msg.get_srcSystem(), msg.get_srcComponent()) != (self.target_system, self.target_component):
|
||||
return
|
||||
result = mavutil.mavlink.enums["MAV_RESULT"].get(msg.result)
|
||||
result_name = result.name if result else str(msg.result)
|
||||
self.events.put(("ack", int(msg.command), result_name))
|
||||
self.events.put(("ack", int(msg.command), result_name, self.last_rx))
|
||||
elif msg_type == "STATUSTEXT":
|
||||
text = msg.text
|
||||
if isinstance(text, bytes):
|
||||
@@ -343,10 +354,17 @@ class MavlinkWorker:
|
||||
if not conn or not self.target_system:
|
||||
return
|
||||
with self.lock:
|
||||
active = not force_neutral
|
||||
now = time.monotonic()
|
||||
expired = self.require_input_lease and (
|
||||
not self.armed or now - self.last_heartbeat > 3.0
|
||||
or now - self.last_input_at > self.input_timeout)
|
||||
if expired or force_neutral:
|
||||
# Never replay a stored command after telemetry/UI recovery.
|
||||
self.axes = Axes()
|
||||
self.output_axes = Axes()
|
||||
active = not (force_neutral or expired)
|
||||
target = self.axes if active else Axes()
|
||||
gain = self.gain
|
||||
now = time.monotonic()
|
||||
if force_neutral:
|
||||
self.output_axes = Axes()
|
||||
else:
|
||||
@@ -418,7 +436,7 @@ class MavlinkWorker:
|
||||
manual,
|
||||
)
|
||||
|
||||
def set_axes(self, axes: Axes):
|
||||
def set_axes(self, axes: Axes, sequence=None):
|
||||
def conditioned(value):
|
||||
# Ignore tiny pointer/key return noise, then quantize to stable 1% steps.
|
||||
if abs(value) < 0.04:
|
||||
@@ -426,6 +444,11 @@ class MavlinkWorker:
|
||||
return round(max(-1.0, min(1.0, value)), 2)
|
||||
|
||||
with self.lock:
|
||||
if sequence is not None:
|
||||
if sequence <= self.last_input_sequence:
|
||||
return
|
||||
self.last_input_sequence = sequence
|
||||
self.last_input_at = time.monotonic()
|
||||
self.axes = Axes(
|
||||
conditioned(axes.forward), conditioned(axes.lateral),
|
||||
conditioned(axes.vertical), conditioned(axes.yaw),
|
||||
@@ -1185,7 +1208,7 @@ class App(tk.Tk):
|
||||
event = self.events.get_nowait()
|
||||
kind = event[0]
|
||||
if kind == "heartbeat":
|
||||
_, system, autopilot, mode, armed = event
|
||||
_, system, autopilot, mode, armed = event[:5]
|
||||
self.vehicle_label.configure(
|
||||
text=f"{mode} • {'ARMED' if armed else 'DISARMED'}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user