mrtautopilot 8__tar.gz → 10__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-8 → mrtautopilot-10}/PKG-INFO +1 -1
- {mrtautopilot-8 → mrtautopilot-10}/mrtautopilot/__init__.py +1 -1
- {mrtautopilot-8 → mrtautopilot-10}/mrtautopilot/autopilot.py +431 -47
- {mrtautopilot-8 → mrtautopilot-10}/mrtautopilot.egg-info/PKG-INFO +1 -1
- {mrtautopilot-8 → mrtautopilot-10}/README.md +0 -0
- {mrtautopilot-8 → mrtautopilot-10}/mrtautopilot/mission.py +0 -0
- {mrtautopilot-8 → mrtautopilot-10}/mrtautopilot.egg-info/SOURCES.txt +0 -0
- {mrtautopilot-8 → mrtautopilot-10}/mrtautopilot.egg-info/dependency_links.txt +0 -0
- {mrtautopilot-8 → mrtautopilot-10}/mrtautopilot.egg-info/requires.txt +0 -0
- {mrtautopilot-8 → mrtautopilot-10}/mrtautopilot.egg-info/top_level.txt +0 -0
- {mrtautopilot-8 → mrtautopilot-10}/pyproject.toml +0 -0
- {mrtautopilot-8 → mrtautopilot-10}/setup.cfg +0 -0
- {mrtautopilot-8 → mrtautopilot-10}/tests/test_mission.py +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,
|
|
@@ -278,6 +460,7 @@ class MavlinkThread:
|
|
|
278
460
|
):
|
|
279
461
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
280
462
|
self.sock.setblocking(False)
|
|
463
|
+
self.msg_callback: Callable[[mrtmavlink.MAVLink_message], None] = lambda x: None
|
|
281
464
|
|
|
282
465
|
if multicast_group:
|
|
283
466
|
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
@@ -297,9 +480,12 @@ class MavlinkThread:
|
|
|
297
480
|
self.remote_port = remote_port
|
|
298
481
|
self.remote_address_list = [remote_address]
|
|
299
482
|
if remote_address == "127.0.0.1":
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
483
|
+
try:
|
|
484
|
+
self.remote_address_list.extend(
|
|
485
|
+
socket.gethostbyname_ex(socket.gethostname())[2]
|
|
486
|
+
)
|
|
487
|
+
except socket.gaierror:
|
|
488
|
+
logging.warning("Failed to get local IP address")
|
|
303
489
|
|
|
304
490
|
self.is_started = False
|
|
305
491
|
self.is_started_cv = threading.Condition()
|
|
@@ -324,6 +510,9 @@ class MavlinkThread:
|
|
|
324
510
|
self.expected_cmd_uuid = 0
|
|
325
511
|
self.ack_result: Union[int, None] = None
|
|
326
512
|
|
|
513
|
+
self.is_requesting_parameters = False
|
|
514
|
+
self.param_value: Union[ParamValue, None] = None
|
|
515
|
+
|
|
327
516
|
def write(self, data: bytes):
|
|
328
517
|
self.sock.sendto(data, (self.remote_address, self.remote_port))
|
|
329
518
|
|
|
@@ -363,15 +552,25 @@ class MavlinkThread:
|
|
|
363
552
|
for msg in messages:
|
|
364
553
|
self._msg_callback(msg)
|
|
365
554
|
|
|
555
|
+
async def _notify_param_result(self, result: ParamValue):
|
|
556
|
+
async with self.param_cond:
|
|
557
|
+
self.param_result = result
|
|
558
|
+
self.param_cond.notify()
|
|
559
|
+
|
|
366
560
|
async def _notify_ack_result(self, result: int):
|
|
367
561
|
async with self.ack_cond:
|
|
368
562
|
self.ack_result = result
|
|
369
563
|
self.ack_cond.notify()
|
|
370
564
|
|
|
371
|
-
def
|
|
372
|
-
|
|
565
|
+
def register_message_callback(
|
|
566
|
+
self, callback: Callable[[mrtmavlink.MAVLink_message], None]
|
|
567
|
+
):
|
|
568
|
+
self.msg_callback = callback
|
|
373
569
|
|
|
570
|
+
def _msg_callback(self, msg: mrtmavlink.MAVLink_message):
|
|
571
|
+
self.msg_callback(msg)
|
|
374
572
|
sys_id = msg.get_srcSystem()
|
|
573
|
+
logging.debug(f"Received: {msg.msgname}, sys_id={sys_id}, {msg}")
|
|
375
574
|
if self.system_id != sys_id:
|
|
376
575
|
self.system_id = msg.get_srcSystem()
|
|
377
576
|
logging.info(f"Setting System ID to {sys_id}")
|
|
@@ -411,6 +610,10 @@ class MavlinkThread:
|
|
|
411
610
|
):
|
|
412
611
|
logging.debug(f"Received Command Ack: {msg}")
|
|
413
612
|
self.loop.create_task(self._notify_ack_result(msg.result))
|
|
613
|
+
elif type(msg) is mrtmavlink.MAVLink_param_value_message:
|
|
614
|
+
param = ParamValue.from_mavlink(msg)
|
|
615
|
+
logging.debug(f"Received Param Value: {param}")
|
|
616
|
+
self.loop.create_task(self._notify_param_result(param))
|
|
414
617
|
|
|
415
618
|
def send_heartbeat(self):
|
|
416
619
|
self.loop.call_soon_threadsafe(lambda: self._send_heartbeat())
|
|
@@ -421,55 +624,150 @@ class MavlinkThread:
|
|
|
421
624
|
mrtmavlink.MAV_TYPE_GCS, mrtmavlink.MAV_AUTOPILOT_INVALID, 0, 0, 0
|
|
422
625
|
)
|
|
423
626
|
|
|
627
|
+
def get_parameter(
|
|
628
|
+
self,
|
|
629
|
+
id: str,
|
|
630
|
+
callback: Callable[[Union[ParamValue, None]], None],
|
|
631
|
+
):
|
|
632
|
+
self.loop.create_task(self._get_parameter(id, callback))
|
|
633
|
+
|
|
634
|
+
async def _get_parameter(
|
|
635
|
+
self,
|
|
636
|
+
id: str,
|
|
637
|
+
callback: Callable[[Union[ParamValue, None]], None],
|
|
638
|
+
):
|
|
639
|
+
assert len(id) <= 16
|
|
640
|
+
if self.system_id is None:
|
|
641
|
+
logging.info("Failed to get parameter, system_id not set")
|
|
642
|
+
return
|
|
643
|
+
|
|
644
|
+
if self.is_requesting_parameters:
|
|
645
|
+
logging.warning("Already requesting parameters")
|
|
646
|
+
callback(None)
|
|
647
|
+
return
|
|
648
|
+
|
|
649
|
+
RETRY_PERIOD_S = 0.25
|
|
650
|
+
try:
|
|
651
|
+
self.is_requesting_parameters = True
|
|
652
|
+
|
|
653
|
+
logging.info(f"Getting Param {id}")
|
|
654
|
+
|
|
655
|
+
self.param_result = None
|
|
656
|
+
self.conn.param_request_read_send(
|
|
657
|
+
self.system_id,
|
|
658
|
+
mrtmavlink.MAV_COMP_ID_AUTOPILOT1,
|
|
659
|
+
id.encode("utf-8"),
|
|
660
|
+
-1,
|
|
661
|
+
)
|
|
662
|
+
try:
|
|
663
|
+
async with self.param_cond:
|
|
664
|
+
await asyncio.wait_for(self.param_cond.wait(), RETRY_PERIOD_S)
|
|
665
|
+
except asyncio.TimeoutError:
|
|
666
|
+
logging.error("Timeout waiting for parameter ack")
|
|
667
|
+
callback(None)
|
|
668
|
+
return
|
|
669
|
+
|
|
670
|
+
if self.param_result is not None:
|
|
671
|
+
if self.param_result.name == id:
|
|
672
|
+
callback(self.param_result)
|
|
673
|
+
else:
|
|
674
|
+
logging.warning(
|
|
675
|
+
f"Set parameter {id} but got {self.param_result.name}"
|
|
676
|
+
)
|
|
677
|
+
callback(None)
|
|
678
|
+
else:
|
|
679
|
+
logging.warning(f"Set parameter {id} but got None")
|
|
680
|
+
callback(None)
|
|
681
|
+
finally:
|
|
682
|
+
self.is_requesting_parameters = False
|
|
683
|
+
|
|
424
684
|
def set_parameter(
|
|
425
685
|
self,
|
|
426
686
|
id: str,
|
|
427
|
-
value:
|
|
428
|
-
|
|
429
|
-
component: int = mrtmavlink.MAV_COMP_ID_AUTOPILOT1,
|
|
687
|
+
value: ParamValueType,
|
|
688
|
+
callback: Callable[[Union[ParamValue, None]], None] = lambda x: None,
|
|
430
689
|
):
|
|
431
|
-
self.loop.
|
|
432
|
-
lambda: self._set_parameter(id, value, typ, component)
|
|
433
|
-
)
|
|
690
|
+
self.loop.create_task(self._set_parameter(id, value, callback))
|
|
434
691
|
|
|
435
|
-
def _set_parameter(
|
|
692
|
+
async def _set_parameter(
|
|
693
|
+
self,
|
|
694
|
+
id: str,
|
|
695
|
+
value: ParamValueType,
|
|
696
|
+
callback: Callable[[Union[ParamValue, None]], None],
|
|
697
|
+
):
|
|
436
698
|
assert len(id) <= 16
|
|
437
|
-
if
|
|
699
|
+
if self.system_id is None:
|
|
438
700
|
logging.info("Failed to set parameter, system_id not set")
|
|
439
701
|
return
|
|
440
702
|
|
|
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
|
-
|
|
703
|
+
if self.is_requesting_parameters:
|
|
704
|
+
logging.warning("Already requesting parameters")
|
|
705
|
+
callback(None)
|
|
706
|
+
return
|
|
707
|
+
|
|
708
|
+
RETRY_PERIOD_S = 0.25
|
|
709
|
+
try:
|
|
710
|
+
self.is_requesting_parameters = True
|
|
711
|
+
|
|
712
|
+
logging.info(f"Setting Param {id} to {value}")
|
|
713
|
+
|
|
714
|
+
if isinstance(value, ParamUint8):
|
|
715
|
+
val_bytes = struct.pack("BBBB", int(value.value), 0, 0, 0)
|
|
716
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_UINT8
|
|
717
|
+
elif isinstance(value, ParamInt8):
|
|
718
|
+
val_bytes = struct.pack("bBBB", int(value.value), 0, 0, 0)
|
|
719
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_INT8
|
|
720
|
+
elif isinstance(value, ParamUint16):
|
|
721
|
+
val_bytes = struct.pack("<HBB", int(value.value), 0, 0)
|
|
722
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_UINT16
|
|
723
|
+
elif isinstance(value, ParamInt16):
|
|
724
|
+
val_bytes = struct.pack("<hBB", int(value.value), 0, 0)
|
|
725
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_INT16
|
|
726
|
+
elif isinstance(value, ParamUint32):
|
|
727
|
+
val_bytes = struct.pack("<I", int(value.value))
|
|
728
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_UINT32
|
|
729
|
+
elif isinstance(value, ParamInt32):
|
|
730
|
+
val_bytes = struct.pack("<i", int(value.value))
|
|
731
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_INT32
|
|
732
|
+
elif isinstance(value, ParamReal32):
|
|
733
|
+
val_bytes = struct.pack("<f", value.value)
|
|
734
|
+
typ = mrtmavlink.MAV_PARAM_TYPE_REAL32
|
|
735
|
+
else:
|
|
736
|
+
assert False, "unsupported type"
|
|
737
|
+
|
|
738
|
+
self.param_result = None
|
|
739
|
+
self.conn.param_set_send(
|
|
740
|
+
self.system_id,
|
|
741
|
+
mrtmavlink.MAV_COMP_ID_AUTOPILOT1,
|
|
742
|
+
id.encode("utf-8"),
|
|
743
|
+
struct.unpack("f", val_bytes)[0],
|
|
744
|
+
typ,
|
|
745
|
+
)
|
|
746
|
+
try:
|
|
747
|
+
async with self.param_cond:
|
|
748
|
+
await asyncio.wait_for(self.param_cond.wait(), RETRY_PERIOD_S)
|
|
749
|
+
except asyncio.TimeoutError:
|
|
750
|
+
logging.error("Timeout waiting for parameter ack")
|
|
751
|
+
callback(None)
|
|
752
|
+
return
|
|
753
|
+
|
|
754
|
+
if self.param_result is not None:
|
|
755
|
+
if self.param_result.name == id:
|
|
756
|
+
callback(self.param_result)
|
|
757
|
+
else:
|
|
758
|
+
logging.warning(
|
|
759
|
+
f"Set parameter {id} but got {self.param_result.name}"
|
|
760
|
+
)
|
|
761
|
+
callback(None)
|
|
762
|
+
else:
|
|
763
|
+
logging.warning(f"Set parameter {id} but got None")
|
|
764
|
+
callback(None)
|
|
765
|
+
finally:
|
|
766
|
+
self.is_requesting_parameters = False
|
|
467
767
|
|
|
468
768
|
def set_motor_enablement(self, enable: bool):
|
|
469
769
|
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
|
-
)
|
|
770
|
+
self.set_parameter("MOTOR_ENABLE", ParamUint8(1 if enable else 0))
|
|
473
771
|
|
|
474
772
|
async def _run(self):
|
|
475
773
|
with self.is_started_cv:
|
|
@@ -478,6 +776,7 @@ class MavlinkThread:
|
|
|
478
776
|
|
|
479
777
|
self.loop = asyncio.get_running_loop()
|
|
480
778
|
self.ack_cond = asyncio.Condition()
|
|
779
|
+
self.param_cond = asyncio.Condition()
|
|
481
780
|
await self.loop.create_datagram_endpoint(lambda: self, sock=self.sock) # type: ignore
|
|
482
781
|
|
|
483
782
|
while not self.is_done:
|
|
@@ -491,11 +790,57 @@ class MavlinkThread:
|
|
|
491
790
|
def _send_system_time(self):
|
|
492
791
|
self.conn.system_time_send(int(time.time() * 1e6), 0)
|
|
493
792
|
|
|
793
|
+
def _send_param_request_list(self):
|
|
794
|
+
self.conn.param_request_list_send(
|
|
795
|
+
self.system_id, # target_system
|
|
796
|
+
mrtmavlink.MAV_COMP_ID_AUTOPILOT1, # target_component
|
|
797
|
+
)
|
|
798
|
+
|
|
799
|
+
def request_parameters(self, callback: Callable[[List[ParamValue]], None]):
|
|
800
|
+
self.loop.create_task(self._request_parameters(callback))
|
|
801
|
+
|
|
802
|
+
async def _request_parameters(self, callback: Callable[[List[ParamValue]], None]):
|
|
803
|
+
if self.system_id is None:
|
|
804
|
+
logging.warning("System ID not set, not requesting parameters")
|
|
805
|
+
return
|
|
806
|
+
|
|
807
|
+
if self.is_requesting_parameters:
|
|
808
|
+
logging.warning("Already requesting parameters")
|
|
809
|
+
return
|
|
810
|
+
|
|
811
|
+
RETRY_PERIOD_S = 0.25
|
|
812
|
+
params: List[ParamValue] = []
|
|
813
|
+
try:
|
|
814
|
+
self.is_requesting_parameters = True
|
|
815
|
+
self._send_param_request_list()
|
|
816
|
+
while True:
|
|
817
|
+
try:
|
|
818
|
+
self.param_result = None
|
|
819
|
+
async with self.param_cond:
|
|
820
|
+
await asyncio.wait_for(self.param_cond.wait(), RETRY_PERIOD_S)
|
|
821
|
+
|
|
822
|
+
if self.param_result is not None:
|
|
823
|
+
params.append(self.param_result)
|
|
824
|
+
if (
|
|
825
|
+
self.param_result.param_idx
|
|
826
|
+
== self.param_result.num_param - 1
|
|
827
|
+
):
|
|
828
|
+
break
|
|
829
|
+
except asyncio.TimeoutError:
|
|
830
|
+
logging.error("Timeout waiting for parameter")
|
|
831
|
+
break
|
|
832
|
+
|
|
833
|
+
finally:
|
|
834
|
+
self.is_requesting_parameters = False
|
|
835
|
+
self.param_result = None
|
|
836
|
+
|
|
837
|
+
callback(params)
|
|
838
|
+
|
|
494
839
|
def send_autopilot_stop(self):
|
|
495
840
|
self.loop.call_soon_threadsafe(lambda: self._send_autopilot_stop())
|
|
496
841
|
|
|
497
842
|
def _send_autopilot_stop(self):
|
|
498
|
-
if
|
|
843
|
+
if self.system_id is None:
|
|
499
844
|
logging.warning("System ID not set, not sending STOP")
|
|
500
845
|
return
|
|
501
846
|
logging.info("Sending STOP")
|
|
@@ -532,7 +877,7 @@ class MavlinkThread:
|
|
|
532
877
|
)
|
|
533
878
|
|
|
534
879
|
def _send_waypoint(self, lat_deg: float, lon_deg: float, speed_mps: float):
|
|
535
|
-
if
|
|
880
|
+
if self.system_id is None:
|
|
536
881
|
logging.warning("System ID not set, not sending waypoint")
|
|
537
882
|
return
|
|
538
883
|
logging.info(
|
|
@@ -559,7 +904,7 @@ class MavlinkThread:
|
|
|
559
904
|
)
|
|
560
905
|
|
|
561
906
|
def _send_loiter(self, speed_mps: float, radius_m: float, duration_s: float):
|
|
562
|
-
if
|
|
907
|
+
if self.system_id is None:
|
|
563
908
|
logging.warning("System ID not set, not sending loiter")
|
|
564
909
|
return
|
|
565
910
|
logging.info(
|
|
@@ -707,7 +1052,7 @@ class MavlinkThread:
|
|
|
707
1052
|
)
|
|
708
1053
|
|
|
709
1054
|
for retry_num in range(max_retries):
|
|
710
|
-
logging.debug(f"Set mission index: ({retry_num+1}/{max_retries})")
|
|
1055
|
+
logging.debug(f"Set mission index: ({retry_num + 1}/{max_retries})")
|
|
711
1056
|
|
|
712
1057
|
self.ack_result = None
|
|
713
1058
|
self.conn.send(cmd)
|
|
@@ -732,3 +1077,42 @@ class MavlinkThread:
|
|
|
732
1077
|
|
|
733
1078
|
finally:
|
|
734
1079
|
self.is_sending_mission = False
|
|
1080
|
+
|
|
1081
|
+
def set_attitude(
|
|
1082
|
+
self,
|
|
1083
|
+
roll_rad: float = 0,
|
|
1084
|
+
pitch_rad: float = 0,
|
|
1085
|
+
yaw_rad: float = 0,
|
|
1086
|
+
roll_rate_rps: float = 0,
|
|
1087
|
+
pitch_rate_rps: float = 0,
|
|
1088
|
+
yaw_rate_rps: float = 0,
|
|
1089
|
+
):
|
|
1090
|
+
self.loop.call_soon_threadsafe(
|
|
1091
|
+
lambda: self._set_attitude(
|
|
1092
|
+
roll_rad,
|
|
1093
|
+
pitch_rad,
|
|
1094
|
+
yaw_rad,
|
|
1095
|
+
roll_rate_rps,
|
|
1096
|
+
pitch_rate_rps,
|
|
1097
|
+
yaw_rate_rps,
|
|
1098
|
+
)
|
|
1099
|
+
)
|
|
1100
|
+
|
|
1101
|
+
def _set_attitude(
|
|
1102
|
+
self,
|
|
1103
|
+
roll_rad: float,
|
|
1104
|
+
pitch_rad: float,
|
|
1105
|
+
yaw_rad: float,
|
|
1106
|
+
roll_rate_rps: float,
|
|
1107
|
+
pitch_rate_rps: float,
|
|
1108
|
+
yaw_rate_rps: float,
|
|
1109
|
+
):
|
|
1110
|
+
self.conn.attitude_send(
|
|
1111
|
+
0,
|
|
1112
|
+
roll_rad,
|
|
1113
|
+
pitch_rad,
|
|
1114
|
+
yaw_rad,
|
|
1115
|
+
roll_rate_rps,
|
|
1116
|
+
pitch_rate_rps,
|
|
1117
|
+
yaw_rate_rps,
|
|
1118
|
+
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|