Notices
ECU Flash

PID boost control code

Thread Tools
 
Search this Thread
 
Old May 16, 2008 | 05:00 AM
  #1  
jcsbanks's Avatar
Thread Starter
Evolved Member
 
Joined: May 2006
Posts: 2,399
Likes: 6
From: UK
PID boost control code

To avoid polluting Tephra's V5 thread. To discuss V6/PID boost control. Code below is from my 2002 EBC project using Atmel AVR microcontroller and BASCOM-AVR. It was for a slowbaru hence only 20PSI at the time... Discuss...

The throttle position and MAP sensor are read from ADC channels. So are the gains for P, I and D.

Code:
   Dim Setpoint As Byte                                     ' Setpoint
   Dim Tps As Byte                                          'throttle position
   Dim Map As Byte                                          ' MAP
   Dim Cv As Integer                                        ' output
   Dim Pterm As Integer
   Dim Dterm As Integer
   Dim Iterm As Integer
   Dim Kp As Integer                                        ' gain
   Dim Kd As Integer
   Dim Ki As Integer
   Dim Duty As Byte                                         ' target duty cycle if no error
   Dim X As Word                                            'temporary unsigned variable for ADC
   Dim Error As Integer                                     ' Difference between Setpoint and Map
   Dim Lastmap As Byte
   Dim Integrate As Byte
   Dim Sum_error As Integer

   'still space for 8 more integers at least

   Const Psi0 = 116                                         'ADC input for 0 PSI
   Const Psi1 = 121
   Const Psi2 = 126
   Const Psi3 = 131
   Const Psi17 = 200
   Const Psi18 = 205
   Const Psi19 = 210
   Const Psi20 = 215                                        'ADC input for 20 PSI
   Const Mindutycycle = 0
   Const Maxdutycycle = 238                                 'dutycycle %*2.55
   Const Tpstarget = 170                                    'throttle position reference
   Const Mintps = 100

Config Adc = Single , Prescaler = Auto                      'start analog/digital converter
Start Adc                                                   'hardware configure 10 bits 0-5V

Config Portb = Output

Config Timer1 = Pwm , Pwm = 8 , Compare A Pwm = Clear Down , Prescale = 1024
                                                            'start PWM output 15.3Hz

Enable Interrupts                                           'each PWM cycle run loop
Enable Timer1
On Timer1 Calculate Nosave                                  'no registers to save

Setpoint = Psi18

Do                                                          'endless loop until interrupt
Loop

Calculate:

X = Getadc(0)                                               '10 bits unsigned
Shift X , Right , 2                                         'convert to 8 bit
Tps = X                                                     'throttle position

X = Getadc(1)                                               '10 bits unsigned
Shift X , Right , 2                                         'convert to 8 bit
Duty = X                                                    'target duty cycle if no error

X = Getadc(5)
Shift X , Right , 2
Ki = X                                                      'integral gain

X = Getadc(3)                                               'MAP sensor
Shift X , Right , 2
Map = X

X = Getadc(2)
Shift X , Right , 2
Kp = X                                                      'proportional gain

X = Getadc(4)
Shift X , Right , 2
Kd = X                                                      'differential gain


   Error = Setpoint - Map

   Portb = 63                                               'flash 4 LEDS to show how near to target
   If Error > 0 Then
    Reset Portb.5
    If Error < 3 Then Reset Portb.4
   End If
   If Error < 0 Then
    Reset Portb.2
    If Error > -3 Then Reset Portb.3
   End If

   Dterm = Map - Lastmap                                    'caluclate differential part
   Lastmap = Map
   Dterm = Dterm * Kd
   Dterm = Dterm / 128

   Pterm = Kp * Error                                       'calculate proportional part
   Pterm = Pterm / 128                                      'kp is in range 0-255
                                                            'representing 0-2 therefore divide by 128
                                                            'quick and dirty FP math using integers
                                                            'not using shifts because signed variable!

If Integrate = 1 Then
Sum_error = Sum_error + Error                               'calculate integral part with antiwindup
Else
Sum_error = 0
End If
Iterm = Ki * Sum_error
Iterm = Iterm / 128

