board: make telemetry profile selection explicit
This commit is contained in:
1 parent
c44286bdcf
commit
01463fa878
5 files changed
+158
-96
No files matched your search
@@ -1,9 +1,11 @@
|
|||||||
//! Declarative support for the GEPRC TAKER F722 BLS 60A V2 stack.
|
//! Declarative support for the GEPRC TAKER F722 BLS 60A V2 stack.
|
||||||
|
|
||||||
use kaptan_board::{BoardConfig, DataChannelRates, MavlinkEndpoint, VerticalSensingKind};
|
use kaptan_board::{
|
||||||
|
BoardConfig, BoardProfile, DataChannelRates, MavlinkEndpoint, TelemetryProfile,
|
||||||
|
VerticalSensingKind,
|
||||||
|
};
|
||||||
use platform_stm32f7::{
|
use platform_stm32f7::{
|
||||||
BoardError, F7Board, F7BoardBuilder, F722BoardRoutes, Icm42688, Mavlink, MotorOutputs, Pc3,
|
BoardError, F7Board, F7BoardBuilder, F722BoardRoutes, Icm42688, Mavlink, Pc3, VerticalSensor,
|
||||||
VerticalSensor,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// ICM-42688-P-based GEP-F722-HD V2 paired with the 60 A stack.
|
/// ICM-42688-P-based GEP-F722-HD V2 paired with the 60 A stack.
|
||||||
@@ -16,20 +18,21 @@ impl F7Board for GeprcF722V2 {
|
|||||||
system_id: 1,
|
system_id: 1,
|
||||||
component_id: 1,
|
component_id: 1,
|
||||||
},
|
},
|
||||||
vertical_sensing: VerticalSensingKind::None,
|
profile: BoardProfile::TelemetryOnly(TelemetryProfile {
|
||||||
data_channel: DataChannelRates {
|
vertical_sensing: VerticalSensingKind::None,
|
||||||
service_hz: 100,
|
data_channel: DataChannelRates {
|
||||||
raw_imu_hz: 20,
|
service_hz: 100,
|
||||||
range_hz: None,
|
raw_imu_hz: 20,
|
||||||
optical_flow_hz: None,
|
range_hz: None,
|
||||||
heartbeat_hz: 2,
|
optical_flow_hz: None,
|
||||||
},
|
heartbeat_hz: 2,
|
||||||
|
},
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
fn build(platform: F7BoardBuilder) -> Result<F722BoardRoutes, BoardError> {
|
fn build(platform: F7BoardBuilder) -> Result<F722BoardRoutes, BoardError> {
|
||||||
platform
|
platform
|
||||||
.imu(Icm42688::on_spi3().with_drdy(Pc3))
|
.imu(Icm42688::on_spi3().with_drdy(Pc3))
|
||||||
.motors(MotorOutputs::geprc_tim3_tim5().dshot600())
|
|
||||||
.mavlink(Mavlink::on_usart2())
|
.mavlink(Mavlink::on_usart2())
|
||||||
.vertical_sensor(VerticalSensor::none())
|
.vertical_sensor(VerticalSensor::none())
|
||||||
.build()
|
.build()
|
||||||
|
|||||||
@@ -4,61 +4,43 @@
|
|||||||
//! code, interrupt names, DMA handling, or task scheduling. Those concerns
|
//! code, interrupt names, DMA handling, or task scheduling. Those concerns
|
||||||
//! belong to the STM32F7 platform crate.
|
//! belong to the STM32F7 platform crate.
|
||||||
|
|
||||||
use kaptan_board::{BoardConfig, DataChannelRates, MavlinkEndpoint, VerticalSensingKind};
|
use kaptan_board::{
|
||||||
|
BoardConfig, BoardProfile, DataChannelRates, MavlinkEndpoint, TelemetryProfile,
|
||||||
|
VerticalSensingKind,
|
||||||
|
};
|
||||||
use platform_stm32f7::{
|
use platform_stm32f7::{
|
||||||
BoardError, F7Board, F7BoardBuilder, F722BoardRoutes, Mavlink, MotorOutputs, Mpu6000, Pa4,
|
BoardError, F7Board, F7BoardBuilder, F722BoardRoutes, Mavlink, Mpu6000, Pa4, VerticalSensor,
|
||||||
VerticalSensor,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Holybro Kakute F7 Mini V3.
|
/// Holybro Kakute F7 Mini V3.
|
||||||
pub struct KakuteF7MiniV3;
|
pub struct KakuteF7MiniV3;
|
||||||
|
|
||||||
#[cfg(not(feature = "lidar-lite-v3"))]
|
|
||||||
const CONFIG: BoardConfig = BoardConfig {
|
const CONFIG: BoardConfig = BoardConfig {
|
||||||
name: "Kakute F7 Mini V3",
|
name: "Kakute F7 Mini V3",
|
||||||
mavlink: MavlinkEndpoint {
|
mavlink: MavlinkEndpoint {
|
||||||
system_id: 1,
|
system_id: 1,
|
||||||
component_id: 1,
|
component_id: 1,
|
||||||
},
|
},
|
||||||
vertical_sensing: VerticalSensingKind::RangeAndOpticalFlow,
|
profile: BoardProfile::TelemetryOnly(TelemetryProfile {
|
||||||
data_channel: DataChannelRates {
|
vertical_sensing: VerticalSensingKind::RangeAndOpticalFlow,
|
||||||
service_hz: 100,
|
data_channel: DataChannelRates {
|
||||||
raw_imu_hz: 20,
|
service_hz: 100,
|
||||||
range_hz: Some(20),
|
raw_imu_hz: 20,
|
||||||
optical_flow_hz: Some(20),
|
range_hz: Some(20),
|
||||||
heartbeat_hz: 2,
|
optical_flow_hz: Some(20),
|
||||||
},
|
heartbeat_hz: 2,
|
||||||
};
|
},
|
||||||
|
}),
|
||||||
#[cfg(feature = "lidar-lite-v3")]
|
|
||||||
const CONFIG: BoardConfig = BoardConfig {
|
|
||||||
name: "Kakute F7 Mini V3",
|
|
||||||
mavlink: MavlinkEndpoint {
|
|
||||||
system_id: 1,
|
|
||||||
component_id: 1,
|
|
||||||
},
|
|
||||||
vertical_sensing: VerticalSensingKind::Range,
|
|
||||||
data_channel: DataChannelRates {
|
|
||||||
service_hz: 100,
|
|
||||||
raw_imu_hz: 20,
|
|
||||||
range_hz: Some(20),
|
|
||||||
optical_flow_hz: None,
|
|
||||||
heartbeat_hz: 2,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
impl F7Board for KakuteF7MiniV3 {
|
impl F7Board for KakuteF7MiniV3 {
|
||||||
const CONFIG: BoardConfig = CONFIG;
|
const CONFIG: BoardConfig = CONFIG;
|
||||||
|
|
||||||
fn build(platform: F7BoardBuilder) -> Result<F722BoardRoutes, BoardError> {
|
fn build(platform: F7BoardBuilder) -> Result<F722BoardRoutes, BoardError> {
|
||||||
let platform = platform
|
platform
|
||||||
.imu(Mpu6000::on_spi1().with_drdy(Pa4))
|
.imu(Mpu6000::on_spi1().with_drdy(Pa4))
|
||||||
.motors(MotorOutputs::kakute_tim3_tim5().dshot600())
|
.mavlink(Mavlink::on_usart1())
|
||||||
.mavlink(Mavlink::on_usart1());
|
.vertical_sensor(VerticalSensor::mtf01_on_uart4())
|
||||||
#[cfg(feature = "lidar-lite-v3")]
|
.build()
|
||||||
let platform = platform.vertical_sensor(VerticalSensor::lidar_lite_v3_on_i2c1());
|
|
||||||
#[cfg(not(feature = "lidar-lite-v3"))]
|
|
||||||
let platform = platform.vertical_sensor(VerticalSensor::mtf01_on_uart4());
|
|
||||||
platform.build()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,5 +2,4 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
mod board;
|
mod board;
|
||||||
|
|
||||||
platform_stm32f7::flight_firmware!(board::KakuteF7MiniV3);
|
platform_stm32f7::flight_firmware!(board::KakuteF7MiniV3);
|
||||||
+102
-25
@@ -1,8 +1,9 @@
|
|||||||
//! Portable board-support contract for Kaptan.
|
//! Portable board-support contract for Kaptan.
|
||||||
//!
|
//!
|
||||||
//! This crate describes logical board identity, sensing capability and
|
//! This crate describes logical board identity, sensing capability and
|
||||||
//! outbound data-channel policy. It intentionally has no dependency on an MCU family,
|
//! outbound data-channel policy. It intentionally has no dependency on an MCU
|
||||||
//! peripheral access crate, RTIC, or a runtime framework.
|
//! family, peripheral access crate, RTIC, or a runtime framework.
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
/// The vertical-sensing data a board support package makes available.
|
/// The vertical-sensing data a board support package makes available.
|
||||||
@@ -41,26 +42,75 @@ pub struct DataChannelRates {
|
|||||||
pub heartbeat_hz: usize,
|
pub heartbeat_hz: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Static board identity, capability, and data-channel configuration.
|
/// Telemetry-only physical-sensor and outbound-data policy.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub struct TelemetryProfile {
|
||||||
|
/// Supported physical vertical-sensing capability.
|
||||||
|
pub vertical_sensing: VerticalSensingKind,
|
||||||
|
/// Data-channel timer and publication rates.
|
||||||
|
pub data_channel: DataChannelRates,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Exclusive build-time image selection.
|
||||||
|
///
|
||||||
|
/// `ExternalControlOnly` remains representable for an explicit validation
|
||||||
|
/// rejection rather than silently falling back to telemetry.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub enum BoardProfile {
|
||||||
|
/// Physical-sensor telemetry image.
|
||||||
|
TelemetryOnly(TelemetryProfile),
|
||||||
|
/// Reserved and deliberately unimplemented production authority profile.
|
||||||
|
ExternalControlOnly,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Static board identity and exclusive build-time image configuration.
|
||||||
///
|
///
|
||||||
/// The selected platform trait determines the MCU family. Keeping a free-form
|
/// The selected platform trait determines the MCU family. Keeping a free-form
|
||||||
/// MCU string here would duplicate that type-level fact without validating it.
|
/// MCU string here would duplicate that type-level fact without validating it.
|
||||||
|
///
|
||||||
|
/// TODO(configuration): board images currently receive this complete profile
|
||||||
|
/// at build time. Ground-station configuration must stage and validate a
|
||||||
|
/// whole profile (identity, sensor topology, link rates, actuator profile,
|
||||||
|
/// and calibration revision) before it is persisted. It must never apply
|
||||||
|
/// independent field updates or permit an active output while a profile is
|
||||||
|
/// staged, committed, or restored after power loss.
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub struct BoardConfig {
|
pub struct BoardConfig {
|
||||||
/// Stable board name used in build and diagnostic tooling.
|
/// Stable board name used in build and diagnostic tooling.
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
/// MAVLink endpoint identity.
|
/// MAVLink endpoint identity.
|
||||||
pub mavlink: MavlinkEndpoint,
|
pub mavlink: MavlinkEndpoint,
|
||||||
/// Supported vertical-sensing capability.
|
/// Exactly one immutable image profile.
|
||||||
pub vertical_sensing: VerticalSensingKind,
|
pub profile: BoardProfile,
|
||||||
/// Data-channel timer and publication rates.
|
|
||||||
pub data_channel: DataChannelRates,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoardConfig {
|
impl BoardConfig {
|
||||||
/// Validates rate bounds and the one-frame-per-service-tick budget.
|
/// Returns physical telemetry configuration only for a telemetry image.
|
||||||
|
pub const fn telemetry(self) -> Option<TelemetryProfile> {
|
||||||
|
match self.profile {
|
||||||
|
BoardProfile::TelemetryOnly(profile) => Some(profile),
|
||||||
|
BoardProfile::ExternalControlOnly => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validates the selected exclusive profile.
|
||||||
pub const fn validate(self) -> Result<(), BoardConfigError> {
|
pub const fn validate(self) -> Result<(), BoardConfigError> {
|
||||||
let rates = self.data_channel;
|
match self.profile {
|
||||||
|
BoardProfile::TelemetryOnly(profile) => Self::validate_telemetry(profile),
|
||||||
|
BoardProfile::ExternalControlOnly => {
|
||||||
|
// TODO(flight-config): replace this hard rejection only with a
|
||||||
|
// complete runtime and atomic configuration activation. Required
|
||||||
|
// inputs are vehicle geometry, calibrated sensors, actuator
|
||||||
|
// limits, authenticated MAVLink-v2 authority, persistent replay
|
||||||
|
// state, estimator/controller/allocator readiness, and a
|
||||||
|
// verified output watchdog.
|
||||||
|
Err(BoardConfigError::UnsupportedFlightProfile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn validate_telemetry(profile: TelemetryProfile) -> Result<(), BoardConfigError> {
|
||||||
|
let rates = profile.data_channel;
|
||||||
if rates.service_hz == 0 {
|
if rates.service_hz == 0 {
|
||||||
return Err(BoardConfigError::ZeroServiceFrequency);
|
return Err(BoardConfigError::ZeroServiceFrequency);
|
||||||
}
|
}
|
||||||
@@ -96,24 +146,29 @@ impl BoardConfig {
|
|||||||
return Err(BoardConfigError::DataChannelOvercommitted);
|
return Err(BoardConfigError::DataChannelOvercommitted);
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.vertical_sensing {
|
let vertical_schedule_is_valid = match profile.vertical_sensing {
|
||||||
VerticalSensingKind::None
|
VerticalSensingKind::None
|
||||||
if rates.range_hz.is_none() && rates.optical_flow_hz.is_none() =>
|
if rates.range_hz.is_none() && rates.optical_flow_hz.is_none() =>
|
||||||
{
|
{
|
||||||
Ok(())
|
true
|
||||||
}
|
}
|
||||||
VerticalSensingKind::Range
|
VerticalSensingKind::Range
|
||||||
if rates.range_hz.is_some() && rates.optical_flow_hz.is_none() =>
|
if rates.range_hz.is_some() && rates.optical_flow_hz.is_none() =>
|
||||||
{
|
{
|
||||||
Ok(())
|
true
|
||||||
}
|
}
|
||||||
VerticalSensingKind::RangeAndOpticalFlow
|
VerticalSensingKind::RangeAndOpticalFlow
|
||||||
if rates.range_hz.is_some() && rates.optical_flow_hz.is_some() =>
|
if rates.range_hz.is_some() && rates.optical_flow_hz.is_some() =>
|
||||||
{
|
{
|
||||||
Ok(())
|
true
|
||||||
}
|
}
|
||||||
_ => Err(BoardConfigError::CapabilityDataChannelMismatch),
|
_ => false,
|
||||||
|
};
|
||||||
|
if !vertical_schedule_is_valid {
|
||||||
|
return Err(BoardConfigError::CapabilityDataChannelMismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,12 +185,15 @@ pub enum BoardConfigError {
|
|||||||
DataChannelOvercommitted,
|
DataChannelOvercommitted,
|
||||||
/// Declared vertical sensing and published streams disagree.
|
/// Declared vertical sensing and published streams disagree.
|
||||||
CapabilityDataChannelMismatch,
|
CapabilityDataChannelMismatch,
|
||||||
|
/// The selected operation profile has no complete runtime implementation.
|
||||||
|
UnsupportedFlightProfile,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{
|
use super::{
|
||||||
BoardConfig, BoardConfigError, DataChannelRates, MavlinkEndpoint, VerticalSensingKind,
|
BoardConfig, BoardConfigError, BoardProfile, DataChannelRates, MavlinkEndpoint,
|
||||||
|
TelemetryProfile, VerticalSensingKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
const BASE: BoardConfig = BoardConfig {
|
const BASE: BoardConfig = BoardConfig {
|
||||||
@@ -144,14 +202,16 @@ mod tests {
|
|||||||
system_id: 1,
|
system_id: 1,
|
||||||
component_id: 1,
|
component_id: 1,
|
||||||
},
|
},
|
||||||
vertical_sensing: VerticalSensingKind::RangeAndOpticalFlow,
|
profile: BoardProfile::TelemetryOnly(TelemetryProfile {
|
||||||
data_channel: DataChannelRates {
|
vertical_sensing: VerticalSensingKind::RangeAndOpticalFlow,
|
||||||
service_hz: 100,
|
data_channel: DataChannelRates {
|
||||||
raw_imu_hz: 20,
|
service_hz: 100,
|
||||||
range_hz: Some(20),
|
raw_imu_hz: 20,
|
||||||
optical_flow_hz: Some(20),
|
range_hz: Some(20),
|
||||||
heartbeat_hz: 2,
|
optical_flow_hz: Some(20),
|
||||||
},
|
heartbeat_hz: 2,
|
||||||
|
},
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -162,7 +222,10 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rejects_streams_that_exceed_the_service_budget() {
|
fn rejects_streams_that_exceed_the_service_budget() {
|
||||||
let mut config = BASE;
|
let mut config = BASE;
|
||||||
config.data_channel.optical_flow_hz = Some(80);
|
let BoardProfile::TelemetryOnly(profile) = &mut config.profile else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
profile.data_channel.optical_flow_hz = Some(80);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.validate(),
|
config.validate(),
|
||||||
@@ -173,11 +236,25 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rejects_capability_and_data_channel_mismatch() {
|
fn rejects_capability_and_data_channel_mismatch() {
|
||||||
let mut config = BASE;
|
let mut config = BASE;
|
||||||
config.vertical_sensing = VerticalSensingKind::Range;
|
let BoardProfile::TelemetryOnly(profile) = &mut config.profile else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
profile.vertical_sensing = VerticalSensingKind::Range;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.validate(),
|
config.validate(),
|
||||||
Err(BoardConfigError::CapabilityDataChannelMismatch)
|
Err(BoardConfigError::CapabilityDataChannelMismatch)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rejects_external_control_until_its_runtime_exists() {
|
||||||
|
let mut config = BASE;
|
||||||
|
config.profile = BoardProfile::ExternalControlOnly;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
config.validate(),
|
||||||
|
Err(BoardConfigError::UnsupportedFlightProfile)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,8 @@
|
|||||||
//!
|
//!
|
||||||
//! This crate owns fixed-rate scheduling, mailbox consumption, vertical-data
|
//! This crate owns fixed-rate scheduling, mailbox consumption, vertical-data
|
||||||
//! freshness, MAVLink encoding, and bounded queue classification. A platform
|
//! freshness, MAVLink encoding, and bounded queue classification. A platform
|
||||||
//! supplies only mailbox references, health/arming state, and a transport sink.
|
//! supplies only mailbox references, a declared MAVLink state, arming state,
|
||||||
|
//! and a transport sink.
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
@@ -57,6 +58,8 @@ pub struct VerticalDataConfig {
|
|||||||
/// Data-channel construction failure.
|
/// Data-channel construction failure.
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub enum DataChannelError {
|
pub enum DataChannelError {
|
||||||
|
/// Rejected profiles must not construct a physical telemetry channel.
|
||||||
|
NotTelemetryProfile,
|
||||||
/// A configured channel must be due at least once per second.
|
/// A configured channel must be due at least once per second.
|
||||||
ZeroRate,
|
ZeroRate,
|
||||||
/// A configured channel exceeds the service frequency.
|
/// A configured channel exceeds the service frequency.
|
||||||
@@ -92,7 +95,10 @@ where
|
|||||||
vertical: VerticalDataConfig,
|
vertical: VerticalDataConfig,
|
||||||
sources: DataSources<'a>,
|
sources: DataSources<'a>,
|
||||||
) -> Result<Self, DataChannelError> {
|
) -> Result<Self, DataChannelError> {
|
||||||
let schedule = Schedule::from_rates(config.data_channel)?;
|
let telemetry = config
|
||||||
|
.telemetry()
|
||||||
|
.ok_or(DataChannelError::NotTelemetryProfile)?;
|
||||||
|
let schedule = Schedule::from_rates(telemetry.data_channel)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
sink,
|
sink,
|
||||||
encoder: MavlinkEncoder::new(config.mavlink.system_id, config.mavlink.component_id),
|
encoder: MavlinkEncoder::new(config.mavlink.system_id, config.mavlink.component_id),
|
||||||
@@ -114,7 +120,7 @@ where
|
|||||||
/// No schedule token escapes this method. It refreshes cached vertical
|
/// No schedule token escapes this method. It refreshes cached vertical
|
||||||
/// observations, selects due data, encodes the MAVLink message, and admits
|
/// observations, selects due data, encodes the MAVLink message, and admits
|
||||||
/// it with the correct bounded-queue class.
|
/// it with the correct bounded-queue class.
|
||||||
pub fn on_service_tick(&mut self, imu_healthy: bool, motors_armed: bool) {
|
pub fn on_service_tick(&mut self, system_status: MavState, motors_armed: bool) {
|
||||||
self.refresh_vertical_data();
|
self.refresh_vertical_data();
|
||||||
|
|
||||||
match self.schedule.next_due() {
|
match self.schedule.next_due() {
|
||||||
@@ -148,14 +154,7 @@ where
|
|||||||
}
|
}
|
||||||
Some(DueData::Heartbeat) => self.sink.send(
|
Some(DueData::Heartbeat) => self.sink.send(
|
||||||
FrameClass::Critical,
|
FrameClass::Critical,
|
||||||
self.encoder.heartbeat(
|
self.encoder.heartbeat(system_status, motors_armed),
|
||||||
if imu_healthy {
|
|
||||||
MavState::MAV_STATE_STANDBY
|
|
||||||
} else {
|
|
||||||
MavState::MAV_STATE_CRITICAL
|
|
||||||
},
|
|
||||||
motors_armed,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Some(DueData::Distance | DueData::OpticalFlow) | None => {}
|
Some(DueData::Distance | DueData::OpticalFlow) | None => {}
|
||||||
}
|
}
|
||||||
@@ -281,7 +280,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
use kaptan_board::{BoardConfig, DataChannelRates, MavlinkEndpoint, VerticalSensingKind};
|
use kaptan_board::{BoardConfig, DataChannelRates, MavlinkEndpoint, VerticalSensingKind};
|
||||||
use kaptan_dma::TxCompletion;
|
use kaptan_dma::TxCompletion;
|
||||||
use kaptan_mavlink::{MavlinkFrame, transmitter::FrameClass};
|
use kaptan_mavlink::{MavlinkFrame, message::MavState, transmitter::FrameClass};
|
||||||
use kaptan_sensor::{
|
use kaptan_sensor::{
|
||||||
imu::ImuSnapshot, optical_flow::OpticalFlowSnapshot, range::RangeSnapshot,
|
imu::ImuSnapshot, optical_flow::OpticalFlowSnapshot, range::RangeSnapshot,
|
||||||
};
|
};
|
||||||
@@ -312,14 +311,16 @@ mod tests {
|
|||||||
system_id: 1,
|
system_id: 1,
|
||||||
component_id: 1,
|
component_id: 1,
|
||||||
},
|
},
|
||||||
vertical_sensing: VerticalSensingKind::RangeAndOpticalFlow,
|
profile: kaptan_board::BoardProfile::TelemetryOnly(kaptan_board::TelemetryProfile {
|
||||||
data_channel: DataChannelRates {
|
vertical_sensing: VerticalSensingKind::RangeAndOpticalFlow,
|
||||||
service_hz: 100,
|
data_channel: DataChannelRates {
|
||||||
raw_imu_hz: 20,
|
service_hz: 100,
|
||||||
range_hz: Some(20),
|
raw_imu_hz: 20,
|
||||||
optical_flow_hz: Some(20),
|
range_hz: Some(20),
|
||||||
heartbeat_hz: 2,
|
optical_flow_hz: Some(20),
|
||||||
},
|
heartbeat_hz: 2,
|
||||||
|
},
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -367,7 +368,7 @@ mod tests {
|
|||||||
100,
|
100,
|
||||||
100,
|
100,
|
||||||
));
|
));
|
||||||
channel.on_service_tick(true, false);
|
channel.on_service_tick(MavState::MAV_STATE_STANDBY, false);
|
||||||
}
|
}
|
||||||
channel.on_dma_complete(TxCompletion::Complete);
|
channel.on_dma_complete(TxCompletion::Complete);
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user