Homepage | Demos | Overview | Downloads | Dev. Resources | Reference | Credits |
WaypointEngine< MAX_WAY > Class Template Reference#include <WaypointEngine.h>
Inheritance diagram for WaypointEngine< MAX_WAY >: ![]() Detailed Descriptiontemplate<unsigned int MAX_WAY>
Provides computation and management of a desired path through a series of waypoints.
|
![]() Egocentric: the x and y parameters are relative to the body itself; x is always forward and y is always left. Handy for turtle/logo style specification of instructions | ![]() Offset: the x and y parameters are relative to the current body position, but not its heading. | ![]() Absolute: the x and y parameters are direct coordinates |
These specify the position of the next waypoint, but we also need to be able to specify the orientation (heading) of the robot. This is done by specifying an angle and a mode which controls how that angle is interpreted: Waypoint::angleIsRelative, which can be true
or false
.
![]() angleIsRelative== true: The angle is relative to the path, so that 0 will keep the robot pointed in the direction of travel, even when arcing. Similarly, ![]() | ![]() angleIsRelative== false: The angle is relative to the world coordinate system, so a constant heading is maintained throughout execution of the path. |
The final orientation of the robot is simply the heading it was facing when it reaches the end point. To turn in place, you can use a (0,0) egocentric or offset waypoint with an angle parameter.
In order to execute curves, you can supply an arc value:
![]() Here you see the results of 3 different arc values ![]() |
There are two ways to specify arcs. The add*Waypoint
functions use the position arguments to specify the end point of the arc, and the arc parameter serves to "bow" the path. The add*Arc
functions specify the center of the circle as the position, and the end point is inferred from the amount of the arc to sweep.
Beware that arcs greater than are entirely possible, but will create larger and larger circles which may cause the robot to initially start moving away from the destination. This isn't necessarily a bad thing, but may be unanticipated. Values approaching
may cause numerical instability yielding infinitely large circles. Values larger than
will be normalized to the range
.
Dead reckoning is very prone to accruing error. It is highly recommended that you calibrate the locomotion mechanism carefully (see WalkCalibration, available under the "Walk Edit" menu with a run-time help menu) and implement some form of localization to handle the inevitable drift.
If you have a localization module in place, you can use the setCurPos() function to update the position of the robot within the world. WaypointEngine provides two ways to handle this ensuing discrepency from the path the robot had been tracing:
![]() The effect of the Waypoint::trackPath flag. When true , the robot will attempt to catch up to its "ideal" location after a perterbation. When false , the robot will ignore the "ideal" path, and just go straight to the destination from wherever perterbations may push it. |
trackPath is a per-waypoint setting, setTracking() sets the default value for any new waypoints which are thereafter created (the default default is false ;)
Waypoint list files are a fairly straightforward plain text format. The extension .wyp is suggested.
The waypoint file format is:
#WyP
' - header to verify file typemax_turn_speed
num' - sets the maximum error-correction turning speed used for all following waypointstrack_path
bool' - sets trackpath mode on or off for all following waypoints (see Waypoint::trackPath)add_point
{ego
|off
|abs
}
x_val
y_val
{hold
|follow
}
angle_val
speed_val
arc_val' - adds the waypoint with the parameters given, see Waypoint, similar to add*Waypoint functionsadd_arc
{ego
|off
|abs
}
x_val
y_val
{hold
|follow
}
angle_val
speed_val
arc_val' - adds the waypoint with the parameters given, see Waypoint, similar to add*Arc functions#END
' - footer to verify ending of file
Definition at line 115 of file WaypointEngine.h.
Public Types | |
typedef ListMemBuf< Waypoint, MAX_WAYPOINTS > | WaypointList_t |
convenient shorthand | |
typedef ListMemBuf< Waypoint, MAX_WAYPOINTS >::index_t | WaypointListIter_t |
convenient shorthand | |
Public Member Functions | |
WaypointEngine () | |
constructor | |
WaypointEngine (char *f) | |
constructor | |
virtual unsigned int | getBinSize () const |
returns a rough overestimate of the size needed | |
virtual unsigned int | LoadBuffer (const char buf[], unsigned int len) |
Load from a saved buffer. | |
virtual unsigned int | SaveBuffer (char buf[], unsigned int len) const |
Save to a given buffer. | |
virtual unsigned int | LoadFile (const char *filename) |
initiate opening of the specified file and loading/saving of all appropriate information. | |
virtual unsigned int | SaveFile (const char *filename) const |
initiate opening of the specified file and loading/saving of all appropriate information. | |
virtual void | go () |
starts walking towards the first waypoint | |
virtual void | pause () |
halts execution of waypoint list | |
virtual void | unpause () |
resumes execution of waypoint list from last paused location | |
virtual void | setIsLooping (bool isl) |
sets isLooping | |
virtual bool | getIsLooping () const |
returns isLooping | |
virtual WaypointList_t & | getWaypointList () |
returns a reference to waypoints | |
virtual const WaypointList_t & | getWaypointList () const |
returns a const reference to waypoints | |
virtual WaypointListIter_t | getCurWaypointID () const |
returns id value of current waypoint (curWaypoint) | |
virtual float | getCurX () const |
returns current x position | |
virtual float | getCurY () const |
returns current y position | |
virtual float | getCurA () const |
virtual void | setCurPos (float x, float y, float a) |
sets the current position (for instance your localization module has an update) | |
virtual void | setTracking (bool b) |
sets the isTracking flag, only affects future waypoints which are added, not currently listed waypoints (use getWaypointList() to modify existing waypoints) | |
virtual bool | getTracking () const |
returns isTracking | |
virtual bool | cycle () |
call this on each opportunity to check current location and correct velocities | |
virtual void | setTargetWaypoint (WaypointListIter_t iter) |
will set the currently active waypoint to another waypoint; correctly calculates location of intermediate waypoints so target location will be the same as if the intervening waypoints had actually been executed | |
Waypoint | calcAbsoluteCoords (WaypointListIter_t it) |
if it follows the current waypoint, applies all the waypoints between curWaypoint and it and returns result as an absolute position (angle field stores heading); otherwise calls the other calcAbsoluteCoords(WaypointListIter_t, float, float, float) | |
Waypoint | calcAbsoluteCoords (WaypointListIter_t it, float sx, float sy, float sa) |
starts at (sx, sy, heading=sa) and then applies all the waypoints up through it and returns result as an absolute position (angle field stores heading) | |
Adding Waypoints | |
these are for convenience - can also directly edit the waypoint list using access from getWaypointList() | |
virtual void | addEgocentricWaypoint (float forward, float left, float angle, bool angleIsRelative, float speed) |
adds a waypoint to the end of the list, allows you to specify turtle-style instructions | |
virtual void | addOffsetWaypoint (float x, float y, float angle, bool angleIsRelative, float speed) |
adds a waypoint to the end of the list, allows you to set locations relative to the location of the previous waypoint (or starting position) | |
virtual void | addAbsoluteWaypoint (float x, float y, float angle, bool angleIsRelative, float speed) |
adds a waypoint to the end of the list, allows you to set locations relative to the world coordinate frame | |
virtual void | addEgocentricArc (float forward, float left, float angle, bool angleIsRelative, float speed, float arc) |
adds a waypoint to the end of the list, using an arcing path to get there, allows you to specify turtle-style instructions to specify the focus of the arc | |
virtual void | addOffsetArc (float x, float y, float angle, bool angleIsRelative, float speed, float arc) |
adds a waypoint to the end of the list, using an arcing path to get there, allows you to specify locations relative to previous waypoint to specify the focus of the arc | |
virtual void | addAbsoluteArc (float x, float y, float angle, bool angleIsRelative, float speed, float arc) |
adds a waypoint to the end of the list, using an arcing path to get there, allows you to specify absolute locations to specify the focus of the arc | |
Static Public Attributes | |
static const unsigned int | MAX_WAYPOINTS = MAX_WAY |
for external access to maximum waypoints | |
Protected Member Functions | |
void | init () |
basic memory initialization if next is a relative waypoint (offset or egocentric), it is added to the location held in cur; otherwise if next is absolute, cur is set to next | |
void | applyWaypoint (Waypoint &cur, const Waypoint &next) |
void | fixArc (float arc) |
assumes the last waypoint is actually center of circle, adjusts it to be the endpoint of following arc radians around that circle instead | |
void | computeCurrentPosition (unsigned int t) |
based on current velocity and time since last call, dead reckons current location in curPos | |
void | checkNextWaypoint (unsigned int t) |
checks to see if curPos is within eps of targetPos; if so, setTargetWaypoint() to next waypoint | |
void | computeIdeal (unsigned int t) |
computes the ideal location (idealPos) if we were following the intended path at the intended speed | |
void | computeNewVelocity (unsigned int t) |
computes the velocity which should be used given the current position (curPos) relative to the ideal position (idealPos) | |
Static Protected Member Functions | |
static float | normalizeAngle (float a) |
will set a to be between (-pi,pi) (inclusive), just like atan2() | |
static float | clipRange (float x, float min, float max) |
returns x such that it is at most max and at minimum min | |
Protected Attributes | |
WaypointList_t | waypoints |
storage for the waypoints | |
bool | isRunning |
true if we're currently executing the path | |
bool | isLooping |
true if we should loop when done | |
bool | isTracking |
new waypoints will use trackPath mode | |
unsigned int | curWaypoint |
index of current waypoint | |
unsigned int | waypointTime |
time we started working on current waypoint | |
float | waypointDistance |
distance from sourcePos to targetPos | |
float | pathLength |
distance to be traveled from sourcePos to targetPos (may differ from waypointDistance due to arcing) | |
float | arcRadius |
radius of current arc, may be inf or NaN if using a straight line; can also be negative depending on direction! | |
unsigned int | lastUpdateTime |
time we last updated curPos | |
float | pathStartPos [3] |
position when started execution of current path (aka origin offset for relative positions which preceed an absolute waypoint) | |
float | sourcePos [3] |
source position of the robot relative to the origin, aka absolute position of previous waypoint | |
float | targetPos [3] |
target position of the robot relative to the origin, aka absolute position of next waypoint | |
float | idealPos [4] |
ideal position of the robot relative to the origin, (x, y, heading, last element is desired direction of motion) | |
float | curPos [3] |
current position of the robot relative to the origin | |
float | curVel [3] |
current velocity | |
float | eps [3] |
epsilon - "close enough" to register a hit on the waypoint | |
float | Pcorr |
proportional correction factor for tracking path | |
float | turnSpeed |
maximum turning speed for new waypoints | |
Classes | |
struct | Waypoint |
Holds information about each waypoint, see WaypointEngine for overview. More... |
|
convenient shorthand
Definition at line 144 of file WaypointEngine.h. |
|
convenient shorthand
Definition at line 145 of file WaypointEngine.h. |
|
constructor
Definition at line 148 of file WaypointEngine.h. |
|
constructor
Definition at line 154 of file WaypointEngine.h. |
|
adds a waypoint to the end of the list, using an arcing path to get there, allows you to specify absolute locations to specify the focus of the arc
![]()
Definition at line 265 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::LoadBuffer(). |
|
adds a waypoint to the end of the list, allows you to set locations relative to the world coordinate frame
![]()
Definition at line 226 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::addAbsoluteArc(), and WaypointEngine< MAX_WAY >::LoadBuffer(). |
|
adds a waypoint to the end of the list, using an arcing path to get there, allows you to specify turtle-style instructions to specify the focus of the arc
![]()
Definition at line 239 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::LoadBuffer(). |
|
adds a waypoint to the end of the list, allows you to specify turtle-style instructions
![]()
Definition at line 206 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::addEgocentricArc(), and WaypointEngine< MAX_WAY >::LoadBuffer(). |
|
adds a waypoint to the end of the list, using an arcing path to get there, allows you to specify locations relative to previous waypoint to specify the focus of the arc
![]()
Definition at line 252 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::LoadBuffer(). |
|
adds a waypoint to the end of the list, allows you to set locations relative to the location of the previous waypoint (or starting position)
![]()
Definition at line 216 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::addOffsetArc(), and WaypointEngine< MAX_WAY >::LoadBuffer(). |
|
the Waypoint::angle field is used to store the headings Definition at line 648 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::calcAbsoluteCoords(), and WaypointEngine< MAX_WAY >::go(). |
|
starts at (sx, sy, heading=sa) and then applies all the waypoints up through it and returns result as an absolute position (angle field stores heading)
Definition at line 345 of file WaypointEngine.h. |
|
if it follows the current waypoint, applies all the waypoints between curWaypoint and it and returns result as an absolute position (angle field stores heading); otherwise calls the other calcAbsoluteCoords(WaypointListIter_t, float, float, float)
Definition at line 323 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::fixArc(), and WaypointEngine< MAX_WAY >::setTargetWaypoint(). |
|
checks to see if curPos is within eps of targetPos; if so, setTargetWaypoint() to next waypoint
Definition at line 723 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::cycle(). |
|
returns x such that it is at most max and at minimum min
Definition at line 383 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::computeNewVelocity(). |
|
based on current velocity and time since last call, dead reckons current location in curPos doesn't take acceleration into account, but should... :( Definition at line 704 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::cycle(). |
|
computes the ideal location (idealPos) if we were following the intended path at the intended speed
Definition at line 734 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::cycle(). |
|
computes the velocity which should be used given the current position (curPos) relative to the ideal position (idealPos)
Definition at line 803 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::cycle(). |
|
call this on each opportunity to check current location and correct velocities
Definition at line 447 of file WaypointEngine.h. Referenced by WaypointWalk< MAX_WAY >::updateOutputs(). |
|
assumes the last waypoint is actually center of circle, adjusts it to be the endpoint of following arc radians around that circle instead
Definition at line 683 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::addAbsoluteArc(), WaypointEngine< MAX_WAY >::addEgocentricArc(), and WaypointEngine< MAX_WAY >::addOffsetArc(). |
|
returns a rough overestimate of the size needed pretends we need to switch max_turn_speed and track_path on every point, and the longest options are given for every point Implements LoadSave. Definition at line 465 of file WaypointEngine.h. |
|
returns current heading Definition at line 183 of file WaypointEngine.h. |
|
returns id value of current waypoint (curWaypoint)
Definition at line 179 of file WaypointEngine.h. |
|
returns current x position
Definition at line 181 of file WaypointEngine.h. |
|
returns current y position
Definition at line 182 of file WaypointEngine.h. |
|
returns isLooping
Definition at line 174 of file WaypointEngine.h. |
|
returns isTracking
Definition at line 190 of file WaypointEngine.h. |
|
returns a const reference to waypoints
Definition at line 177 of file WaypointEngine.h. |
|
returns a reference to waypoints
Definition at line 176 of file WaypointEngine.h. |
|
starts walking towards the first waypoint
Definition at line 415 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::unpause(). |
|
basic memory initialization if next is a relative waypoint (offset or egocentric), it is added to the location held in cur; otherwise if next is absolute, cur is set to next
Definition at line 638 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::WaypointEngine(). |
|
Load from a saved buffer.
Implements LoadSave. Definition at line 479 of file WaypointEngine.h. |
|
initiate opening of the specified file and loading/saving of all appropriate information.
Reimplemented from LoadSave. Definition at line 166 of file WaypointEngine.h. Referenced by WaypointWalk< MAX_WAY >::LoadWaypointFile(), and WaypointEngine< MAX_WAY >::WaypointEngine(). |
|
will set a to be between (-pi,pi) (inclusive), just like atan2()
Definition at line 374 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::applyWaypoint(), WaypointEngine< MAX_WAY >::computeCurrentPosition(), WaypointEngine< MAX_WAY >::computeIdeal(), and WaypointEngine< MAX_WAY >::computeNewVelocity(). |
|
halts execution of waypoint list
Definition at line 432 of file WaypointEngine.h. |
|
Save to a given buffer.
Implements LoadSave. Definition at line 588 of file WaypointEngine.h. |
|
initiate opening of the specified file and loading/saving of all appropriate information.
Reimplemented from LoadSave. Definition at line 167 of file WaypointEngine.h. Referenced by WaypointWalk< MAX_WAY >::SaveWaypointFile(). |
|
sets the current position (for instance your localization module has an update)
Definition at line 185 of file WaypointEngine.h. |
|
sets isLooping
Definition at line 173 of file WaypointEngine.h. |
|
will set the currently active waypoint to another waypoint; correctly calculates location of intermediate waypoints so target location will be the same as if the intervening waypoints had actually been executed
Definition at line 273 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::checkNextWaypoint(), and WaypointEngine< MAX_WAY >::go(). |
|
sets the isTracking flag, only affects future waypoints which are added, not currently listed waypoints (use getWaypointList() to modify existing waypoints)
Definition at line 189 of file WaypointEngine.h. |
|
resumes execution of waypoint list from last paused location
Definition at line 437 of file WaypointEngine.h. |
|
radius of current arc, may be inf or NaN if using a straight line; can also be negative depending on direction!
Definition at line 401 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::computeIdeal(), WaypointEngine< MAX_WAY >::computeNewVelocity(), and WaypointEngine< MAX_WAY >::setTargetWaypoint(). |
|
current position of the robot relative to the origin
Definition at line 407 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::checkNextWaypoint(), WaypointEngine< MAX_WAY >::computeCurrentPosition(), WaypointEngine< MAX_WAY >::computeIdeal(), WaypointEngine< MAX_WAY >::computeNewVelocity(), WaypointEngine< MAX_WAY >::getCurA(), WaypointEngine< MAX_WAY >::getCurX(), WaypointEngine< MAX_WAY >::getCurY(), WaypointEngine< MAX_WAY >::go(), WaypointEngine< MAX_WAY >::init(), WaypointEngine< MAX_WAY >::setCurPos(), and WaypointEngine< MAX_WAY >::setTargetWaypoint(). |
|
current velocity
Definition at line 408 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::computeCurrentPosition(), WaypointEngine< MAX_WAY >::computeNewVelocity(), WaypointEngine< MAX_WAY >::go(), WaypointEngine< MAX_WAY >::init(), WaypointEngine< MAX_WAY >::setTargetWaypoint(), WaypointEngine< MAX_WAY >::unpause(), and WaypointWalk< MAX_WAY >::updateOutputs(). |
|
|
epsilon - "close enough" to register a hit on the waypoint
Definition at line 409 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::applyWaypoint(), WaypointEngine< MAX_WAY >::checkNextWaypoint(), WaypointEngine< MAX_WAY >::computeIdeal(), and WaypointEngine< MAX_WAY >::init(). |
|
ideal position of the robot relative to the origin, (x, y, heading, last element is desired direction of motion)
Definition at line 406 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::computeIdeal(), WaypointEngine< MAX_WAY >::computeNewVelocity(), and WaypointEngine< MAX_WAY >::init(). |
|
true if we should loop when done
Definition at line 395 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::getIsLooping(), WaypointEngine< MAX_WAY >::setIsLooping(), and WaypointEngine< MAX_WAY >::setTargetWaypoint(). |
|
true if we're currently executing the path
Definition at line 394 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::cycle(), WaypointEngine< MAX_WAY >::go(), WaypointEngine< MAX_WAY >::pause(), WaypointEngine< MAX_WAY >::setTargetWaypoint(), and WaypointEngine< MAX_WAY >::unpause(). |
|
new waypoints will use trackPath mode
Definition at line 396 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::addAbsoluteWaypoint(), WaypointEngine< MAX_WAY >::addEgocentricWaypoint(), WaypointEngine< MAX_WAY >::addOffsetWaypoint(), WaypointEngine< MAX_WAY >::calcAbsoluteCoords(), WaypointEngine< MAX_WAY >::getTracking(), WaypointEngine< MAX_WAY >::go(), WaypointEngine< MAX_WAY >::LoadBuffer(), and WaypointEngine< MAX_WAY >::setTracking(). |
|
time we last updated curPos
Definition at line 402 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::computeCurrentPosition(), WaypointEngine< MAX_WAY >::go(), and WaypointEngine< MAX_WAY >::unpause(). |
|
for external access to maximum waypoints
Reimplemented in WaypointWalk< MAX_WAY >. Definition at line 117 of file WaypointEngine.h. |
|
distance to be traveled from sourcePos to targetPos (may differ from waypointDistance due to arcing)
Definition at line 400 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::computeIdeal(), and WaypointEngine< MAX_WAY >::setTargetWaypoint(). |
|
position when started execution of current path (aka origin offset for relative positions which preceed an absolute waypoint)
Definition at line 403 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::calcAbsoluteCoords(), WaypointEngine< MAX_WAY >::go(), WaypointEngine< MAX_WAY >::init(), and WaypointEngine< MAX_WAY >::setTargetWaypoint(). |
|
proportional correction factor for tracking path
Definition at line 410 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::computeNewVelocity(). |
|
source position of the robot relative to the origin, aka absolute position of previous waypoint
Definition at line 404 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::computeIdeal(), WaypointEngine< MAX_WAY >::go(), WaypointEngine< MAX_WAY >::init(), and WaypointEngine< MAX_WAY >::setTargetWaypoint(). |
|
target position of the robot relative to the origin, aka absolute position of next waypoint
Definition at line 405 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::calcAbsoluteCoords(), WaypointEngine< MAX_WAY >::checkNextWaypoint(), WaypointEngine< MAX_WAY >::computeIdeal(), WaypointEngine< MAX_WAY >::computeNewVelocity(), WaypointEngine< MAX_WAY >::go(), WaypointEngine< MAX_WAY >::init(), and WaypointEngine< MAX_WAY >::setTargetWaypoint(). |
|
maximum turning speed for new waypoints
Definition at line 411 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::addAbsoluteWaypoint(), WaypointEngine< MAX_WAY >::addEgocentricWaypoint(), WaypointEngine< MAX_WAY >::addOffsetWaypoint(), WaypointEngine< MAX_WAY >::calcAbsoluteCoords(), WaypointEngine< MAX_WAY >::go(), and WaypointEngine< MAX_WAY >::LoadBuffer(). |
|
distance from sourcePos to targetPos
Definition at line 399 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::setTargetWaypoint(). |
|
|
time we started working on current waypoint
Definition at line 398 of file WaypointEngine.h. Referenced by WaypointEngine< MAX_WAY >::computeIdeal(), and WaypointEngine< MAX_WAY >::setTargetWaypoint(). |
Tekkotsu v2.4.1 |
Generated Tue Aug 16 16:35:12 2005 by Doxygen 1.4.4 |