Integrate = 1                                               'set to integrate next time unless cancelled by conditions

Cv = Pterm + Dterm                                          'add all three together (can only add 2 variables at once)
Cv = Cv + Iterm

If Tps < Tpstarget Then
 Cv = 0                                                     'use static target at partial throttle
 Integrate = 0
End If

Cv = Cv + Duty                                              'error adjust target duty cycle

If Map < Psi1 Then Cv = Mindutycycle                        'if no boost shut up/rest solenoid
If Tps < Mintps Then Cv = Mindutycycle
If Map > Psi20 Then Cv = Mindutycycle                       'overboost cutout for momentary 20PSI

If Cv <= Mindutycycle Then
 Cv = Mindutycycle
 Integrate = 0
End If

If Cv >= Maxdutycycle Then
 Cv = Maxdutycycle
 Integrate = 0
End If

Pwm1a = Cv                                                  'adjust duty cycle output

Return

Last edited by jcsbanks; May 16, 2008 at 05:03 AM.
Reply
Old May 16, 2008 | 05:28 AM
  #2  
jcsbanks's Avatar
Thread Starter
Evolved Member
 
Joined: May 2006
Posts: 2,399
Likes: 6
From: UK
Useful info on PID control http://newton.ex.ac.uk/teaching/CDHW/Feedback/

Includes Excel spreadsheet that plots graphs with different gains for PID for an over controller! You can see the oscillations, over/underdamping etc from incorrect gains. Useful to experiment in a simulator before on the car unless you've tuned PID systems before. Certainly helped me with this project.
Reply
Old May 16, 2008 | 06:02 AM
  #3  
tephra's Avatar
EvoM Guru
15 Year Member
iTrader: (6)
 
Joined: Feb 2007
Posts: 9,486
Likes: 67
From: Melbourne, Australia
ive already written the basics in asm...

i just need to debug it

what sort of issues did you run into?

what gains did you use for P I and D?
Reply
Old May 16, 2008 | 06:07 AM
  #4  
jcsbanks's Avatar
Thread Starter
Evolved Member
 
Joined: May 2006
Posts: 2,399
Likes: 6
From: UK
Post what you've got it you like...

Gains were unitless as I did not convert pressures or duty cycles into real values but left them as integers as the microcontroller I used had no floating point.

Issues were of setting the gains, or the range available to something sensible, required a lot of experimentation. Also issues of sorting out integral wind up and small bugs in code that produce odd results.

I did find that it most definitely needed a starting duty cycle to work with, it wouldn't just find it without. So I got the duty cycle to approx that required to run the boost level then started to add proportional gain. This made a nice controller. I then added a small amount of integral gain, and in the end I think I left out derivative/differential as it was difficult to setup and I was juggling too many variables. When I got into the Subaru ECU ROM I abandoned the project, but I had intended to make it RPM aware, this is easy in our case because we have the variable sitting right there in the ECU
Reply
Old May 16, 2008 | 07:12 AM
  #5  
tephra's Avatar
EvoM Guru
15 Year Member
iTrader: (6)
 
Joined: Feb 2007
Posts: 9,486
Likes: 67
From: Melbourne, Australia
next week ill debug what code I have so it "runs" sensibly... then I can post it.

basically its going to use the current BDEL table to resolve what WGDC it needs...

If ppl like i can make a 3d map tps vs rpm vs psi but thats all detail we can worry about later
Reply
Old May 16, 2008 | 08:38 AM
  #6  
honki24's Avatar
Evolved Member
20 Year Member
iTrader: (23)
 
Joined: Apr 2003
Posts: 1,580
Likes: 0
From: Houston, TX
lol a few of you need your own forum. Geniusforums.com
Reply
Old May 16, 2008 | 02:17 PM
  #7  
dan l's Avatar
Account Disabled
iTrader: (3)
 
