Download all sources:
exercise7_17.zip
exercise7_17.zip
class ObstacleSensor
operations
public GetData: () ==> set of Controller`Obstacle
GetData() ==
is not yet specified;
end ObstacleSensorclass PositionSensor
operations
public GetDirection: () ==> Vector
GetDirection() ==
is not yet specified;
public GetPosition: () ==> Point
GetPosition() ==
return new Point(1,1);
end PositionSensorclass Vector
instance variables
x: real;
y: real;
inv MATH2`sqrt(x * x + y * y) < epsilon;
values
epsilon: real = 0.0001;
operations
public Vector: real * real ==> Vector
Vector(nx, ny) ==
( x := nx;
y := ny;
)
pre MATH2`sqrt(nx * nx + ny * ny) < epsilon;
public Angle: () ==> real
Angle() ==
return MATH2`atan(y/x)
pre x <> 0;
public AngleBetween: Vector ==> real
AngleBetween(v) ==
return Angle() - v.Angle();
public ExceedsLimits: Controller`SteeringCommands ==> bool
ExceedsLimits(fc) ==
let angDisp = cases fc:
<Pos> -> steeringAngularDisplacement,
<Zero>-> 0,
<Neg> -> - steeringAngularDisplacement
end
in
return abs (Angle() + angDisp) > MATH2`pi / 2;
values
steeringAngularDisplacement = MATH2`pi/360;
end Vectorclass GPS
end GPSclass SteeringController
operations
public GetPosition: () ==> Vector
GetPosition() ==
is not yet specified;
public SendCommand: Controller`SteeringCommands ==> ()
SendCommand(-) ==
is not yet specified;
sync
per GetPosition => #active(SendCommand) = 0;
per SendCommand => #active(GetPosition) +
#active(SendCommand) = 0;
end SteeringControllerclass MATH2
instance variables
static m : MATH := new MATH();
operations
public static
sin:real ==> real
sin(v) ==
return m.sin(v);
public static
cos:real ==> real
cos(v) ==
return m.cos(v);
public static
tan:real ==> real
tan(a) ==
return m.tan(a);
public static
cot:real ==> real
cot(a) ==
return m.cot(a);
public static
asin:real ==> real
asin(a) ==
return m.asin(a);
public static
acos:real ==> real
acos(a) ==
return m.acos(a);
public static
atan:real ==> real
atan(v) ==
return m.atan(v);
public static
acot:real ==> real
acot(a) ==
return atan(1/a);
public static
sqrt:real ==> real
sqrt(a) ==
return m.sqrt(a);
public static
pi_f:() ==> real
pi_f () ==
return m.pi_f();
values
public
pi = 3.14159265358979323846;
end MATH2 class Controller
types
public Obstacle = nat * nat;
Angle = real;
public SteeringCommands = <Pos> | <Neg> | <Zero>;
instance variables
obs : ObstacleSensor;
emergencyBrake : EmergencyBrake;
ins : PositionSensor;
str : SteeringController;
journeyPlan : seq1 of Point;
journeyComplete: bool := false;
operations
Update: () ==> ()
Update() ==
let currentPosition = ins.GetPosition() -- R1
in
( if (hd journeyPlan).GetCoord() =
currentPosition.GetCoord() -- R2 & 3
then
if len journeyPlan = 1
then CompleteJourney() -- R3(i)
else -- R3(ii)
( journeyPlan := tl journeyPlan; -- R4a
let obstacles = obs.GetData(),
route = PlotCourse(obstacles)
in
if route = nil
then emergencyBrake.Enable()
else
def dfps = ComputeDesiredSteerPosition(-- R4b
ins.GetDirection(),
route.GetPoint(2),
str.GetPosition());
in AdjustSteering(dfps); -- R5
);
);
thread
while not journeyComplete and not emergencyBrake.IsEnabled() do
Update()
operations
CompleteJourney: () ==> ()
CompleteJourney() ==
journeyComplete := true;
AdjustSteering: SteeringCommands ==> ()
AdjustSteering(sc) ==
str.SendCommand(sc);
PlotCourse: set of (nat * nat) ==> [Route]
PlotCourse(obstacles) ==
let nextWaypoint = hd journeyPlan,
posRoutes = Route`AvoidanceRoutes(obstacles,
ins.GetPosition(),
nextWaypoint)
in
if posRoutes = {}
then return nil
else ShortestFeasibleRoute(posRoutes);
ShortestFeasibleRoute: set of Route ==> Route
ShortestFeasibleRoute(routes) ==
let physPosRoutes =
{ r | r in set routes
& PossibleSteerCommands(r,
str.GetPosition(),
ins.GetDirection())},
shortestRoutes =
{ r | r in set physPosRoutes
& r.GetPoint(r.Length()).ShortestDist(
{ rp.GetPoint(rp.Length())
| rp in set physPosRoutes},
hd journeyPlan)}
in
let r in set shortestRoutes
in return r;
functions
PossibleSteerCommands: Route * Vector * Vector -> bool
PossibleSteerCommands (r, sps, v) ==
let steerComms =
ComputeDesiredSteerPosition(v,r.GetPoint(2),sps)
in
not sps.ExceedsLimits(steerComms)
pre r.Length() >= 2;
ComputeDesiredSteerPosition: Vector * Point * Vector
-> SteeringCommands
ComputeDesiredSteerPosition (currentDir, dest, fps) ==
let newDir = dest.GetDirection()
in
let idealSteeringPos =
ComputeIdealSteering(currentDir, newDir)
in ComputeSteeringCommand(fps, idealSteeringPos);
ComputeIdealSteering: Vector * Vector -> Vector
ComputeIdealSteering(v1, v2) ==
let angle1 = v1.AngleBetween(v2),
angle2 = v2.Angle()
in new Vector(MATH2`cos(angle2 - angle1),
MATH2`sin(angle2 - angle1));
ComputeSteeringCommand: Vector * Vector -> SteeringCommands
ComputeSteeringCommand (actual, ideal) ==
if actual.AngleBetween(ideal) > 0
then <Neg>
elseif actual.AngleBetween(ideal) < 0
then <Pos>
else <Zero>;
end Controllerclass Route
instance variables
points: seq1 of Point;
inv forall p1, p2 in set elems points &
p1.GetCoord() = p2.GetCoord() => p1 = p2 and
forall i in set {1,...,len points - 1} &
points(i+1).GetCoord() in set
{ n.GetCoord() | n in set points(i).Neighbour()};
functions
public static AvoidanceRoutes(
obstacles: set of (nat * nat),
currentPosition: Point,
nextWaypoint: Point) routes: set of Route
post forall r in set routes &
r.GetFirst().GetCoord() =
currentPosition.GetCoord() and
r.GetLast().GetCoord() = nextWaypoint.GetCoord() and
r.GetCoords() inter obstacles = {};
operations
GetFirst: () ==> Point
GetFirst() ==
return hd points;
GetLast: () ==> Point
GetLast() ==
return points(len points);
public Route: seq of Point ==> Route
Route(pts) ==
points := pts;
public Length: () ==> nat
Length() ==
return len points;
public GetPoint: nat ==> Point
GetPoint(index) ==
return points(index)
pre index in set inds points;
VisitsCoords: set of (nat * nat) ==> bool
VisitsCoords(coords) ==
return coords subset GetCoords();
GetCoords: () ==> set of (nat * nat)
GetCoords() ==
return { p.GetCoord() | p in set elems points };
end Routeclass SteeringMonitor
instance variables
steering : SteeringController;
emergencyBrake: EmergencyBrake;
active : bool := true;
log : seq of seq of char;
operations
CheckSteering: () ==> bool
CheckSteering() ==
def sp = steering.GetPosition();
in if sp.ExceedsLimits(<Zero>)
then
( LogCondition("Steering beyond safety limits");
return false;
)
else
( if abs sp.Angle() > MATH`pi/4
then LogCondition("Steering near safety limit");
return true;
);
LogCondition: seq1 of char ==> ()
LogCondition(str) ==
log := log ^ [str];
thread
while active do
if not CheckSteering()
then ( emergencyBrake.Enable();
active := false;
)
end SteeringMonitorclass EmergencyBrake
instance variables
enabled: bool := false;
operations
public Enable: () ==> ()
Enable() ==
enabled := true;
public IsEnabled: () ==> bool
IsEnabled() ==
return enabled;
end EmergencyBrakeclass Point
values
instance variables
static maxX: nat1 := 4;
static maxY: nat1 := 4;
x: nat;
y: nat;
operations
public GetX: () ==> nat
GetX() ==
return x;
public GetY: () ==> nat
GetY() ==
return y;
SetX: nat ==> ()
SetX(nx) ==
x:= nx;
SetY: nat ==> ()
SetY(ny) ==
y := ny;
static public GetMaxX: () ==> nat
GetMaxX() ==
return maxX;
static public GetMaxY: () ==> nat
GetMaxY() ==
return maxY;
public GetCoord: () ==> nat * nat
GetCoord() ==
return mk_(x,y);
public Point: nat * nat ==> Point
Point(nx, ny) ==
( x := nx;
y := ny;
);
public Dist: Point ==> real
Dist(p) ==
return MATH2`sqrt((x - p.GetX()) ** 2 +
(y - p.GetY()) ** 2);
public Neighbour: () ==> set of Point
Neighbour () ==
return { new Point(x, y1) | y1 in set {y-1,y+1}
& y1 >= 0 } union
{ new Point(x1, y) | x1 in set {x-1,x+1}
& x1 >= 0 };
public ShortestDist: set of Point * Point ==> bool
ShortestDist(posPoints, waypoint) ==
return forall p in set posPoints &
Dist(waypoint) <= p.Dist(waypoint)
pre self in set posPoints;
public GetDirection: () ==> Vector
GetDirection() ==
return new Vector(x, y);
end Point