Let's Make Robots!

Car maintaining same speeds as the one ahead

I have previously posted in the beginners section but I feel this is more advanced than I had first anticipated.
Previously I was trying to code something that would react to a change in distance... but I've found a similar problem which would require the same bit of code however is much easier to explain and think about.

Say you decide to put a picaxe in your car so that when you're on the motorway you can switch a button and then the picaxe will accelerate/decelerate/hold-contstant-speed dependant on the car in front.  

Now, my purposose for this programming is to place it into a coating machine im trying to build, which requires a tension arm to be steady. However, for all that matters its the same as the cruise control idea above.

(To make explaining easier, i think its best we talk as though its the cruise control from here on out)

What doesnt work?

Simply saying if the car gets x distance away accelerate and if its x distance too close decelerate. This is because it makes an  inverted bouncy ball effect. (the bounces get indefinately higher and higher) In other words, the car would start to get too close the car, then too far way, then even closer, then even further, then hit the car in front. This is because the pic isnt reacting intuitively enough.

I.e when it gets so far away I step down a potentiometer which will cause the car to go faster until it gets passed the upper limit (the point at which Ive said its too close) and then will step up the potentiometer and allow less voltage through which will cause the car to slow right down.

I need a system which will allow it to almost predict where the car will be in relation to the car infront and then speed up, slow down accordingly.


So if it gets  really close I need the system to step up the potentiometer so that the car returns to its desired distance from the car ahead and then step down just enough to stop the car getting any further away.


I hope this makes sense!

Any Ideas?  

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Thank you Birdmun.

I have coded a PD controller using snippets of information from around the web and hopefully tailored it to my need.

 

'Tension Arm
 symbol CS = 7 

symbol UD = 5  

symbol RLED = 6

symbol GLED = 4 

 

symbol trig = 3 'Define output pin for Trigger pulse

symbol echo = 6 'Define input pin for Echo pulse

symbol range = w1 '16 bit word variable for range

symbol break = b1

 

 

 

 

 

 

'#############################################################'

 

' PID constants

symbol kP = 1

symbol kD = 100

symbol SV = 10

 

 

' software constants

symbol false = 0

symbol true  = 1

 

 

' software variables

symbol temp     = w6

symbol errAct   = w5

symbol errPrv   = w4

symbol PWR      = w3

symbol gain     = w2

 

symbol drange     = w1

 

symbol ErrNeg   = w9

symbol PErrNeg  = w8

symbol DGainNeg = w7

 

Init:

HIGH CS ; set the chip select high to disable serial control.

 

main:

