Index: firmware/App/Controllers/ROPump.c =================================================================== diff -u -r036a11ec6f48682b47e67ddcc7a7772d81647f4b -r5e8f96e11c797bddeddfc009c87f20df3b7a8664 --- firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision 036a11ec6f48682b47e67ddcc7a7772d81647f4b) +++ firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision 5e8f96e11c797bddeddfc009c87f20df3b7a8664) @@ -7,8 +7,8 @@ * * @file ROPump.c * -* @author (last) Bill Bracken -* @date (last) 24-Oct-2022 +* @author (last) Michael Garthwaite +* @date (last) 21-Nov-2022 * * @author (original) Sean * @date (original) 04-Apr-2020 @@ -36,6 +36,7 @@ #include "TaskGeneral.h" #include "TaskPriority.h" #include "Timers.h" +#include "Utilities.h" #include "Valves.h" /** @@ -51,13 +52,11 @@ #define MIN_RO_PUMP_DUTY_CYCLE 0.0F ///< Min duty cycle. #define ROP_CONTROL_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the RO pump is controlled. -#define ROP_RAMP_UP_CONTROL_INTERVAL ( 500 / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the RO pump is controlled. -#define ROP_RAMP_UP_P_COEFFICIENT 0.22F ///< P term for RO pump ramp up to flow control. -#define ROP_FLOW_CONTROL_P_COEFFICIENT 0.4F ///< P term for RO pump flow control. -#define ROP_FLOW_CONTROL_I_COEFFICIENT 0.3F ///< I term for RO pump flow control. +#define ROP_FLOW_CONTROL_P_COEFFICIENT 0.15F ///< P term for RO pump flow control. +#define ROP_FLOW_CONTROL_I_COEFFICIENT 0.65F ///< I term for RO pump flow control. #define ROP_MAX_PRESSURE_P_COEFFICIENT 0.01F ///< P term for RO pump max pressure control. #define ROP_MAX_PRESSURE_I_COEFFICIENT 0.01F ///< I term for RO pump max pressure control. - +#define ROP_PWM_STEP_LIMIT 0.50F ///< Current maximum PWM step limit used in RO Profiles. #define ROP_FLOW_TARGET_TOLERANCE 0.03F ///< Tolerance in between the target flow rate and the actual flow rate in percentage. #define ROP_RAMP_DOWN_DUTY_CYCLE_RATIO 0.03F ///< Pump ramp down duty cycle ratio when the pressure higher than max defined. @@ -70,7 +69,7 @@ // 110000 pulses/liter // For 2 LPM => 2LPM x 110000 pulses/liter * 1 edges/pulse * 1 min/60 seconds = 3666.66 counts/sec => 272.72 microseconds => for 1 LPM = 136.36 counts #define RO_FLOW_ADC_TO_LPM_FACTOR 272.72F ///< Conversion factor from ADC counts to LPM (liters/min) for RO flow rate (multiply this by inverse of FPGA reading). -#define ROP_FLOW_TO_PWM_SLOPE 0.1F ///< Slope of flow to PWM line equation. +#define ROP_FLOW_TO_PWM_SLOPE 0.5F ///< Slope of flow to PWM line equation. #define ROP_FLOW_TO_PWM_INTERCEPT 0.0F ///< Intercept of flow to PWM line equation. /// Initial conversion factor from target flow rate to PWM duty cycle estimate. @@ -133,15 +132,17 @@ static RO_PI_FLOW_PROFILES_T currentROPumpProfile; ///< RO Pump flow profile table. +///< Most values are currently the same until future efforts into tuning op modes. +///< TODO: Fine tune each op mode. static PI_CONTROLLER_PROFILE_DATA_T roPIFlowProfiles[ NUM_OF_RO_PI_FLOW_PROFILES ] = -{ // Kp Ki uMin uMax Control Interval - { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_FLUSH - { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_GEN_IDLE - { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_FILL - { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_DRAIN - { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_HEAT - { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_OPEN_LOOP -};// Kp Ki uMin uMax Control Interval +{ // Kp Ki uMin uMax maxErrorSumStep Control Interval + { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_PWM_STEP_LIMIT, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_FLUSH + { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_PWM_STEP_LIMIT, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_GEN_IDLE + { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_PWM_STEP_LIMIT, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_FILL + { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_PWM_STEP_LIMIT, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_DRAIN + { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_PWM_STEP_LIMIT, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_HEAT + { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_PWM_STEP_LIMIT, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_OPEN_LOOP +};// Kp Ki uMin uMax maxErrorSumStep Control Interval // ********** private function prototypes ********** @@ -156,7 +157,7 @@ static void setROPumpControlSignalDutyCycle( F32 dutyCycle ); static void stopROPump( void ); static void publishROPumpData( void ); -static F32 getROFeedbackVoltage( void ); +static F32 getROFeedbackDutyCycle( void ); /*********************************************************************//** * @brief @@ -217,9 +218,9 @@ * The setROPumpTargetFlowRate function sets a new target flow rate for the * RO pump. * @details Inputs: targetROPumpPressure, targetROPumpFlowRate, - * roPumpControlMode, rampUp2FlowTimeoutCounter + * roPumpControlMode, rampUp2FlowTimeoutCounter, currentROPumpProfile * @details Outputs: targetROPumpPressure, targetROPumpFlowRate, - * roPumpControlMode, rampUp2FlowTimeoutCounter + * roPumpControlMode, rampUp2FlowTimeoutCounter, roPumpPWMDutyCyclePct * @param roFlowRate which is target RO flow rate * @param maxPressure which is the maximum allowed pressure that the RO pump * can reach @@ -240,9 +241,8 @@ targetROPumpMaxPressure = maxPressure; targetROPumpFlowRateLPM = roFlowRate; roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; - roPumpState = RO_PUMP_RAMP_UP_TO_TARGET_FLOW_STATE; // Get the initial guess of the duty cycle - roPumpPWMDutyCyclePct = ROP_FLOW_TO_PWM_DC( roFlowRate ); + roPumpPWMDutyCyclePct = roPumpFlowToPWM( currentROPumpProfile, targetROPumpFlowRateLPM ); roControlTimerCounter = 0; isROPumpOn = TRUE; result = TRUE; @@ -338,10 +338,10 @@ * The execROPumpMonitor function executes the RO pump monitor. The RO flow * sensor is read, filtered, converted to L/min and calibrated. * @details Inputs: measuredFlowReadingsSum, flowFilterCounter, - * measuredROFlowRateLPM, measuredROFlowRateLPM, roPumpState, - * flowOutOfRangeCounter, roPumpControlMode + * measuredROFlowRateLPM, roPumpState, roPumpFeedbackDutyCyclePct, + * flowOutOfRangeCounter, roPumpControlMode, Ppo * @details Outputs: measuredFlowReadingsSum, flowFilterCounter, - * measuredROFlowRateLPM, measuredROFlowRateLPM + * measuredROFlowRateLPM, roVolumeL, roPumpFeedbackDutyCyclePct * @return none *************************************************************************/ void execROPumpMonitor( void ) @@ -390,15 +390,15 @@ } #ifndef _RELEASE_ - if ( getSoftwareConfigStatus( SW_CONFIG_ENABLE_V3_SYSTEM ) != SW_CONFIG_ENABLE_VALUE ) + if ( getHardwareConfigStatus() != HW_CONFIG_BETA ) #endif { // The feedback voltage is on the 0V line so when the duty cycle is 0, the feedback is 2.5V // The duty cycle is calculated by getting the 1 - (ratio of feedback / to the voltage at 0 percent duty cycle). roPumpFeedbackDutyCyclePct.data = 1.0F - ( roFeedbackVoltage / ROP_FEEDBACK_0_PCT_DUTY_CYCLE_VOLTAGE ); - isDutyCylceOutOfRange = ( fabs( getROFeedbackVoltage() - roPumpDutyCyclePctSet ) > ROP_DUTY_CYCLE_OUT_OF_RANGE_TOLERANCE ? TRUE : FALSE ); + isDutyCylceOutOfRange = ( fabs( getROFeedbackDutyCycle() - roPumpDutyCyclePctSet ) > ROP_DUTY_CYCLE_OUT_OF_RANGE_TOLERANCE ? TRUE : FALSE ); - checkPersistentAlarm( ALARM_ID_RO_PUMP_DUTY_CYCLE_OUT_OF_RANGE, isDutyCylceOutOfRange, getROFeedbackVoltage(), roPumpDutyCyclePctSet ); + checkPersistentAlarm( ALARM_ID_RO_PUMP_DUTY_CYCLE_OUT_OF_RANGE, isDutyCylceOutOfRange, getROFeedbackDutyCycle(), roPumpDutyCyclePctSet ); // Check if it the alarm has timed out and if the pump is supposed to be off but it is still on, activate the safety shutdown if ( ( TRUE == isAlarmActive( ALARM_ID_RO_PUMP_DUTY_CYCLE_OUT_OF_RANGE ) ) && ( FALSE == isROPumpOn ) ) @@ -432,7 +432,6 @@ pendingROPumpCmdMaxPressure = 0.0F; pendingROPumpCmdTargetFlow = 0.0F; roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; - roPumpState = RO_PUMP_RAMP_UP_TO_TARGET_FLOW_STATE; // Get the initial guess of the duty cycle roPumpPWMDutyCyclePct = roPumpFlowToPWM( currentROPumpProfile, targetROPumpFlowRateLPM ); roControlTimerCounter = 0; @@ -539,17 +538,17 @@ /*********************************************************************//** * @brief - * The getROFeedbackVoltage function returns the RO pump feedback - * voltage. + * The getROFeedbackDutyCyle function returns the RO pump feedback + * duty cycle. * @details Inputs: roPumpFeedbackDutyCyclePct * @details Outputs: none - * @return ro pump voltage feedback + * @return ro pump feedback duty cycle *************************************************************************/ -static F32 getROFeedbackVoltage( void ) +static F32 getROFeedbackDutyCycle( void ) { - F32 feedbackVotlage = getF32OverrideValue( &roPumpFeedbackDutyCyclePct ); + F32 feedbackdutyCycle = getF32OverrideValue( &roPumpFeedbackDutyCyclePct ); - return feedbackVotlage; + return feedbackdutyCycle; } /*********************************************************************//** @@ -578,17 +577,17 @@ RO_PUMP_STATE_T state = RO_PUMP_OFF_STATE; // If there is a flow, transition to the PI controller to get the corresponding pressure of that flow - if ( getTargetROPumpFlowRateLPM() > 0.0F && roPumpControlMode == PUMP_CONTROL_MODE_CLOSED_LOOP ) + if ( ( getTargetROPumpFlowRateLPM() > 0.0F ) && ( PUMP_CONTROL_MODE_CLOSED_LOOP == roPumpControlMode ) ) { // Set pump to on isROPumpOn = TRUE; roPumpDutyCyclePctSet = roPumpFlowToPWM( currentROPumpProfile, getTargetROPumpFlowRateLPM() ); setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); - state = RO_PUMP_RAMP_UP_TO_TARGET_FLOW_STATE; + state = RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE; } // If the target duty cycle is greater than zero (minimum is 10%) and the mode has been set to open // loop, set the duty cycle - if ( roPumpOpenLoopTargetDutyCycle > 0.0F && roPumpControlMode == PUMP_CONTROL_MODE_OPEN_LOOP ) + if ( ( roPumpOpenLoopTargetDutyCycle > 0.0F ) && ( PUMP_CONTROL_MODE_OPEN_LOOP == roPumpControlMode ) ) { setROPumpControlSignalDutyCycle( roPumpOpenLoopTargetDutyCycle ); isROPumpOn = TRUE; @@ -602,55 +601,16 @@ * @brief * The handleROPumpRampUpToTargetFlowState function handles the RO pump * ramp up to flow state of the controller state machine. - * @details Inputs: roControlTimerCounter, roPumpPWMDutyCyclePctSet, - * rampUp2FlowTimeoutCounter - * @details Outputs: roControlTimerCounter, roPumpPWMDutyCyclePctSet, - * rampUp2FlowTimeoutCounter + * @details Inputs: none + * @details Outputs: none * @return next state of the controller state machine *************************************************************************/ static RO_PUMP_STATE_T handleROPumpRampUpToTargetFlowState( void ) { - RO_PUMP_STATE_T state = RO_PUMP_RAMP_UP_TO_TARGET_FLOW_STATE; + RO_PUMP_STATE_T state = RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE; - // Get the current pressure from the sensor - F32 actualPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); - F32 targetFlowRate = getTargetROPumpFlowRateLPM(); - F32 actualFlowRate = getMeasuredFlowRateLPM( RO_FLOW_SENSOR ); - F32 flowRateDeviation = fabs( targetFlowRate - actualFlowRate ) / targetFlowRate; - BOOL isFlowOutOfRange = flowRateDeviation > ROP_FLOW_TARGET_TOLERANCE; - F32 targetPressure = getTargetROPumpPressurePSI(); + // TODO - remove function and state - obsolete - if ( ++roControlTimerCounter >= ROP_RAMP_UP_CONTROL_INTERVAL ) - { - // If the actual pressure is greater than the target pressure or it is within the tolerance of the maximum pressure, move to set - // to target pressure straight. At the beginning the maximum pressure is set in the targetROPumpPressure override variable. - // If the flow rate was reached without reaching to maximum pressure, the pressure that was set to targetROPumpPressure override will - // be reset to the corresponding pressure of the target flow rate. - if ( ( actualPressure > targetPressure ) || ( ( targetPressure - actualPressure ) < MAX_PRESSURE_TARGET_TOLERANCE ) ) - { - resetPIController( PI_CONTROLLER_ID_RO_PUMP_MAX_PRES, roPumpDutyCyclePctSet ); - state = RO_PUMP_CONTROL_TO_MAX_PRESSURE_STATE; - } - // If the actual flow is still far from target flow, update the duty cycle using the I controller and stay in this state - else if ( TRUE == isFlowOutOfRange ) - { - roPumpDutyCyclePctSet += ( targetFlowRate - actualFlowRate ) * ROP_RAMP_UP_P_COEFFICIENT; - // If the duty cycle is out of the define range for the RO pump, set the boundaries - roPumpDutyCyclePctSet = roPumpDutyCyclePctSet < MIN_RO_PUMP_DUTY_CYCLE ? MIN_RO_PUMP_DUTY_CYCLE : roPumpDutyCyclePctSet; - roPumpDutyCyclePctSet = roPumpDutyCyclePctSet > MAX_RO_PUMP_DUTY_CYCLE ? MAX_RO_PUMP_DUTY_CYCLE : roPumpDutyCyclePctSet; - - setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); - } - // Reached to the target flow go to the next state - else - { - resetPIController( PI_CONTROLLER_ID_RO_PUMP_FLOW, roPumpDutyCyclePctSet ); - state = RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE; - } - - roControlTimerCounter = 0; - } - return state; } @@ -667,7 +627,7 @@ RO_PUMP_STATE_T state = RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE; // Control at set interval - if ( ++roControlTimerCounter >= roPumpControlInterval && roPumpControlMode == PUMP_CONTROL_MODE_CLOSED_LOOP ) + if ( ( ++roControlTimerCounter >= roPumpControlInterval ) && ( PUMP_CONTROL_MODE_CLOSED_LOOP == roPumpControlMode ) ) { // Get the pressure to use it for setting the control F32 actualPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); @@ -818,7 +778,7 @@ pumpData.roPumpDutyCycle = roPumpDutyCyclePctSet * FRACTION_TO_PERCENT_FACTOR; pumpData.roMeasFlowRateLPM = getMeasuredFlowRateLPM( RO_FLOW_SENSOR ); pumpData.roPumpState = (U32)roPumpState; - pumpData.roPumpFBDutyCycle = getROFeedbackVoltage() * FRACTION_TO_PERCENT_FACTOR; + pumpData.roPumpFBDutyCycle = getROFeedbackDutyCycle() * FRACTION_TO_PERCENT_FACTOR; broadcastData( MSG_ID_RO_PUMP_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&pumpData, sizeof( RO_PUMP_DATA_T ) ); roPumpDataPublicationTimerCounter = 0; @@ -847,6 +807,7 @@ roPIFlowProfiles[ profileID ].Kp, roPIFlowProfiles[ profileID ].Ki, roPIFlowProfiles[ profileID ].uMin, roPIFlowProfiles[ profileID ].uMax ); + setPIControllerStepLimit( PI_CONTROLLER_ID_RO_PUMP_FLOW, roPIFlowProfiles[ profileID ].maxErrorSumStep ); currentROPumpProfile = profileID; } else @@ -899,6 +860,7 @@ return dutyCyclePct; } + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ @@ -1036,14 +998,14 @@ /*********************************************************************//** * @brief - * The testSetDrainPumpMeasuredRPMOverride function overrides the drain pump - * measured RPM data. + * The testSetROPumpMeasuredFeedbackDutyCycleOverride function overrides the + * feedback duty cycle. * @details Inputs: none - * @details Outputs: drainPumpMeasuredRPM - * @param value override drain pump measured data + * @details Outputs: roPumpFeedbackDutyCyclePct + * @param value override feedback duty cycle. * @return TRUE if override successful, FALSE if not *************************************************************************/ -BOOL testSetROPumpMeasuredFeedbackVoltageOverride( F32 value ) +BOOL testSetROPumpMeasuredFeedbackDutyCycleOverride( F32 value ) { BOOL status = FALSE; @@ -1064,13 +1026,13 @@ /*********************************************************************//** * @brief - * The testResetDrainPumpMeasuredRPMOverride function resets the drain pump - * measured RPM data. + * The testResetROPumpMeasuredFeedbackDutyCycleOverride function resets the + * feedback duty cycle. * @details Inputs: none - * @details Outputs: drainPumpMeasuredRPM + * @details Outputs: roPumpFeedbackDutyCyclePct * @return TRUE if override reset successful, FALSE if not *************************************************************************/ -BOOL testResetROPumpMeasuredFeedbackVoltageOverride( void ) +BOOL testResetROPumpMeasuredFeedbackDutyCycleOverride( void ) { BOOL status = FALSE;