/** @defgroup ImportantClasses Important Classes @brief These classes are essential far all programs using Aria to control a robot. @defgroup OptionalClasses Optional Classes @brief These classes provide additional features that may be used in some programs. @defgroup ActionClasses Predefined ArAction Classes @brief These classes implement component behaviors as ArAction subclasses (see ArAction and the overview for more details on actions) @defgroup DeviceClasses Device Interface Classes @brief These classes provide interfaces to hardware devices such as sensors. Some use "connector" objects for configure, connection and sometimes to create the interface objects. Read documentation fro details. @defgroup UtilityClasses Utility Classes @brief These classes provide useful cross-platform system tools, math and string tools, and other miscellaneous programming utilities. @defgroup MTX MTX/Pioneer LX Specific Classes @brief These classes are only used on Pioneer LX and other MTX-type robots. */ /** \mainpage ARIA Developer's Reference Manual MobileRobots Advanced Robotics Interface for Applications (ARIA)
Copyright 2002, 2003, 2004, 2005 ActivMedia Robotics, LLC. All rights reserved.
Copyright 2006, 2007, 2008, 2009, 2010 MobileRobots Inc. All rights reserved.
Copyright 2011, 2012, 2013 Adept Technology. All rights reserved.
likeThisForExample
/etc/Aria.args
file or ARIAARGS
environment variable,
and provide that object to any class constructors that accept it.
Once all such objects are created, you can call Aria::logOptions() to
print out a summary of all relevant options (e.g. call Aria::logOptions();
and Aria::exit() if ArArgumentParser::checkHelpAndWarnUnparsed() returns
true
, because the user gave the --help
option). Finally, call
Aria::parseArgs() to cause each of them to check the ArArgumentParser for
their respective arguments.
\section robot ArRobot
ArRobot is the heart of an ARIA program, acting as
robot communications gateway, central manager
of robot state, tool for synchronizing program-added tasks and callbacks,
ArAction objects, etc.
\subsection commands Client Commands and Server Information Packets
Client-server communications between ARIA and a
mobile robot platform or simulator use packet-based
protocols. (In this context, the client is the software using
ARIA to operate a robot, and the server is the robot platform's firmware.)
The details of the client-server protocol can be found in your robot's
Operations or Technical Manual.
ArRobot (using the
ArDeviceConnection, ArRobotPacketReceiver, ArRobotPacketSender, ArRobotPacket,
and ArSerialConnection classes)
handles the details of constructing and sending a
command packets to the robot as well as receiving and decoding
the packets recieved from the robot server.
\subsection packetHandlers Packet Handlers
Server Information Packets (SIPs) are packets sent by the robot server
containing information updates about the
robot and its accessories.
The standard SIP is sent by the
robot to a connected client automatically every 100 milliseconds
(this frequency may be configured in the firmware parameters).
It contains the robot's current position and estimates,
current translational and rotational speeds, sonar
reading updates, battery voltage, analog and digital I/O states, and more.
These data are stored and used
by ArRobot's State Reflection (see \ref stateReflection
below) and are accessible via methods of the ArRobot class.
(Note, within the ArRobot source code the standard SIP is also called a "motor" packet.)
Extended SIPs use the same packet format as the
standard SIP, but with a different packet "type" code. Examples of extended
SIPs include I/O port data, data from the gripper, or special robot
data like raw encoder data.
To receive extended SIPs, the client program
must request them. In ARIA, this is normally done by the device interface
classes (see @ref devices) when they are initialized or when the robot connection is established.
You may also attach your own custom packet handlers to ArRobot using
ArRobot::addPacketHandler(). You can use this to do your own additional processing
of extended SIP data, or if creating an alternate implementation of a device
interface class.
\subsection CommandPackets Command Packets
To control the robot platform, a client program sends command packets
through the robot connection. This can be done using %ArRobot's @ref
robotMotionCommands, using @ref actions, or at the most basic level,
@ref robotDirectCommands.
Each of these methods results in command packets sent to
the robot. This means that if both Actions and motion commands are used,
or if independent program modules are sending motion commands, they may conflict.
See \ref ClientCommands below for more about sending motion commands.
\subsection syncRobot Robot Synchronization Cycle
The standard SIP is sent on a constant cycle, and reception of this
SIP triggers a new iteration of ArRobot's
synchronized task processing cycle.
This cycle consists of a series of tasks,
including SIP packet handling, invocation of sensor interpretation tasks, action handling and
resolution, state reflection, and invocation of user tasks, in that order.
Since the task cycle is (normally) triggered by the
reception of each SIP (unless the robot platform begins to fails to send SIPs
or the task cycle is explicitly dissasociated from the robot connection -- see
below), each task will be invoked in a predictable order,
have the most recent data to act upon, no task will miss an opportunity
to use a SIP, and as long as the tasks do not take too much time to execute,
each SIP is handled as soon as possible after the robot sends it.
@image html ArRobot_Task_Cycle.png Overview of the ArRobot task cycle
To begin the processing cycle, call ArRobot::run() to enter
the cycle synchronously, or ArRobot::runAsync() to run the cycle
in a new background thread. ArRobot::stopRunning() stops the
processing cycle.
ArRobot provides methods to add your own sensor-interpretation
and generic user task callbacks. To add a task callback, create an ArFunctor
function object (see \ref functors) and
then add it using ArRobot::addSensorInterpTask() or
ArRobot::addUserTask(). These tasks
can be removed using ArRobot::remSensorInterpTask() or
ArRobot::remUserTask().
ArRobot locks it's mutex (see ArRobot::lock() and ArRobot::unlock()) during
each iteration of the task cycle, so your task callbacks must not lock this
mutex--a deadlock will occur.
(However, locks must still be used for safe access to any other thread
or ArAsyncTask, such as lasers and other range devices, or ARNL's planning or
localization tasks.) This mutex lock protects ArRobot data from
modification by other threads (if they correctly use the lock during access),
and interruption of the series of tasks. So if you access ArRobot from any other thread (including the main
thread, if you used ArRobot::runAsync() to run the task cycle), you must
use ArRobot::lock() and ArRobot::unlock() to lock and unlock the robot before
and after any method call or use of any data in ArRobot.
It is also possible to run the processing cycle without a connection to a robot,
if desired.
This alternative cycle is not triggered by receiving a packet, instead it has its own
steady, "chained" cycle time (default is 100 milliseconds which you may
examine and reset with ArRobot::getCycleTime() and
ArRobot::setCycleTime()).
You may also explicitly disassociate ArRobot's processing cycle from incoming
SIP processing at any time by calling ArRobot::setCycleChained() ("Chained" means that it is
the end of a previous cycle that triggers the next after suitable delay to meet
the desired cycle frequency). However, in doing so,
you may degrade performance, as the robot's cycle will only be
run every ArRobot::getCycleTime() milliseconds, and each time only the most recently
read (oldest) SIP is used (even if the robot has sent more than one since the
last cycle).
ArRobot's synchronization task list is ipmlemented as a tree, with five
major branches. Though it is uncommon to do so, a client program may modify this
tree or disable branch tasks of the tree.
If a particular task is disabled, none of its
children will be called.
The root of the task tree can be obtained by calling ArRobot::getSyncTaskRoot(),
which returns an ArSyncTask object.
@warning A user task or sensor interpretation task must run quickly. If one or more
user tasks or actions runs such that the task cycle takes too long (more that 100ms)
then the performance and behavior of the robot and of ARIA-robot communications
will be negatively affected. In particular, do not call any functions that
could block or wait for an unknown amount of time (such as locking a mutex
that could be locked for a long time by another thread)
or do any long loops waiting for a condition. Long-running activity can be performed
in a separate asynchronous thread (See ArASyncTask) instead, and results can be
shared with the user task via storage which is protected by a mutex only during
immediate reading and writing of the storage variables.
\subsection stateReflection State Reflection
State reflection in the ArRobot class is the way ARIA maintains
a snapshot of the robot's operating conditions and values, such
as estimated pose, current velocity, battery voltage, etc.
as extracted from the latest standard SIP. ArRobot methods for
examining these values include ArRobot::getPose(), ArRobot::getX(),
ArRobot::getY(), ArRobot::getTh(), ArRobot::getVel(), ArRobot::getRotVel(),
ArRobot::getBatteryVoltage(), ArRobot::isLeftMotorStalled(),
ArRobot::isRightMotorStalled(), ArRobot::getCompass(),
ArRobot::getAnalogPortSelected(), ArRobot::getAnalog(), ArRobot::getDigIn(),
ArRobot::getDigOut().
The standard SIP also contains sonar reading updates, which are
reflected in ArRobot and examined with the methods:
ArRobot::getNumSonar(), ArRobot::getSonarRange(), ArRobot::isSonarNew(),
ArRobot::getSonarReading(), ArRobot::getClosestSonarRange(),
ArRobot::getClosestSonarNumber(). The sonar interface class, ArSonarDevice,
also receives this information (see \ref rangeDevices).
ArRobot also uses the state reflection task to send previously requested
motion commands (see @ref robotMotionCommands) to the robot, so the motion
commands sent to the robot reflects those desired values set in ArRobot's state
reflection by actions or motion command methods, and also so that the watchdog
on the robot does not time out and disable the robot (if no motion command is
set, ArCommands::PULSE is sent each cycle).
You can further tune state reflection's motion command sending rate if neccesary with ArRobot::setStateReflectionRefreshTime().)
If desired, you may turn the motion-control state reflector off in the
ArRobot::ArRobot() constructor (set the @a doStateReflection parameter to
false). This will cause motion command functions to only be send the command once directly to the
robot whenever they are called, rather than storing the command to send each cycle.
\subsection callback Robot Callbacks
There are a number of useful callbacks invoked by ArRobot on connection
events. You can add and remove them with the functions
ArRobot::addConnectCB(), ArRobot::remConnectCB(),
ArRobot::addFailedConnectCB(), ArRobot::remFailedConnectCB(),
ArRobot::addDisconnectNormallyCB(), ArRobot::remDisconnectNormallyCB(),
ArRobot::addDisconnectOnErrorCB(), ArRobot::remDisconnectOnErrorCB(),
ArRobot::addRunExitCB(), ArRobot::remRunExitCB(). Read their individual
documentation pages for details.
@sa @ref robotConnectionCallbacks.cpp
\section ClientCommands Controlling the robot with Commands and Actions
Your ARIA client can drive the robot and run its various accessories
through ArRobot's Direct Commands, Motion Commands, or through Actions.
@note The robot's movement speed will be limited by several parameters. First,
the maximum velocities, accelerations and decelerations given in ARIA's robot
parameter file (.p file) (TransVelMax,
RotVelMax, TransAccel, TransDecel, RotAccel, RotDecel, and for the Seekur only,
LatVelMax, LatAccel and LatDecel) are used to limit motion
commands sent by ARIA, if the value is nonzero. Next, the max velocities given in the
robot firmware (ARCOS) configuration are used to limit motion commands recieved by the robot.
All of these maximum values can be changed at runtime with the ArRobot::setTransVelMax(),
ArRobot::setRotVelMax(), and for the Seekur only, ArRobot::setLatVelMax() calls.
These calls change the parameters in the robot firmware, as well as in ARIA.
That is, they override any maximum values given in the robot parameter file (.p file).
Finally, the "Top" parameters in the firmware (ARCOS) configuration limit
speeds; these cannot be changed at runtime, only using the configuration
program. Most robot parameter files use 0 values as maximums, disabling ARIA's
initial limiting check; however, to make the Seekur easier to initially teleoperate at safe
speeds, the velocity limits in seekur.p are set. Change these limits to 0 to remove
those speed limits, and use the platform's defaults, or use ArRobot's methods to
change them at program runtime.
\subsection robotDirectCommands Direct Commands
At the lowest level of robot access, you may send any command packet directly to the robot
or simulator platform through ArRobot. Direct commands consist of a 1-byte command
number followed by none or more arguments, as defined by the robot's
operating system (ARCOS, AROS, P2OS, AmigOS, etc.). For example, the command
number 4, ENABLE, enables the robot's motors if accompanied by the
argument 1, and disables the motors with the argument 0.
Use ArRobot::com() for commands that
have no argument, such as PULSE; ArRobot::comInt() for a 2-byte integer
argument, signed or unsigned, such as the motors ENABLE command;
ArRobot::com2Bytes() for commands that accept two individual bytes
as the argument, such as the VEL2 command; and ArRobot::comStr() or
ArRobot::comStrN() for a null-terminated or fixed-length
string argument, respectively, such as the sonar POLLING
sequencing command.
The ArCommands class contains an enum with all the direct commands;
ArCommands::ENABLE, for example. Not all Direct Commands are supported by every
MobileRobots robot, but unrecognized (or malformed)
commands are simply ignored.
Please consult your robot's technical manual for details, such
as the Chapter 6 in the Pioneer 3
Operations Manual, for client command numbers and syntax.
For most commands, a method exists in ArRobot that either sends the command
immediately, or stores it for the state reflection task to send. However,
the direct command methods allow you to send any unusual or special commands
directly to the robot platform or simulator, without any intervening processing.
\subsection robotMotionCommands Motion Command Functions
At a level just above ArRobot's Direct Commands are the Motion
Command Functions. These are explicit simple movement commands sent by ArRobot's
state reflection task.
For example, ArRobot::setVel() to set the translational velocity,
ArRobot::setRotVel to set rotational velocity, ArRobot::setVel2() to
or set each wheel speeds separately, ArRobot::setHeading() to set a
global heading angle to turn to, ArRobot::move() to drive a given distance,
or ArRobot::stop() to stop all motion. ArRobot also provides methods
for setting speed limits beyond the limits set in the firmware configuration.
These motion functions work at part of with @ref stateReflection, and ArRobot may
resend commands each cycle to try to achieve the desired state.
Be aware that a Direct or a Motion Command may conflict with controls
from Actions or other upper-level processes and lead to unexpected
consequences. Use ArRobot::clearDirectMotion() to cancel the overriding
effect of a previously set Motion Command so that your Action is able to regain
control the robot. Or limit the time a Motion Command prevents other
motion actions with ArRobot::setDirectMotionPrecedenceTime(). Otherwise,
the Motion Command will prevent actions forever. Use
ArRobot::getDirectMotionPrecedenceTime() to see how long a Motion
Command takes precedence once set.
\subsection actions Actions
While simple sequences motion commands can be easy to use, trying to achieve
more sophisticated motion using only motion commands
can quickly become difficult. To make it possible to define
complex behaviors out of independent, reusable components,
ARIA provides the higher-level Actions system.
Actions are individual objects that independently
provide motion requests which are evaluated and then combined each cycle
to produce a final set of movement commands. This allows you to build complex
behavior from simple building blocks for dynamic and continuous motion control.
Actions are defined by creating a subclass of the ArAction the base class
which overloads the ArAction::fire() method.
See the @ref actionExample.cpp
example program.
ARIA also includes some useful pre-made action classes (see @ref ActionClasses
for a list). Include these in your programs, or use them as examples when
creating your own custom ArAction subclass.
Actions are attached to an ArRobot object with ArRobot::addAction(), along with
a priority which determines its position in the action list.
ArAction::setRobot() is called on an action object when it is added to a robot.
You can override this in your action subclass. (For example, this would be useful to add a
connection callback, if there were some calculations you wished to do
upon connection to the robot.)
Actions are evaluated by ArRobot's action resolver in descending order of priority
(highest priority first, lowest priority last) in each task cycle just prior
to @ref stateReflection. The action resolver invokes each action's fire()
method, combining their desired motion commands (the ArActionDesired objects
they return) to a
single ArActionDesired object, which is then used in state reflection to send
motion commands to the robot.
@note Sending simple motion commands (e.g. by using ArRobot::setVel()) while
actions are also active can result in conflicts between your simple motion
commands and the action resolver's commands. See the discussion of
@ref robotMotionCommands above.
As the resolver is invoking each action, by it passes
the current desired motion combined from the previously invoked, higher priority
actions, as the currentDesired argument to fire().
This can be useful information if
needed. (For example, a stall-recovery action could
be programmed not to exert its motion effects if it has been
pre-empted by a stop action, so this stall-recovery action would check
currentDesired to see if either the "strength" is "used up" or if there is a maximum
velocity, and if so, reset its own state.) However, there is no need
for an action to pay attention to the currentDesired if not necessary.
@warning An action must run quickly. If one or more actions or robot
user tasks runs such that the task cycle takes too long (more that 100ms)
then the performance and behavior of the robot and of ARIA-robot communications
will be negatively affected. In particular, do not call any functions that
could block or wait for an unknown amount of time (such as locking a mutex
that could be locked for a long time by another thread)
or do any long loops waiting for a condition. Long-running activity can be performed
in a separate asynchronous thread (See ArASyncTask) instead, and results can be
shared with the action via storage which is protected by a mutex only during
immediate reading and writing of the storage variables.
\subsection actionDesired Action Desired
ArActionDesired objects are used to pass desired action channel values
and strengths out of an ArAction::fire() method back to the resolver.
An ArActionDesired object should always be
reset (ArActionDesired::reset()) before it is reused.
There are six action channels: velocity (ArActionDesired::setVel),
heading (ArActionDesired::setDeltaHeading or
ArActionDesired::setHeading for absolute heading),
maximum forward translational velocity
(ArActionDesired::setMaxVel), maximum reverse translational velocity
(ArActionDesired::setMaxNegVel), and maximum rotational velocity
(ArActionDesired::setMaxRotVel).
An action gives each channel a strength between 0.0, the lowest, and 1.0,
the highest. Strengths are used by the resolver to compute the
relative effect of the associated channel when combining multiple
actions' desired movements.
The maximum velocity, maximum negative velocity, and maximum
rotational velocity channels simply impose speed limits and thereby
indirectly control the robot.
For more advanced usage, ArActionDesired objects can be merged
(ArActionDesired::merge) and averaged (ArActionDesired::startAverage,
ArActionDesired::addAverage, ArActionDesired::endAverage).
\subsection resolvers The Action Resolver
ArResolver is the base action resolver class. ArPriorityResolver is
the default resolver used by ArRobot.
The resolver used by ArRobot may be changed by calling ArRobot::setResolver,
if you wish to create an alternative ArResolver implementation.
There may only be one resolver per ArRobot object.
(Though a resolver could contain
within it multiple resolvers of its own.) Note that although a robot has
one particular resolver bound to it, a resolver instance is not tied to
any robot.
The priority resolver works by iterating through the action list in descending
priority (from greatest priority value to lowest), setting each robot movement channel (trans. velocity, heading,
max. velocity, etc.) based on
the contributing actions' desired values (as returned from their fire() methods)
in proportion to their
respective strengths as well as the actions' priorities, updating each movement channel
until its strength becomes 1.0 or the action
list is exhausted. Once a channel's accumulated strength reaches 1.0, no more changes may be made to
that channel (this is how higher priority actions can prevent lower priority
actions from changing a channel). Same-priority actions are averaged together if
they both provide outputs for the same channel.
As an example, the following table illustrates at each step an action's desired value
and strength for the velocity channel, and the resulting change to
the resolver's final velocity channel value and strength decision,
for four fictional actions (A, B, C and D):
step # | action | priority | value of action's desired-velocity channel | strength of action's desired-velocity channel | current final velocity value | current final velocity strength |
---|---|---|---|---|---|---|
1 | A | 4 | -400 | 0.25 | -400 | 0.25 |
2 | B | 3 | -100 | 1.0 | Combined for use in step 4 | |
3 | C | 3 | 200 | 0.50 | ||
4 | B&C | 3 | 0 | 0.75 | -100 | 1.0 |
5 | D | 1 | 500 | 0.50 | no change | no change |
final result | -100 | 1.0 |
ExampleClass
is a class which contains a function called
aFunction()
. The functor functor
is declared
as an ArFunctor1C
, a functor which invokes a class method
and takes one argument. The template parameters specify the type of the
class (ExampleClass
) and the type of the method argument
(int
). functor
is then initialized with
a pointer to the ExampleClass
instance to call the
method on, and a pointer to the class method to call. When a functor
is contained within the class, it is typcially initialized in the
constructor, giving this
as the object instance.
A functor must be initialized with the method to call and, if a "C" functor,
a class instance. An unitilialized functor will crash at runtime when invoked.
It is also possible to give values for the method arguments in the functor
initialization, see ArFunctor documentation for details.
Once the functor object is created in this fashion, it can now be
passed to another function or object that wants a callback functor. And the
method ExampleClass::aFunction()
will be called on the object
obj
when the functor is invoked.
To invoke a functor, simply call the invoke() function
on the functor. If it takes arguments, call invoke() with those
arguments. If the functor has a return value, call invokeR. The
return value of the function will be passed back through the invokeR()
function. If the functor was initialized with argument values,
and invoke() is called without argument values, the argument values
provided at initialization are passed.
\section userInput Keyboard and Joystick Input
ARIA provides several classes getting live joystick and keyboard input,
and action classes (see @ref actions) that use that input to drive the robot.
ArJoyHandler is a cross-platform interface to joystick data.
It's key functions are ArJoyHandler::getButtons, ArJoyHandler::getAdjusted,
ArJoyHandler::setSpeeds, and ArJoyHandler::getDoubles.
ArKeyHandler is a cross-platform interface for recieving single keystroke
events (instead of buffered lines of text).
It's key function is ArKeyHandler::addKeyHandler,
which binds a specific key to a given functor. It contains an enum
ArKeyHandler::KEY that contains values for special keys.
You can also attach a key handler to a robot with ArRobot::attachKeyHandler(),
which adds some default key handlers, including a handler for Escape that
disconnects and exits the program (especially useful on Windows, where Ctrl-C
or the terminal close box won't properly clean up).
Since a PC can only have ony keyboard, ARIA keeps an ArKeyHandler pointer
globally, which may be queried with Aria::getKeyHandler().
@note if you are using Linux, creating a key handler will make the program hang
if put into the background with Ctrl-Z.
ARIA provides two simple actions, ArActionKeydrive and ArActionJoydrive, to
drive a robot from keyboard and joystick input.
These actions are used by
the @ref teleopActionsExample.cpp example program.
ARIA also provides a more flexible
ArActionRatioInput, which can combine several input sources (such as keyboard,
computer joystick, robot-platform (microcontroller) joystick,
or teleoperation commands recieved via ArNetworking) in a more
consistent and configurable manner. See the class documentation for more
details.
\section threading Threading
ARIA is highly multi-threaded. This section presents some of the
critical concepts behind writing threaded ARIA code.
ARIA provides a number of support classes to make it easier to write
object-oriented threaded code. They are: ArASyncTask, ArCondition,
ArMutex, and ArThread.
Thread-safe code mostly means proper coordination between threads when
handling the same data. You want to avoid the problem of one
or more threads reading or writing the data at the same time that other
threads read or write the data.
data. To prevent this problem from happening, the data needs to be
protected with synchronization objects.
\subsection syncObject Thread Syncronizing Objects
In ARIA, the synchronization objects are ArMutex and ArCondition.
ArMutex is the most useful one. ArMutex (mutex is short for mutual
exclusion.) provides a wrapper around system calls (pthreads functions
on Linux and CriticalSection functions on Windows) that
exclude other threads from continuing while the mutex object is "locked".
When threads lock a mutex while accessing shared data, it is ensured
that only one thread is accessing that shared data at a time.
Therefore, the proper way to use a mutex is to lock it right
before accessing the shared data, and to always unlock it when done.
If the mutex is not already locked, then it becomes locked and the thread
continues. If the mutex is already locked by another thread, then it blocks
in the lock call until the other thread unlocks it. If a mutex is never
unlocked (e.g. a function returns due to an error condition without unlocking
it), then any further attempts to lock it will block forever, creating
a "deadlock".
See the mutex example program to see how ArMutex is used. The documentation of a method
may indicate whether locking is necessary before using it; in general,
when using an object that may be shared by other threads,
all threads using it must lock the same mutex (usually contained within
the object's class with methods provided for locking and unlocking) while using
the object.
ArCondition is an occasionally used utility that puts the current thread to sleep until another thread
signals it to wake up and continue executing. This can be used to wait in a
thread for an indefinite amount of time until some event occurs in a another
thread which signals the ArCondition.
\subsection asynctasks Asynchronous Task Class
ARIA provides the ArASyncTask which can be subclassed to implement a
long-running thread and its state
as an object. As opposed to robot-syncronized tasks, asynchronous tasks run
in seperate threads. Like ArMutex, this class wraps the operating system's threading
calls in a cross-platform way. Typically, an ArASyncTask will reperesent a
thread that runs in a loop for the entire program.
To use ArASyncTask, derive a class from ArASyncTask and
override the ArASyncTask::runThread() function. This function is
automatically called within the new thread when that new thread
gets created. To create and start the thread, call
ArASyncTask::create(). When the ArASyncTask::runThread() function
exits, the thread will exit and be destroyed. Seperate threads can
request that the task exit by calling ArASyncTask::stopRunning(), and within the thread,
you can check for this request with ArASyncTask::getRunningWithLock().
This class is mainly a convenience wrapper around ArThread so that you
can easily create your own object that encapsulates the concept of a
thread.
\section aria Global Data
The static Aria class contains miscellaneous global data in ARIA.
ARIA contains a list of all the ArRobot instances. Use the
Aria::findRobot() to find a robot by name, or use Aria::getRobotList()
to get a list of the robots.
Use Aria::getDirectory() to find ARIA's top-level path
(Usually either C:\\Program Files\\MobileRobots\\%Aria
on Windows, or
/usr/local/Aria
on Linux). This is useful,
for instance, to locate
robot parameter files for individual operational details. Use
Aria::setDirectory() to change this path for the run of the program if
you feel the need to override what ARIA has decided.
Call Aria::init() at program start to perform global initialization, and use
Aria::exit() to exit all ARIA threads before exiting your program.
The Aria class also contains global objects for sharing configuration
parameters and other information: see \ref arconfig and \ref arinfogroup
sections below.
@sa @ref arconfig
@sa @ref arinfogroup
\section devices Device and Accessory Interface Classes
ARIA includes classes to communicate with various kinds of devices.
(Many of these devices are optional accessories, and not all robots have them
installed.)
Some are mentioned below. See @ref DeviceClasses for a list.
open(4040, ArSocket::TCP)
on an ArSocket object constructed
with the default constructor.
\section ArNetworking ArNetworking
For a more advanced networking infrastructure, see the ArNetworking companion
library,
distributed with ARIA. ArNetworking provides an extensible system of
data requests and updates between client and server applications via TCP or
UDP, using the same base "packet" concept as robot communication.
For example, use ArNetworking to connect multiple robots working together,
off-board user interfaces to on-board control servers, or robot control programs to
off-board data resources.
\section sound Sound and Speech
ARIA provides foundation sound support, and separate libraries use this
for speech and network audio.
Functions common to both of the speech synthesis libraries are included in a base class, ArSpeechSynth.
(setq c-default-style '((other . "user"))) (c-set-offset 'substatement-open 0) (c-set-offset 'defun-block-intro 2) (c-set-offset 'statement-block-intro 2) (c-set-offset 'substatement 2) (c-set-offset 'topmost-intro -2) (c-set-offset 'arglist-intro '++) (c-set-offset 'statement-case-intro '*) (c-set-offset 'member-init-intro 2) (c-set-offset 'inline-open 0) (c-set-offset 'brace-list-intro 2) (c-set-offset 'statement-cont 0) (defvar c-mode-hook 'c++-mode)\section noneverydayC Non-everyday use of C++ ARIA uses some features of C++ that some programmers may not be aware of yet, and includes some workarounds for platform differences. \subsection stl Standard Template Library ARIA makes heavy use of the C++ standard template library (STL). So you should understand the STL in order to get the best use from some of the more advanced parts of ARIA. \subsection defaultArgs Default Arguments In the function declaration a default value for an argument may be specified. Arguments with default values may then be omitted from the function call. For example, after declaring this function with a default value for its integer argument: @code void foo(int number = 3); @endcode it can be used in two different ways: @code // Use the default value for the argument: foo(); // Or, use don't use the default: foo(99); @endcode This behavior is quite useful for having defaults for more obscure options you will usually not need to change, but still allowing you to change them if necessary without making ARIA more complex. Also note that the function definition must not have the assignment in it, only the declaration. Therefore the definition if our example function would look like this: @code void foo(int number) { //... } @endcode \subsection constructorChaining Constructor Chaining Constructor chaining is quite simple though sometimes not used by C++ programmers. Each constructor can give arguments to the constructors of the member variables it contains and to the constructors of classes from which it inherits. For example if you have: @code class BaseClass { public: BaseClass(int someNumber); }; @endcode and @code class SubClass : public BaseClass { public: SubClass(void); int anotherNumber; }; @endcode When you write your constructor for SubClass you can initialize both baseClass and anotherNumber: @code SubClass::SubClass(void) : BaseClass(3), anotherNumber(37) { // ... } @endcode Note how the constructors to be initialized must follow a colon (:) after the constructor, and be separated by commas. Member variables must be initialized in the order they are in the class. Note that initializing integers is not all that unique or useful, but using this to initialize callback \ref functors is quite useful. Constructor chaining is used in many many places by ARIA, thus it must be understood in order to understand ARIA, but the above is all that really needs to be known. \subsection charsAndStrings Chars and Strings, Win workaround During development problems were encountered with Windows if a
std::string
was passed into a DLL. Thus for all input to ARIA
const char *
is used, but for all internal storage and all reporting
std::string
s are passed back out of ARIA.
\subsection arexport AREXPORT
Because of the Windows set up for using DLLs, this macro is used
to take care of the required declaration attributes for DLLs. Largely
users do not need to worry about AREXPORT
, but only functions which have
AREXPORT
and inline functions are usable with DLLs in Windows (all of the
ARIA functions which are documented in this manual are usable).
\subsection exceptions Exceptions
ARIA neither throws nor catches any exceptions.
\section Advanced Topics and Esoterica
\subsection pieceMealUse Piecemeal Use of ARIA
The most basic layer of ARIA is ArDeviceConnection and subclasses, which
handle low-level communication with the robot server. On top of the
connection layer, we have a packet layer--ArBasePacket and
ArRobotPacket--the basic algorithms for constructing command packets
and decoding server information packets.
Above the packet layer is the packet handler classes,
ArRobotPacketReceiver and ArRobotPacketSender, when send and receive
packets to and from the robot. Finally, on top of all these lowest
layers is ArRobot, which is a gathering point for all things, but can
be used in a quite basic format without all of the bells and whistles.
ArRobot has built-in tasks, actions, state reflection and so forth, all
of which can be disabled from the constructor (ArRobot::ArRobot) and
ignored or reimplemented.
Also note that if all you do is turn off state reflection, which only
affects sending ArRobot-mediated motion commands to the robot, not
receiving SIPs from the robot, none of the other activities which
ArRobot engages on its loop will take up hardly any time, so it
probably isn't worth building your own set of tasks, but the power to
do so is there for the intrepid.
One other thing worth noting is that you can call ArRobot::loopOnce()
and it will run through its loop a single time and return. This is so
that you can use ARIA from your own control structure. If you are
using loopOnce you may also find it beneficial to call
ArRobot::incCounter, so that the loop counter will be updated. You
could also just call ArRobot::packetHandler, ArRobot::actionHandler,
or ArRobot::stateReflector on your own, as these are the most
important internal functions, though if you make your own loop you
should probably call ArRobot::incCounter any way that you do it, as
this is how sonar are known to be new or not, and such.
We recommend that whatever you do you use the same type of strict
threading/locking that ARIA observes.
\subsection hardConnectRobot Connecting with a Robot or the Simulator the hard way
ArDeviceConnection is ARIA's communications object; ArSerialConnection
and ArTcpConnection are its built-in children most commonly used to
manage communication between a MobileRobots or ActivMedia robot or the robot
simulator, respectively. These classes are not device-specific,
however, so use ArSerialConnection, for instance, to also configure a
serial port and establish a connection with a robot accessory, such as
with the SICK laser range finder.
\subsection openDevice Opening the Connection
After creating and opening a device connection, associate it with its
ARIA device handlers, most commonly with ArRobot::setDeviceConnection
for the robot or the simulator.
For example, early in an ARIA program, specify the connection device and
associate it with the robot:
@code
ArTcpConnection con;
ArRobot robot;
@endcode
Later in the program, after initializing the ARIA system
(Aria::init(); is mandatory), set the Connection port to its default
values (for TCP, host is "localhost" and port number is 8101), and
then open the port:
@code
con.setPort();
if (!con.openSimple())
{
printf("Open failed.");
Aria::shutdown();
return 1;
}
@endcode
TCP and Serial connections have their own implementation of open which
is not inherited, but has default arguments that make the generic open
work for the all default cases. And open returns a status integer
which can be passed to the re-implemented and inherited
ArDeviceConnection::getOpenMessage in order to retrieve related status
string, which is useful in reporting errors to the user without having
to know about the underlying device.
\subsection devConnect Robot Client-Server Connection
After associating the device with the robot, now connect with the
robot's servers, ArRobot::blockingConnect or ArRobot::asyncConnect, for
example, to establish the client-server connection between ARIA
ArRobot and the robot microcontroller or robot
simulator. The blockingConnect method doesn't return from the call until
a connection succeeds or fails:
@code
robot.setDeviceConnection(&con);
if (!robot.blockingConnect())
{
printf("Could not connect to robot... Exiting.");
Aria::shutdown();
return 1;
}
@endcode
The previous examples connect with the simulator through a TCP
socket on your PC. Use tcpConn.setPort(host, port)
to set the TCP
hostname or IP address and related socket number to another machine on
the network. For instance, use tcpConn.setPort("bill", 8101);
to
connect to the simulator which is running on the networked computer
"bill" through port 8101.
Replace ArTcpConnection con;
with ArSerialConnection con;
to connect with a robot through the default serial port (/dev/ttyS0
or COM1
), or another you specify with ArSerialConnection::setPort(),
such as con.setPort("COM3");
.
At some point, you may want to open the port with the more
verbose con.open()
.
\subsection connrw Connection Read, Write, Close and Timestamping
The two main functions of a device connection are
ArDeviceConnection::read and ArDeviceConnection::write. Simple
enough. ArDeviceConnection::close also is inherited and important. You
probably won't use direct read or write to the robot device, although
you could. Rather, ArRobot provides a host of convenient methods that
package your robot commands, and gather and distribute the various
robot information packets, so that you don't have to attend those
mundane details. See the next section for details.
All ArDeviceConnection subclasses have support for timestamping
(ArDeviceConnection::getTimeRead). With the robot connection,
timestamping merely says what time a robot SIP came in, which can be
useful for interpolating the robot's location more precisely.
*/