gosub distance

 

  ' error calculation

  errPrv = errAct

  PErrNeg = ErrNeg

  if range > SV then

    errAct = range - SV

 

    ErrNeg = false

  else

    errAct = SV - range

    ErrNeg = true

  endif

 

  ' proportional gain calculation

  gain = errAct*kP

  if ErrNeg = true then

    PWR = PWR - gain max 1000

  else

    if ErrNeg = false then

      PWR = PWR + gain

    else

      PWR = 0

    endif

  endif

 

  ' derivated gain calculation

  drange = errAct 

  errPrv = errPrv 

  if drange =>errPrv then

    gain = drange - errPrv  

    DGainNeg = false

  else

    gain = errPrv - drange

    DGainNeg = true

  endif

  gain = gain*kD

 

  if DGainNeg = true then

    PWR = PWR + gain max 1000

 

  else

    if PWR > gain then

      PWR = PWR - gain

 

    else

      PWR = 0

      endif

      endif

      sertxd (#PWR)

if range > SV then goto Increment

if range < SV then goto Decrement

 

 

 

 

 

distance:

pulsout trig,2 'produce 20uS trigger pulse (must be minimum of 10uS)

pulsin echo,1,range 'measures the range in 10uS steps

pause 20 'recharge period after ranging completes

 

let range = range * 10 / 58 ;divide by 2 if PICAXE 28x2 instead of PICAXE 28x1

let range = 13 'just to test

'sertxd (#range) 

 

return

 

 

 

 

 

   Decrement:

   if PWR = 0 then goto main

break =0

DO

 HIGH RLED 

 LOW UD ; set U/D pin to low state to indicate decrement mode

 LOW CS ; set CS pin low to enable serial control of the MCP4011

 PULSOUT UD, 1 ; 1 msec pulse on the UD line to step down

 HIGH CS ; Finished stepping down so must set CS pin high before can select a new mode.

 LOW RLED

 break= break +1

 pause 80

 LOOP UNTIL break=PWR

pause 400

GOTO Main

 

 

Increment:

if PWR = 0 then goto main

break=0

DO

 HIGH GLED 

 HIGH UD ; set U/D pin to high state to indicate increment mode

 LOW CS ; set CS pin low to enable serial control of the MCP4011

 

 PULSOUT UD, 1 ; 1 msec pulse on the UD line to step up

 HIGH CS

 LOW GLED

 break=break + 1

 pause 80

LOOP UNTIL break=PWR

pause 400

GOTO Main

 

 

 

Does this look feasible to you?

symbol range = w1 '16 bit word variable for range

symbol drange     = w1

Otherwise, I am not sure I am up to the task of following that monster. I, myself, would probably attempt to convert the quick and dirty PID snippet. I can't believe it would be anywhere near the size of the code you are showing. I could be wrong.

Theres no way it could be something as (seemingly) simple as this?

SetPoint       CON     0                     ' Set point
Kp             CON     10                    ' Proportionality constant
Ki             CON     10                    ' Integral constant
Kd             CON     10                    ' Derivative constant
 
Current        CON     0                     ' Array index - current error
Accumulator    CON     1                     ' Array index - accumulated error
Previous       CON     2                     ' Array index - previous error
Delta          CON     3                     ' Array index - change in error
 
sensorInput    VAR     Word                  ' Sensor input variable
error          VAR     Word(4)               ' Four different types of errors
p              VAR     Word                  ' Proportional term
i              VAR     Word                  ' Integral term
d              VAR     Word                  ' Derivative term
drive          VAR     Word                  ' Output
 
DO
 
  DEBUG "Enter sensor input value: "
  DEBUGIN SDEC sensorInput
 
  ' Calculate error.
  error(Current) = SetPoint - sensorInput
 
  ' Calculate proportional term.
  p = Kp * error(current)
 
  ' Calculate integral term.
  error(Accumulator) = error(Accumulator) + error(Current)
  i = Ki * error(Accumulator)
 
  ' Calculate derivative term.
  error(Delta) = error(Current) - error(Previous)
  d = Kd * error(delta)
 
  ' Calculate output.
  drive = p + i + d
 
  ' Display values.
  DEBUG CR, CR, "ERROR", CR,
        SDEC ? SetPoint, SDEC ? sensorInput, SDEC ? error(Current), CR,
        "PROPORTIONAL", CR,
        SDEC ? Kp, SDEC ? error(Current), SDEC ? p, CR,
        "INTEGRAL", CR,
        SDEC ? Ki, SDEC ? error(accumulator), SDEC ? i, CR,
        "DERIVATIVE", CR, 
        SDEC ? Kd, SDEC ? error(Delta), SDEC ? d, CR,
        "OUTPUT", CR, 
        SDEC ? p, SDEC ? i, SDEC ? d, SDEC ? drive, CR, CR
 
  ' Save current error to previous error before next iteration.
  error(Previous) = error(Current) 


Code is from a basic stamp tutorial



 

Thank you, I'll try and convert the code you linked me too. 

On this piece of code, he hasnt assigned any values to kp, ki or kd... is this because it is a geneneric PID.. or? 

 

void SetTunings(double Kp, double Ki, double Kd) {
   kp = Kp;
   ki = Ki;
   kd = Kd;
}

you will see that the values are set here. There is no reason for you to copy the code exactly. :)

BASIC being what it is, I would suggest you find a different way to go about setting the P I D variables, maybe via a serial connection to allow you to tune the values while the machine is running.

http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/

I would suggest you just attempt to convert the code on the first page to BASIC. If you can't, let us know.

I found the following site http://www.engin.umich.edu/group/ctm/examples/motor/PID2.html which explains PID very well. It also gives an example code for matlab which is for a motor. (Could be similar to my problem?)

Their seems to be very little examples of PID for picaxe chips. Does anyone have any explained code samples? Or an idea of how I might go about coding it?

I dont understand how I can do a derivitave or integral on the chip or the exact equation I need to work from.

Regards,
Luke 

Thank you very much Birdmun.

I will definately look into it and try and come up with some code that will make it work.

Cheers NilsB :)
Regards,
Luke 

a PID algorithm. If you don't know what PID is, look it up. You will see it will cover the exact problem you are mentioning with the rubberband effect.

... also use this tip to learn from LMR about PID.