Copyright 2002, 2003, 2004, 2005 ActivMedia Robotics, LLC. All rights reserved.
Copyright 2006, 2007, 2008, 2009 MobileRobots Inc. All rights reserved.
Written in the C++ language, ARIA is client-side software for easy, high-performance access to and management of the robot, as well as to the many accessory robot sensors and effectors. ARIA includes many useful utilities for general robot programming and cross-platform (Linux and Windows) programming as well.
ARIA can be run multi- or single-threaded, using its own wrapper around Linux pthreads or Win32 threads. You can access ARIA at different levels, from simply sending commands to the robot through ArRobot to development of higher-level intelligent behavior using Actions. (For a description of how to integrate parts of ARIA with your other code, see Piecemeal Use of ARIA.)
An auxiliary library called ArNetworking is also included with ARIA. ArNetworking provides an easy to use, extensible framework for communication with remote programs over a network, such as MobileEyes.
This page contains an overview of ARIA. Read this overview to become familiar with the ARIA library and how to get started using it. Click a class or function link to view its detail pages. New users should view this document along with the ARIA examples, README.txt, and your robot's operating manual.
You can download new versions of ARIA from http://robots.mobilerobots.com/ARIA
In addition to providing a complete robot and accessory API to developers, ARIA also serves as a foundation for other libraries providing additional capabilities: For creating applications with built-in advanced navigation routines, you can use the additional ARNL or SONARNL libraries. To communicate with the MobileEyes graphical display/control program, or for general communication over the network, you can use ArNetworking. ArNetworking is included with ARIA in the ArNetworking directory. See the ArNetworking Reference Manual for more information.
Other libraries are available as well for specialized purposes, including speech synthesis and recognition, audio stream recording, playback and network transmission, video image capture, color tracking, etc. Browse the MobileRobots support web pages http://www.activrobots.com and http://robots.mobilerobots.com for these libraries and other mobile robotics resources, including the MobileSim simulator which can be used used for programming and debugging before driving an actual robot.
Programmers working with ARIA should be familiar with using typical C++ concepts, including using classes and objects with simple inheritance, pointers, memory management, the STL containers, and the compiling and linking process. (See below for notes about accessing ARIA from Python or Java.) Experience with multiple threads is also helpful.
Read on for information about the key pieces of ARIA and how to get started. See the README.txt file for a brief practical overview of ARIA software development on Linux and Windows. Many example programs are available as well.
Read javaExamples/README.txt file for directions on how to use the Java wrapper and pythonExamples/README.txt for directions on how to use the Python wrapper, and likewise see ArNetworking/javaExamples and ArNetworking/pythonExamples for information about and examples of the ArNetworking Java and Python wrappers.
Accordingly, please do share your work, and please sign up for the exclusive ARIA-users@mobilerobots.com newslist so that you can benefit from others' work, too.
For answers to frequently asked questions about what the GPL allows and requires, see http://www.gnu.org/licenses/gpl-faq.html .
On the other hand, ARIA may be also licensed for proprietary, closed-source applications. Contact sales@mobilerobots.com for details.
likeThisForExample
The core mobile robot "server" proceses are implemented in the Pioneer and AmigoBot Operating System firmware (ARCOS, AROS, P2OS, AmigOS, etc.), which runs on the robot's microcontroller. These proceses manage the more critical and time-sensitive low-level tasks of robot control and operation, including maintaining requested motion and heading state and estimating position from odometry, as well as acquiring sensor information (sonar and compass, for example) and driving many accessory components like the PTZ camera, TCM2 compass/inclinometer, and the Pioneer 5-DOF Arm. The robot, its microcontroller, firmware, and integrated devices (such as sonar) together are sometimes referred to as the "robot platform". The robot firmware does not, however, perform any high-level robotic tasks. Rather, it is the job of an intelligent client running on a connected PC to perform these application-level robotic control strategies and tasks, such as obstacle detection and avoidance, sensor fusion, localization, features recognition, mapping, intelligent navigation, PTZ camera control, Arm motion, and much more. ARIA's role is to support these client applications and their communcation with the robot firmware, to any devices that connect to the computer rather than the robot platform, and to remote software via a network.
The heart of ARIA is the ArRobot class. This class manages the communication cycle with the firmware, receiving and providing access to data about the robot platform's operating state, triggering tasks within that cycle and determining commands to be sent back to the robot (see Actions and Robot Synchronization Cycle). It also serves as a container for references to other ARIA objects (such as range devices) and a toolbox of general functions related to the mobile robot.
Through its Actions infrastructure, ARIA provides a powerful mechanism for combining independent behaviors to achieve coordinated motion control and intelligent guidance. With Actions, you easily implement the motion aspects of applications such as guided teleoperation, visual tracking, autonomous navigation, etc.
Other ARIA classes provide interfaces to access and control accessory sensors and devices, including operation and state reflection for sonar and laser range finders, pan-tilt units, arms, inertial navigation devices, and many others.
In addition to the mobile robot itself, some accessories, such as the sonar, the Pioneer Gripper, PTZ cameras, Pioneer Arm, compass, and others, are internally connected to the robot microcontroller's AUX or digital I/O lines, and use the robot connection as well (therefore the interface classes for these objects require a reference to an ArRobot object, which must be connected for the devices to work). Other accessories, such as the SICK laser, video capture cards, etc. are connected directly to the onboard computer.
There are several ways to connect a computer running ARIA to the robot's microcontroller or to a simulator. This figure provides a schematic overview of the many ARIA-robot communication options. Consult your robot Operations Manual for more information about computer-robot hardware setup and communications.
Here is an example which uses ArRobotConnector to connect the ArRobot and ArLaserConnector to connect to a laser rangefinder.
#include "Aria.h" int main(int argc, char** argv) { Aria::init(); ArArgumentParser parser(&argc, argv); parser.loadDefaultArguments(); ArRobot robot; ArRobotConnector robotConnector(&parser, &robot); // Try connecting to the robot. if(!connector.connectRobot(&robot)) { // Error! ArLog::log(ArLog::Terse, "Error, could not connect to robot.\n"); robotConnector.logOptions(); Aria::exit(1); } // Run the ArRobot processing/task cycle thread. robot.runAsync(true); ArLaserConnector laserConnector(&parser, &robot, &robotConnector); // Parse command line arguments (there may be arguments specifying // what lasers to try to connect to) if(!Aria::parseArgs()) { Aria::logOptions(); Aria::exit(2); } // Try connecting to all lasers specified in the robot's parameter file // and in command line arguments if(!laserConnector.connectLasers()) { ArLog::log(ArLog::Terse, "Error, could not connect to lasers.\n"); Aria::logOptions(); Aria::exit(3); } // Now we're connected, and the robot and laser objects are running in // background threads reading and processing data. (You can get access // to the ArLaser objects using ArRobot::findLaser() or // ArRobot::getLaserMap(). ...
This information is obtained from two sources: the robot's parameter files, and from program runtime arguments via ArArgumentParser (which reads default program argument values from /etc/Aria.args (on Linux) and the ARIAARGS environment variable (on both Linux and Windows), then reads current program arguments from the command line).
Some examples of hardware configuration options that may need to be specified are what kinds of laser rangefinders are connected, and to which ports, laser connection and data parameters, what kind of GPS is connected and to what port (if a GPS is used). Furthermore, if you are connecting to a robot over a wireless TCP connection from an offboard computer rather than an onboard computer, you must provide a runtime command line argument giving the robot network name (and optionally port number).
See Robot Parameter Files for more information.
See Command Line Option Summary for a summary of all the options that various classes in ARIA accept.
Arguments are provided to other ARIA classes by an ArArgumentParser object. All ARIA programs should create an ArArgumentParser, call ArArgumentParser::loadDefaultArguments() to load any arguments that appear in the /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.
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.
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 Device and Accessory Interface Classes) 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.
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 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 ArSick or 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.
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 Range Devices).
ArRobot also uses the state reflection task to send previously requested motion commands (see Motion Command Functions) 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 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.
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.
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.
Actions are defined by creating a subclass of the ArAction the base class which overloads the ArAction::fire() method. See the actionExample::cpp
example program. ARIA also includes some pre-made action classes: look for them as subclasses of ArAction in its class documentation or in in the ARIA source code (the files begin with ArAction...).
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 State Reflection. 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.
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).
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 |
Notice in the example that the same-priority actions B and C are averaged before being combined with the previously computed values from step 1. The resulting combination is: ( (B desired velocity: -100) X (B velocity strength: 1.0) + (C desired velocity: 200) X (C velocity strength: 0.5) ) / 2 => (-100 + 100) / 2 => 0 Therefore actions B and C end up cancelling each other out. Combining this result with the "currentDesired" values computed in step 1 gives (step 1 desired velocity: -400) X (step 1 velocity strength: 0.25) + (step 4 desired velocity: 0) X (step 4 velocity strength: 0.75) => -100.
In this example, it turns out that at step 5, action D has no effect since the strength for this channel has reached 1.0 at step 4, before that action was considered by the resolver.
The same method is used for all of the other channels.
See the ArAction base class's list of subclasses.
This example also illustrates fundamental, yet very powerful features of ARIA actions and how they contribute to the overall behavior of the mobile robot. Because they are individuals, contributing discretely to the movements of the robot, actions are easily reusable. For example, a limiting action that prevents the robot from crashing into a wall when translating forward, can be used, as is, in another ARIA program and have the identical effect, except that instead of driving the robot with a joystick, the new program's lower-priority movement action might use color-tracking to have the robot follow a rolling ball. The ball-following action doesn't need to know anything about the finer arts of safe navigation--the higher-priority limiting actions take care of that.
Another ARIA example program, wander::cpp demonstrates how different movement actions can be used and how they interact. The stall-recover action in wander (ArActionStallRecover) influences the robot's movements only when the motors are stalled, disabling the lower priority actions by using up all translational and rotational strength until the robot has extracted from the stall. You should also examine ArActionStallRecover.cpp in the src/ directory to see how the action changes its motion control influences based on the stall state. Also note how ArActionAvoidFront and ArActionConstantVelocity interact.
Several predefined action groups are provided by ARIA.
Currently, the main ArRangeDevice implementations included with ARIA are: sonar (ArSonarDevice), laser (ArLaser and subclasses), the robot bumpers (ArBumpers), and the "table-sensing" infrared sensors of a PeopleBot (ArIRs). Camera and 3D range devices (MobileRanger devices) are supported by separate software. In addition, ArForbiddenRangeDevice is a "virtual" range device that creates range readings that border "forbidden area" and "forbidden line" regions in an ArMap, and ArRangeDeviceFilter processes the output another ArRangeDevice object in a few ways and provides the processed data through the ArRangeDevice interface. Its parameters can be modified on line through ArConfig.
ArRangeDevice holds two kinds of ArRangeBuffer objects to store readings: current and cumulative, though not all ArRangeDevice implementations supply data to the cumulative buffer. The current buffer contains the most recent set of readings; the cumulative buffer contains readings gathered over a longer period time, limited by the buffer's size (see ArRangeBuffer::setSize()).
Some range devices also provide "raw" readings, which are the original values given by the device itself. Some range devices are also considered "Planar", which means that the readings may undergo some processing to remove duplicates etc., and which include raw readings. This includes the lasers.
Range devices are connected to a specific ArRobot instance, to obtain position and other information from the robot when readings are received and stored, and also to provide a way to find all range devices attached to the robot. Some range devices use the robot connection to communicate to their device (e.g. ArSonarDevice, ArBumpers, ArIRs). Attach an ArRangeDevice to your ArRobot object with ArRobot::addRangeDevice() and remove it with ArRobot::remRangeDevice(). The list of all attached devices can be queried using ArRobot::findRangeDevice() and ArRobot::hasRangeDevice(). The list can be obtained by calling ArRobot::getRangeDeviceList().
(Note that although sonar are integrated with the robot microcontroller, and the microcontroller always sends sonar data to the robot (if the robot has sonar), you still must attach an ArSonarDevice object to the robot to use it.)
ArRangeDevice also includes some methods to help find the closest reading to the robot within a selected box, or a polar sector: ArRangeDevice::currentReadingPolar(), ArRangeDevice::currentReadingBox(), ArRangeDevice::cumulativeReadingPolar(), ArRangeDevice::cumulativeReadingBox().
ArRobot also includes similar methods to do common operations on all attached range devices, including ArRobot::checkRangeDevicesCurrentPolar(), ArRobot::checkRangeDevicesCurrentBox(), ArRobot::checkRangesDevicesCumulativePolar(), and ArRobot::checkRangeDevicesCumulativeBox() to find the closest range reading to the robot within some region.
Each range device has a mutex (Use ArRangeDevice::lockDevice() and ArRangeDevice::unlockDevice() to lock and unlock it) so that it can be accessed safely by multiple threads. For example, ArSick uses a thread to read data from a laser, but the checkRangeDevice functions in ArRobot lockDevice() so they can read the data without conflicting with ArSick's data-reading thread, then use unlockDevice() when done. See Threading for more about threading in ARIA.
Function pointers are fully supported by the C language. C++ treats function pointers like C, but to call class methods, an instance object is required, as well as type information about the class. Therefore, ARIA contains a set of template classes to contain this information.
ARIA makes heavy use of ArFunctors as "callback" functions. To instantiate a functor, you first need to identify how many parameters the function needs and if it returns a value. Many times a pointer to the abstract ArFunctor base class is used, which can be invoked with no parameters and no return value. Subclasses are used for functions with different numbers of parameters and return values. ArFunctor1, ArFunctor2, ArRetFunctor, ArRetFunctor1, and ArRetFunctor2 for example. When invoked, the parameters may be supplied which are passed to the target function or method, and a return value may also be given. The types for the arguments and/or return value are given as template arguments.
When creating a functor object, however, you must also provide the type and instance of an object to invoke the method of; or explicitly state that the function is a class-less global function. Do this by using one of the concrete base classes of ArFunctor instead of the abstract classes: ArFunctorC, ArFunctor1C, ArFunctor2C, ArRetFunctorC, ArRetFunctor1C, ArRetFunctor2C, ArGlobalFunctor, ArGlobalFunctor1, etc.
Example:
class ExampleClass { public: void aFunction(int n); }; ... ExampleClass obj; ArFunctor1C<ExampleClass, int> functor(obj, &ExampleClass::aFunction); ... functor.invoke(42);
ExampleClass
is a class which contains a function called aFunction()
. Once the functor is created in this fashion, it can now be passed off to an ARIA function 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 parameters, call invoke with those parameters. If the functor has a return value, call invokeR. The return value of the function will be passed back through the invokeR function.
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().
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.
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.
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.
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 ArConfig and Shared Info Groups sections below.
(Many of these devices are optional accessories, and not all robots have them installed.)
Some device interfaces are provided by additional libraries, as well. See those libraries for details.
The Map File Format page describes the map file format in detail.
ARNL, SONARNL and MobileSim all use ArMap format map files.
To connect to a port, simply construct a socket containing the hostname or IP address of the host, a port number, and the ARIA socket type (TCP or UDP). For example:
ArSocket sock("host.name.com", 4040, ArSocket::TCP);
Or call the ArSocket::connect() function, such as:
To open a server on (for example) port 4040, simply construct a socket:
ArSocket sock(4040, true, ArSocket::TCP);
Or call open(4040, ArSocket::TCP)
on an ArSocket object constructed with the default constructor.
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)
For example, after declaring this function with a default value for its integer argument:
void foo(int number = 3);
// Use the default value for the argument: foo(); // Or, use don't use the default: foo(99);
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:
void foo(int number) { //... }
class BaseClass { public: BaseClass(int someNumber); };
class SubClass : public BaseClass { public: SubClass(void); int anotherNumber; };
SubClass::SubClass(void) : BaseClass(3), anotherNumber(37) { // ... }
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.
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.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).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.
For example, early in an ARIA program, specify the connection device and associate it with the robot:
ArTcpConnection con; ArRobot robot;
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:
con.setPort(); if (!con.openSimple()) { printf("Open failed."); Aria::shutdown(); return 1; }
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.
robot.setDeviceConnection(&con); if (!robot.blockingConnect()) { printf("Could not connect to robot... Exiting."); Aria::shutdown(); return 1; }
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()
.
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.