diff --git a/flight/modules/Actuator/actuator.c b/flight/modules/Actuator/actuator.c index 7cc78c7b1..891537bd6 100644 --- a/flight/modules/Actuator/actuator.c +++ b/flight/modules/Actuator/actuator.c @@ -53,20 +53,23 @@ static int8_t counter; #endif // Private constants -#define MAX_QUEUE_SIZE 2 +#define MAX_QUEUE_SIZE 2 #if defined(PIOS_ACTUATOR_STACK_SIZE) -#define STACK_SIZE_BYTES PIOS_ACTUATOR_STACK_SIZE +#define STACK_SIZE_BYTES PIOS_ACTUATOR_STACK_SIZE #else -#define STACK_SIZE_BYTES 1312 +#define STACK_SIZE_BYTES 1312 #endif -#define TASK_PRIORITY (tskIDLE_PRIORITY + 4) // device driver -#define FAILSAFE_TIMEOUT_MS 100 -#define MAX_MIX_ACTUATORS ACTUATORCOMMAND_CHANNEL_NUMELEM +#define TASK_PRIORITY (tskIDLE_PRIORITY + 4) // device driver +#define FAILSAFE_TIMEOUT_MS 100 +#define MAX_MIX_ACTUATORS ACTUATORCOMMAND_CHANNEL_NUMELEM -#define CAMERA_BOOT_DELAY_MS 7000 +#define CAMERA_BOOT_DELAY_MS 7000 +#define ACTUATOR_ONESHOT125_CLOCK 2000000 +#define ACTUATOR_ONESHOT125_PULSE_SCALE 4 +#define ACTUATOR_PWM_CLOCK 1000000 // Private types @@ -74,8 +77,9 @@ static int8_t counter; static xQueueHandle queue; static xTaskHandle taskHandle; -static float lastResult[MAX_MIX_ACTUATORS] = { 0, 0, 0, 0, 0, 0, 0, 0 }; -static float filterAccumulator[MAX_MIX_ACTUATORS] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +static float lastResult[MAX_MIX_ACTUATORS] = { 0 }; +static float filterAccumulator[MAX_MIX_ACTUATORS] = { 0 }; +static uint8_t pinsMode[MAX_MIX_ACTUATORS]; // used to inform the actuator thread that actuator update rate is changed static volatile bool actuator_settings_updated; // used to inform the actuator thread that mixer settings are changed @@ -436,7 +440,6 @@ static void actuatorTask(__attribute__((unused)) void *parameters) if (command.UpdateTime > command.MaxUpdateTime) { command.MaxUpdateTime = command.UpdateTime; } - // Update output object ActuatorCommandSet(&command); // Update in case read only (eg. during servo configuration) @@ -454,6 +457,8 @@ static void actuatorTask(__attribute__((unused)) void *parameters) success &= set_channel(n, command.Channel[n], &actuatorSettings); } + PIOS_Servo_Update(); + if (!success) { command.NumFailedUpdates++; ActuatorCommandSet(&command); @@ -476,11 +481,11 @@ float ProcessMixer(const int index, const float curve1, const float curve2, const Mixer_t *mixers = (Mixer_t *)&mixerSettings->Mixer1Type; // pointer to array of mixers in UAVObjects const Mixer_t *mixer = &mixers[index]; - float result = (((float)mixer->matrix[MIXERSETTINGS_MIXER1VECTOR_THROTTLECURVE1] / 128.0f) * curve1) + - (((float)mixer->matrix[MIXERSETTINGS_MIXER1VECTOR_THROTTLECURVE2] / 128.0f) * curve2) + - (((float)mixer->matrix[MIXERSETTINGS_MIXER1VECTOR_ROLL] / 128.0f) * desired->Roll) + - (((float)mixer->matrix[MIXERSETTINGS_MIXER1VECTOR_PITCH] / 128.0f) * desired->Pitch) + - (((float)mixer->matrix[MIXERSETTINGS_MIXER1VECTOR_YAW] / 128.0f) * desired->Yaw); + float result = ((((float)mixer->matrix[MIXERSETTINGS_MIXER1VECTOR_THROTTLECURVE1]) * curve1) + + (((float)mixer->matrix[MIXERSETTINGS_MIXER1VECTOR_THROTTLECURVE2]) * curve2) + + (((float)mixer->matrix[MIXERSETTINGS_MIXER1VECTOR_ROLL]) * desired->Roll) + + (((float)mixer->matrix[MIXERSETTINGS_MIXER1VECTOR_PITCH]) * desired->Pitch) + + (((float)mixer->matrix[MIXERSETTINGS_MIXER1VECTOR_YAW]) * desired->Yaw)) / 128.0f; // note: no feedforward for reversable motors yet for safety reasons if (mixer->type == MIXERSETTINGS_MIXER1TYPE_MOTOR) { @@ -615,6 +620,8 @@ static void setFailsafe(const ActuatorSettingsData *actuatorSettings, const Mixe for (int n = 0; n < ACTUATORCOMMAND_CHANNEL_NUMELEM; ++n) { set_channel(n, Channel[n], actuatorSettings); } + // Send the updated command + PIOS_Servo_Update(); // Update output object's parts that we changed ActuatorCommandChannelSet(Channel); @@ -730,8 +737,19 @@ static bool set_channel(uint8_t mixer_channel, uint16_t value, const ActuatorSet return true; case ACTUATORSETTINGS_CHANNELTYPE_PWM: - PIOS_Servo_Set(actuatorSettings->ChannelAddr[mixer_channel], value); + { + uint8_t mode = pinsMode[actuatorSettings->ChannelAddr[mixer_channel]]; + switch (mode) { + case ACTUATORSETTINGS_BANKMODE_ONESHOT125: + // Remap 1000-2000 range to 125-250 + PIOS_Servo_Set(actuatorSettings->ChannelAddr[mixer_channel], value / ACTUATOR_ONESHOT125_PULSE_SCALE); + break; + default: + PIOS_Servo_Set(actuatorSettings->ChannelAddr[mixer_channel], value); + break; + } return true; + } #if defined(PIOS_INCLUDE_I2C_ESC) case ACTUATORSETTINGS_CHANNELTYPE_MK: @@ -754,18 +772,57 @@ static bool set_channel(uint8_t mixer_channel, uint16_t value, const ActuatorSet */ static void actuator_update_rate_if_changed(const ActuatorSettingsData *actuatorSettings, bool force_update) { - static uint16_t prevChannelUpdateFreq[ACTUATORSETTINGS_CHANNELUPDATEFREQ_NUMELEM]; + static uint16_t prevBankUpdateFreq[ACTUATORSETTINGS_BANKUPDATEFREQ_NUMELEM]; + static uint8_t prevBankMode[ACTUATORSETTINGS_BANKMODE_NUMELEM]; // check if the any rate setting is changed if (force_update || - memcmp(prevChannelUpdateFreq, - actuatorSettings->ChannelUpdateFreq, - sizeof(prevChannelUpdateFreq)) != 0) { + (memcmp(prevBankUpdateFreq, + actuatorSettings->BankUpdateFreq, + sizeof(prevBankUpdateFreq)) != 0) || + (memcmp(prevBankUpdateFreq, + actuatorSettings->BankMode, + sizeof(prevBankMode)) != 0) + ) { /* Something has changed, apply the settings to HW */ - memcpy(prevChannelUpdateFreq, - actuatorSettings->ChannelUpdateFreq, - sizeof(prevChannelUpdateFreq)); - PIOS_Servo_SetHz(actuatorSettings->ChannelUpdateFreq, ACTUATORSETTINGS_CHANNELUPDATEFREQ_NUMELEM); + memcpy(prevBankUpdateFreq, + actuatorSettings->BankUpdateFreq, + sizeof(prevBankUpdateFreq)); + memcpy(prevBankMode, + actuatorSettings->BankMode, + sizeof(prevBankMode)); + + uint16_t freq[ACTUATORSETTINGS_BANKUPDATEFREQ_NUMELEM]; + uint32_t clock[ACTUATORSETTINGS_BANKUPDATEFREQ_NUMELEM] = { 0 }; + for (uint8_t i = 0; i < ACTUATORSETTINGS_BANKMODE_NUMELEM; i++) { + PIOS_Servo_SetBankMode(i, + actuatorSettings->BankMode[i] == + ACTUATORSETTINGS_BANKMODE_PWM ? + PIOS_SERVO_BANK_MODE_PWM : + PIOS_SERVO_BANK_MODE_SINGLE_PULSE + ); + switch (actuatorSettings->BankMode[i]) { + case ACTUATORSETTINGS_BANKMODE_ONESHOT125: + freq[i] = 100; // Value must be small enough so CCr isn't update until the PIOS_Servo_Update is triggered + clock[i] = ACTUATOR_ONESHOT125_CLOCK; // Setup an 8MHz timer clock + break; + case ACTUATORSETTINGS_BANKMODE_ONESHOT: + freq[i] = 100; + clock[i] = ACTUATOR_PWM_CLOCK; + break; + default: // PWM + freq[i] = actuatorSettings->BankUpdateFreq[i]; + clock[i] = ACTUATOR_PWM_CLOCK; + break; + } + } + PIOS_Servo_SetHz(freq, clock, ACTUATORSETTINGS_BANKUPDATEFREQ_NUMELEM); + + // retrieve mode from related bank + for (uint8_t i = 0; i < MAX_MIX_ACTUATORS; i++) { + uint8_t bank = PIOS_Servo_GetPinBank(i); + pinsMode[i] = actuatorSettings->BankMode[bank]; + } } } diff --git a/flight/pios/inc/pios_servo.h b/flight/pios/inc/pios_servo.h index fd905edbe..f3e9621ad 100644 --- a/flight/pios/inc/pios_servo.h +++ b/flight/pios/inc/pios_servo.h @@ -30,9 +30,17 @@ #ifndef PIOS_SERVO_H #define PIOS_SERVO_H +/* Global types */ +enum pios_servo_bank_mode { + PIOS_SERVO_BANK_MODE_PWM = 0, + PIOS_SERVO_BANK_MODE_SINGLE_PULSE = 1 +}; /* Public Functions */ -extern void PIOS_Servo_SetHz(const uint16_t *update_rates, uint8_t banks); +extern void PIOS_Servo_SetHz(const uint16_t *speeds, const uint32_t *clock, uint8_t banks); extern void PIOS_Servo_Set(uint8_t Servo, uint16_t Position); +extern void PIOS_Servo_Update(); +extern void PIOS_Servo_SetBankMode(uint8_t bank, uint8_t mode); +extern uint8_t PIOS_Servo_GetPinBank(uint8_t pin); #endif /* PIOS_SERVO_H */ diff --git a/flight/pios/posix/pios_servo.c b/flight/pios/posix/pios_servo.c index c3b4ba05b..ae00eaa04 100644 --- a/flight/pios/posix/pios_servo.c +++ b/flight/pios/posix/pios_servo.c @@ -43,13 +43,13 @@ static volatile uint16_t ServoPosition[PIOS_SERVO_NUM_TIMERS]; */ void PIOS_Servo_Init(void) {} - /** * Set the servo update rate (Max 500Hz) - * \param[in] onetofour Rate for outputs 1 to 4 (Hz) - * \param[in] fivetoeight Rate for outputs 5 to 8 (Hz) + * \param[in] array of rates in Hz + * \param[in] array of timer clocks in Hz + * \param[in] maximum number of banks */ -void PIOS_Servo_SetHz(const uint16_t *banks, uint8_t num_banks) +void PIOS_Servo_SetHz(const uint16_t *speeds, const uint32_t *clock, uint8_t banks) {} /** diff --git a/flight/pios/stm32f10x/pios_servo.c b/flight/pios/stm32f10x/pios_servo.c index a0ea16916..f0a11d8e2 100644 --- a/flight/pios/stm32f10x/pios_servo.c +++ b/flight/pios/stm32f10x/pios_servo.c @@ -39,6 +39,17 @@ static const struct pios_servo_cfg *servo_cfg; +// determine if the related timer will work in synchronous (or OneShot/OneShot125) One Pulse mode. +// static uint8_t pios_servo_bank_mode[PIOS_SERVO_BANKS] = { 0 }; + +// timer associated to each bank +static TIM_TypeDef *pios_servo_bank_timer[PIOS_SERVO_BANKS] = { 0 }; + +// index of bank used for each pin +static uint8_t *pios_servo_pin_bank; + +#define PIOS_SERVO_TIMER_CLOCK 1000000 + /** * Initialise Servos */ @@ -52,10 +63,36 @@ int32_t PIOS_Servo_Init(const struct pios_servo_cfg *cfg) /* Store away the requested configuration */ servo_cfg = cfg; + pios_servo_pin_bank = pios_malloc(sizeof(uint8_t) * cfg->num_channels); + uint8_t bank = 0; /* Configure the channels to be in output compare mode */ for (uint8_t i = 0; i < cfg->num_channels; i++) { - const struct pios_tim_channel *chan = &cfg->channels[i]; + const struct pios_tim_channel *chan = &servo_cfg->channels[i]; + bool new = true; + /* See if any previous channels use that same timer */ + for (uint8_t j = 0; (j < i) && new; j++) { + new &= chan->timer != servo_cfg->channels[j].timer; + } + + if (new) { + PIOS_Assert(bank < PIOS_SERVO_BANKS); + for (uint8_t j = i; j < servo_cfg->num_channels; j++) { + if (servo_cfg->channels[j].timer == chan->timer) { + pios_servo_pin_bank[j] = bank; + } + } + pios_servo_bank_timer[bank] = chan->timer; + + PIOS_Assert(bank < PIOS_SERVO_BANKS); + + for (uint8_t j = i; j < servo_cfg->num_channels; j++) { + if (servo_cfg->channels[j].timer == chan->timer) { + pios_servo_pin_bank[j] = bank; + } + } + bank++; + } /* Set up for output compare function */ switch (chan->timer_chan) { @@ -88,10 +125,12 @@ int32_t PIOS_Servo_Init(const struct pios_servo_cfg *cfg) /** * Set the servo update rate (Max 500Hz) * \param[in] array of rates in Hz + * \param[in] array of timer clocks in Hz * \param[in] maximum number of banks */ -void PIOS_Servo_SetHz(const uint16_t *speeds, uint8_t banks) +void PIOS_Servo_SetHz(const uint16_t *speeds, const uint32_t *clock, uint8_t banks) { + PIOS_Assert(banks <= PIOS_SERVO_BANKS); if (!servo_cfg) { return; } @@ -99,23 +138,18 @@ void PIOS_Servo_SetHz(const uint16_t *speeds, uint8_t banks) TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = servo_cfg->tim_base_init; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; - TIM_TimeBaseStructure.TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1; - uint8_t set = 0; + for (uint8_t i = 0; i < banks && i < PIOS_SERVO_BANKS; i++) { + const TIM_TypeDef *timer = pios_servo_bank_timer[i]; + if (timer) { + uint32_t new_clock = PIOS_SERVO_TIMER_CLOCK; + if (clock[i]) { + new_clock = clock[i]; + } + TIM_TimeBaseStructure.TIM_Prescaler = (PIOS_MASTER_CLOCK / new_clock) - 1; + TIM_TimeBaseStructure.TIM_Period = ((new_clock / speeds[i]) - 1); - for (uint8_t i = 0; (i < servo_cfg->num_channels) && (set < banks); i++) { - bool new = true; - const struct pios_tim_channel *chan = &servo_cfg->channels[i]; - - /* See if any previous channels use that same timer */ - for (uint8_t j = 0; (j < i) && new; j++) { - new &= chan->timer != servo_cfg->channels[j].timer; - } - - if (new) { - TIM_TimeBaseStructure.TIM_Period = ((1000000 / speeds[set]) - 1); - TIM_TimeBaseInit(chan->timer, &TIM_TimeBaseStructure); - set++; + TIM_TimeBaseInit((TIM_TypeDef *)timer, &TIM_TimeBaseStructure); } } } @@ -150,4 +184,27 @@ void PIOS_Servo_Set(uint8_t servo, uint16_t position) } } +void PIOS_Servo_Update() +{ + /* + for (uint8_t i = 0; (i < PIOS_SERVO_BANKS); i++) { + const TIM_TypeDef *timer = pios_servo_bank_timer[i]; + if (timer) { + TIM_Cmd((TIM_TypeDef *)timer, ENABLE); + } + } + */ +} + +void PIOS_Servo_SetBankMode(__attribute__((unused)) uint8_t bank, __attribute__((unused)) uint8_t mode) {} + +uint8_t PIOS_Servo_GetPinBank(uint8_t pin) +{ + if (pin < servo_cfg->num_channels) { + return pios_servo_pin_bank[pin]; + } else { + return 0; + } +} + #endif /* PIOS_INCLUDE_SERVO */ diff --git a/flight/pios/stm32f4xx/pios_servo.c b/flight/pios/stm32f4xx/pios_servo.c index 32803a57b..7e66c09e2 100644 --- a/flight/pios/stm32f4xx/pios_servo.c +++ b/flight/pios/stm32f4xx/pios_servo.c @@ -39,6 +39,19 @@ static const struct pios_servo_cfg *servo_cfg; +// determine if the related timer will work in synchronous (or OneShot/OneShot125) One Pulse mode. +static uint8_t pios_servo_bank_mode[PIOS_SERVO_BANKS] = { 0 }; +// used to skip updates when pulse length is higher than update cycle +static uint16_t pios_servo_bank_next_update[PIOS_SERVO_BANKS] = { 0 }; +static uint16_t pios_servo_bank_max_pulse[PIOS_SERVO_BANKS] = { 0 }; +// timer associated to each bank +static TIM_TypeDef *pios_servo_bank_timer[PIOS_SERVO_BANKS] = { 0 }; + +// index of bank used for each pin +static uint8_t *pios_servo_pin_bank; + +#define PIOS_SERVO_TIMER_CLOCK 1000000 +#define PIOS_SERVO_SAFE_MARGIN 50 /** * Initialise Servos */ @@ -52,46 +65,141 @@ int32_t PIOS_Servo_Init(const struct pios_servo_cfg *cfg) /* Store away the requested configuration */ servo_cfg = cfg; + pios_servo_pin_bank = pios_malloc(sizeof(uint8_t) * cfg->num_channels); - /* Configure the channels to be in output compare mode */ - for (uint8_t i = 0; i < cfg->num_channels; i++) { - const struct pios_tim_channel *chan = &cfg->channels[i]; + uint8_t bank = 0; + for (uint8_t i = 0; (i < servo_cfg->num_channels); i++) { + const struct pios_tim_channel *chan = &servo_cfg->channels[i]; + bool new = true; + /* See if any previous channels use that same timer */ + for (uint8_t j = 0; (j < i) && new; j++) { + new &= chan->timer != servo_cfg->channels[j].timer; + } + + if (new) { + PIOS_Assert(bank < PIOS_SERVO_BANKS); + for (uint8_t j = i; j < servo_cfg->num_channels; j++) { + if (servo_cfg->channels[j].timer == chan->timer) { + pios_servo_pin_bank[j] = bank; + } + } + pios_servo_bank_timer[bank] = chan->timer; + + TIM_ARRPreloadConfig(chan->timer, ENABLE); + TIM_CtrlPWMOutputs(chan->timer, ENABLE); + TIM_Cmd(chan->timer, DISABLE); + + bank++; + } /* Set up for output compare function */ switch (chan->timer_chan) { case TIM_Channel_1: - TIM_OC1Init(chan->timer, &cfg->tim_oc_init); + TIM_OC1Init(chan->timer, &servo_cfg->tim_oc_init); TIM_OC1PreloadConfig(chan->timer, TIM_OCPreload_Enable); break; case TIM_Channel_2: - TIM_OC2Init(chan->timer, &cfg->tim_oc_init); + TIM_OC2Init(chan->timer, &servo_cfg->tim_oc_init); TIM_OC2PreloadConfig(chan->timer, TIM_OCPreload_Enable); break; case TIM_Channel_3: - TIM_OC3Init(chan->timer, &cfg->tim_oc_init); + TIM_OC3Init(chan->timer, &servo_cfg->tim_oc_init); TIM_OC3PreloadConfig(chan->timer, TIM_OCPreload_Enable); break; case TIM_Channel_4: - TIM_OC4Init(chan->timer, &cfg->tim_oc_init); + TIM_OC4Init(chan->timer, &servo_cfg->tim_oc_init); TIM_OC4PreloadConfig(chan->timer, TIM_OCPreload_Enable); break; } - - TIM_ARRPreloadConfig(chan->timer, ENABLE); - TIM_CtrlPWMOutputs(chan->timer, ENABLE); - TIM_Cmd(chan->timer, ENABLE); } return 0; } +void PIOS_Servo_SetBankMode(uint8_t bank, uint8_t mode) +{ + PIOS_Assert(bank < PIOS_SERVO_BANKS); + pios_servo_bank_mode[bank] = mode; + + if (pios_servo_bank_timer[bank]) { + for (uint8_t i = 0; (i < servo_cfg->num_channels); i++) { + if (pios_servo_pin_bank[i] == bank) { + const struct pios_tim_channel *chan = &servo_cfg->channels[i]; + /* Set up for output compare function */ + switch (chan->timer_chan) { + case TIM_Channel_1: + TIM_OC1PolarityConfig(chan->timer, TIM_OCPolarity_High); + break; + case TIM_Channel_2: + TIM_OC2PolarityConfig(chan->timer, TIM_OCPolarity_High); + break; + case TIM_Channel_3: + TIM_OC3PolarityConfig(chan->timer, TIM_OCPolarity_High); + break; + case TIM_Channel_4: + TIM_OC4PolarityConfig(chan->timer, TIM_OCPolarity_High); + break; + } + } + } + if (mode != PIOS_SERVO_BANK_MODE_PWM) { + // TIM_UpdateDisableConfig(pios_servo_bank_timer[bank], ENABLE); + } else { + // TIM_UpdateDisableConfig(pios_servo_bank_timer[bank], DISABLE); + } + // Setup the timer accordingly + TIM_SelectOnePulseMode(pios_servo_bank_timer[bank], TIM_OPMode_Repetitive); + TIM_Cmd(pios_servo_bank_timer[bank], ENABLE); + } +} + + +void PIOS_Servo_Update() +{ + for (uint8_t i = 0; (i < PIOS_SERVO_BANKS); i++) { + const TIM_TypeDef *timer = pios_servo_bank_timer[i]; + if (timer && pios_servo_bank_mode[i] == PIOS_SERVO_BANK_MODE_SINGLE_PULSE) { + // a pulse to be generated is longer than cycle period. skip this update. + if (TIM_GetCounter((TIM_TypeDef *)timer) > (uint32_t)(pios_servo_bank_next_update[i] + PIOS_SERVO_SAFE_MARGIN)) { + TIM_GenerateEvent((TIM_TypeDef *)timer, TIM_EventSource_Update); + pios_servo_bank_next_update[i] = pios_servo_bank_max_pulse[i]; + } + } + pios_servo_bank_max_pulse[i] = 0; + } + for (uint8_t i = 0; (i < servo_cfg->num_channels); i++) { + uint8_t bank = pios_servo_pin_bank[i]; + uint8_t mode = pios_servo_bank_mode[bank]; + if (mode == PIOS_SERVO_BANK_MODE_SINGLE_PULSE) { + /* Update the position */ + const struct pios_tim_channel *chan = &servo_cfg->channels[i]; + + switch (chan->timer_chan) { + case TIM_Channel_1: + TIM_SetCompare1(chan->timer, 0); + break; + case TIM_Channel_2: + TIM_SetCompare2(chan->timer, 0); + break; + case TIM_Channel_3: + TIM_SetCompare3(chan->timer, 0); + break; + case TIM_Channel_4: + TIM_SetCompare4(chan->timer, 0); + break; + } + } + } +} /** * Set the servo update rate (Max 500Hz) * \param[in] array of rates in Hz + * \param[in] array of timer clocks in Hz * \param[in] maximum number of banks */ -void PIOS_Servo_SetHz(const uint16_t *speeds, uint8_t banks) +void PIOS_Servo_SetHz(const uint16_t *speeds, const uint32_t *clock, uint8_t banks) { + PIOS_Assert(banks <= PIOS_SERVO_BANKS); if (!servo_cfg) { return; } @@ -99,30 +207,22 @@ void PIOS_Servo_SetHz(const uint16_t *speeds, uint8_t banks) TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = servo_cfg->tim_base_init; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; - // - uint8_t set = 0; - - for (uint8_t i = 0; (i < servo_cfg->num_channels) && (set < banks); i++) { - bool new = true; - const struct pios_tim_channel *chan = &servo_cfg->channels[i]; - - /* See if any previous channels use that same timer */ - for (uint8_t j = 0; (j < i) && new; j++) { - new &= chan->timer != servo_cfg->channels[j].timer; - } - - if (new) { - // Choose the correct prescaler value for the APB the timer is attached - if (chan->timer == TIM1 || chan->timer == TIM8 || chan->timer == TIM9 || chan->timer == TIM10 || chan->timer == TIM11) { - TIM_TimeBaseStructure.TIM_Prescaler = (PIOS_PERIPHERAL_APB2_CLOCK / 1000000) - 1; - } else { - TIM_TimeBaseStructure.TIM_Prescaler = (PIOS_PERIPHERAL_APB1_CLOCK / 1000000) - 1; + for (uint8_t i = 0; i < banks && i < PIOS_SERVO_BANKS; i++) { + const TIM_TypeDef *timer = pios_servo_bank_timer[i]; + if (timer) { + uint32_t new_clock = PIOS_SERVO_TIMER_CLOCK; + if (clock[i]) { + new_clock = clock[i]; } - - TIM_TimeBaseStructure.TIM_Period = ((1000000 / speeds[set]) - 1); - TIM_TimeBaseInit(chan->timer, &TIM_TimeBaseStructure); - set++; + // Choose the correct prescaler value for the APB the timer is attached + if (timer == TIM1 || timer == TIM8 || timer == TIM9 || timer == TIM10 || timer == TIM11) { + TIM_TimeBaseStructure.TIM_Prescaler = (PIOS_PERIPHERAL_APB2_CLOCK / new_clock) - 1; + } else { + TIM_TimeBaseStructure.TIM_Prescaler = (PIOS_PERIPHERAL_APB1_CLOCK / new_clock) - 1; + } + TIM_TimeBaseStructure.TIM_Period = ((new_clock / speeds[i]) - 1); + TIM_TimeBaseInit((TIM_TypeDef *)timer, &TIM_TimeBaseStructure); } } } @@ -139,22 +239,42 @@ void PIOS_Servo_Set(uint8_t servo, uint16_t position) return; } + /* Update the position */ const struct pios_tim_channel *chan = &servo_cfg->channels[servo]; + uint16_t val = position; + uint16_t margin = chan->timer->ARR / 50; // Leave 2% of period as margin to prevent overlaps + if (val > (chan->timer->ARR - margin)) { + val = chan->timer->ARR - margin; + } + + uint8_t bank = pios_servo_pin_bank[servo]; + if (pios_servo_bank_max_pulse[bank] < val) { + pios_servo_bank_max_pulse[bank] = val; + } switch (chan->timer_chan) { case TIM_Channel_1: - TIM_SetCompare1(chan->timer, position); + TIM_SetCompare1(chan->timer, val); break; case TIM_Channel_2: - TIM_SetCompare2(chan->timer, position); + TIM_SetCompare2(chan->timer, val); break; case TIM_Channel_3: - TIM_SetCompare3(chan->timer, position); + TIM_SetCompare3(chan->timer, val); break; case TIM_Channel_4: - TIM_SetCompare4(chan->timer, position); + TIM_SetCompare4(chan->timer, val); break; } } +uint8_t PIOS_Servo_GetPinBank(uint8_t pin) +{ + if (pin < servo_cfg->num_channels) { + return pios_servo_pin_bank[pin]; + } else { + return 0; + } +} + #endif /* PIOS_INCLUDE_SERVO */ diff --git a/flight/targets/boards/coptercontrol/pios_board.h b/flight/targets/boards/coptercontrol/pios_board.h index 0c131518b..f3c3e34d3 100644 --- a/flight/targets/boards/coptercontrol/pios_board.h +++ b/flight/targets/boards/coptercontrol/pios_board.h @@ -251,6 +251,7 @@ extern uint32_t pios_com_hkosd_id; // ------------------------- #define PIOS_SERVO_UPDATE_HZ 50 #define PIOS_SERVOS_INITIAL_POSITION 0 /* dont want to start motors, have no pulse till settings loaded */ +#define PIOS_SERVO_BANKS 6 // -------------------------- // Timer controller settings diff --git a/flight/targets/boards/discoveryf4bare/pios_board.h b/flight/targets/boards/discoveryf4bare/pios_board.h index 0a7b0e50b..82e8df8f9 100644 --- a/flight/targets/boards/discoveryf4bare/pios_board.h +++ b/flight/targets/boards/discoveryf4bare/pios_board.h @@ -248,6 +248,7 @@ extern uint32_t pios_packet_handler; // ------------------------- #define PIOS_SERVO_UPDATE_HZ 50 #define PIOS_SERVOS_INITIAL_POSITION 0 /* dont want to start motors, have no pulse till settings loaded */ +#define PIOS_SERVO_BANKS 6 // -------------------------- // Timer controller settings diff --git a/flight/targets/boards/oplinkmini/pios_board.h b/flight/targets/boards/oplinkmini/pios_board.h index 4a976fc3e..b571a87d4 100644 --- a/flight/targets/boards/oplinkmini/pios_board.h +++ b/flight/targets/boards/oplinkmini/pios_board.h @@ -260,6 +260,7 @@ extern uint32_t pios_ppm_out_id; // ------------------------- #define PIOS_SERVO_UPDATE_HZ 50 #define PIOS_SERVOS_INITIAL_POSITION 0 /* dont want to start motors, have no pulse till settings loaded */ +#define PIOS_SERVO_BANKS 6 // -------------------------- // Timer controller settings diff --git a/flight/targets/boards/osd/pios_board.h b/flight/targets/boards/osd/pios_board.h index 9b88a5e3b..f0068f978 100644 --- a/flight/targets/boards/osd/pios_board.h +++ b/flight/targets/boards/osd/pios_board.h @@ -247,6 +247,8 @@ extern uint32_t pios_com_telem_usb_id; // -------------------------- #define PIOS_TIM_MAX_DEVS 6 +#define PIOS_SERVO_BANKS 6 + // ------------------------- // USB // ------------------------- diff --git a/flight/targets/boards/revolution/pios_board.h b/flight/targets/boards/revolution/pios_board.h index 09a2be105..7f9ab9d77 100644 --- a/flight/targets/boards/revolution/pios_board.h +++ b/flight/targets/boards/revolution/pios_board.h @@ -268,7 +268,7 @@ extern uint32_t pios_packet_handler; // ------------------------- #define PIOS_SERVO_UPDATE_HZ 50 #define PIOS_SERVOS_INITIAL_POSITION 0 /* dont want to start motors, have no pulse till settings loaded */ - +#define PIOS_SERVO_BANKS 6 // -------------------------- // Timer controller settings // -------------------------- diff --git a/flight/targets/boards/revoproto/pios_board.h b/flight/targets/boards/revoproto/pios_board.h index 6da2bbd9c..d3a421114 100644 --- a/flight/targets/boards/revoproto/pios_board.h +++ b/flight/targets/boards/revoproto/pios_board.h @@ -225,6 +225,7 @@ extern uint32_t pios_com_hkosd_id; // ------------------------- #define PIOS_SERVO_UPDATE_HZ 50 #define PIOS_SERVOS_INITIAL_POSITION 0 /* dont want to start motors, have no pulse till settings loaded */ +#define PIOS_SERVO_BANKS 6 // -------------------------- // Timer controller settings diff --git a/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp b/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp index 769c25066..f1a767614 100644 --- a/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp @@ -98,9 +98,18 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren addWidget(ui->cb_outputRate1); addWidget(ui->spinningArmed); + addWidgetBinding("ActuatorSettings", "BankMode", ui->cb_outputMode1, 0, 0, true); + addWidgetBinding("ActuatorSettings", "BankMode", ui->cb_outputMode2, 1, 0, true); + addWidgetBinding("ActuatorSettings", "BankMode", ui->cb_outputMode3, 2, 0, true); + addWidgetBinding("ActuatorSettings", "BankMode", ui->cb_outputMode4, 3, 0, true); + addWidgetBinding("ActuatorSettings", "BankMode", ui->cb_outputMode5, 4, 0, true); + addWidgetBinding("ActuatorSettings", "BankMode", ui->cb_outputMode6, 5, 0, true); + disconnect(this, SLOT(refreshWidgetsValues(UAVObject *))); + populateWidgets(); refreshWidgetsValues(); + updateEnableControls(); } @@ -240,6 +249,17 @@ void ConfigOutputWidget::sendChannelTest(int index, int value) actuatorCommand->setData(actuatorCommandFields); } +void ConfigOutputWidget::setColor(QWidget *widget, const QColor color) +{ + QPalette p(palette()); + + p.setColor(QPalette::Background, color); + p.setColor(QPalette::Base, color); + p.setColor(QPalette::Active, QPalette::Button, color); + p.setColor(QPalette::Inactive, QPalette::Button, color); + widget->setAutoFillBackground(true); + widget->setPalette(p); +} /******************************** * Output settings @@ -250,22 +270,33 @@ void ConfigOutputWidget::sendChannelTest(int index, int value) */ void ConfigOutputWidget::refreshWidgetsValues(UAVObject *obj) { - Q_UNUSED(obj); - bool dirty = isDirty(); + ConfigTaskWidget::refreshWidgetsValues(obj); + // Get Actuator Settings ActuatorSettings *actuatorSettings = ActuatorSettings::GetInstance(getObjectManager()); + Q_ASSERT(actuatorSettings); ActuatorSettings::DataFields actuatorSettingsData = actuatorSettings->getData(); // Get channel descriptions - QStringList ChannelDesc = ConfigVehicleTypeWidget::getChannelDescriptions(); + QStringList channelDesc = ConfigVehicleTypeWidget::getChannelDescriptions(); + + QList channelBanks; + QList bankColors; + bankColors + << QColor("#C6ECAE") + << QColor("#91E5D3") + << QColor("#FCEC52") + << QColor("#C3A8FF") + << QColor("#F7F7F2") + << QColor("#FF9F51"); // Initialize output forms QList outputChannelForms = findChildren(); foreach(OutputChannelForm * outputChannelForm, outputChannelForms) { - outputChannelForm->setName(ChannelDesc[outputChannelForm->index()]); + outputChannelForm->setName(channelDesc[outputChannelForm->index()]); // init min,max,neutral int minValue = actuatorSettingsData.ChannelMin[outputChannelForm->index()]; @@ -279,89 +310,78 @@ void ConfigOutputWidget::refreshWidgetsValues(UAVObject *obj) // Get the SpinWhileArmed setting ui->spinningArmed->setChecked(actuatorSettingsData.MotorsSpinWhileArmed == ActuatorSettings::MOTORSSPINWHILEARMED_TRUE); - // Setup output rates for all banks - if (ui->cb_outputRate1->findText(QString::number(actuatorSettingsData.ChannelUpdateFreq[0])) == -1) { - ui->cb_outputRate1->addItem(QString::number(actuatorSettingsData.ChannelUpdateFreq[0])); - } - if (ui->cb_outputRate2->findText(QString::number(actuatorSettingsData.ChannelUpdateFreq[1])) == -1) { - ui->cb_outputRate2->addItem(QString::number(actuatorSettingsData.ChannelUpdateFreq[1])); - } - if (ui->cb_outputRate3->findText(QString::number(actuatorSettingsData.ChannelUpdateFreq[2])) == -1) { - ui->cb_outputRate3->addItem(QString::number(actuatorSettingsData.ChannelUpdateFreq[2])); - } - if (ui->cb_outputRate4->findText(QString::number(actuatorSettingsData.ChannelUpdateFreq[3])) == -1) { - ui->cb_outputRate4->addItem(QString::number(actuatorSettingsData.ChannelUpdateFreq[3])); - } - if (ui->cb_outputRate5->findText(QString::number(actuatorSettingsData.ChannelUpdateFreq[4])) == -1) { - ui->cb_outputRate5->addItem(QString::number(actuatorSettingsData.ChannelUpdateFreq[4])); - } - if (ui->cb_outputRate6->findText(QString::number(actuatorSettingsData.ChannelUpdateFreq[5])) == -1) { - ui->cb_outputRate6->addItem(QString::number(actuatorSettingsData.ChannelUpdateFreq[5])); - } - ui->cb_outputRate1->setCurrentIndex(ui->cb_outputRate1->findText(QString::number(actuatorSettingsData.ChannelUpdateFreq[0]))); - ui->cb_outputRate2->setCurrentIndex(ui->cb_outputRate2->findText(QString::number(actuatorSettingsData.ChannelUpdateFreq[1]))); - ui->cb_outputRate3->setCurrentIndex(ui->cb_outputRate3->findText(QString::number(actuatorSettingsData.ChannelUpdateFreq[2]))); - ui->cb_outputRate4->setCurrentIndex(ui->cb_outputRate4->findText(QString::number(actuatorSettingsData.ChannelUpdateFreq[3]))); - ui->cb_outputRate5->setCurrentIndex(ui->cb_outputRate5->findText(QString::number(actuatorSettingsData.ChannelUpdateFreq[4]))); - ui->cb_outputRate6->setCurrentIndex(ui->cb_outputRate6->findText(QString::number(actuatorSettingsData.ChannelUpdateFreq[5]))); + QList bank; + bank << ui->chBank1 << ui->chBank2 << ui->chBank3 << ui->chBank4 << ui->chBank5 << ui->chBank6; - // Reset to all disabled - ui->chBank1->setText("-"); - ui->chBank2->setText("-"); - ui->chBank3->setText("-"); - ui->chBank4->setText("-"); - ui->chBank5->setText("-"); - ui->chBank6->setText("-"); - ui->cb_outputRate1->setEnabled(false); - ui->cb_outputRate2->setEnabled(false); - ui->cb_outputRate3->setEnabled(false); - ui->cb_outputRate4->setEnabled(false); - ui->cb_outputRate5->setEnabled(false); - ui->cb_outputRate6->setEnabled(false); + QList outputRateCombos; + outputRateCombos << ui->cb_outputRate1 << ui->cb_outputRate2 << ui->cb_outputRate3 << + ui->cb_outputRate4 << ui->cb_outputRate5 << ui->cb_outputRate6; + + QList outputModeCombos; + outputModeCombos << ui->cb_outputMode1 << ui->cb_outputMode2 << ui->cb_outputMode3 << + ui->cb_outputMode4 << ui->cb_outputMode5 << ui->cb_outputMode6; + + Q_ASSERT(outputModeCombos.count() == outputRateCombos.count()); + Q_ASSERT(outputRateCombos.count() == bank.count()); + + for(int i = 0; i < outputModeCombos.count();i++){ + // Setup output rates for all banks + if (outputRateCombos.at(i)->findText(QString::number(actuatorSettingsData.BankUpdateFreq[i])) == -1) { + outputRateCombos.at(i)->addItem(QString::number(actuatorSettingsData.BankUpdateFreq[i])); + } + outputRateCombos.at(i)->setCurrentIndex(outputRateCombos.at(i)->findText(QString::number(actuatorSettingsData.BankUpdateFreq[i]))); + + // Reset to all disabled + bank.at(i)->setText("-"); + + outputRateCombos.at(i)->setEnabled(false); + setColor(outputRateCombos.at(i), palette().color(QPalette::Background)); + + outputModeCombos.at(i)->setEnabled(false); + setColor(outputModeCombos.at(i), palette().color(QPalette::Background)); + } // Get connected board model ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); Q_ASSERT(pm); UAVObjectUtilManager *utilMngr = pm->getObject(); Q_ASSERT(utilMngr); + QStringList bankLabels; if (utilMngr) { int board = utilMngr->getBoardModel(); // Setup labels and combos for banks according to board type if ((board & 0xff00) == 0x0400) { // Coptercontrol family of boards 4 timer banks - ui->chBank1->setText("1-3"); - ui->chBank2->setText("4"); - ui->chBank3->setText("5,7-8"); - ui->chBank4->setText("6,9-10"); - ui->cb_outputRate1->setEnabled(true); - ui->cb_outputRate2->setEnabled(true); - ui->cb_outputRate3->setEnabled(true); - ui->cb_outputRate4->setEnabled(true); + bankLabels << "1 (1-3)" << "2 (4)" << "3 (5,7-8)" << "4 (6,9-10)"; + channelBanks << 1 << 1 << 1 << 2 << 3 << 4 << 3 << 3 << 4 << 4; } else if ((board & 0xff00) == 0x0900) { // Revolution family of boards 6 timer banks - ui->chBank1->setText("1-2"); - ui->chBank2->setText("3"); - ui->chBank3->setText("4"); - ui->chBank4->setText("5-6"); - ui->chBank5->setText("7-8"); - ui->chBank6->setText("9-10"); - ui->cb_outputRate1->setEnabled(true); - ui->cb_outputRate2->setEnabled(true); - ui->cb_outputRate3->setEnabled(true); - ui->cb_outputRate4->setEnabled(true); - ui->cb_outputRate5->setEnabled(true); - ui->cb_outputRate6->setEnabled(true); + bankLabels << "1 (1-2)" << "2 (3)" << "3 (4)" << "4 (5-6)" << "5 (7-8)" << "6 (9-10)"; + channelBanks << 1 << 1 << 2 << 3 << 4 << 4 << 5 << 5 << 6 << 6; } } + int i = 0; + foreach(QString banklabel, bankLabels) { + bank[i]->setText(banklabel); + outputRateCombos[i]->setEnabled(true); + setColor(outputRateCombos[i], bankColors[i]); + outputModeCombos[i]->setEnabled(true); + setColor(outputModeCombos[i], bankColors[i]); + i++; + } // Get Channel ranges: + i = 0; foreach(OutputChannelForm * outputChannelForm, outputChannelForms) { int minValue = actuatorSettingsData.ChannelMin[outputChannelForm->index()]; int maxValue = actuatorSettingsData.ChannelMax[outputChannelForm->index()]; outputChannelForm->setRange(minValue, maxValue); - + if (channelBanks.count() > i) { + outputChannelForm->setBank(QString("%1").arg(channelBanks.at(i))); + outputChannelForm->setColor(bankColors[channelBanks.at(i++) - 1]); + } int neutral = actuatorSettingsData.ChannelNeutral[outputChannelForm->index()]; outputChannelForm->setNeutral(neutral); } @@ -374,7 +394,7 @@ void ConfigOutputWidget::refreshWidgetsValues(UAVObject *obj) */ void ConfigOutputWidget::updateObjectsFromWidgets() { - emit updateObjectsFromWidgetsRequested(); + ConfigTaskWidget::updateObjectsFromWidgets(); ActuatorSettings *actuatorSettings = ActuatorSettings::GetInstance(getObjectManager()); @@ -391,12 +411,12 @@ void ConfigOutputWidget::updateObjectsFromWidgets() } // Set update rates - actuatorSettingsData.ChannelUpdateFreq[0] = ui->cb_outputRate1->currentText().toUInt(); - actuatorSettingsData.ChannelUpdateFreq[1] = ui->cb_outputRate2->currentText().toUInt(); - actuatorSettingsData.ChannelUpdateFreq[2] = ui->cb_outputRate3->currentText().toUInt(); - actuatorSettingsData.ChannelUpdateFreq[3] = ui->cb_outputRate4->currentText().toUInt(); - actuatorSettingsData.ChannelUpdateFreq[4] = ui->cb_outputRate5->currentText().toUInt(); - actuatorSettingsData.ChannelUpdateFreq[5] = ui->cb_outputRate6->currentText().toUInt(); + actuatorSettingsData.BankUpdateFreq[0] = ui->cb_outputRate1->currentText().toUInt(); + actuatorSettingsData.BankUpdateFreq[1] = ui->cb_outputRate2->currentText().toUInt(); + actuatorSettingsData.BankUpdateFreq[2] = ui->cb_outputRate3->currentText().toUInt(); + actuatorSettingsData.BankUpdateFreq[3] = ui->cb_outputRate4->currentText().toUInt(); + actuatorSettingsData.BankUpdateFreq[4] = ui->cb_outputRate5->currentText().toUInt(); + actuatorSettingsData.BankUpdateFreq[5] = ui->cb_outputRate6->currentText().toUInt(); actuatorSettingsData.MotorsSpinWhileArmed = ui->spinningArmed->isChecked() ? ActuatorSettings::MOTORSSPINWHILEARMED_TRUE : diff --git a/ground/openpilotgcs/src/plugins/config/configoutputwidget.h b/ground/openpilotgcs/src/plugins/config/configoutputwidget.h index bb1d37c27..3b25fed69 100644 --- a/ground/openpilotgcs/src/plugins/config/configoutputwidget.h +++ b/ground/openpilotgcs/src/plugins/config/configoutputwidget.h @@ -59,6 +59,8 @@ private: void assignOutputChannel(UAVDataObject *obj, QString &str); + void setColor(QWidget *widget, const QColor color); + OutputChannelForm *getOutputChannelForm(const int index) const; void sendAllChannelTests(); diff --git a/ground/openpilotgcs/src/plugins/config/output.ui b/ground/openpilotgcs/src/plugins/config/output.ui index e80ea0764..f804aab1d 100644 --- a/ground/openpilotgcs/src/plugins/config/output.ui +++ b/ground/openpilotgcs/src/plugins/config/output.ui @@ -122,8 +122,8 @@ 0 0 - 674 - 677 + 680 + 672 @@ -157,7 +157,7 @@ - Output Update Speed + Output configuration @@ -183,7 +183,7 @@ - Channel: + Bank(Channels): Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -282,9 +282,15 @@ - Setup "RapidESC" here: usual value is 490 Hz for multirotor airframes. + Setup PWM rate here: usual value is 490 Hz for multirotor airframes. OneShot and OneShot125 does not use this value + + false + + + + 50 @@ -345,8 +351,10 @@ - Setup "RapidESC" here: usual value is 490 Hz for multirotor airframes. - + Setup PWM rate here: usual value is 490 Hz for multirotor airframes. OneShot and OneShot125 does not use this value + + + @@ -430,8 +438,10 @@ - Setup "RapidESC" here: usual value is 490 Hz for multirotor airframes. - + Setup PWM rate here: usual value is 490 Hz for multirotor airframes. OneShot and OneShot125 does not use this value + + + @@ -493,8 +503,10 @@ - Setup "RapidESC" here: usual value is 490 Hz for multirotor airframes. - + Setup PWM rate here: usual value is 490 Hz for multirotor airframes. OneShot and OneShot125 does not use this value + + + @@ -566,8 +578,10 @@ - Setup "RapidESC" here: usual value is 490 Hz for multirotor airframes. - + Setup PWM rate here: usual value is 490 Hz for multirotor airframes. OneShot and OneShot125 does not use this value + + + @@ -629,8 +643,10 @@ - Setup "RapidESC" here: usual value is 490 Hz for multirotor airframes. - + Setup PWM rate here: usual value is 490 Hz for multirotor airframes. OneShot and OneShot125 does not use this value + + + @@ -674,6 +690,190 @@ + + + + + 0 + 0 + + + + + 0 + 20 + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 5 + 20 + + + + + + + + + 0 + 0 + + + + + 0 + 20 + + + + Mode: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + false + + + + 0 + 0 + + + + + 0 + 20 + + + + Setup output mode. Use PWM or OneShot with Standard ESCs. +Several other ESCs like BLHeli 13+ can use the more advanced OneShot125. +When using OneShot125 all values set in min/max and idle are divided by eight before being sent to esc (i.e. 1000 = 125, 2000 = 250). + + + + + + + false + + + + 0 + 0 + + + + + 0 + 20 + + + + Setup output mode. Use PWM or OneShot with Standard ESCs.\nSeveral other ESCs like BLHeli 13+ can use the more advanced OneShot125.\nWhen using OneShot125 all values set in min/max and idle are divided by eight before being sent to esc (i.e. 1000 = 125, 2000 = 250). + + + + + + + false + + + + 0 + 0 + + + + + 0 + 20 + + + + Setup output mode. Use PWM or OneShot with Standard ESCs.\nSeveral other ESCs like BLHeli 13+ can use the more advanced OneShot125.\nWhen using OneShot125 all values set in min/max and idle are divided by eight before being sent to esc (i.e. 1000 = 125, 2000 = 250). + + + + + + + false + + + + 0 + 0 + + + + + 0 + 20 + + + + Setup output mode. Use PWM or OneShot with Standard ESCs.\nSeveral other ESCs like BLHeli 13+ can use the more advanced OneShot125.\nWhen using OneShot125 all values set in min/max and idle are divided by eight before being sent to esc (i.e. 1000 = 125, 2000 = 250). + + + + + + + false + + + + 0 + 0 + + + + + 0 + 20 + + + + Setup output mode. Use PWM or OneShot with Standard ESCs.\nSeveral other ESCs like BLHeli 13+ can use the more advanced OneShot125.\nWhen using OneShot125 all values set in min/max and idle are divided by eight before being sent to esc (i.e. 1000 = 125, 2000 = 250). + + + + + + + false + + + + 0 + 0 + + + + + 0 + 20 + + + + Setup output mode. Use PWM or OneShot with Standard ESCs.\nSeveral other ESCs like BLHeli 13+ can use the more advanced OneShot125.\nWhen using OneShot125 all values set in min/max and idle are divided by eight before being sent to esc (i.e. 1000 = 125, 2000 = 250). + + + diff --git a/ground/openpilotgcs/src/plugins/config/outputchannelform.cpp b/ground/openpilotgcs/src/plugins/config/outputchannelform.cpp index 0ca1ecaf7..8732aa43d 100644 --- a/ground/openpilotgcs/src/plugins/config/outputchannelform.cpp +++ b/ground/openpilotgcs/src/plugins/config/outputchannelform.cpp @@ -33,8 +33,8 @@ OutputChannelForm::OutputChannelForm(const int index, QWidget *parent) : ui.setupUi(this); // The convention for OP is Channel 1 to Channel 10. - ui.actuatorNumber->setText(QString("%1:").arg(index + 1)); - + ui.actuatorNumber->setText(QString("%1").arg(index + 1)); + setBank("-"); // Register for ActuatorSettings changes: connect(ui.actuatorMin, SIGNAL(editingFinished()), this, SLOT(setChannelRange())); connect(ui.actuatorMax, SIGNAL(editingFinished()), this, SLOT(setChannelRange())); @@ -58,6 +58,11 @@ QString OutputChannelForm::name() return ui.actuatorName->text(); } +QString OutputChannelForm::bank() +{ + return ui.actuatorBankNumber->text(); +} + /** * Set the channel assignment label. */ @@ -66,6 +71,25 @@ void OutputChannelForm::setName(const QString &name) ui.actuatorName->setText(name); } +void OutputChannelForm::setColor(const QColor &color) +{ + QString stylesheet = ui.actuatorNumberFrame->styleSheet(); + + stylesheet = stylesheet.split("background-color").first(); + stylesheet.append( + QString("background-color: rgb(%1, %2, %3)") + .arg(color.red()).arg(color.green()).arg(color.blue())); + ui.actuatorNumberFrame->setStyleSheet(stylesheet); +} + +/** + * Set the channel bank label. + */ +void OutputChannelForm::setBank(const QString &bank) +{ + ui.actuatorBankNumber->setText(bank); +} + /** * Restrict UI to protect users from accidental misuse. */ diff --git a/ground/openpilotgcs/src/plugins/config/outputchannelform.h b/ground/openpilotgcs/src/plugins/config/outputchannelform.h index 78d008115..e17155f41 100644 --- a/ground/openpilotgcs/src/plugins/config/outputchannelform.h +++ b/ground/openpilotgcs/src/plugins/config/outputchannelform.h @@ -43,8 +43,12 @@ public: friend class ConfigOutputWidget; virtual QString name(); - virtual void setName(const QString &name); + virtual QString bank(); + virtual void setName(const QString &name); + virtual void setBank(const QString &bank); + + virtual void setColor(const QColor &color); public slots: int min() const; void setMin(int minimum); diff --git a/ground/openpilotgcs/src/plugins/config/outputchannelform.ui b/ground/openpilotgcs/src/plugins/config/outputchannelform.ui index f6227939a..459841ace 100644 --- a/ground/openpilotgcs/src/plugins/config/outputchannelform.ui +++ b/ground/openpilotgcs/src/plugins/config/outputchannelform.ui @@ -7,7 +7,7 @@ 0 0 768 - 51 + 54 @@ -29,7 +29,7 @@ 12 - + @@ -72,7 +72,7 @@ margin:1px; - + @@ -115,7 +115,7 @@ margin:1px; - + @@ -152,7 +152,7 @@ margin:1px; - + Qt::Horizontal @@ -168,7 +168,7 @@ margin:1px; - + @@ -207,7 +207,7 @@ font: bold 12px; margin:1px; - # + # - Bank Qt::AlignCenter @@ -217,7 +217,7 @@ margin:1px; - + Qt::Horizontal @@ -233,7 +233,7 @@ margin:1px; - + Qt::Horizontal @@ -249,7 +249,7 @@ margin:1px; - + Qt::Horizontal @@ -265,7 +265,7 @@ margin:1px; - + @@ -289,7 +289,8 @@ margin:1px; Qt::StrongFocus - Minimum PWM value, beware of not overdriving your servo. + Minimum PWM value, beware of not overdriving your servo. +Using OneShot125 a value of 1000(uS) here will produce a pulse of 125(uS). Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -302,38 +303,151 @@ margin:1px; - - + + 0 0 - - - 20 - 0 - - - 16777215 - 16777215 + 100 + 22 - - Channel Number + + border-radius: 5; margin:1px; - - 0: + + QFrame::NoFrame - - Qt::AlignCenter + + QFrame::Raised + + + 2 + + + 0 + + + 2 + + + 0 + + + + + + 0 + 0 + + + + + 20 + 0 + + + + + 16777215 + 16777215 + + + + + 75 + true + + + + Channel Number + + + border-radius: 5;\nfont: bold 12px;\nmargin:1px; + + + 0 + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + border-radius: 5;\nfont: 12px;\nmargin:1px; + + + + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 20 + 0 + + + + + 16777215 + 16777215 + + + + Bank number + + + border-radius: 5;\nfont: 12px;\nmargin:1px; + + + 0 + + + Qt::AlignCenter + + + + - + @@ -376,7 +490,7 @@ margin:1px; - + @@ -419,7 +533,7 @@ margin:1px; - + @@ -462,7 +576,7 @@ margin:1px; - + @@ -490,7 +604,7 @@ margin:1px; - + @@ -514,7 +628,8 @@ margin:1px; Qt::StrongFocus - Maximum PWM value, beware of not overdriving your servo. + Maximum value, beware of not overdriving your servo. +Using OneShot125 a value of 2000(uS) here will produce a pulse of 250(uS). Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -524,8 +639,8 @@ margin:1px; - - + + 0 @@ -607,7 +722,7 @@ margin:1px; - + @@ -665,7 +780,7 @@ margin:1px; - + diff --git a/ground/openpilotgcs/src/plugins/setupwizard/vehicleconfigurationhelper.cpp b/ground/openpilotgcs/src/plugins/setupwizard/vehicleconfigurationhelper.cpp index 2a66485f5..81bf4fd40 100644 --- a/ground/openpilotgcs/src/plugins/setupwizard/vehicleconfigurationhelper.cpp +++ b/ground/openpilotgcs/src/plugins/setupwizard/vehicleconfigurationhelper.cpp @@ -404,32 +404,32 @@ void VehicleConfigurationHelper::applyActuatorConfiguration() data.MotorsSpinWhileArmed = ActuatorSettings::MOTORSSPINWHILEARMED_FALSE; - for (quint16 i = 0; i < ActuatorSettings::CHANNELUPDATEFREQ_NUMELEM; i++) { - data.ChannelUpdateFreq[i] = LEGACY_ESC_FREQUENCY; + for (quint16 i = 0; i < ActuatorSettings::BANKUPDATEFREQ_NUMELEM; i++) { + data.BankUpdateFreq[i] = LEGACY_ESC_FREQUENCY; } switch (m_configSource->getVehicleSubType()) { case VehicleConfigurationSource::MULTI_ROTOR_TRI_Y: // Servo always on channel 4 - data.ChannelUpdateFreq[0] = escFrequence; + data.BankUpdateFreq[0] = escFrequence; if (m_configSource->getControllerType() == VehicleConfigurationSource::CONTROLLER_CC || m_configSource->getControllerType() == VehicleConfigurationSource::CONTROLLER_CC3D) { - data.ChannelUpdateFreq[1] = servoFrequence; + data.BankUpdateFreq[1] = servoFrequence; } else if (m_configSource->getControllerType() == VehicleConfigurationSource::CONTROLLER_REVO) { - data.ChannelUpdateFreq[1] = escFrequence; - data.ChannelUpdateFreq[2] = servoFrequence; + data.BankUpdateFreq[1] = escFrequence; + data.BankUpdateFreq[2] = servoFrequence; } else if (m_configSource->getControllerType() == VehicleConfigurationSource::CONTROLLER_NANO) { - data.ChannelUpdateFreq[1] = escFrequence; - data.ChannelUpdateFreq[2] = escFrequence; - data.ChannelUpdateFreq[3] = servoFrequence; + data.BankUpdateFreq[1] = escFrequence; + data.BankUpdateFreq[2] = escFrequence; + data.BankUpdateFreq[3] = servoFrequence; } break; case VehicleConfigurationSource::MULTI_ROTOR_QUAD_X: case VehicleConfigurationSource::MULTI_ROTOR_QUAD_PLUS: - data.ChannelUpdateFreq[0] = escFrequence; - data.ChannelUpdateFreq[1] = escFrequence; + data.BankUpdateFreq[0] = escFrequence; + data.BankUpdateFreq[1] = escFrequence; if (m_configSource->getControllerType() == VehicleConfigurationSource::CONTROLLER_REVO) { - data.ChannelUpdateFreq[2] = escFrequence; + data.BankUpdateFreq[2] = escFrequence; } break; case VehicleConfigurationSource::MULTI_ROTOR_HEXA: @@ -441,10 +441,10 @@ void VehicleConfigurationHelper::applyActuatorConfiguration() case VehicleConfigurationSource::MULTI_ROTOR_OCTO_COAX_X: case VehicleConfigurationSource::MULTI_ROTOR_OCTO_COAX_PLUS: case VehicleConfigurationSource::MULTI_ROTOR_OCTO_V: - data.ChannelUpdateFreq[0] = escFrequence; - data.ChannelUpdateFreq[1] = escFrequence; - data.ChannelUpdateFreq[2] = escFrequence; - data.ChannelUpdateFreq[3] = escFrequence; + data.BankUpdateFreq[0] = escFrequence; + data.BankUpdateFreq[1] = escFrequence; + data.BankUpdateFreq[2] = escFrequence; + data.BankUpdateFreq[3] = escFrequence; break; default: break; @@ -467,15 +467,15 @@ void VehicleConfigurationHelper::applyActuatorConfiguration() data.ChannelMax[i] = actuatorSettings[i].channelMax; } - for (quint16 i = 0; i < ActuatorSettings::CHANNELUPDATEFREQ_NUMELEM; i++) { - data.ChannelUpdateFreq[i] = servoFrequence; + for (quint16 i = 0; i < ActuatorSettings::BANKUPDATEFREQ_NUMELEM; i++) { + data.BankUpdateFreq[i] = servoFrequence; if (m_configSource->getControllerType() == VehicleConfigurationSource::CONTROLLER_REVO) { if (i == 1) { - data.ChannelUpdateFreq[i] = escFrequence; + data.BankUpdateFreq[i] = escFrequence; } } else if (m_configSource->getControllerType() == VehicleConfigurationSource::CONTROLLER_NANO) { if (i == 2) { - data.ChannelUpdateFreq[i] = escFrequence; + data.BankUpdateFreq[i] = escFrequence; } } } @@ -503,15 +503,15 @@ void VehicleConfigurationHelper::applyActuatorConfiguration() data.ChannelMax[i] = actuatorSettings[i].channelMax; } - for (quint16 i = 0; i < ActuatorSettings::CHANNELUPDATEFREQ_NUMELEM; i++) { - data.ChannelUpdateFreq[i] = servoFrequence; + for (quint16 i = 0; i < ActuatorSettings::BANKUPDATEFREQ_NUMELEM; i++) { + data.BankUpdateFreq[i] = servoFrequence; if (m_configSource->getControllerType() == VehicleConfigurationSource::CONTROLLER_REVO) { if (i == 1) { - data.ChannelUpdateFreq[i] = escFrequence; + data.BankUpdateFreq[i] = escFrequence; } } else if (m_configSource->getControllerType() == VehicleConfigurationSource::CONTROLLER_NANO) { if (i == 2) { - data.ChannelUpdateFreq[i] = escFrequence; + data.BankUpdateFreq[i] = escFrequence; } } } diff --git a/shared/uavobjectdefinition/actuatorsettings.xml b/shared/uavobjectdefinition/actuatorsettings.xml index 051fdceb1..303770f4d 100644 --- a/shared/uavobjectdefinition/actuatorsettings.xml +++ b/shared/uavobjectdefinition/actuatorsettings.xml @@ -1,7 +1,15 @@ Settings for the @ref ActuatorModule that controls the channel assignments for the mixer based on AircraftType - + +