@@ -1417,6 +1417,130 @@ def to_numpy(cls, messages: Sequence['RawGNSSAttitudeOutput']):
14171417 result .update (MeasurementDetails .to_numpy ([m .details for m in messages ]))
14181418 return result
14191419
1420+ ################################################################################
1421+ # External Pose Measurements
1422+ ################################################################################
1423+
1424+
1425+ class ExternalPoseInput (MessagePayload ):
1426+ """! @brief External pose measurement input.
1427+
1428+ Position is expressed in the ECEF frame. Orientation is the yaw, pitch, roll
1429+ (YPR) angles in the local ENU frame. Velocity is expressed in the local ENU
1430+ frame. Any elements that are not available should be set to `nan`. Standard
1431+ deviation fields are specified in the same units.
1432+ """
1433+ MESSAGE_TYPE = MessageType .EXTERNAL_POSE_INPUT
1434+ MESSAGE_VERSION = 0
1435+
1436+ FLAG_RESET_POSITION_DATA = 0x1
1437+
1438+ _STRUCT = struct .Struct ('<B3xI3d3f3f3f3f3f' )
1439+
1440+ def __init__ (self ):
1441+ self .details = MeasurementDetails ()
1442+
1443+ self .solution_type = SolutionType .Invalid
1444+
1445+ self .flags = 0
1446+
1447+ self .position_ecef_m = np .full ((3 ,), np .nan )
1448+ self .position_std_ecef_m = np .full ((3 ,), np .nan )
1449+
1450+ self .ypr_deg = np .full ((3 ,), np .nan )
1451+ self .ypr_std_deg = np .full ((3 ,), np .nan )
1452+
1453+ self .velocity_enu_mps = np .full ((3 ,), np .nan )
1454+ self .velocity_std_enu_mps = np .full ((3 ,), np .nan )
1455+
1456+ def pack (self , buffer : bytes = None , offset : int = 0 ,
1457+ return_buffer : bool = True ) -> (bytes , int ):
1458+ if buffer is None :
1459+ buffer = bytearray (self .calcsize ())
1460+ offset = 0
1461+
1462+ initial_offset = offset
1463+
1464+ offset += self .details .pack (buffer , offset , return_buffer = False )
1465+
1466+ offset += self .pack_values (
1467+ self ._STRUCT , buffer , offset ,
1468+ int (self .solution_type ),
1469+ self .flags ,
1470+ self .position_ecef_m [0 ], self .position_ecef_m [1 ], self .position_ecef_m [2 ],
1471+ self .position_std_ecef_m [0 ], self .position_std_ecef_m [1 ], self .position_std_ecef_m [2 ],
1472+ self .ypr_deg [0 ], self .ypr_deg [1 ], self .ypr_deg [2 ],
1473+ self .ypr_std_deg [0 ], self .ypr_std_deg [1 ], self .ypr_std_deg [2 ],
1474+ self .velocity_enu_mps [0 ], self .velocity_enu_mps [1 ], self .velocity_enu_mps [2 ],
1475+ self .velocity_std_enu_mps [0 ], self .velocity_std_enu_mps [1 ], self .velocity_std_enu_mps [2 ])
1476+ if return_buffer :
1477+ return buffer
1478+ else :
1479+ return offset - initial_offset
1480+
1481+ def unpack (self , buffer : bytes , offset : int = 0 ,
1482+ message_version : int = MessagePayload ._UNSPECIFIED_VERSION ) -> int :
1483+ initial_offset = offset
1484+
1485+ offset += self .details .unpack (buffer , offset )
1486+
1487+ (solution_type_int ,
1488+ self .flags ,
1489+ self .position_ecef_m [0 ], self .position_ecef_m [1 ], self .position_ecef_m [2 ],
1490+ self .position_std_ecef_m [0 ], self .position_std_ecef_m [1 ], self .position_std_ecef_m [2 ],
1491+ self .ypr_deg [0 ], self .ypr_deg [1 ], self .ypr_deg [2 ],
1492+ self .ypr_std_deg [0 ], self .ypr_std_deg [1 ], self .ypr_std_deg [2 ],
1493+ self .velocity_enu_mps [0 ], self .velocity_enu_mps [1 ], self .velocity_enu_mps [2 ],
1494+ self .velocity_std_enu_mps [0 ], self .velocity_std_enu_mps [1 ], self .velocity_std_enu_mps [2 ]) = \
1495+ self ._STRUCT .unpack_from (buffer , offset )
1496+ offset += self ._STRUCT .size
1497+
1498+ self .solution_type = SolutionType (solution_type_int )
1499+
1500+ return offset - initial_offset
1501+
1502+ @classmethod
1503+ def calcsize (cls ) -> int :
1504+ return MeasurementDetails .calcsize () + cls ._STRUCT .size
1505+
1506+ @classmethod
1507+ def to_numpy (cls , messages : Sequence ['ExternalPoseInput' ]):
1508+ result = {
1509+ 'solution_type' : np .array ([int (m .solution_type ) for m in messages ], dtype = int ),
1510+ 'flags' : np .array ([m .flags for m in messages ], dtype = np .uint32 ),
1511+ 'position_ecef_m' : np .array ([m .position_ecef_m for m in messages ]).T ,
1512+ 'position_std_ecef_m' : np .array ([m .position_std_ecef_m for m in messages ]).T ,
1513+ 'ypr_deg' : np .array ([m .ypr_deg for m in messages ]).T ,
1514+ 'ypr_std_deg' : np .array ([m .ypr_std_deg for m in messages ]).T ,
1515+ 'velocity_enu_mps' : np .array ([m .velocity_enu_mps for m in messages ]).T ,
1516+ 'velocity_std_enu_mps' : np .array ([m .velocity_std_enu_mps for m in messages ]).T ,
1517+ }
1518+ result .update (MeasurementDetails .to_numpy ([m .details for m in messages ]))
1519+ return result
1520+
1521+ def __getattr__ (self , item ):
1522+ if item == 'p1_time' :
1523+ return self .details .p1_time
1524+ else :
1525+ return super ().__getattr__ (item )
1526+
1527+ def __repr__ (self ):
1528+ result = super ().__repr__ ()[:- 1 ]
1529+ result += f', solution_type={ self .solution_type } , position_ecef={ self .position_ecef_m } , ' \
1530+ f'ypr_deg={ self .ypr_deg } , velocity_enu_mps={ self .velocity_enu_mps } ]'
1531+ return result
1532+
1533+ def __str__ (self ):
1534+ string = 'External Pose Measurement @ %s\n ' % str (self .details .p1_time )
1535+ string += ' Solution type: %s\n ' % self .solution_type .name
1536+ string += ' Position (ECEF): %.2f, %.2f, %.2f (m, m, m)\n ' % tuple (self .position_ecef_m )
1537+ string += ' Position std (ECEF): %.2f, %.2f, %.2f (m, m, m)\n ' % tuple (self .position_std_ecef_m )
1538+ string += ' YPR: %.2f, %.2f, %.2f (deg, deg, deg)\n ' % tuple (self .ypr_deg )
1539+ string += ' YPR std: %.2f, %.2f, %.2f (deg, deg, deg)\n ' % tuple (self .ypr_std_deg )
1540+ string += ' Velocity (ENU): %.2f, %.2f, %.2f (m/s, m/s, m/s)\n ' % tuple (self .velocity_enu_mps )
1541+ string += ' Velocity std (ENU): %.2f, %.2f, %.2f (m/s, m/s, m/s)' % tuple (self .velocity_std_enu_mps )
1542+ return string
1543+
14201544################################################################################
14211545# Binary Sensor Data Definitions
14221546################################################################################
0 commit comments