diff --git a/flight/modules/Receiver/receiver.c b/flight/modules/Receiver/receiver.c index 900e1194c..f98850937 100644 --- a/flight/modules/Receiver/receiver.c +++ b/flight/modules/Receiver/receiver.c @@ -114,7 +114,8 @@ static bool updateRcvrActivity(struct rcvr_activity_fsm *fsm); static void resetRcvrStatus(struct rcvr_activity_fsm *fsm); static bool updateRcvrStatus( struct rcvr_activity_fsm *fsm, - ManualControlSettingsChannelGroupsOptions group); + ManualControlSettingsChannelGroupsOptions group, + int8_t rssiValue); #define assumptions \ ( \ @@ -209,6 +210,9 @@ static void receiverTask(__attribute__((unused)) void *parameters) AccessoryDesiredCreateInstance(); AccessoryDesiredCreateInstance(); + // Rssi input + AccessoryDesiredCreateInstance(); + // Whenever the configuration changes, make sure it is safe to fly ManualControlCommandGet(&cmd); @@ -232,6 +236,8 @@ static void receiverTask(__attribute__((unused)) void *parameters) PIOS_WDG_UpdateFlag(PIOS_WDG_MANUAL); #endif + int8_t rssiValue = -1; + // Read settings ManualControlSettingsGet(&settings); SystemSettingsThrustControlGet(&thrustType); @@ -244,7 +250,8 @@ static void receiverTask(__attribute__((unused)) void *parameters) } /* Read signal quality from the group used for the throttle */ (void)updateRcvrStatus(&activity_fsm, - settings.ChannelGroups.Throttle); + settings.ChannelGroups.Throttle, + rssiValue); } if (timeDifferenceMs(lastActivityTime, lastSysTime) > 5000) { resetRcvrActivity(&activity_fsm); @@ -267,6 +274,7 @@ static void receiverTask(__attribute__((unused)) void *parameters) } bool valid_input_detected = true; + bool valid_rssi_input = false; // Read channel values in us for (uint8_t n = 0; n < MANUALCONTROLSETTINGS_CHANNELGROUPS_NUMELEM && n < MANUALCONTROLCOMMAND_CHANNEL_NUMELEM; ++n) { @@ -285,16 +293,27 @@ static void receiverTask(__attribute__((unused)) void *parameters) if (cmd.Channel[n] == (uint16_t)PIOS_RCVR_TIMEOUT) { valid_input_detected = false; } else { + int16_t neutralValue = ManualControlSettingsChannelNeutralToArray(settings.ChannelNeutral)[n]; + + if (n == MANUALCONTROLSETTINGS_CHANNELGROUPS_RSSI) { + // Rssi neutral is ignored and set to min, for 0 - 100% output range + neutralValue = ManualControlSettingsChannelMinToArray(settings.ChannelMin)[n]; + valid_rssi_input = true; + } scaledChannel[n] = scaleChannel(cmd.Channel[n], ManualControlSettingsChannelMaxToArray(settings.ChannelMax)[n], ManualControlSettingsChannelMinToArray(settings.ChannelMin)[n], - ManualControlSettingsChannelNeutralToArray(settings.ChannelNeutral)[n]); + neutralValue); } } + if (valid_rssi_input) { + rssiValue = (int8_t)(scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_RSSI] * 100); + } /* Read signal quality from the group used for the throttle */ (void)updateRcvrStatus(&activity_fsm, - settings.ChannelGroups.Throttle); + settings.ChannelGroups.Throttle, + rssiValue); // Sanity Check Throttle and Yaw if (settings.ChannelGroups.Yaw >= MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE @@ -383,6 +402,10 @@ static void receiverTask(__attribute__((unused)) void *parameters) valid_input_detected &= validInputRange(settings.ChannelMin.Accessory3, settings.ChannelMax.Accessory3, cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_ACCESSORY3]); } + if (settings.ChannelGroups.Rssi != MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE) { + valid_input_detected &= validInputRange(settings.ChannelMin.Rssi, + settings.ChannelMax.Rssi, cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_RSSI]); + } // Implement hysteresis loop on connection status if (valid_input_detected && (++connected_count > 10)) { @@ -569,6 +592,18 @@ static void receiverTask(__attribute__((unused)) void *parameters) AlarmsSet(SYSTEMALARMS_ALARM_RECEIVER, SYSTEMALARMS_ALARM_WARNING); } } + // Set Rssi input + if (settings.ChannelGroups.Rssi != MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE) { + accessory.AccessoryVal = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_RSSI]; +#ifdef USE_INPUT_LPF + // Allow some Rssi filtering without deadband + applyLPF(&accessory.AccessoryVal, MANUALCONTROLSETTINGS_RESPONSETIME_RSSI, &settings.ResponseTime, 0.0f, dT); +#endif + + if (AccessoryDesiredInstSet(4, &accessory) != 0) { + AlarmsSet(SYSTEMALARMS_ALARM_RECEIVER, SYSTEMALARMS_ALARM_WARNING); + } + } } // Update cmd object @@ -625,6 +660,9 @@ static void updateRcvrActivitySample(uint32_t rcvr_id, uint16_t samples[], uint8 static bool updateRcvrActivityCompare(uint32_t rcvr_id, struct rcvr_activity_fsm *fsm) { bool activity_updated = false; + ManualControlSettingsData settings; + + ManualControlSettingsGet(&settings); /* Compare the current value to the previous sampled value */ for (uint8_t channel = 1; channel <= RCVR_ACTIVITY_MONITOR_CHANNELS_PER_GROUP; channel++) { @@ -637,6 +675,13 @@ static bool updateRcvrActivityCompare(uint32_t rcvr_id, struct rcvr_activity_fsm delta = prev - curr; } + // Ignore activity from this Group/Channel because already used/set for Rssi input + // Without that, the ReceiverActivity will be saturated just with Rssi value activity. + if ((ManualControlSettingsChannelGroupsToArray(settings.ChannelGroups)[MANUALCONTROLSETTINGS_CHANNELGROUPS_RSSI] == fsm->group) && + (ManualControlSettingsChannelNumberToArray(settings.ChannelNumber)[MANUALCONTROLSETTINGS_CHANNELNUMBER_RSSI] == channel)) { + delta = 0; + } + if (delta > RCVR_ACTIVITY_MONITOR_MIN_RANGE) { /* Mark this channel as active */ ReceiverActivityActiveGroupOptions group; @@ -748,16 +793,16 @@ group_completed: return activity_updated; } -/* Read signal quality from the specified group */ +/* Read signal quality from the specified group or use Rssi input value if any */ static bool updateRcvrStatus( struct rcvr_activity_fsm *fsm, - ManualControlSettingsChannelGroupsOptions group) + ManualControlSettingsChannelGroupsOptions group, int8_t rssiValue) { extern uint32_t pios_rcvr_group_map[]; bool activity_updated = false; int8_t quality; - quality = PIOS_RCVR_GetQuality(pios_rcvr_group_map[group]); + quality = (rssiValue > 0) ? rssiValue : PIOS_RCVR_GetQuality(pios_rcvr_group_map[group]); /* If no driver is detected or any other error then return */ if (quality < 0) { diff --git a/flight/pios/common/pios_sbus.c b/flight/pios/common/pios_sbus.c index e354a5c5f..240a7c51c 100644 --- a/flight/pios/common/pios_sbus.c +++ b/flight/pios/common/pios_sbus.c @@ -125,6 +125,7 @@ static void PIOS_SBus_ResetChannels(struct pios_sbus_state *state) { for (int i = 0; i < PIOS_SBUS_NUM_INPUTS; i++) { state->channel_data[i] = PIOS_RCVR_TIMEOUT; + state->quality = 0.0f; } } @@ -302,6 +303,7 @@ static void PIOS_SBus_UpdateState(struct pios_sbus_state *state, uint8_t b) } #ifndef SBUS_GOOD_FRAME_COUNT /* Present quality as a weighted average of good frames */ + // TODO: Refactor quality computation, give 4% (quality_trend / SBUS_FL_WEIGHTED_AVE) at minimum state->quality = ((state->quality * (SBUS_FL_WEIGHTED_AVE - 1)) + quality_trend) / SBUS_FL_WEIGHTED_AVE; #endif /* SBUS_GOOD_FRAME_COUNT */ diff --git a/ground/gcs/src/plugins/config/configinputwidget.cpp b/ground/gcs/src/plugins/config/configinputwidget.cpp index 47e075b55..9adcfb837 100644 --- a/ground/gcs/src/plugins/config/configinputwidget.cpp +++ b/ground/gcs/src/plugins/config/configinputwidget.cpp @@ -83,7 +83,8 @@ ConfigInputWidget::ConfigInputWidget(QWidget *parent) : accessoryDesiredObj0(NULL), accessoryDesiredObj1(NULL), accessoryDesiredObj2(NULL), - accessoryDesiredObj3(NULL) + accessoryDesiredObj3(NULL), + rssiDesiredObj4(NULL) { manualCommandObj = ManualControlCommand::GetInstance(getObjectManager()); manualSettingsObj = ManualControlSettings::GetInstance(getObjectManager()); @@ -94,6 +95,7 @@ ConfigInputWidget::ConfigInputWidget(QWidget *parent) : accessoryDesiredObj1 = AccessoryDesired::GetInstance(getObjectManager(), 1); accessoryDesiredObj2 = AccessoryDesired::GetInstance(getObjectManager(), 2); accessoryDesiredObj3 = AccessoryDesired::GetInstance(getObjectManager(), 3); + rssiDesiredObj4 = AccessoryDesired::GetInstance(getObjectManager(), 4); actuatorSettingsObj = ActuatorSettings::GetInstance(getObjectManager()); systemSettingsObj = SystemSettings::GetInstance(getObjectManager()); @@ -138,7 +140,12 @@ ConfigInputWidget::ConfigInputWidget(QWidget *parent) : // Slider position based on real time Rcinput (allow monitoring) addWidgetBinding("ManualControlCommand", "Channel", inputChannelForm->ui->channelNeutral, index); // Neutral value stored on board (SpinBox) - addWidgetBinding("ManualControlSettings", "ChannelNeutral", inputChannelForm->ui->neutralValue, index); + // Rssi neutral is always set to min + if (index == ManualControlSettings::CHANNELGROUPS_RSSI) { + addWidgetBinding("ManualControlSettings", "ChannelMin", inputChannelForm->ui->neutralValue, index); + } else { + addWidgetBinding("ManualControlSettings", "ChannelNeutral", inputChannelForm->ui->neutralValue, index); + } addWidgetBinding("ManualControlSettings", "ChannelMax", inputChannelForm->ui->channelMax, index); addWidgetBinding("ManualControlSettings", "ChannelMin", inputChannelForm->ui->channelMin, index); addWidgetBinding("ManualControlSettings", "ChannelMax", inputChannelForm->ui->channelMax, index); @@ -153,7 +160,10 @@ ConfigInputWidget::ConfigInputWidget(QWidget *parent) : inputChannelForm->ui->channelRev->setVisible(reversable); // Input filter response time fields supported for some channels only + // Set Neutral field to readonly for Rssi switch (index) { + case ManualControlSettings::CHANNELGROUPS_RSSI: + inputChannelForm->ui->neutralValue->setReadOnly(true); case ManualControlSettings::CHANNELGROUPS_ROLL: case ManualControlSettings::CHANNELGROUPS_PITCH: case ManualControlSettings::CHANNELGROUPS_YAW: @@ -832,7 +842,7 @@ void ConfigInputWidget::wizardSetUpStep(enum wizardSteps step) { setTxMovement(nothing); manualSettingsData = manualSettingsObj->getData(); - for (uint i = 0; i < ManualControlSettings::CHANNELMAX_NUMELEM; ++i) { + for (uint i = 0; i < ManualControlSettings::CHANNELNUMBER_RSSI; ++i) { // Preserve the inverted status if (manualSettingsData.ChannelMin[i] <= manualSettingsData.ChannelMax[i]) { manualSettingsData.ChannelMin[i] = manualSettingsData.ChannelNeutral[i]; @@ -937,7 +947,8 @@ void ConfigInputWidget::wizardTearDownStep(enum wizardSteps step) case wizardIdentifyCenter: manualCommandData = manualCommandObj->getData(); manualSettingsData = manualSettingsObj->getData(); - for (unsigned int i = 0; i < ManualControlCommand::CHANNEL_NUMELEM; ++i) { + // Ignore last Rssi channel + for (unsigned int i = 0; i < ManualControlSettings::CHANNELNUMBER_RSSI; ++i) { // Set Accessory neutral to middle range if (i >= ManualControlSettings::CHANNELNUMBER_ACCESSORY0) { manualSettingsData.ChannelNeutral[i] = manualSettingsData.ChannelMin[i] + ((manualSettingsData.ChannelMax[i] - manualSettingsData.ChannelMin[i]) / 2); @@ -1195,7 +1206,7 @@ void ConfigInputWidget::identifyLimits() bool newFlightModeValue = false; manualCommandData = manualCommandObj->getData(); - for (uint i = 0; i < ManualControlSettings::CHANNELMAX_NUMELEM; ++i) { + for (uint i = 0; i < ManualControlSettings::CHANNELNUMBER_RSSI; ++i) { inputValue = manualCommandData.Channel[i]; // Check if channel is already detected and prevent glitches if ((manualSettingsData.ChannelNumber[i] != CHANNEL_NUMBER_NONE) && @@ -1934,7 +1945,7 @@ void ConfigInputWidget::updateConfigAlarmStatus() void ConfigInputWidget::updateCalibration() { manualCommandData = manualCommandObj->getData(); - for (uint i = 0; i < ManualControlSettings::CHANNELMAX_NUMELEM; ++i) { + for (uint i = 0; i < ManualControlSettings::CHANNELNUMBER_RSSI; ++i) { if ((!reverse[i] && manualSettingsData.ChannelMin[i] > manualCommandData.Channel[i]) || (reverse[i] && manualSettingsData.ChannelMin[i] < manualCommandData.Channel[i])) { manualSettingsData.ChannelMin[i] = manualCommandData.Channel[i]; @@ -1984,8 +1995,8 @@ void ConfigInputWidget::simpleCalibration(bool enable) flightModeSettingsData = flightModeSettingsObj->getData(); flightModeSettingsData.Arming = FlightModeSettings::ARMING_ALWAYSDISARMED; flightModeSettingsObj->setData(flightModeSettingsData); - - for (unsigned int i = 0; i < ManualControlCommand::CHANNEL_NUMELEM; i++) { + // Ignore last Rssi channel + for (unsigned int i = 0; i < ManualControlSettings::CHANNELNUMBER_RSSI; i++) { reverse[i] = manualSettingsData.ChannelMax[i] < manualSettingsData.ChannelMin[i]; manualSettingsData.ChannelMin[i] = manualCommandData.Channel[i]; manualSettingsData.ChannelNeutral[i] = manualCommandData.Channel[i]; @@ -2023,7 +2034,7 @@ void ConfigInputWidget::simpleCalibration(bool enable) forceOneFlightMode(); } - for (unsigned int i = 0; i < ManualControlCommand::CHANNEL_NUMELEM; i++) { + for (unsigned int i = 0; i < ManualControlSettings::CHANNELNUMBER_RSSI; i++) { if ((i == ManualControlSettings::CHANNELNUMBER_FLIGHTMODE) || (i == ManualControlSettings::CHANNELNUMBER_THROTTLE)) { adjustSpecialNeutrals(); checkThrottleRange(); @@ -2096,8 +2107,8 @@ bool ConfigInputWidget::shouldObjectBeSaved(UAVObject *object) void ConfigInputWidget::resetChannelSettings() { manualSettingsData = manualSettingsObj->getData(); - // Clear all channel data : Channel Type (PPM,PWM..) and Number - for (unsigned int channel = 0; channel < ManualControlSettings::CHANNELNUMBER_NUMELEM; channel++) { + // Clear all channel data : Channel Type (PPM,PWM..) and Number, except for Rssi + for (unsigned int channel = 0; channel < ManualControlSettings::CHANNELNUMBER_RSSI; channel++) { manualSettingsData.ChannelGroups[channel] = ManualControlSettings::CHANNELGROUPS_NONE; manualSettingsData.ChannelNumber[channel] = CHANNEL_NUMBER_NONE; UAVObjectUpdaterHelper updateHelper; diff --git a/ground/gcs/src/plugins/config/configinputwidget.h b/ground/gcs/src/plugins/config/configinputwidget.h index a110d62c3..26bda23a1 100644 --- a/ground/gcs/src/plugins/config/configinputwidget.h +++ b/ground/gcs/src/plugins/config/configinputwidget.h @@ -130,6 +130,7 @@ private: AccessoryDesired *accessoryDesiredObj1; AccessoryDesired *accessoryDesiredObj2; AccessoryDesired *accessoryDesiredObj3; + AccessoryDesired *rssiDesiredObj4; ManualControlSettings *manualSettingsObj; ManualControlSettings::DataFields manualSettingsData; diff --git a/shared/uavobjectdefinition/manualcontrolcommand.xml b/shared/uavobjectdefinition/manualcontrolcommand.xml index f50990a07..7654c29ed 100644 --- a/shared/uavobjectdefinition/manualcontrolcommand.xml +++ b/shared/uavobjectdefinition/manualcontrolcommand.xml @@ -8,7 +8,7 @@ - + diff --git a/shared/uavobjectdefinition/manualcontrolsettings.xml b/shared/uavobjectdefinition/manualcontrolsettings.xml index ef1cb93e4..7b4879b2e 100644 --- a/shared/uavobjectdefinition/manualcontrolsettings.xml +++ b/shared/uavobjectdefinition/manualcontrolsettings.xml @@ -1,34 +1,32 @@ - Settings to indicate how to decode receiver input by @ref ManualControlModule. - + Settings to indicate how to decode receiver input by @ref ManualControlModule. + + elementnames="Throttle,Roll,Pitch,Yaw,FlightMode,Collective,Accessory0,Accessory1,Accessory2,Accessory3,Rssi"/> + elementnames="Throttle,Roll,Pitch,Yaw,FlightMode,Collective,Accessory0,Accessory1,Accessory2,Accessory3,Rssi"/> + elementnames="Throttle,Roll,Pitch,Yaw,FlightMode,Collective,Accessory0,Accessory1,Accessory2,Accessory3,Rssi"/> + elementnames="Throttle,Roll,Pitch,Yaw,FlightMode,Collective,Accessory0,Accessory1,Accessory2,Accessory3,Rssi"/> + elementnames="Roll,Pitch,Yaw,Collective,Accessory0,Accessory1,Accessory2,Accessory3,Rssi"/> - + - - + - + - - - - - - - + + + + + +