Automation and
PID Control

Watch

multiple intelligent agent simulation platform

Download 

Introducing NetLogo

"INTERFACE"

"CODE"

Introducing NetLogo

The "INTERFACE" consists of a UI (switches, buttons, etc.) and a "gridworld" where squares are called "patches" and a command center where we can interact directly with the underlying code.

Let's Implement the
Soccer Field Example

  1. Start NetLogo
  2. Resize the interface
  3. Write code by stepwise refinement

Stepwise Refinement


Simulation
 

Go - code that runs the thing

Setup - code that takes care of preliminaries

Draw the soccer field

Create the agent

Compute the ERROR

Compute the COMMAND

Set system parameters

to setup
  draw_field
  create_agent
  set_system_parameters  
end

to go
  print "ERROR COMPUTED"
  print "COMMAND GENERATED AND EXECUTED"
end

to draw_field
  print "FIELD DRAWN"
end

to create_agent
  print "AGENT CREATED"
end

to set_system_parameters
  print "SYSTEM PARAMETERS SET"
end

Stepwise Refinement

Change
Settings
For
Soccer
Field
Example

Draw the Field

Draw the Field

Code

to draw_field
  ca
  ask patches [if pycor = max-pycor [set pcolor white]]
  ask patches [if pycor = min-pycor [set pcolor white]]
  ask patches [if pxcor = max-pxcor [set pcolor white]]
  ask patches [if pxcor = min-pxcor [set pcolor white]]
  ask patches [if pxcor = max-pxcor / 2 [set pcolor white]]
  print "FIELD DRAWN"
end

Code

to create_agent
  crt 1 [                ;create one agent with these properties
    set shape "circle"   ;make it a circle
    set size 2           ;not so big
    set heading 90       ;pointed to the right
  ]
  print "AGENT CREATED"
end

So Far

Example 1

NetLogo Info

commands can be given to patches, turtles (agents), or the "world" 

we say we are in "turtle context" or "observer context" or "patch context" 

in observer context you can "reach" patches or turtles by saying 

ask agentset [command(s)]

where agentset is either turtles or patches 

In the interface, we can designate a procedure's context.

NetLogo Set Procedure/Button Context

Code

globals [target err]

First line of NetLogo code

declares "GLOBAL" (i.e., know everywhere) names

Code

to go
  set err target - xcor
  type "err = " type err type " "
  print "ERROR COMPUTED"
  print "COMMAND COMPUTED AND EXECUTED"
end
set varname expression 

sets value of varname to expression (no "=")

type value

outputs value in command center w/o CRLF

print value

outputs value in command center w CRLF

Code

to go
  set err target - xcor
  type "err = " type err type " "
  print "ERROR COMPUTED"
  fd 0.1 * err
  print "COMMAND COMPUTED AND EXECUTED"
end
fd expression

turtle moves forward number of spaces equal to value of expression

PLANT

TARGET

POSITION

E

Kp

So Far

Add a few bells and whistles

add monitor for err on interface

add slider so we can set target

have to remove target from globals and set system parameters 

let's make draw_field use target rather than hard-coding 100/2.

globals [err]

to setup
  draw_field
  create_agent
  set_system_parameters
end

to go
  set err target - xcor
  type "err = " type err type " "
  print "ERROR COMPUTED"
  fd 0.1 * err
  print "COMMAND COMPUTED AND EXECUTED"
end

to draw_field
  ca
  ask patches [if pycor = max-pycor [set pcolor white]]
  ask patches [if pycor = min-pycor [set pcolor white]]
  ask patches [if pxcor = max-pxcor [set pcolor white]]
  ask patches [if pxcor = min-pxcor [set pcolor white]]
  ask patches [if pxcor = target [set pcolor white]]
  print "FIELD DRAWN"
end

to create_agent
  crt 1 [
    set shape "circle"
    set size 2
    set heading 90
    pd
  ]
  print "AGENT CREATED"
end

to set_system_parameters
  set target 50
  print "SYSTEM PARAMETERS SET"
end

start the agent out with its "pen" down

So Far

DRONE

Drone 0

  1. Reconfigure interface with 0,0 at lower left (100x100, patch size 5, nowrap vertical)
  2. create empty setup and go procedures
  3. create empty create agent, draw world, set parameter procedures
  4. create slider for target
  5. create monitor for err
  6. fill in a few details
globals [err]

to setup
  ca
  create_agent
  set_system_parameters
  draw_world
end

to go
  print "COMPUTING ERROR"
  print "COMPUTING COMMAND"
end

to create_agent
  crt 1 [
    set shape "circle"
    set size 2
  ]
  print "AGENT CREATED"
end

to set_system_parameters
  print "SYSTEM PARAMETERS SET"
end

to draw_world
  ask patches [if pycor = target [set pcolor yellow]]
end

Drone 0

Drone

Assume 100 revolutions per minute (RPM) is hovering.
Faster ascending, slower descending.

speed_{vertical } = (propSpeed - 100) \times something \frac {m}{s}
speed_vert = (prop_speed - 100) / 10
prop_speed = k_p * err

