Subsumption: An Example

If you have a knee-jerk reaction to this, you're on the right track.

Subsumption in occam-pi

This example code accompanies the paper Mobile Robot Control: The Subsumption Architecture and occam-pi and demonstrates a simple subsumptive architecture implemented in occam-pi.

#INCLUDE "player.inc"
#USE "course.lib"

-- Constants for motor commands
VAL INT motor.stop IS 0:
VAL INT motor.forward IS 1:
VAL INT motor.back.right IS 2:

PROC motor (CHAN INT motor.command?, CHAN MOTORS motor.control!)
  VAL INT speed IS 50:
  VAL INT turn.rate IS 40:
  WHILE TRUE
    INT command:
    SEQ
      motor.command ? command
      CASE command
        motor.stop
          motor.control ! 0 ; 0 ; 0
        motor.forward
          motor.control ! speed ; 0 ; 0
        motor.back.right
          motor.control ! -speed ; 0 ; -turn.rate
        ELSE
          STOP
:

PROC motor.command.suppressor (VAL INT time, CHAN INT suppress?, in?, out!)
  TIMER tim:
  INITIAL INT timeout IS 0:
  INITIAL BOOL suppressing IS FALSE:
  INT value:
  WHILE TRUE
    PRI ALT
      NOT suppressing & suppress ? value
        SEQ
          suppressing := TRUE
          tim ? timeout
          timeout := timeout PLUS time
          out ! value
      NOT suppressing & in ? value
        out ! value
      suppressing & tim? AFTER timeout
        suppressing := FALSE
      suppressing & suppress ? value
        out ! value
:

PROC prevent.collision (CHAN INT minimum.distance?, CHAN INT motor.command!)
  WHILE TRUE
    INITIAL INT min IS 0:
    SEQ
      minimum.distance ? min
      IF
        min = 0
          SKIP
        min < 20
          motor.command ! motor.stop
        TRUE
          motor.command ! motor.forward
:

PROC min.distance (SHARED CHAN LASER laser.data?, CHAN INT min.distance!)
  LASER data:
  WHILE TRUE
    INITIAL INT min IS (MOSTPOS INT):
    SEQ
      CLAIM laser.data?
        laser.data ? data
      SEQ i = 0 FOR SIZE data
        SEQ
          IF
            data[i] = 0
              SKIP
            data[i] < min
              min := data[i]
            TRUE
              SKIP
      min.distance ! min
:

PROC object.in.front (SHARED CHAN LASER laser.data?, CHAN BOOL object!)
  LASER data:
  WHILE TRUE
    SEQ
      CLAIM laser.data?
        laser.data ? data
      SEQ i = 75 FOR 90
        IF
          data[i] = 0
            SKIP
          data[i] < 150
            object ! TRUE
          TRUE
            SKIP
:

PROC pivot.if.object (CHAN BOOL object?, CHAN INT motor.command!)
  WHILE TRUE
    BOOL flag:
    SEQ
      object ? flag
      IF
        flag
          motor.command ! motor.back.right
        TRUE
          SKIP
:

PROC check.has.space (CHAN SONAR sonar.data?, CHAN BOOL no.space!)
  WHILE TRUE
    SONAR data:
    SEQ
      sonar.data ? data
      SEQ i = 11 FOR 4
        IF
          data[i] < 50
            no.space ! TRUE
          TRUE
            SKIP
:

PROC pivot.inhibitor (VAL INT time, CHAN BOOL inhibit, CHAN INT in?, out!)
  TIMER tim:
  INITIAL INT timeout IS 0:
  INITIAL BOOL inhibiting IS FALSE:
  INT data:
  BOOL flag:
  WHILE TRUE
    PRI ALT
      inhibit ? flag 
        SEQ
          inhibiting := TRUE
          tim ? timeout
          timeout := timeout PLUS time
      inhibiting & tim? AFTER timeout
        inhibiting := FALSE
      NOT inhibiting & in ? data
        out ! data
      inhibiting & in ? data
        SKIP
:


PROC circle.or.line.follow (CHAN BYTE kyb?, scr!, err!)
  CHAN MOTORS motor.control:
  CHAN INT minimum.distance:
  CHAN INT motor.command.in, motor.command.out, motor.command.suppress:
  CHAN INT pivot.motor.command.in, pivot.motor.command.out: 
  SHARED ? CHAN LASER laser.data:
  CHAN SONAR sonar.data:
  CHAN BOOL object, inhibit:
  PAR
    motor(motor.command.out?, motor.control!)
    brain.stem(motor.control?, laser.data!, sonar.data!, default.player.host, default.player.port)
    min.distance(laser.data?, minimum.distance!)
    prevent.collision(minimum.distance?, motor.command.in!)
    object.in.front(laser.data?, object!)
    pivot.if.object(object?, pivot.motor.command.in!)
    motor.command.suppressor(10000, pivot.motor.command.out?, motor.command.in?, motor.command.out!)
    pivot.inhibitor(100000, inhibit?, pivot.motor.command.in?, pivot.motor.command.out!)
    check.has.space(sonar.data?, inhibit!)
: