mrtautopilot 7__tar.gz → 9__tar.gz
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.
- {mrtautopilot-7 → mrtautopilot-9}/PKG-INFO +1 -1
- {mrtautopilot-7 → mrtautopilot-9}/mrtautopilot/__init__.py +1 -1
- {mrtautopilot-7 → mrtautopilot-9}/mrtautopilot/autopilot.py +385 -47
- {mrtautopilot-7 → mrtautopilot-9}/mrtautopilot.egg-info/PKG-INFO +1 -1
- {mrtautopilot-7 → mrtautopilot-9}/tests/test_mission.py +19 -39
- {mrtautopilot-7 → mrtautopilot-9}/README.md +0 -0
- {mrtautopilot-7 → mrtautopilot-9}/mrtautopilot/mission.py +0 -0
- {mrtautopilot-7 → mrtautopilot-9}/mrtautopilot.egg-info/SOURCES.txt +0 -0
- {mrtautopilot-7 → mrtautopilot-9}/mrtautopilot.egg-info/dependency_links.txt +0 -0
- {mrtautopilot-7 → mrtautopilot-9}/mrtautopilot.egg-info/requires.txt +0 -0
- {mrtautopilot-7 → mrtautopilot-9}/mrtautopilot.egg-info/top_level.txt +0 -0
- {mrtautopilot-7 → mrtautopilot-9}/pyproject.toml +0 -0
- {mrtautopilot-7 → mrtautopilot-9}/setup.cfg +0 -0
|
@@ -3,12 +3,13 @@ import threading
|
|
|
3
3
|
import multiprocessing
|
|
4
4
|
import socket
|
|
5
5
|
import asyncio
|
|
6
|
+
import datetime
|
|
6
7
|
import logging
|
|
7
8
|
import struct
|
|
8
9
|
import uuid
|
|
9
10
|
from dataclasses import dataclass
|
|
10
11
|
from enum import Enum
|
|
11
|
-
from typing import List, Union, Tuple
|
|
12
|
+
from typing import List, Union, Tuple, Callable
|
|
12
13
|
|
|
13
14
|
import mrtmavlink
|
|
14
15
|
from . import mission
|
|
@@ -267,6 +268,187 @@ class LowBandwidth:
|
|
|
267
268
|
fault_response: Union[HealthResponse, None]
|
|
268
269
|
|
|
269
270
|
|
|
271
|
+
class GpsFixType(Enum):
|
|
272
|
+
NoGps = 0
|
|
273
|
+
NoFix = 1
|
|
274
|
+
Fix2d = 2
|
|
275
|
+
Fix3d = 3
|
|
276
|
+
Dgps = 4
|
|
277
|
+
RtkFloat = 5
|
|
278
|
+
RtkFixed = 6
|
|
279
|
+
Static = 7
|
|
280
|
+
Ppp = 8
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
@dataclass
|
|
284
|
+
class Gps2Raw:
|
|
285
|
+
def __init__(self, msg: mrtmavlink.MAVLink_gps2_raw_message):
|
|
286
|
+
self.timestamp = datetime.datetime.fromtimestamp(
|
|
287
|
+
msg.time_usec / 1e6, tz=datetime.timezone.utc
|
|
288
|
+
)
|
|
289
|
+
self.fix_type = GpsFixType(msg.fix_type)
|
|
290
|
+
|
|
291
|
+
if msg.lat != 0x7FFFFFFF:
|
|
292
|
+
self.latitude_deg = msg.lat / 1e7
|
|
293
|
+
else:
|
|
294
|
+
self.latitude_deg = None
|
|
295
|
+
|
|
296
|
+
if msg.lon != 0x7FFFFFFF:
|
|
297
|
+
self.longitude_deg = msg.lon / 1e7
|
|
298
|
+
else:
|
|
299
|
+
self.longitude_deg = None
|
|
300
|
+
|
|
301
|
+
if msg.alt != 0x7FFFFFF:
|
|
302
|
+
self.altitude_m = msg.alt / 1000
|
|
303
|
+
else:
|
|
304
|
+
self.altitude_m = None
|
|
305
|
+
|
|
306
|
+
if msg.eph != 0xFFFF:
|
|
307
|
+
self.hdop = msg.eph / 100
|
|
308
|
+
else:
|
|
309
|
+
self.hdop = None
|
|
310
|
+
|
|
311
|
+
if msg.epv != 0xFFFF:
|
|
312
|
+
self.vdop = msg.epv / 100
|
|
313
|
+
else:
|
|
314
|
+
self.vdop = None
|
|
315
|
+
|
|
316
|
+
if msg.vel != 0xFFFF:
|
|
317
|
+
self.velocity_mps = msg.vel / 100
|
|
318
|
+
else:
|
|
319
|
+
self.velocity_mps = None
|
|
320
|
+
|
|
321
|
+
if msg.cog != 0xFFFF:
|
|
322
|
+
self.course_deg = msg.cog / 100
|
|
323
|
+
else:
|
|
324
|
+
self.course_deg = None
|
|
325
|
+
|
|
326
|
+
if msg.satellites_visible != 0xFF:
|
|
327
|
+
self.num_set = msg.satellites_visible
|
|
328
|
+
else:
|
|
329
|
+
self.num_set = None
|
|
330
|
+
|
|
331
|
+
timestamp: datetime.datetime
|
|
332
|
+
fix_type: GpsFixType
|
|
333
|
+
latitude_deg: Union[float, None]
|
|
334
|
+
longitude_deg: Union[float, None]
|
|
335
|
+
altitude_m: Union[float, None]
|
|
336
|
+
hdop: Union[float, None]
|
|
337
|
+
vdop: Union[float, None]
|
|
338
|
+
velocity_mps: Union[float, None]
|
|
339
|
+
course_deg: Union[float, None]
|
|
340
|
+
num_set: Union[int, None]
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
@dataclass
|
|
344
|
+
class ParamUint8:
|
|
345
|
+
value: int
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
@dataclass
|
|
349
|
+
class ParamInt8:
|
|
350
|
+
value: int
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
@dataclass
|
|
354
|
+
class ParamUint16:
|
|
355
|
+
value: int
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
@dataclass
|
|
359
|
+
class ParamInt16:
|
|
360
|
+
value: int
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
@dataclass
|
|
364
|
+
class ParamUint32:
|
|
365
|
+
value: int
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
@dataclass
|
|
369
|
+
class ParamInt32:
|
|
370
|
+
value: int
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
@dataclass
|
|
374
|
+
class ParamReal32:
|
|
375
|
+
value: float
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
ParamValueType = Union[
|
|
379
|
+
ParamUint8,
|
|
380
|
+
ParamInt8,
|
|
381
|
+
ParamUint16,
|
|
382
|
+
ParamInt16,
|
|
383
|
+
ParamUint32,
|
|
384
|
+
ParamInt32,
|
|
385
|
+
ParamReal32,
|
|
386
|
+
]
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
@dataclass
|
|
390
|
+
class ParamValue:
|
|
391
|
+
@staticmethod
|
|
392
|
+
def from_mavlink(msg: mrtmavlink.MAVLink_param_value_message):
|
|
393
|
+
buffer = struct.pack("<f", msg.param_value)
|
|
394
|
+
if msg.param_type == mrtmavlink.MAV_PARAM_TYPE_UINT8:
|
|
395
|
+
value = ParamUint8(int(struct.unpack("BBBB", buffer)[0]))
|
|
396
|
+
elif msg.param_type == mrtmavlink.MAV_PARAM_TYPE_INT8:
|
|
397
|
+
value = ParamInt8(int(struct.unpack("bBBB", buffer)[0]))
|
|
398
|
+
elif msg.param_type == mrtmavlink.MAV_PARAM_TYPE_UINT16:
|
|
399
|
+
value = ParamUint16(int(struct.unpack("<HBB", buffer)[0]))
|
|
400
|
+
elif msg.param_type == mrtmavlink.MAV_PARAM_TYPE_INT16:
|
|
401
|
+
value = ParamInt16(int(struct.unpack("<hBB", buffer)[0]))
|
|
402
|
+
elif msg.param_type == mrtmavlink.MAV_PARAM_TYPE_UINT32:
|
|
403
|
+
value = ParamUint32(int(struct.unpack("<I", buffer)[0]))
|
|
404
|
+
elif msg.param_type == mrtmavlink.MAV_PARAM_TYPE_INT32:
|
|
405
|
+
value = ParamInt32(int(struct.unpack("<i", buffer)[0]))
|
|
406
|
+
elif msg.param_type == mrtmavlink.MAV_PARAM_TYPE_REAL32:
|
|
407
|
+
value = ParamReal32(float(struct.unpack("<f", buffer)[0]))
|
|
408
|
+
else:
|
|
409
|
+
raise ValueError(f"Unsupported parameter type: {msg.param_type}")
|
|
410
|
+
|
|
411
|
+
return ParamValue(msg.param_id, value, msg.param_index, msg.param_count)
|
|
412
|
+
|
|
413
|
+
def to_mavlink(self) -> mrtmavlink.MAVLink_param_value_message:
|
|
414
|
+
if isinstance(self.value, ParamUint8):
|
|
415
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_UINT8
|
|
416
|
+
value = struct.pack("BBBB", self.value.value, 0, 0, 0)
|
|
417
|
+
elif isinstance(self.value, ParamInt8):
|
|
418
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_INT8
|
|
419
|
+
value = struct.pack("bBBB", self.value.value, 0, 0, 0)
|
|
420
|
+
elif isinstance(self.value, ParamUint16):
|
|
421
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_UINT16
|
|
422
|
+
value = struct.pack("<HBB", self.value.value, 0, 0)
|
|
423
|
+
elif isinstance(self.value, ParamInt16):
|
|
424
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_INT16
|
|
425
|
+
value = struct.pack("<hBB", self.value.value, 0, 0)
|
|
426
|
+
elif isinstance(self.value, ParamUint32):
|
|
427
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_UINT32
|
|
428
|
+
value = struct.pack("<I", self.value.value)
|
|
429
|
+
elif isinstance(self.value, ParamInt32):
|
|
430
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_INT32
|
|
431
|
+
value = struct.pack("<i", self.value.value)
|
|
432
|
+
elif isinstance(self.value, ParamReal32):
|
|
433
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_REAL32
|
|
434
|
+
value = struct.pack("<f", self.value.value)
|
|
435
|
+
else:
|
|
436
|
+
raise ValueError(f"Unsupported parameter type: {type(self.value)}")
|
|
437
|
+
|
|
438
|
+
return mrtmavlink.MAVLink_param_value_message(
|
|
439
|
+
param_id=self.name.encode("utf-8"),
|
|
440
|
+
param_value=struct.unpack("f", value)[0],
|
|
441
|
+
param_type=typ,
|
|
442
|
+
param_index=self.param_idx,
|
|
443
|
+
param_count=self.num_param,
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
name: str
|
|
447
|
+
value: ParamValueType
|
|
448
|
+
param_idx: int
|
|
449
|
+
num_param: int
|
|
450
|
+
|
|
451
|
+
|
|
270
452
|
class MavlinkThread:
|
|
271
453
|
def __init__(
|
|
272
454
|
self,
|
|
@@ -297,9 +479,12 @@ class MavlinkThread:
|
|
|
297
479
|
self.remote_port = remote_port
|
|
298
480
|
self.remote_address_list = [remote_address]
|
|
299
481
|
if remote_address == "127.0.0.1":
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
482
|
+
try:
|
|
483
|
+
self.remote_address_list.extend(
|
|
484
|
+
socket.gethostbyname_ex(socket.gethostname())[2]
|
|
485
|
+
)
|
|
486
|
+
except socket.gaierror:
|
|
487
|
+
logging.warning("Failed to get local IP address")
|
|
303
488
|
|
|
304
489
|
self.is_started = False
|
|
305
490
|
self.is_started_cv = threading.Condition()
|
|
@@ -324,6 +509,9 @@ class MavlinkThread:
|
|
|
324
509
|
self.expected_cmd_uuid = 0
|
|
325
510
|
self.ack_result: Union[int, None] = None
|
|
326
511
|
|
|
512
|
+
self.is_requesting_parameters = False
|
|
513
|
+
self.param_value: Union[ParamValue, None] = None
|
|
514
|
+
|
|
327
515
|
def write(self, data: bytes):
|
|
328
516
|
self.sock.sendto(data, (self.remote_address, self.remote_port))
|
|
329
517
|
|
|
@@ -363,15 +551,19 @@ class MavlinkThread:
|
|
|
363
551
|
for msg in messages:
|
|
364
552
|
self._msg_callback(msg)
|
|
365
553
|
|
|
554
|
+
async def _notify_param_result(self, result: ParamValue):
|
|
555
|
+
async with self.param_cond:
|
|
556
|
+
self.param_result = result
|
|
557
|
+
self.param_cond.notify()
|
|
558
|
+
|
|
366
559
|
async def _notify_ack_result(self, result: int):
|
|
367
560
|
async with self.ack_cond:
|
|
368
561
|
self.ack_result = result
|
|
369
562
|
self.ack_cond.notify()
|
|
370
563
|
|
|
371
564
|
def _msg_callback(self, msg: mrtmavlink.MAVLink_message):
|
|
372
|
-
logging.debug(f"Received: {msg.msgname}, addr")
|
|
373
|
-
|
|
374
565
|
sys_id = msg.get_srcSystem()
|
|
566
|
+
logging.debug(f"Received: {msg.msgname}, sys_id={sys_id}, {msg}")
|
|
375
567
|
if self.system_id != sys_id:
|
|
376
568
|
self.system_id = msg.get_srcSystem()
|
|
377
569
|
logging.info(f"Setting System ID to {sys_id}")
|
|
@@ -411,6 +603,10 @@ class MavlinkThread:
|
|
|
411
603
|
):
|
|
412
604
|
logging.debug(f"Received Command Ack: {msg}")
|
|
413
605
|
self.loop.create_task(self._notify_ack_result(msg.result))
|
|
606
|
+
elif type(msg) is mrtmavlink.MAVLink_param_value_message:
|
|
607
|
+
param = ParamValue.from_mavlink(msg)
|
|
608
|
+
logging.debug(f"Received Param Value: {param}")
|
|
609
|
+
self.loop.create_task(self._notify_param_result(param))
|
|
414
610
|
|
|
415
611
|
def send_heartbeat(self):
|
|
416
612
|
self.loop.call_soon_threadsafe(lambda: self._send_heartbeat())
|
|
@@ -421,55 +617,150 @@ class MavlinkThread:
|
|
|
421
617
|
mrtmavlink.MAV_TYPE_GCS, mrtmavlink.MAV_AUTOPILOT_INVALID, 0, 0, 0
|
|
422
618
|
)
|
|
423
619
|
|
|
620
|
+
def get_parameter(
|
|
621
|
+
self,
|
|
622
|
+
id: str,
|
|
623
|
+
callback: Callable[[Union[ParamValue, None]], None],
|
|
624
|
+
):
|
|
625
|
+
self.loop.create_task(self._get_parameter(id, callback))
|
|
626
|
+
|
|
627
|
+
async def _get_parameter(
|
|
628
|
+
self,
|
|
629
|
+
id: str,
|
|
630
|
+
callback: Callable[[Union[ParamValue, None]], None],
|
|
631
|
+
):
|
|
632
|
+
assert len(id) <= 16
|
|
633
|
+
if self.system_id is None:
|
|
634
|
+
logging.info("Failed to get parameter, system_id not set")
|
|
635
|
+
return
|
|
636
|
+
|
|
637
|
+
if self.is_requesting_parameters:
|
|
638
|
+
logging.warning("Already requesting parameters")
|
|
639
|
+
callback(None)
|
|
640
|
+
return
|
|
641
|
+
|
|
642
|
+
RETRY_PERIOD_S = 0.25
|
|
643
|
+
try:
|
|
644
|
+
self.is_requesting_parameters = True
|
|
645
|
+
|
|
646
|
+
logging.info(f"Getting Param {id}")
|
|
647
|
+
|
|
648
|
+
self.param_result = None
|
|
649
|
+
self.conn.param_request_read_send(
|
|
650
|
+
self.system_id,
|
|
651
|
+
mrtmavlink.MAV_COMP_ID_AUTOPILOT1,
|
|
652
|
+
id.encode("utf-8"),
|
|
653
|
+
-1,
|
|
654
|
+
)
|
|
655
|
+
try:
|
|
656
|
+
async with self.param_cond:
|
|
657
|
+
await asyncio.wait_for(self.param_cond.wait(), RETRY_PERIOD_S)
|
|
658
|
+
except asyncio.TimeoutError:
|
|
659
|
+
logging.error("Timeout waiting for parameter ack")
|
|
660
|
+
callback(None)
|
|
661
|
+
return
|
|
662
|
+
|
|
663
|
+
if self.param_result is not None:
|
|
664
|
+
if self.param_result.name == id:
|
|
665
|
+
callback(self.param_result)
|
|
666
|
+
else:
|
|
667
|
+
logging.warning(
|
|
668
|
+
f"Set parameter {id} but got {self.param_result.name}"
|
|
669
|
+
)
|
|
670
|
+
callback(None)
|
|
671
|
+
else:
|
|
672
|
+
logging.warning(f"Set parameter {id} but got None")
|
|
673
|
+
callback(None)
|
|
674
|
+
finally:
|
|
675
|
+
self.is_requesting_parameters = False
|
|
676
|
+
|
|
424
677
|
def set_parameter(
|
|
425
678
|
self,
|
|
426
679
|
id: str,
|
|
427
|
-
value:
|
|
428
|
-
|
|
429
|
-
component: int = mrtmavlink.MAV_COMP_ID_AUTOPILOT1,
|
|
680
|
+
value: ParamValueType,
|
|
681
|
+
callback: Callable[[Union[ParamValue, None]], None] = lambda x: None,
|
|
430
682
|
):
|
|
431
|
-
self.loop.
|
|
432
|
-
lambda: self._set_parameter(id, value, typ, component)
|
|
433
|
-
)
|
|
683
|
+
self.loop.create_task(self._set_parameter(id, value, callback))
|
|
434
684
|
|
|
435
|
-
def _set_parameter(
|
|
685
|
+
async def _set_parameter(
|
|
686
|
+
self,
|
|
687
|
+
id: str,
|
|
688
|
+
value: ParamValueType,
|
|
689
|
+
callback: Callable[[Union[ParamValue, None]], None],
|
|
690
|
+
):
|
|
436
691
|
assert len(id) <= 16
|
|
437
|
-
if
|
|
692
|
+
if self.system_id is None:
|
|
438
693
|
logging.info("Failed to set parameter, system_id not set")
|
|
439
694
|
return
|
|
440
695
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
696
|
+
if self.is_requesting_parameters:
|
|
697
|
+
logging.warning("Already requesting parameters")
|
|
698
|
+
callback(None)
|
|
699
|
+
return
|
|
700
|
+
|
|
701
|
+
RETRY_PERIOD_S = 0.25
|
|
702
|
+
try:
|
|
703
|
+
self.is_requesting_parameters = True
|
|
704
|
+
|
|
705
|
+
logging.info(f"Setting Param {id} to {value}")
|
|
706
|
+
|
|
707
|
+
if isinstance(value, ParamUint8):
|
|
708
|
+
val_bytes = struct.pack("BBBB", int(value.value), 0, 0, 0)
|
|
709
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_UINT8
|
|
710
|
+
elif isinstance(value, ParamInt8):
|
|
711
|
+
val_bytes = struct.pack("bBBB", int(value.value), 0, 0, 0)
|
|
712
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_INT8
|
|
713
|
+
elif isinstance(value, ParamUint16):
|
|
714
|
+
val_bytes = struct.pack("<HBB", int(value.value), 0, 0)
|
|
715
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_UINT16
|
|
716
|
+
elif isinstance(value, ParamInt16):
|
|
717
|
+
val_bytes = struct.pack("<hBB", int(value.value), 0, 0)
|
|
718
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_INT16
|
|
719
|
+
elif isinstance(value, ParamUint32):
|
|
720
|
+
val_bytes = struct.pack("<I", int(value.value))
|
|
721
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_UINT32
|
|
722
|
+
elif isinstance(value, ParamInt32):
|
|
723
|
+
val_bytes = struct.pack("<i", int(value.value))
|
|
724
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_INT32
|
|
725
|
+
elif isinstance(value, ParamReal32):
|
|
726
|
+
val_bytes = struct.pack("<f", value.value)
|
|
727
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_REAL32
|
|
728
|
+
else:
|
|
729
|
+
assert False, "unsupported type"
|
|
730
|
+
|
|
731
|
+
self.param_result = None
|
|
732
|
+
self.conn.param_set_send(
|
|
733
|
+
self.system_id,
|
|
734
|
+
mrtmavlink.MAV_COMP_ID_AUTOPILOT1,
|
|
735
|
+
id.encode("utf-8"),
|
|
736
|
+
struct.unpack("f", val_bytes)[0],
|
|
737
|
+
typ,
|
|
738
|
+
)
|
|
739
|
+
try:
|
|
740
|
+
async with self.param_cond:
|
|
741
|
+
await asyncio.wait_for(self.param_cond.wait(), RETRY_PERIOD_S)
|
|
742
|
+
except asyncio.TimeoutError:
|
|
743
|
+
logging.error("Timeout waiting for parameter ack")
|
|
744
|
+
callback(None)
|
|
745
|
+
return
|
|
746
|
+
|
|
747
|
+
if self.param_result is not None:
|
|
748
|
+
if self.param_result.name == id:
|
|
749
|
+
callback(self.param_result)
|
|
750
|
+
else:
|
|
751
|
+
logging.warning(
|
|
752
|
+
f"Set parameter {id} but got {self.param_result.name}"
|
|
753
|
+
)
|
|
754
|
+
callback(None)
|
|
755
|
+
else:
|
|
756
|
+
logging.warning(f"Set parameter {id} but got None")
|
|
757
|
+
callback(None)
|
|
758
|
+
finally:
|
|
759
|
+
self.is_requesting_parameters = False
|
|
467
760
|
|
|
468
761
|
def set_motor_enablement(self, enable: bool):
|
|
469
762
|
logging.info(f"Setting Motor Enablement to {enable}")
|
|
470
|
-
self.set_parameter(
|
|
471
|
-
"MOTOR_ENABLE", 1 if enable else 0, mrtmavlink.MAV_PARAM_TYPE_UINT8
|
|
472
|
-
)
|
|
763
|
+
self.set_parameter("MOTOR_ENABLE", ParamUint8(1 if enable else 0))
|
|
473
764
|
|
|
474
765
|
async def _run(self):
|
|
475
766
|
with self.is_started_cv:
|
|
@@ -478,6 +769,7 @@ class MavlinkThread:
|
|
|
478
769
|
|
|
479
770
|
self.loop = asyncio.get_running_loop()
|
|
480
771
|
self.ack_cond = asyncio.Condition()
|
|
772
|
+
self.param_cond = asyncio.Condition()
|
|
481
773
|
await self.loop.create_datagram_endpoint(lambda: self, sock=self.sock) # type: ignore
|
|
482
774
|
|
|
483
775
|
while not self.is_done:
|
|
@@ -491,11 +783,57 @@ class MavlinkThread:
|
|
|
491
783
|
def _send_system_time(self):
|
|
492
784
|
self.conn.system_time_send(int(time.time() * 1e6), 0)
|
|
493
785
|
|
|
786
|
+
def _send_param_request_list(self):
|
|
787
|
+
self.conn.param_request_list_send(
|
|
788
|
+
self.system_id, # target_system
|
|
789
|
+
mrtmavlink.MAV_COMP_ID_AUTOPILOT1, # target_component
|
|
790
|
+
)
|
|
791
|
+
|
|
792
|
+
def request_parameters(self, callback: Callable[[List[ParamValue]], None]):
|
|
793
|
+
self.loop.create_task(self._request_parameters(callback))
|
|
794
|
+
|
|
795
|
+
async def _request_parameters(self, callback: Callable[[List[ParamValue]], None]):
|
|
796
|
+
if self.system_id is None:
|
|
797
|
+
logging.warning("System ID not set, not requesting parameters")
|
|
798
|
+
return
|
|
799
|
+
|
|
800
|
+
if self.is_requesting_parameters:
|
|
801
|
+
logging.warning("Already requesting parameters")
|
|
802
|
+
return
|
|
803
|
+
|
|
804
|
+
RETRY_PERIOD_S = 0.25
|
|
805
|
+
params: List[ParamValue] = []
|
|
806
|
+
try:
|
|
807
|
+
self.is_requesting_parameters = True
|
|
808
|
+
self._send_param_request_list()
|
|
809
|
+
while True:
|
|
810
|
+
try:
|
|
811
|
+
self.param_result = None
|
|
812
|
+
async with self.param_cond:
|
|
813
|
+
await asyncio.wait_for(self.param_cond.wait(), RETRY_PERIOD_S)
|
|
814
|
+
|
|
815
|
+
if self.param_result is not None:
|
|
816
|
+
params.append(self.param_result)
|
|
817
|
+
if (
|
|
818
|
+
self.param_result.param_idx
|
|
819
|
+
== self.param_result.num_param - 1
|
|
820
|
+
):
|
|
821
|
+
break
|
|
822
|
+
except asyncio.TimeoutError:
|
|
823
|
+
logging.error("Timeout waiting for parameter")
|
|
824
|
+
break
|
|
825
|
+
|
|
826
|
+
finally:
|
|
827
|
+
self.is_requesting_parameters = False
|
|
828
|
+
self.param_result = None
|
|
829
|
+
|
|
830
|
+
callback(params)
|
|
831
|
+
|
|
494
832
|
def send_autopilot_stop(self):
|
|
495
833
|
self.loop.call_soon_threadsafe(lambda: self._send_autopilot_stop())
|
|
496
834
|
|
|
497
835
|
def _send_autopilot_stop(self):
|
|
498
|
-
if
|
|
836
|
+
if self.system_id is None:
|
|
499
837
|
logging.warning("System ID not set, not sending STOP")
|
|
500
838
|
return
|
|
501
839
|
logging.info("Sending STOP")
|
|
@@ -532,7 +870,7 @@ class MavlinkThread:
|
|
|
532
870
|
)
|
|
533
871
|
|
|
534
872
|
def _send_waypoint(self, lat_deg: float, lon_deg: float, speed_mps: float):
|
|
535
|
-
if
|
|
873
|
+
if self.system_id is None:
|
|
536
874
|
logging.warning("System ID not set, not sending waypoint")
|
|
537
875
|
return
|
|
538
876
|
logging.info(
|
|
@@ -559,7 +897,7 @@ class MavlinkThread:
|
|
|
559
897
|
)
|
|
560
898
|
|
|
561
899
|
def _send_loiter(self, speed_mps: float, radius_m: float, duration_s: float):
|
|
562
|
-
if
|
|
900
|
+
if self.system_id is None:
|
|
563
901
|
logging.warning("System ID not set, not sending loiter")
|
|
564
902
|
return
|
|
565
903
|
logging.info(
|
|
@@ -707,7 +1045,7 @@ class MavlinkThread:
|
|
|
707
1045
|
)
|
|
708
1046
|
|
|
709
1047
|
for retry_num in range(max_retries):
|
|
710
|
-
logging.debug(f"Set mission index: ({retry_num+1}/{max_retries})")
|
|
1048
|
+
logging.debug(f"Set mission index: ({retry_num + 1}/{max_retries})")
|
|
711
1049
|
|
|
712
1050
|
self.ack_result = None
|
|
713
1051
|
self.conn.send(cmd)
|
|
@@ -36,17 +36,7 @@ class TestMission(unittest.TestCase):
|
|
|
36
36
|
self.assertEqual(len(mav.rally_items), 0)
|
|
37
37
|
|
|
38
38
|
### check fence items ###
|
|
39
|
-
self.assertEqual(len(mav.fence_items),
|
|
40
|
-
|
|
41
|
-
# fence return point (not used)
|
|
42
|
-
i = mav.fence_items[0]
|
|
43
|
-
self.assertEqual(i.seq, 0)
|
|
44
|
-
self.assertEqual(i.frame, mrtmavlink.MAV_FRAME_MISSION)
|
|
45
|
-
self.assertEqual(i.command, mrtmavlink.MAV_CMD_NAV_FENCE_RETURN_POINT)
|
|
46
|
-
self.assertEqual(i.mission_type, mrtmavlink.MAV_MISSION_TYPE_FENCE)
|
|
47
|
-
self.assertEqual(i.param1, 0)
|
|
48
|
-
self.assertEqual(i.x, 0)
|
|
49
|
-
self.assertEqual(i.y, 0)
|
|
39
|
+
self.assertEqual(len(mav.fence_items), 0)
|
|
50
40
|
|
|
51
41
|
### check mission items ###
|
|
52
42
|
self.assertEqual(len(mav.mission_items), 18)
|
|
@@ -312,22 +302,12 @@ class TestMission(unittest.TestCase):
|
|
|
312
302
|
self.assertEqual(i.y, -4e7)
|
|
313
303
|
|
|
314
304
|
### check fence items ###
|
|
315
|
-
self.assertEqual(len(mav.fence_items),
|
|
305
|
+
self.assertEqual(len(mav.fence_items), 9)
|
|
316
306
|
|
|
317
|
-
#
|
|
307
|
+
# keep in circle
|
|
318
308
|
i = mav.fence_items[0]
|
|
319
309
|
self.assertEqual(i.seq, 0)
|
|
320
310
|
self.assertEqual(i.frame, mrtmavlink.MAV_FRAME_MISSION)
|
|
321
|
-
self.assertEqual(i.command, mrtmavlink.MAV_CMD_NAV_FENCE_RETURN_POINT)
|
|
322
|
-
self.assertEqual(i.mission_type, mrtmavlink.MAV_MISSION_TYPE_FENCE)
|
|
323
|
-
self.assertEqual(i.param1, 0)
|
|
324
|
-
self.assertEqual(i.x, 0)
|
|
325
|
-
self.assertEqual(i.y, 0)
|
|
326
|
-
|
|
327
|
-
# keep in circle
|
|
328
|
-
i = mav.fence_items[1]
|
|
329
|
-
self.assertEqual(i.seq, 1)
|
|
330
|
-
self.assertEqual(i.frame, mrtmavlink.MAV_FRAME_MISSION)
|
|
331
311
|
self.assertEqual(i.command, mrtmavlink.MAV_CMD_NAV_FENCE_CIRCLE_INCLUSION)
|
|
332
312
|
self.assertEqual(i.mission_type, mrtmavlink.MAV_MISSION_TYPE_FENCE)
|
|
333
313
|
self.assertEqual(i.param1, 25)
|
|
@@ -335,8 +315,8 @@ class TestMission(unittest.TestCase):
|
|
|
335
315
|
self.assertEqual(i.y, -6e7)
|
|
336
316
|
|
|
337
317
|
# keep out polygon
|
|
338
|
-
i = mav.fence_items[
|
|
339
|
-
self.assertEqual(i.seq,
|
|
318
|
+
i = mav.fence_items[1]
|
|
319
|
+
self.assertEqual(i.seq, 1)
|
|
340
320
|
self.assertEqual(i.frame, mrtmavlink.MAV_FRAME_MISSION)
|
|
341
321
|
self.assertEqual(
|
|
342
322
|
i.command, mrtmavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION
|
|
@@ -346,8 +326,8 @@ class TestMission(unittest.TestCase):
|
|
|
346
326
|
self.assertEqual(i.x, 7e7)
|
|
347
327
|
self.assertEqual(i.y, -8e7)
|
|
348
328
|
|
|
349
|
-
i = mav.fence_items[
|
|
350
|
-
self.assertEqual(i.seq,
|
|
329
|
+
i = mav.fence_items[2]
|
|
330
|
+
self.assertEqual(i.seq, 2)
|
|
351
331
|
self.assertEqual(i.frame, mrtmavlink.MAV_FRAME_MISSION)
|
|
352
332
|
self.assertEqual(
|
|
353
333
|
i.command, mrtmavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION
|
|
@@ -357,8 +337,8 @@ class TestMission(unittest.TestCase):
|
|
|
357
337
|
self.assertEqual(i.x, 9e7)
|
|
358
338
|
self.assertEqual(i.y, -10e7)
|
|
359
339
|
|
|
360
|
-
i = mav.fence_items[
|
|
361
|
-
self.assertEqual(i.seq,
|
|
340
|
+
i = mav.fence_items[3]
|
|
341
|
+
self.assertEqual(i.seq, 3)
|
|
362
342
|
self.assertEqual(i.frame, mrtmavlink.MAV_FRAME_MISSION)
|
|
363
343
|
self.assertEqual(
|
|
364
344
|
i.command, mrtmavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION
|
|
@@ -369,8 +349,8 @@ class TestMission(unittest.TestCase):
|
|
|
369
349
|
self.assertEqual(i.y, -12e7)
|
|
370
350
|
|
|
371
351
|
# keep in polygon
|
|
372
|
-
i = mav.fence_items[
|
|
373
|
-
self.assertEqual(i.seq,
|
|
352
|
+
i = mav.fence_items[4]
|
|
353
|
+
self.assertEqual(i.seq, 4)
|
|
374
354
|
self.assertEqual(i.frame, mrtmavlink.MAV_FRAME_MISSION)
|
|
375
355
|
self.assertEqual(
|
|
376
356
|
i.command, mrtmavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION
|
|
@@ -380,8 +360,8 @@ class TestMission(unittest.TestCase):
|
|
|
380
360
|
self.assertEqual(i.x, 13e7)
|
|
381
361
|
self.assertEqual(i.y, -14e7)
|
|
382
362
|
|
|
383
|
-
i = mav.fence_items[
|
|
384
|
-
self.assertEqual(i.seq,
|
|
363
|
+
i = mav.fence_items[5]
|
|
364
|
+
self.assertEqual(i.seq, 5)
|
|
385
365
|
self.assertEqual(i.frame, mrtmavlink.MAV_FRAME_MISSION)
|
|
386
366
|
self.assertEqual(
|
|
387
367
|
i.command, mrtmavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION
|
|
@@ -391,8 +371,8 @@ class TestMission(unittest.TestCase):
|
|
|
391
371
|
self.assertEqual(i.x, 15e7)
|
|
392
372
|
self.assertEqual(i.y, -16e7)
|
|
393
373
|
|
|
394
|
-
i = mav.fence_items[
|
|
395
|
-
self.assertEqual(i.seq,
|
|
374
|
+
i = mav.fence_items[6]
|
|
375
|
+
self.assertEqual(i.seq, 6)
|
|
396
376
|
self.assertEqual(i.frame, mrtmavlink.MAV_FRAME_MISSION)
|
|
397
377
|
self.assertEqual(
|
|
398
378
|
i.command, mrtmavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION
|
|
@@ -402,8 +382,8 @@ class TestMission(unittest.TestCase):
|
|
|
402
382
|
self.assertEqual(i.x, 17e7)
|
|
403
383
|
self.assertEqual(i.y, -18e7)
|
|
404
384
|
|
|
405
|
-
i = mav.fence_items[
|
|
406
|
-
self.assertEqual(i.seq,
|
|
385
|
+
i = mav.fence_items[7]
|
|
386
|
+
self.assertEqual(i.seq, 7)
|
|
407
387
|
self.assertEqual(i.frame, mrtmavlink.MAV_FRAME_MISSION)
|
|
408
388
|
self.assertEqual(
|
|
409
389
|
i.command, mrtmavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION
|
|
@@ -414,8 +394,8 @@ class TestMission(unittest.TestCase):
|
|
|
414
394
|
self.assertEqual(i.y, -20e7)
|
|
415
395
|
|
|
416
396
|
# keep out circle
|
|
417
|
-
i = mav.fence_items[
|
|
418
|
-
self.assertEqual(i.seq,
|
|
397
|
+
i = mav.fence_items[8]
|
|
398
|
+
self.assertEqual(i.seq, 8)
|
|
419
399
|
self.assertEqual(i.frame, mrtmavlink.MAV_FRAME_MISSION)
|
|
420
400
|
self.assertEqual(i.command, mrtmavlink.MAV_CMD_NAV_FENCE_CIRCLE_EXCLUSION)
|
|
421
401
|
self.assertEqual(i.mission_type, mrtmavlink.MAV_MISSION_TYPE_FENCE)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|