Joined: Apr 2006
Posts: 1,029
Likes: 0
From: USA
I've tuned a lot of PID systems in the past. Actually the stock BCS code pseudo acts like a PID system if you look at it in a certain way. Anyways if you get code up and running I'll for sure give it a shot.
Reply
Old May 16, 2008 | 02:26 PM
  #8  
EvoBroMA's Avatar
Evolved Member
 
Joined: Feb 2006
Posts: 1,345
Likes: 1
From: MA
Atmel AVRs FTW!!!
Reply
Old May 16, 2008 | 03:39 PM
  #9  
jcsbanks's Avatar
Thread Starter
Evolved Member
 
Joined: May 2006
Posts: 2,399
Likes: 6
From: UK
Just looking through the code again, the reason I maybe wasn't impressed with the derivative control is that I think the sign is wrong. By using map-lastmap then if the boost is rising then a positive differential gain would add further to the duty cycle, which is the opposite to what we require. I also read that the usual method is to differentiate the error, so again we would use setpoint-present value. So as we increase boost towards the target, the error would be quickly reducing which would reduce the derivative term and dampen the overshoot. Once we actually overshot then the error would then become negative and the differential term would take the inertia out of it, and as dexmix pointed out in the other thread effectively smooth it out.
Reply
Old May 16, 2008 | 03:57 PM
  #10  
dan l's Avatar
Account Disabled
iTrader: (3)
 
