For anything you'd like to see added to Speeduino
By Ilotalo
#39285
I have been developing simple idle control. Now it's working and i'd like to share it.

If you like to test it just ask so i can give you those files for it.
By dazq
#39286
So is this standalone ? What's the hardware needed?
By Ilotalo
#39288
dazq wrote: Wed Nov 27, 2019 9:23 pm So is this standalone ? What's the hardware needed?
This is for normal speeduino PWM control. It's done in latest firmware 201911.

I have only got tested this in my own car Mazda MX5 NB.
Attachments
PWM Simple.jpg
PWM Simple.jpg (79.28 KiB) Viewed 9740 times
User avatar
By PSIG
#39295
A simple description may be useful, such as how it works, how it's different than the other options, and why it might be chosen.
8-)
David
By Ilotalo
#39305
PSIG wrote: Thu Nov 28, 2019 12:49 am A simple description may be useful, such as how it works, how it's different than the other options, and why it might be chosen.
8-)
David
Ok,

This base on simple algorithm for Idle adjust.

Basically it try to keep rpm in target rpm. By increasing or decreasing valve control value.
Target rpm comes from Idle RPM Targets table. Then it limits valve min value by Idle PWM Duty Cycle table. Max PWM Dutty Cycle comes from Maximum valve duty setting.

Then when you drive car it will adjust Duty cycle between minimum and maximum. When TPS is more than 1% it calculates Idle duty value. It increase Idle duty when RPM rices from 500-3000 then Duty is min-max. It increase Idle duty when MAP rices from 20-100 then Duty is min-max.
Then there is simple calculation so it slowly drop rpms to targer rpm. You can adjust that by P% and I%. P% means how big steps it drops and I% means time how fast it drops .
This helps that RPM dose not drop under Target RPM when you raise TPS and start Idle. Then this adjust if RPM drops when Fan starts.

Do you need more information?
User avatar
By PSIG
#39324
Interesting way of handling it. Not sure I would want to give it any authority when TPS>idle and rpm>idle. The primary issue with idle recovery (to me) has been PID wrap-up.

While driving above idle, the PID is trying harder and harder to pull the rpm down to idle. When you release the throttle, rpm falls fast, and PID is still trying to pull it lower. The result is a PID wrap-up overshoot below idle. Above idle the valve is closed, and I-term is so strong pulling rpm lower, that it overpowers the D-term trying to settle on the setpoint target.

In some systems they have used a "dashpot" method like yours to slowly reduce the rpm near idle, but I'm not convinced that's the best way to handle the cause of the overshoot. It would seem to me that eliminating the "history" ("I" term) for PID when the engine is throttled above high-idle would allow PID to respond quickly and in better balance with the tuned D-term, when rpm decreases rapidly after lifting throttle. Does that make sense?

I'm hoping this could be simple by either disabling PID above x-rpm (make it blind), or disabling cumulative I-term above x-rpm and/or y-TPS, allowing quicker response when approaching idle setpoint. Your thoughts?

David
User avatar
By pazi88
#39326
Don't see the point in this simple -algorithm. It sounds like regular PID control but with slight changes.

But I agree with PSIG that current speeduino closed loop idle control is missing TPS thresold to dusable PID control for idle. This makes the closed loop idle totally useless. At least in the cars that I work on.
By Ilotalo
#39330
Hi,

That PID control will newer work in this kind of control. It always overshoots that control because it base on that. I haven't got that PID Idle control working on megasquirt and not in speeduino. There is always lag on that valve control so that's why we need to predict that drop and slow it down. I can send some logs while i'm driving so you can see what this dose.
By Ilotalo
#39336
Here is that code so you can see its very simple.
Code: Select all
      case IAC_ALGORITHM_PWM_SIMPLE:       //Case 6 Simple PWM
      if( BIT_CHECK(currentStatus.engine, BIT_ENGINE_RUN) &&  currentStatus.runSecs > 2  )
      {        
        currentStatus.CLIdleTarget = (byte)table2D_getValue(&iacClosedLoopTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET); //All temps are offset by 40 degrees 
        idle_cl_target_rpm = (uint16_t)currentStatus.CLIdleTarget * 10; //Multiply the byte target value back out by 10      
        
        minKpa = 20;
        maxKpa = 100;
        minRPM = 500;
        maxRPM = 3000;
        byte maxDuty = 50;
        byte minDuty = table2D_getValue(&iacPWMTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET);
        if(currentStatus.TPS > 1){
          dutyKpa = (byte) lastIdleDuty + ( ( maxDuty - lastIdleDuty) * (float) ( currentStatus.MAP - minKpa ) / ( maxKpa - minKpa ) );
          dutyRPM = (byte) lastIdleDuty + ( ( maxDuty - lastIdleDuty) * (float) ( currentStatus.RPM - minRPM ) / ( maxRPM - minRPM ) );          
          if ( dutyKpa > dutyRPM ) { idleDuty = dutyKpa;}
          else { idleDuty = dutyRPM; }
        }
        // Normal idle
        else{
          if( idleCounter >= configPage6.idleKI ){
            if(currentStatus.RPM < idle_cl_target_rpm - 50 ){ 
              idleDuty++;
              lastIdleDuty = idleDuty;
              idleCounter= 0;
              }
          }
          // Toimii
          if( idleCounter >= configPage6.idleKI ){                                               
            if( currentStatus.RPM > idle_cl_target_rpm + 50 ){             
                idleDuty = idleDuty -  (byte)( idleDuty - minDuty ) * (float) configPage6.idleKP / 100;
                lastIdleDuty = idleDuty;
                idleCounter = 0;
            }                          
          }
          idleCounter++;           
        }
        // Normal idle end
      }
      else
      {
        //Currently cranking. Use the maxDuty
        BIT_SET(currentStatus.spark, BIT_SPARK_IDLE); //Turn the idle control flag on               
        idleOn = true;        
        idleDuty = configPage2.iacCLmaxDuty; //All temps are offset by 40 degrees        
        idleCounter= 0;
      }       
      if( idleDuty < configPage2.iacCLminDuty) { idleDuty = configPage2.iacCLminDuty; }
      if( idleDuty > configPage2.iacCLmaxDuty) { idleDuty = configPage2.iacCLmaxDuty; }
      idleOn = true;
      enableIdle();
      currentStatus.idleDuty = idleDuty;
      idle_pwm_target_value = percentage(currentStatus.idleDuty, idle_pwm_max_count);
      currentStatus.idleLoad = currentStatus.idleDuty >> 1; //Idle Load is divided by 2 in order to send to TS  
            
      break;

nice first of all, i read all that crap months a[…]

I rewired a few grounds and tested the TPS and rel[…]

Thanks, car runs great now !!! Going to drift even[…]

sauver moteur v8

bonsoir je m appel jean marie et j habite en Franc[…]

Still can't find what you're looking for?