Prop Speed

TARGET

POSITION

E

Kp

Drone 1.0

to go
  print "COMPUTING ERROR"
  set err target - ycor
  print "COMPUTING COMMAND"
  let prop_speed k_p * err
  let speed_vert (prop_speed - 100) / 10
  fd speed_vert
end

Drone Tweaks

globals [err]

to setup
  ca
  create_agent
  set_system_parameters
  draw_world
end

to go
  print "COMPUTING ERROR"
  set err target - ycor
  print "COMPUTING COMMAND"
  let prop_speed k_p * err
  let speed_vert (prop_speed - 100) / 10
  ;fd speed_vert
  setxy xcor + 1 ycor + speed_vert
end

to create_agent
  crt 1 [
    set shape "circle"
    set size 2
    set heading 0
    pd
    set pen-size 3
  ]
  print "AGENT CREATED"
end

to set_system_parameters
  print "SYSTEM PARAMETERS SET"
end

to draw_world
  ask patches [if pycor = target [set pcolor yellow]]
end

Make "time" flow left to right (16,17)

Let's put pen down so we see the trace (25) and make it thicker (26)

Drone 2.0

Drone 3.0

Change k_p slider to -100 to +100 (interface)

Add a "governor" so drone does not fly higher than the sky or lower than the ground. (17-22)

Add an "explode and die" procedure for when the drone hits the ground. (50-56)

globals [err]

to setup
  ca
  create_agent
  set_system_parameters
  draw_world
end

to go
  print "COMPUTING ERROR"
  set err target - ycor
  print "COMPUTING COMMAND"
  let prop_speed k_p * err
  let speed_vert (prop_speed - 100) / 10
  
  if (ycor + speed_vert) > max-pycor [ ;blasting through sky
    set speed_vert max-pycor - pycor
  ]
  if (ycor + speed_vert) < min-pycor [ ;digging into earth
    set speed_vert min-pycor - ycor
  ]
  
  ;fd speed_vert
  setxy xcor + 1 ycor + speed_vert
  
  ;die if you hit the ground
  if ycor = min-pycor [explode_and_die]   
end

to create_agent
  crt 1 [
    set shape "circle"
    set size 2
    set heading 0
    pd
    set pen-size 3
  ]
  print "AGENT CREATED"
end

to set_system_parameters
  print "SYSTEM PARAMETERS SET"
end

to draw_world
  ask patches [if pycor = target [set pcolor yellow]]
end

to explode_and_die
  set color red 
  set size 20 wait 0.2 
  set color yellow 
  set size 40 wait 0.2 
  die
end

Automation: turn it on and it runs by itself

Pay Attention to Future
Derivative as Current Rate of Change

Prop Speed

TARGET

POSITION

E

Kp

Kd

Drone 4.0

Create k_d slider (interface)

Add global variable last_err and delta_err (1). Include them in error computations (12-14)

Add Kd term to command computation. (17)

globals [err last_err delta_err]

to setup
  ca
  create_agent
  set_system_parameters
  draw_world
end

to go
  print "COMPUTING ERROR"
  set last_err err ;remember the error from last round
  set err target - ycor
  set delta_err err - last_err
  
  print "COMPUTING COMMAND"
  let prop_speed k_p * err + k_d * delta_err
  let speed_vert (prop_speed - 100) / 10
  
  if (ycor + speed_vert) > max-pycor [ ;blasting through sky
    set speed_vert max-pycor - pycor
  ]
  if (ycor + speed_vert) < min-pycor [ ;digging into earth
    set speed_vert min-pycor - ycor
  ]
  
  ;fd speed_vert
  setxy xcor + 1 ycor + speed_vert
  
  ;die if you hit the ground
  if ycor = min-pycor [explode_and_die]   
end

to create_agent
  crt 1 [
    set shape "circle"
    set size 2
    set heading 0
    pd
    set pen-size 3
  ]
  print "AGENT CREATED"
end

to set_system_parameters
  print "SYSTEM PARAMETERS SET"
end

to draw_world
  ask patches [if pycor = target [set pcolor yellow]]
end

to explode_and_die
  set color red set size 20 wait 0.2 set color yellow set size 40 wait 0.2 die
end

Add DERIVATIVE Control

Pay Attention to Past
Integral as Cumulative Error

Prop Speed

TARGET

POSITION

E

Kp

Kd

Ki

Drone 5.0

Create k_i slider (interface)

Add global variable cum_err and time_elapsed (1). Include them in error computations (12-14)

Add I term to command computation. (17)

globals [err last_err delta_err cum_error elapsed_time]

to setup
  ca
  create_agent
  set_system_parameters
  draw_world
end

to go
  print "COMPUTING ERROR"
  set last_err err ;remember the error from last round
  set err target - ycor
  set delta_err err - last_err
  set cum_error cum_error + err
  set elapsed_time elapsed_time + 1

  print "COMPUTING COMMAND"
  let prop_speed k_p * err + k_d * delta_err + k_i * cum_error
  let speed_vert (prop_speed - 100) / 10

  if (ycor + speed_vert) > max-pycor [ ;blasting through sky
    set speed_vert max-pycor - pycor
  ]
  if (ycor + speed_vert) < min-pycor [ ;digging into earth
    set speed_vert min-pycor - ycor
  ]

  ;fd speed_vert
  setxy xcor + 1 ycor + speed_vert

  ;die if you hit the ground
  if ycor = min-pycor [explode_and_die]
