@@ -202,7 +202,7 @@ const AP_Param::GroupInfo AP_MotorsHeli_RSC::var_info[] = {
202202
203203 // @Param: GOV_RPM
204204 // @DisplayName: Rotor RPM Setting
205- // @Description: Main rotor RPM that governor maintains when engaged
205+ // @Description: Main rotor RPM that governor maintains when engaged, when used with H_RSC_GOV_ESC it is motor RPM instead.
206206 // @Range: 800 3500
207207 // @Units: RPM
208208 // @Increment: 10
@@ -224,6 +224,19 @@ const AP_Param::GroupInfo AP_MotorsHeli_RSC::var_info[] = {
224224
225225 // 27 was AROT_IDLE, moved to RSC autorotation sub group
226226
227+ // @Param: GOV_ESC
228+ // @DisplayName: Governor ESC index
229+ // @Description: Selects ESC used by helicopter governor for RPM, add 40 to use raw RPM, add 80 to use filtered RPM, set to -1 to use RPM sensor.
230+ // @Range: -1 101
231+ // @User: Advanced
232+ AP_GROUPINFO (" GOV_ESC" , 28 , AP_MotorsHeli_RSC, _esc_index, -1 ),
233+
234+ // @Param: GOV_FLT
235+ // @DisplayName: Governor RPM lowpass filter
236+ // @Description: Controls governor RPM filter, used with ESC telemetry as it typically has lower resolution.
237+ // @Range: 0 50
238+ // @User: Advanced
239+ AP_GROUPINFO (" GOV_FLT" , 29 , AP_MotorsHeli_RSC, _gov_filter_freq, 0 ),
227240 AP_GROUPEND
228241};
229242
@@ -256,15 +269,41 @@ void AP_MotorsHeli_RSC::output(RotorControlState state)
256269 _rsc_state = state;
257270 // _rotor_RPM available to the RSC output
258271#if AP_RPM_ENABLED
259- const AP_RPM *rpm = AP_RPM::get_singleton ();
260- if (rpm != nullptr ) {
261- if (!rpm->get_rpm (0 , _rotor_rpm)) {
262- // No valid RPM data
272+ #ifdef ESC_TELEM_MAX_ESCS
273+ if (_esc_index>=0 && _esc_index<ESC_TELEM_MAX_ESCS )
274+ {
275+ const AP_ESC_Telem *esc_telem = AP_ESC_Telem::get_singleton ();
276+ if (esc_telem != nullptr )
277+ {
278+ float new_rotor_rpm=-1 ;
279+ if (esc_telem->get_rpm (_esc_index, new_rotor_rpm)){
280+ const uint32_t now_us = MAX (1U ,AP_HAL::micros ()); // don't allow a value of 0 in, as we use this as a flag
281+ if (_last_rpm_update == 0 ) {
282+ _rotor_rpm = new_rotor_rpm;
283+ _last_rpm_update = now_us;
284+ } else {
285+ new_rotor_rpm = MIN (new_rotor_rpm, 2 *_governor_rpm); // clamp sensor data to prevent excessively high values from entering the filter
286+ _rotor_rpm += (new_rotor_rpm - _rotor_rpm) * calc_lowpass_alpha_dt (((float )(now_us-_last_rpm_update))/1e6f, _gov_filter_freq);
287+ _last_rpm_update = now_us;
288+ }
289+ } else {
290+ _rotor_rpm = -1 ;
291+ _last_rpm_update = 0 ;
292+ }
293+ }
294+ } else
295+ #endif // ESC_TELEM_MAX_ESCS
296+ {
297+ const AP_RPM *rpm = AP_RPM::get_singleton ();
298+ if (rpm != nullptr ) {
299+ if (!rpm->get_rpm (0 , _rotor_rpm)) {
300+ // No valid RPM data
301+ _rotor_rpm = -1 ;
302+ }
303+ } else {
304+ // No RPM because pointer is null
263305 _rotor_rpm = -1 ;
264306 }
265- } else {
266- // No RPM because pointer is null
267- _rotor_rpm = -1 ;
268307 }
269308#else
270309 _rotor_rpm = -1 ;
@@ -554,11 +593,13 @@ void AP_MotorsHeli_RSC::autothrottle_run()
554593 // if governor is not engaged and rotor is overspeeding by more than governor range due to
555594 // misconfigured throttle curve or stuck throttle, set a fault and governor will not operate
556595 if (_rotor_rpm > (_governor_rpm + _governor_range) && !autorotation.bailing_out ()) {
557- _governor_fault = true ;
558- governor_reset ();
559- GCS_SEND_TEXT (MAV_SEVERITY_WARNING , " Governor Fault: Rotor Overspeed" );
560- _governor_output = 0 .0f ;
561-
596+ _governor_fault_count++;
597+ if (_governor_fault_count > 20 ) { // allow for 20 ticks of governor fault to account for spikes produced by AM32 ESCs
598+ _governor_fault = true ;
599+ governor_reset ();
600+ GCS_SEND_TEXT (MAV_SEVERITY_WARNING , " Governor Fault: Rotor Overspeed" );
601+ _governor_output = 0 .0f ;
602+ };
562603 // when performing power recovery from autorotation, this waits for user to load rotor in order to
563604 // engage the governor
564605 } else if (_rotor_rpm > _governor_rpm && autorotation.bailing_out ()) {
@@ -570,13 +611,19 @@ void AP_MotorsHeli_RSC::autothrottle_run()
570611 float torque_limit = (get_governor_torque () * get_governor_torque ());
571612 _governor_output = (_rotor_rpm / (float )_governor_rpm) * torque_limit;
572613 if (_rotor_rpm >= ((float )_governor_rpm - torque_ref_error_rpm)) {
573- _governor_engage = true ;
574- _autothrottle = true ;
575- GCS_SEND_TEXT (MAV_SEVERITY_NOTICE , " Governor Engaged" );
614+ _governor_engage_count++;
615+ if (_governor_engage_count > 10 ) { // slightly delay engagement to handle spurious RPM signals from AM32 esc telemetry
616+ _governor_engage = true ;
617+ _autothrottle = true ;
618+ GCS_SEND_TEXT (MAV_SEVERITY_NOTICE , " Governor Engaged" );
619+ }
620+ } else {
621+ _governor_engage_count = 0 ;
576622 }
577623 } else {
578624 // temporary use of throttle curve and ramp timer to accelerate rotor to governor min torque rise speed
579625 _governor_output = 0 .0f ;
626+ _governor_fault_count = 0 ;
580627 }
581628 _control_output = constrain_float (_idle_throttle + (_rotor_ramp_output * (throttlecurve + _governor_output - _idle_throttle)), 0 .0f , 1 .0f );
582629 _governor_torque_reference = _control_output; // increment torque setting to be passed to main power loop
@@ -608,21 +655,23 @@ void AP_MotorsHeli_RSC::write_log(void) const
608655 // @Field: Gov: Governor Output
609656 // @Field: Throt: Throttle output
610657 // @Field: Ramp: throttle ramp up
658+ // @Field: RPM: RPM of the main rotor
611659 // @Field: Stat: RSC state
612660
613661 // Write to data flash log
614662 AP::logger ().WriteStreaming (" HRSC" ,
615- " TimeUS,I,DRRPM,ERRPM,Gov,Throt,Ramp,Stat" ,
616- " s#------" ,
617- " F-------" ,
618- " QBfffffB " ,
663+ " TimeUS,I,DRRPM,ERRPM,Gov,Throt,Ramp,RPM, Stat" ,
664+ " s#-----q -" ,
665+ " F------0 -" ,
666+ " QBffffffB " ,
619667 AP_HAL::micros64 (),
620668 _instance,
621669 get_desired_speed (),
622670 _rotor_runup_output,
623671 _governor_output,
624672 get_control_output (),
625673 _rotor_ramp_output,
674+ _rotor_rpm,
626675 uint8_t (_rsc_state));
627676}
628677#endif
0 commit comments