ManualControl: add option to prioritize RC or MAVLink but with fallback

This commit is contained in:
Matthias Grob
2025-07-29 14:22:57 +02:00
parent b876aa5b45
commit a09352c079
4 changed files with 202 additions and 11 deletions
@@ -40,6 +40,8 @@ using namespace time_literals;
static constexpr uint64_t SOME_TIME = 12345678;
static constexpr uint8_t SOURCE_RC = manual_control_setpoint_s::SOURCE_RC;
static constexpr uint8_t SOURCE_MAVLINK_0 = manual_control_setpoint_s::SOURCE_MAVLINK_0;
static constexpr uint8_t SOURCE_MAVLINK_1 = manual_control_setpoint_s::SOURCE_MAVLINK_1;
static constexpr uint8_t SOURCE_MAVLINK_2 = manual_control_setpoint_s::SOURCE_MAVLINK_2;
static constexpr uint8_t SOURCE_MAVLINK_3 = manual_control_setpoint_s::SOURCE_MAVLINK_3;
static constexpr uint8_t SOURCE_MAVLINK_4 = manual_control_setpoint_s::SOURCE_MAVLINK_4;
@@ -175,6 +177,7 @@ TEST(ManualControlSelector, RcMavlinkInputFallback)
uint64_t timestamp = SOME_TIME;
// Valid RC input gets used
manual_control_setpoint_s input {};
input.data_source = SOURCE_RC;
input.valid = true;
@@ -187,7 +190,7 @@ TEST(ManualControlSelector, RcMavlinkInputFallback)
timestamp += 100_ms;
// Now provide input from MAVLink as well which should get ignored.
// Now provide input from MAVLink as well which should get ignored
input.data_source = SOURCE_MAVLINK_0;
input.timestamp_sample = timestamp;
selector.updateWithNewInputSample(timestamp, input, 1);
@@ -198,7 +201,7 @@ TEST(ManualControlSelector, RcMavlinkInputFallback)
timestamp += 500_ms;
// Now we'll let RC time out, so it should switch to MAVLINK.
// Now we update MAVLink and let RC time out, so it should switch to RC
input.data_source = SOURCE_MAVLINK_0;
input.timestamp_sample = timestamp;
selector.updateWithNewInputSample(timestamp, input, 1);
@@ -206,6 +209,15 @@ TEST(ManualControlSelector, RcMavlinkInputFallback)
EXPECT_TRUE(selector.setpoint().valid);
EXPECT_EQ(selector.setpoint().data_source, SOURCE_MAVLINK_0);
EXPECT_EQ(selector.instance(), 1);
// If we get RC back immediately, it stays with MAVLink (until RC is lost again)
input.data_source = SOURCE_RC;
input.timestamp_sample = timestamp;
selector.updateWithNewInputSample(timestamp, input, 1);
EXPECT_TRUE(selector.setpoint().valid);
EXPECT_EQ(selector.setpoint().data_source, SOURCE_MAVLINK_0);
EXPECT_EQ(selector.instance(), 1);
}
TEST(ManualControlSelector, RcMavlinkInputKeepFirst)
@@ -339,3 +351,156 @@ TEST(ManualControlSelector, RcOutdated)
EXPECT_FALSE(selector.setpoint().valid);
EXPECT_EQ(selector.instance(), -1);
}
TEST(ManualControlSelector, RcMavlinkInputRcPriority)
{
ManualControlSelector selector;
selector.setRcInMode(5); // Configure RC priority
selector.setTimeout(500_ms);
uint64_t timestamp = SOME_TIME;
// Valid RC input gets used
manual_control_setpoint_s input{};
input.data_source = SOURCE_RC;
input.valid = true;
input.timestamp_sample = timestamp;
selector.updateWithNewInputSample(timestamp, input, 0);
EXPECT_TRUE(selector.setpoint().valid);
EXPECT_EQ(selector.setpoint().data_source, SOURCE_RC);
EXPECT_EQ(selector.instance(), 0);
timestamp += 100_ms;
// Now provide input from MAVLink as well which should get ignored
input.data_source = SOURCE_MAVLINK_0;
input.timestamp_sample = timestamp;
selector.updateWithNewInputSample(timestamp, input, 1);
EXPECT_TRUE(selector.setpoint().valid);
EXPECT_EQ(selector.setpoint().data_source, SOURCE_RC);
EXPECT_EQ(selector.instance(), 0);
timestamp += 500_ms;
// Now we update MAVLink and let RC time out, so it should switch to RC
input.data_source = SOURCE_MAVLINK_0;
input.timestamp_sample = timestamp;
selector.updateWithNewInputSample(timestamp, input, 1);
EXPECT_TRUE(selector.setpoint().valid);
EXPECT_EQ(selector.setpoint().data_source, SOURCE_MAVLINK_0);
EXPECT_EQ(selector.instance(), 1);
// If we get RC back immediately, it should use it with priority
input.data_source = SOURCE_RC;
input.timestamp_sample = timestamp;
selector.updateWithNewInputSample(timestamp, input, 0);
EXPECT_TRUE(selector.setpoint().valid);
EXPECT_EQ(selector.setpoint().data_source, SOURCE_RC);
EXPECT_EQ(selector.instance(), 0);
}
TEST(ManualControlSelector, RcMavlinkInputMavlinkPriority)
{
ManualControlSelector selector;
selector.setRcInMode(6); // Configure MAVLink priority
selector.setTimeout(500_ms);
uint64_t timestamp = SOME_TIME;
// Valid MAVLink input gets used
manual_control_setpoint_s input{};
input.data_source = SOURCE_MAVLINK_0;
input.valid = true;
input.timestamp_sample = timestamp;
selector.updateWithNewInputSample(timestamp, input, 0);
EXPECT_TRUE(selector.setpoint().valid);
EXPECT_EQ(selector.setpoint().data_source, SOURCE_MAVLINK_0);
EXPECT_EQ(selector.instance(), 0);
timestamp += 100_ms;
// Now provide input from RC as well which should get ignored
input.data_source = SOURCE_RC;
input.timestamp_sample = timestamp;
selector.updateWithNewInputSample(timestamp, input, 1);
EXPECT_TRUE(selector.setpoint().valid);
EXPECT_EQ(selector.setpoint().data_source, SOURCE_MAVLINK_0);
EXPECT_EQ(selector.instance(), 0);
timestamp += 500_ms;
// Now we update RC and let MAVLink time out, so it should switch to RC
input.data_source = SOURCE_RC;
input.timestamp_sample = timestamp;
selector.updateWithNewInputSample(timestamp, input, 1);
EXPECT_TRUE(selector.setpoint().valid);
EXPECT_EQ(selector.setpoint().data_source, SOURCE_RC);
EXPECT_EQ(selector.instance(), 1);
// If we get MAVLink back immediately, it should use it with priority
input.data_source = SOURCE_MAVLINK_0;
input.timestamp_sample = timestamp;
selector.updateWithNewInputSample(timestamp, input, 0);
EXPECT_TRUE(selector.setpoint().valid);
EXPECT_EQ(selector.setpoint().data_source, SOURCE_MAVLINK_0);
EXPECT_EQ(selector.instance(), 0);
}
TEST(ManualControlSelector, MavlinkTwoInstanceInputMavlinkPriority)
{
ManualControlSelector selector;
selector.setRcInMode(6); // Configure MAVLink priority
selector.setTimeout(500_ms);
uint64_t timestamp = SOME_TIME;
// Valid MAVLink 0 input gets used
manual_control_setpoint_s input{};
input.data_source = SOURCE_MAVLINK_0;
input.valid = true;
input.timestamp_sample = timestamp;
selector.updateWithNewInputSample(timestamp, input, 0);
EXPECT_TRUE(selector.setpoint().valid);
EXPECT_EQ(selector.setpoint().data_source, SOURCE_MAVLINK_0);
EXPECT_EQ(selector.instance(), 0);
timestamp += 100_ms;
// Now provide input from MAVLink 1 as well which should get ignored
input.data_source = SOURCE_MAVLINK_1;
input.timestamp_sample = timestamp;
selector.updateWithNewInputSample(timestamp, input, 1);
EXPECT_TRUE(selector.setpoint().valid);
EXPECT_EQ(selector.setpoint().data_source, SOURCE_MAVLINK_0);
EXPECT_EQ(selector.instance(), 0);
timestamp += 500_ms;
// Now we update MAVLink 1 and let MAVLink 0 time out, so it should switch to MAVLink 1
input.data_source = SOURCE_MAVLINK_1;
input.timestamp_sample = timestamp;
selector.updateWithNewInputSample(timestamp, input, 1);
EXPECT_TRUE(selector.setpoint().valid);
EXPECT_EQ(selector.setpoint().data_source, SOURCE_MAVLINK_1);
EXPECT_EQ(selector.instance(), 1);
// If we get MAVLink 0 back immediately, it should not switch since MAVLink 1 has the same priority
input.data_source = SOURCE_MAVLINK_0;
input.timestamp_sample = timestamp;
selector.updateWithNewInputSample(timestamp, input, 0);
EXPECT_TRUE(selector.setpoint().valid);
EXPECT_EQ(selector.setpoint().data_source, SOURCE_MAVLINK_1);
EXPECT_EQ(selector.instance(), 1);
}