libs/kaptan-mavlink: add distance sensor telemetry
This commit is contained in:
1 parent
cb447bc057
commit
f22b45c70a
2 files changed
+97
-7
No files matched your search
@@ -1,6 +1,7 @@
|
|||||||
//! MAVLink frame encoding API.
|
//! MAVLink frame encoding API.
|
||||||
|
|
||||||
use kaptan_sensor::ImuSnapshot;
|
use kaptan_sensor::imu::ImuSnapshot;
|
||||||
|
use kaptan_sensor::range::RangeSnapshot;
|
||||||
use mavlink::MessageData;
|
use mavlink::MessageData;
|
||||||
|
|
||||||
use crate::{MavlinkFrame, message};
|
use crate::{MavlinkFrame, message};
|
||||||
@@ -81,13 +82,44 @@ impl MavlinkEncoder {
|
|||||||
|
|
||||||
self.serialize(&raw_imu)
|
self.serialize(&raw_imu)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Encodes a standard `DISTANCE_SENSOR` frame for a laser rangefinder.
|
||||||
|
///
|
||||||
|
/// MAVLink represents distance in centimetres; the sensor domain keeps
|
||||||
|
/// millimetres so this conversion happens only at the protocol boundary.
|
||||||
|
pub fn distance_sensor_snapshot(
|
||||||
|
&mut self,
|
||||||
|
snapshot: &RangeSnapshot,
|
||||||
|
sensor_id: u8,
|
||||||
|
orientation: message::MavSensorOrientation,
|
||||||
|
minimum_distance_centimetres: u16,
|
||||||
|
maximum_distance_centimetres: u16,
|
||||||
|
) -> MavlinkFrame {
|
||||||
|
let current_distance = (snapshot.distance_millimetres / 10).clamp(
|
||||||
|
u32::from(minimum_distance_centimetres),
|
||||||
|
u32::from(maximum_distance_centimetres),
|
||||||
|
) as u16;
|
||||||
|
let distance_sensor = message::DISTANCE_SENSOR_DATA {
|
||||||
|
time_boot_ms: (snapshot.timestamp.as_microseconds() / 1_000) as u32,
|
||||||
|
min_distance: minimum_distance_centimetres,
|
||||||
|
max_distance: maximum_distance_centimetres,
|
||||||
|
current_distance,
|
||||||
|
mavtype: message::MavDistanceSensor::MAV_DISTANCE_SENSOR_LASER,
|
||||||
|
id: sensor_id,
|
||||||
|
orientation,
|
||||||
|
covariance: u8::MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.serialize(&distance_sensor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::MavlinkEncoder;
|
use super::MavlinkEncoder;
|
||||||
use crate::message::MavState;
|
use crate::message::MavState;
|
||||||
use kaptan_sensor::ImuSnapshot;
|
use kaptan_sensor::imu::ImuSnapshot;
|
||||||
|
use kaptan_sensor::range::RangeSnapshot;
|
||||||
use kaptan_time::Timestamp;
|
use kaptan_time::Timestamp;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -135,4 +167,24 @@ mod tests {
|
|||||||
|
|
||||||
assert_ne!(frame.raw_bytes()[16] & 0x80, 0);
|
assert_ne!(frame.raw_bytes()[16] & 0x80, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn range_snapshot_uses_distance_sensor_centimetres() {
|
||||||
|
let mut encoder = MavlinkEncoder::new(1, 1);
|
||||||
|
let snapshot = RangeSnapshot::new(Timestamp::from_microseconds(123_000), 2_910);
|
||||||
|
|
||||||
|
let frame = encoder.distance_sensor_snapshot(
|
||||||
|
&snapshot,
|
||||||
|
0,
|
||||||
|
crate::message::MavSensorOrientation::MAV_SENSOR_ROTATION_PITCH_270,
|
||||||
|
20,
|
||||||
|
4_000,
|
||||||
|
);
|
||||||
|
let bytes = frame.raw_bytes();
|
||||||
|
|
||||||
|
assert_eq!(&bytes[7..10], &[132, 0, 0]);
|
||||||
|
// MAVLink payload starts after the ten-byte MAVLink 2 header. The
|
||||||
|
// current distance field follows time, minimum, and maximum range.
|
||||||
|
assert_eq!(&bytes[18..20], &291u16.to_le_bytes());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@ use kaptan_tx::{PendingFrame, TransmitQueue};
|
|||||||
use crate::MavlinkFrame;
|
use crate::MavlinkFrame;
|
||||||
|
|
||||||
/// Delivery importance used for bounded MAVLink transmission admission.
|
/// Delivery importance used for bounded MAVLink transmission admission.
|
||||||
pub use kaptan_tx::FrameClass;
|
pub use kaptan_tx::{EnqueueResult, FrameClass};
|
||||||
|
|
||||||
/// Failure while preparing or starting a MAVLink frame transfer.
|
/// Failure while preparing or starting a MAVLink frame transfer.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -45,13 +45,17 @@ where
|
|||||||
Engine: DmaTxEngine,
|
Engine: DmaTxEngine,
|
||||||
{
|
{
|
||||||
/// Admits an already-serialized MAVLink frame for UART transmission.
|
/// Admits an already-serialized MAVLink frame for UART transmission.
|
||||||
|
///
|
||||||
|
/// A full queue is a normal bounded-admission outcome, returned as
|
||||||
|
/// [`EnqueueResult`]. DMA preparation and transfer-start failures remain
|
||||||
|
/// [`MavlinkTransmitFault`] errors.
|
||||||
pub fn send_frame(
|
pub fn send_frame(
|
||||||
&mut self,
|
&mut self,
|
||||||
class: FrameClass,
|
class: FrameClass,
|
||||||
frame: MavlinkFrame,
|
frame: MavlinkFrame,
|
||||||
) -> Result<(), MavlinkTransmitFault<Memory::Error, Engine::StartError>> {
|
) -> Result<EnqueueResult, MavlinkTransmitFault<Memory::Error, Engine::StartError>> {
|
||||||
let _ = self.transmit.enqueue(PendingFrame { class, frame });
|
let admission = self.transmit.enqueue(PendingFrame { class, frame });
|
||||||
self.start_next()
|
self.start_next().map(|()| admission)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Releases a terminal DMA frame and opportunistically starts the next.
|
/// Releases a terminal DMA frame and opportunistically starts the next.
|
||||||
@@ -85,7 +89,7 @@ where
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{FrameClass, MavlinkTransmitter};
|
use super::{EnqueueResult, FrameClass, MavlinkTransmitter};
|
||||||
use crate::{encoder::MavlinkEncoder, message::MavState};
|
use crate::{encoder::MavlinkEncoder, message::MavState};
|
||||||
use kaptan_dma::{DmaReadableBuffer, DmaTxBufferFactory, DmaTxEngine, TxCompletion};
|
use kaptan_dma::{DmaReadableBuffer, DmaTxBufferFactory, DmaTxEngine, TxCompletion};
|
||||||
|
|
||||||
@@ -131,4 +135,38 @@ mod tests {
|
|||||||
transmitter.on_dma_complete(TxCompletion::TransferFault);
|
transmitter.on_dma_complete(TxCompletion::TransferFault);
|
||||||
assert!(!transmitter.transmit.is_active());
|
assert!(!transmitter.transmit.is_active());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn reports_critical_queue_saturation_to_the_policy_owner() {
|
||||||
|
let mut encoder = MavlinkEncoder::new(1, 1);
|
||||||
|
let mut transmitter = MavlinkTransmitter::<Memory, Engine, 1>::new(Memory, Engine);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
transmitter
|
||||||
|
.send_frame(
|
||||||
|
FrameClass::Critical,
|
||||||
|
encoder.heartbeat(MavState::MAV_STATE_STANDBY, false),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
EnqueueResult::Enqueued
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
transmitter
|
||||||
|
.send_frame(
|
||||||
|
FrameClass::Critical,
|
||||||
|
encoder.heartbeat(MavState::MAV_STATE_STANDBY, false),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
EnqueueResult::Enqueued
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
transmitter
|
||||||
|
.send_frame(
|
||||||
|
FrameClass::Critical,
|
||||||
|
encoder.heartbeat(MavState::MAV_STATE_STANDBY, false),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
EnqueueResult::CriticalQueueFull
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user