Processing: Autonomous Steering Behaviours: Part 01

networkswarm_0405

Definitions
SWARM “to mean any loosely structured collection of agents that interact with one another.
Kennedy, James. Eberhart, Russel C. Swarm Intelligence.

AGENTS “refers to an object in a computer program that has an identity and performs some actions, usually with some presumption that the activities of the agent are somewhat autonomous or independent of the activities of the other agents.”
Kennedy, James. Eberhart, Russel C. Swarm Intelligence.

EMERGENCE “the movement from low-level rules to higher-level sophistification”
Johnson, Stephen. Emergence: The Conected Lives of Ants, Brains, Cities and Software.

Introduction
Agent systems are time-based networks driven by simple, highly local and individually motivated rules pertaining to the interaction of objects – deliberately coined agents – as opposed to particles – to exaggerate their programmed or embedded intelligences. The most common examples usually given of such systems are those of bird flocks, ant colonies, and swarms of bees. An agent moves through space motivated by its own desire (velocity), stimulated by goal seeking (attractors, targets, etc..) and is also informed by the presence of fellow members of the population at a local level. It is this latter aspect which gives large populations of agents a collective body as the agents make “steering” decisions based upon the presence, speed and direction of any neghbours who may fall within a range of perception (sight, smell, etc…). These steering behaviours were largely pioneered by Craig Reynolds who has long demonstrated that 3 simple steering behaviors are sufficient for a computer model to exhibit swarm-like character. These behaviors are separation, alignment and cohesion. For further reading on steering behaviours, see:

  • Craig Reynolds Website
  • Dan Shiffman has also written an excellant introduction to steering behaviours in Processing. Indeed he has an excellant teaching page in general for all things Processing. To learn more visit:

  • Dan Shiffman: Nature of Code
  • Prior to reading on, it is assumed that you have already read the tutorials on Object Orientated Programming and those pertaining to particle systems. If you have not done so, then it is best to review these prior to proceeding!

    Applying Steering Forces
    As we have already seen through dealing with the application of forces on particles, an agent is defined by three vectors; its position or coordinate in space (x,y,z), its velocity (x,y,z) which describes both its heading and speed, and finally its acceleration (x,y,z) at each time frame. And again as we have previously seen, the future position of the agent is simply calculated by adding its current velocity to its current position. The acceleration of an agent is the sum of all external and internal forces over and above its velocity. In the example of agent steering it may be the effect of goal seeking (steering toward a target), or the influence of swarm or collective behaviour. We shall deal with population-based steering behaviours later, but essentially the process is the same as we need to calculate the forces of acceleration each time step, add them to the velocity and reset the acceleration to zero prior to the next time step.

    To do so, we first need a function that we can call each iteration to update the agents position. It will look like this:

     
    void run(SuperWorld WORLD){
     
        // calculate acceleration forces
        acc = blah, blah, blah, blah, blah......  // calculate the acceleration forces
     
        // update position
        vel.add(acc);         // add the acceleration to the velocity
        vel.limit(maxVel);    // clip the velocity to a maximum allowable 
        pos.add(vel);         // add velocity to position
        acc.set(0,0,0);       // make sure we set acceleration back to zero!
     
        // standard update functions
        render(); // draw the agent!
      }

    Steering Function
    The first function we shall write is a steering function so that we may steer our agents toward a target or attractor. The steering function receives 3 arguments, a target, a dimensional range, and a third boolean argument called slowDown. The following is modelled after Dan Shiffman’s example (hence the argument name). The slowDown argument allows (when TRUE) the agent to arrive at its target, ie, reduce speed and effectively hover at the target. If the slowDown is not activated (FALSE), the agent will overshoot the target, and appear something like a moth buzzing around a light source. The steer function returns a force (vector) which we then need to add to the agents acceleration in order for any effect to take place. The best way to do this is via a function which handles both the input and output of the steer function – seek.

     
     //-------------------------------------------------------------SEEK TARGET
      void seek(PVector target, float threshold){
        acc.add( steer(target,threshold, true) );
      }
     
      //------------------------------------------------------------STEER
      PVector steer (PVector target, float threshold, boolean slowDown ){
        PVector steerForce;  // The steering vector
        target.sub(pos);
        float d2 = target.mag();
     
        if ( d2 > 0 && d2 < threshold){
          target.normalize();
          if( (slowDown) && d2 < threshold/2 ) target.mult( maxVel * (threshold/ENVX) );
          else target.mult(maxVel);
          target.sub(vel);
          steerForce = target.get();
          steerForce.limit(maxForce);
        }
        else {
          steerForce = new PVector(0,0,0);
        }
        return steerForce;
      }

    swarmSeek

    Example 01: Seeking a Target

     
    /*-------------------------------------------------------------------------------------------------
     Declare our variables
     -------------------------------------------------------------------------------------------------*/
    ArrayList agents;       // an arraylist to store all of our agents!
    PVector TARGET;         // The target will be the current position of the mouse!
     
    int numAgents = 10;
    int ENVX      = 500;    // size of the environment in the X direction 
    int ENVY      = 500;    // size of the environment in the Y direction
     
    /*-------------------------------------------------------------------------------------------------
     Setup Sketch
     -------------------------------------------------------------------------------------------------*/
    void setup(){
     
      size(ENVX,ENVY, P3D);                            // set the applet size to desired environment
      background(0);                                   // set the applet background to black
      ellipseMode(CENTER);
     
      agents = new ArrayList();                        // make our arraylist to store our agents
     
      TARGET = new PVector(ENVX/2, ENVY/2, 0);      // make a starting target
     
     
      // loop to make our agents!
      for(int i = 0; i < numAgents; i++){
        agents.add( new SuperAgent() );                   
      }
     
    }
     
    /*-------------------------------------------------------------------------------------------------
     Draw Loop
     -------------------------------------------------------------------------------------------------*/
    void draw(){
      background(0);                                  // Set the applet background to black
     
      TARGET = new PVector(mouseX, mouseY, 0);        // if mouse is pressed then update target
     
      for(int i = 0; i < agents.size(); i++){
        SuperAgent A = (SuperAgent) agents.get(i);    
        A.run();                                      // Pass the population of agents to the agent!
      }
     
    } 
     
    /*-------------------------------------------------------------------------------------------------
     Agent Class
     -------------------------------------------------------------------------------------------------*/
    class SuperAgent{
     
      // *** CLASS VARIABLES ***
      PVector pos, vel, acc;
      float maxVel, maxForce, rangeOfVision;
      int agentSize, agentColour;
     
      // *** CLASS CONSTRUCTOR ***
      SuperAgent(){
        // 3 vectors to describe agents position, heading & speed
        pos           = new PVector( random(0,width), random(0,height), 0 );
        vel           = new PVector( random(-1,1), random(-1,1), 0 );
        acc           = new PVector(0,0,0);
        // max speed and steering force variables
        maxVel        = random(1.5, 3.0);
        maxForce      = random(0.2, 0.5);    
        rangeOfVision = 120;
        // Appearance of agent
        agentSize     = 10;
        agentColour   = 175;
      }
     
      // *** CLASS METHODS ***
     
      //----------------------PRIMARY FUNCTION - call all other functions here!
      void run(){ 
     
        seek(TARGET.get(), rangeOfVision, true);    // Call the agents seek function and be sure to pass the correct numebr of arguments!     
     
        // update position
        vel.add(acc);         // add the acceleration to the velocity
        vel.limit(maxVel);    // clip the velocity to a maximum allowable 
        pos.add(vel);         // add velocity to position
        acc.set(0,0,0);       // make sure we set acceleration back to zero!
     
        // standard update functions
        toroidalBorders();    // wrap around screen - agent leaves on the left and returns on the right!
        render();             // draw the agent!
      }
     
      //---------------------- SEEK TARGET
      void seek(PVector target, float threshold, boolean slowDown){
        acc.add( steer(target,threshold, slowDown) );
      }
     
      //----------------------STEER
      PVector steer (PVector target, float threshold, boolean slowDown ){
        PVector steerForce;  // The steering vector
        target.sub(pos);
        float d2 = target.mag();
     
        if ( d2 > 0 && d2 < threshold){
          target.normalize();
          if( (slowDown) && d2 < threshold/2 ) target.mult( maxVel * (threshold/ENVX) );
          else target.mult(maxVel);
          target.sub(vel);
          steerForce = target.get();
          steerForce.limit(maxForce);
        }
        else {
          steerForce = new PVector(0,0,0);
        }
        return steerForce;
      }
     
      //----------------------WRAP AROUND SCREEN - KEEP AGENTS ON THE SCREEN
      void toroidalBorders(){
        if(pos.x < 0   ) pos.x = ENVX;
        if(pos.x > ENVX) pos.x = 0;
        if(pos.y < 0   ) pos.y = ENVY;
        if(pos.y > ENVY) pos.y = 0;
      }
     
     
     
      //----------------------DRAW THE AGENT
      void render(){
        stroke(agentColour);
        fill(agentColour,90);
        // put a circle on the agents position
        ellipse(pos.x,pos.y, agentSize, agentSize);
        // draw the heading of the agent
        line(pos.x, pos.y, pos.x+(vel.x*agentSize), pos.y+(vel.y*agentSize) );    
      }
     
    }

    About this entry