end

to create_agent
  crt 1 [
    set shape "circle"
    set size 2
    set heading 0
    pd
    set pen-size 3
  ]
  print "AGENT CREATED"
end

to set_system_parameters
  set cum_error 0
  set elapsed_time 0
  print "SYSTEM PARAMETERS SET"
end

to draw_world
  ask patches [if pycor = target [set pcolor yellow]]
end

to explode_and_die
  set color red set size 20 wait 0.2 set color yellow set size 40 wait 0.2 die
end

Add INTEGRAL Control

Drone 6.0

x (interface)

x(12-14)

x. (17)

globals [err last_err delta_err cum_error elapsed_time]
extensions [sound]

to setup
  ca
  create_agent
  set_system_parameters
  draw_world
end

to go
  ;print "COMPUTING ERROR"
  set last_err err ;remember the error from last round
  set err target - ycor
  set delta_err err - last_err
  set cum_error cum_error + err
  set elapsed_time elapsed_time + 1
  
  if sound_on [sound:play-note "TRUMPET" 60 - ceiling err 64 - ceiling err 0.25]
  ;if sound_on [sound:play-note "gunshot" 60 - ceiling err 64 - ceiling err 2]

  ;print "COMPUTING COMMAND"
  let prop_speed k_p * err + k_d * delta_err + k_i * cum_error
  let speed_vert (prop_speed - 100) / 10

  if (ycor + speed_vert) > max-pycor [ ;blasting through sky
    set speed_vert max-pycor - pycor
  ]
  if (ycor + speed_vert) < min-pycor [ ;digging into earth
    set speed_vert min-pycor - ycor
  ]

  ;fd speed_vert
  setxy xcor + 1 ycor + speed_vert

  ;die if you hit the ground
  if ycor = min-pycor [explode_and_die]
end

to create_agent
  crt 1 [
    set shape "circle"
    set size 2
    set heading 0
    pd
    set pen-size 1
  ]
  ;print "AGENT CREATED"
end

to set_system_parameters
  set cum_error 0
  set elapsed_time 0
  ;print "SYSTEM PARAMETERS SET"
end

to draw_world
  ask patches [if pycor = target [set pcolor yellow]]
end

to explode_and_die
  if sound_on [sound:play-note "gunshot" 60  127 2]
  sound:play-drum "Acoustic Bass Drum" 127
  set color red set size 20 wait 0.2 set color yellow set size 40 wait 0.2 die
end

More Tweaks

Craziness

ISCHOOL VISUAL IDENTITY

#002554

#fed141

#007396

#382F2D

#3eb1c8

#f9423a

#C8102E

NetLogo 0.0

globals [err delta_error cum_error abs_cum_error CE elapsed_time max_rpm max_vy]
turtles-own [vy vx ay ax]
extensions [sound]

to setup
  ; clear all and reset global values
  ca    
  set err 0
  set delta_error 0
  set cum_error 0
  ; create an agent and set initial properties
  crt 1 [ 
         set shape "ufo side" 
         set size 5 
         set heading 0
         setxy min-pxcor + 1 min-pycor + 1
         set ay 0 set vy 0 set ax 0 set vx 0
         pd ]
  ; draw target elevation line
  ask patches [if pycor = targety [set pcolor white]]
end

to go
  if not any? turtles [ stop ]
  ask turtles [   
      ; time passes and drone moves to the right
      ; set xcor xcor + 0.1
      set elapsed_time elapsed_time + 1  
 
      ; compute error values   
      let old_error err
      set err targety - ycor
      set delta_error old_error - err
      set cum_error   cum_error + err
      set abs_cum_error   abs_cum_error + abs err
      ifelse Use_Abs_Cum 
      [ set CE abs_cum_error ]
      [ set CE cum_error ]
      
      sound:play-note "TRUMPET" 60 - ceiling err 64 - ceiling err 0.25

      ; run the PID control equation
      set vy  (((Kp * err + Kd * delta_error + Ki * CE ) - 100) / 100)

      ; compute change in y (vertical) position
      let deltay 0
      if vy < 0 [ ; drone is falling
        set color red
        set deltay max list vy (min-pycor - ycor) ]
      if vy > 0 [ ; drone is rising
        set color green
        set deltay min list vy (max-pycor - ycor) ]
      if vy = 0 [ ; drone is hovering
        set color blue]
    
      setxy xcor + 0.3 ycor + deltay + wind
    if ycor <= min-pycor [set size 20 wait 0.2 die]
    ]

end

to ZeroKd
  set Kd 0
end
to ZeroKi
  set Ki 0
end
to ZeroKp
  set Kp 0
end

to-report wind
  if windy[
    report (windspeed - random (2 * windspeed)) / 10]
  report 0
end