Joined: Apr 2006
Posts: 1,029
Likes: 0
From: USA
Derivative (as I've been taught) is how far away you are from your target. I've always been cautioned to use it sparingly or not at all if I can. The reason being is that it tends to make systems unstable. Too much derivative on a fast control system like boost and you risk overshooting a lot.

Integral (grows bigger with being off of target for a long time) may be difficult. It might have to be triggered by TPS or something because this value could grow very large if just driving around normally for an hour. Or maybe it should be triggered by a certian psi of boost and untriggered when dropping below this boost. Anyways integral tends to make systems more stable.
Reply
Old May 16, 2008 | 11:07 PM
  #11  
tephra's Avatar
EvoM Guru
15 Year Member
iTrader: (6)
 
Joined: Feb 2007
Posts: 9,486
Likes: 67
From: Melbourne, Australia
I thought D was the difference between the error this time and the error lasttime

if if your target is 20psi, and last time you got 17psi, and this time you got 19psi, then D would be 2psi ((20-17)-(20-19))..
Reply
Old May 17, 2008 | 04:07 AM
  #12  
jcsbanks's Avatar
Thread Starter
Evolved Member
 
Joined: May 2006
Posts: 2,399
Likes: 6
From: UK
... so in that case the derivative gain would be negative to damp the rapidly rising boost.

If Map < Psi1 Then Cv = Mindutycycle 'if no boost shut up/rest solenoid
If Tps < Mintps Then Cv = Mindutycycle
If Map > Psi20 Then Cv = Mindutycycle 'overboost cutout for momentary 20PSI

If Cv <= Mindutycycle Then
Cv = Mindutycycle
Integrate = 0
End If

If Cv >= Maxdutycycle Then
Cv = Maxdutycycle
Integrate = 0
End If

The above bits of code were trying to stop the problem with integral wind up you mention dan l. So it has a TPS trigger and boost level only above which it will allow integration. It also turns it off if it has wound up to either end of the duty cycle range - I think this may be undesirable?
Reply
Old May 17, 2008 | 06:25 AM
  #13  
dan l's Avatar
Account Disabled
iTrader: (3)
 
Joined: Apr 2006
Posts: 1,029
Likes: 0
From: USA
Originally Posted by tephra
I thought D was the difference between the error this time and the error lasttime

if if your target is 20psi, and last time you got 17psi, and this time you got 19psi, then D would be 2psi ((20-17)-(20-19))..
My bad I think that you are right.
Reply
Old May 18, 2008 | 10:31 PM
  #14  
fostytou's Avatar
EvoM Community Team
iTrader: (15)
 
Joined: Sep 2006
Posts: 3,143
Likes: 7
From: Aurora, IL
For the rest of us who haven't been introduced, the everpresent wiki helps bring the understanding level up a bit also:

http://en.wikipedia.org/wiki/PID_controller
Reply
Old May 18, 2008 | 10:48 PM
  #15  
tephra's Avatar
EvoM Guru
15 Year Member
iTrader: (6)
 
Joined: Feb 2007
Posts: 9,486
Likes: 67
From: Melbourne, Australia
right so I was thinking about this this morning.

The problem with PID is that it is purely reactive - it can't see into the future so to speak.

What are you guys thoughts on trying to implement a Futures-PID, ie we guess what boost we will be at in the future by what's happened in the past. That should hopefully reduce the amount of overboost spike we will see @ spoolup.

Anyways this is my code so far
Code:
sts.l   pr, @-r15
mov.l   r0, @-r15
mov.l   r1, @-r15
mov.l   r2, @-r15
mov.l   r3, @-r15
mov.l   r4, @-r15
mov.l   r5, @-r15
mov.l   r10, @-r15

! PSEUDO CODE
!  MY_ERROR_PSI = target_boost - ECU_MAP_SENSOR
!  OUTPUT = PGAIN*MY_ERROR_PSI + IGAIN2*MY_TOTAL_ERROR_PSI - DGAIN2*(MY_ERROR_PSI-MY_LAST_ERROR_PSI)
!  MY_LAST_ERROR_PSI = MY_ERROR_PSI

mov.l (MY_BDEL_map_pointer), r0
mov.l @r0, r0
mov.l (alternate_bdel_map), r1
cmp/eq r0, r1
bf not_on_altmaps

mov.l (ECU_RPM_5), r0
mov.w @r0, r0
mov.w (min_rpm_for_boost_control), r1
cmp/hs r0, r1
bt rpm_for_boost_control_not_yet_met

  mov.l (MY_DAVES_COUNTER), r0
  mov.w @r0, r0
  tst r0, r0
  bf interval_countdown_not_zero

    mov.w (interval), r1
    mov.l (MY_DAVES_COUNTER), r0
    mov.w r1, @r0

    mov.l (axis_rpm_boost), r4
    mov.l (Table_Lookup_Axis), r10
    jsr @r10
    nop

    mov.l (MY_BDEL_map_pointer), r4
    mov.l (Query_3D_Table), r10
    jsr @r10
    nop
    mov r0, r1

    mov.l (boost_control_load_offset), r0
    mov.w @r0, r0
    
    add r0, r1
  
    mov.l (ECU_MAP_SENSOR), r0
    mov.w @r0, r0
  
    sub r0, r1                              ! MY_ERROR_PSI = target_boost - ECU_MAP_SENSOR
    mov.l (MY_ERROR_PSI), r0
    mov.w r1, @r0

    mov.w (p_gain_x10), r0
    mul.l r1, r0
    sts macl, r2                            ! r2 = PGAIN*MY_ERROR_PSI
  
    mov.l (MY_TOTAL_ERROR_PSI), r0
    mov.w @r0, r0
    add r0, r1
    
    mov.w (min_i), r3
    cmp/hs r1, r3
    bt output_less_than_min_i
  
      mov.w (max_i), r3
      cmp/hs r3, r1
      bf output_less_than_max_i
  
        mov.w (max_i), r1
  
      output_less_than_max_i:
  
      bra output_i_range_check_done
      nop
  
    output_less_than_min_i:
      mov.w (min_i), r1
    
    output_i_range_check_done:
    
    mov.l (MY_TOTAL_ERROR_PSI), r0
    mov.w r1, @r0

    mov.w (i_gain_x10), r0
    mul.l r1, r0
    sts macl, r3                            ! r3 = IGAIN*MY_TOTAL_ERROR_PSI
  
    mov.l (MY_LAST_ERROR_PSI), r0
    mov.w @r0, r0
    mov.l (MY_ERROR_PSI), r1
    mov.w @r1, r1
    sub r0, r1
  
    mov.w (d_gain_x10), r0
    mul.l r1, r0
    sts macl, r4                            ! r4 = DGAIN*(MY_ERROR_PSI-MY_LAST_ERROR_PSI)
  
    add r3, r2
    sub r4, r2
  
    mov r2, r4
    mov #0x0a, r5 
    mov.l (R4_DIV_R5_Into_R0), r10
    jsr @r10
    nop
  
    mov.w (min_wgdc), r1
    cmp/hs r0, r1
    bt output_less_than_min_wgdc
  
      mov.w (max_wgdc), r1
      cmp/hs r1, r0
      bf output_less_than_max_wgdc
  
        mov.w (max_wgdc), r0
  
      output_less_than_max_wgdc:
  
      bra output_range_check_done
      nop
  
    output_less_than_min_wgdc:
      mov.w (min_wgdc), r0

    output_range_check_done:

    mov #0x02, r1
    mul.l r1, r0
    sts macl, r0

    mov.l (ECU_FINAL_WASTEGATE_DUTY), r1
    mov.w r0, @r1

    mov.l (MY_ERROR_PSI), r0
    mov.w @r0, r0
    mov.l (MY_LAST_ERROR_PSI), r1
    mov.w r0, @r1

    bra boost_control_done
    nop

  interval_countdown_not_zero:

    mov.l (MY_DAVES_COUNTER), r0
    mov.w @r0, r1
    add #-0x1, r1
    mov.w r1, @r0

    bra boost_control_done
    nop

rpm_for_boost_control_not_yet_met:

  mov #0x0, r0
  mov.l (MY_DAVES_COUNTER), r1
  mov.w r0, @r1
  mov.l (MY_LAST_ERROR_PSI), r1
  mov.w r0, @r1
  mov.l (MY_TOTAL_ERROR_PSI), r1
  mov.w r0, @r1
  mov.l (ECU_FINAL_WASTEGATE_DUTY), r1
  mov.w r0, @r1
  
  bra boost_control_done
  nop

not_on_altmaps:
  mov.l (Turbo_Control_Calcs), r10
  jsr @r10
  nop

boost_control_done:

mov.l   @r15+, r10
mov.l   @r15+, r5
mov.l   @r15+, r4
mov.l   @r15+, r3
mov.l   @r15+, r2
mov.l   @r15+, r1
mov.l   @r15+, r0
lds.l   @r15+, pr

rts
nop

.align 4

version:                                        .float 1.0

ECU_MAP_SENSOR:                                 .long 0xFFFF6ACC
ECU_FINAL_WASTEGATE_DUTY:                       .long 0xFFFF6EC6
ECU_RPM_5:                                      .long 0xFFFF6AFE

MY_DAVES_COUNTER:                               .long 0xFFFF8440
MY_ERROR_PSI:                                   .long 0xFFFF8442
MY_LAST_ERROR_PSI:                              .long 0xFFFF8444
MY_TOTAL_ERROR_PSI:                             .long 0xFFFF8446
MY_BDEL_map_pointer:                            .long 0xFFFF8438

R4_DIV_R5_Into_R0:                              .long 0x9FA
Query_3D_Table:                                 .long 0xDE0
Table_Lookup_Axis:                              .long 0xCC6

boost_control_load_offset:                      .long 0x1670 ! OR Atmo base pressure :)
axis_rpm_boost:                                 .long 0x732C

Turbo_Control_Calcs:                            .long 0x40110
alternate_bdel_map:                             .long 0x381e2

p_gain_x10:                                     .word 2
i_gain_x10:                                     .word 2
d_gain_x10:                                     .word 1

min_i:                                          .word 0
max_i:                                          .word 1000

min_wgdc:                                       .word 0
max_wgdc:                                       .word 100

min_rpm_for_boost_control:                      .word 0x200

interval:                                       .word 0x5
edit - just updated the code with better Integral Windup, before I was limiting the output of IGAIN*I, now I am limiting I itself... Also added in code so I can flip between PID boost and Stock Boost... temporary for the timebeing but allows me to drive without fear of exploding something

Last edited by tephra; May 18, 2008 at 11:58 PM.
Reply



All times are GMT -7. The time now is 08:05 AM.