Copyright 2002, 2003, 2004, 2005 ActivMedia Robotics, LLC. All rights reserved.
Copyright 2006, 2007 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 ArSimpleConnector to connect the ArRobot and ArSick classes to their respective hardware (ArRobot to the robot via the default robot serial port -- or to the simulator via TCP -- and the ArSick object to the SICK laser rangefinder via the default laser serial port).
#include "Aria.h" int main(int argc, char** argv) { Aria::init(); ArSimpleConnector connector(&argc, argv); ArRobot robot; ArSick sickLaser; // Check command line arguments used by SimpleConnector if(!connector.parseArgs()) { connector.logOptions(); exit(1); } // Connect to robot, run devices in background threads, and connect to laser. if(!connector.connectRobot(&robot)) { // Error! ... } robot.runAsync(true); sickLaser.runAsync(); if(!connector.connectLaser(&sickLaser)) { // Error! ... } // Now we're connected, and the 'robot' and 'sickLaser' objects are running in // background threads. ...
If, instead of using ArSimpleConnector, you want to have more control over how you connect with the robot or learn about how the pieces that make up a robot connection see Connecting with a Robot or the Simulator the hard way.
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().
It is also possible to run the processing cycle without a connection to a robot, if desired. This alternative cycle has its own default cycle time of 100 milliseconds which you may examine and reset with ArRobot::getCycleTime() and ArRobot::setCycleTime(). During the normal synchronized cycle, ArRobot waits up to twice that cycle time for a standard SIP from the robot before giving up and beginning to cycle automatically. You may also explicitly disassociate ArRobot's processing cycle from incoming SIP processing 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
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.
ArPriorityResolvel works by iterating through the action list in descending priority, 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 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) * (B velocity strength: 1.0) + (C desired velocity: 200) * (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) * (step 1 velocity strength: 0.25) + (step 4 desired velocity: 0) * (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, there are four primary ArRangeDevice implementations included with ARIA: sonar (ArSonarDevice), the SICK laser (ArSick), the robot bumpers (ArBumpers), and IR sensors (ArIRs), for example the "table-sensing" IR sensors of the PeopleBot. In addition, ArForbiddenRangeDevice is a "virtual" range device that creates range readings that border "forbidden area" and "forbidden line" regions in an ArMap.
ArRangeDevice holds two kinds of ArRangeBuffer objects to store readings: current and cumulative, though not all ArRangeDevice implementations supply data to the cumulative buffer. Each buffer has two different reading formats: box and polar (ArRangeDevice::currentReadingPolar(), ArRangeDevice::currentReadingBox(), ArRangeDevice::cumulativeReadingPolar(), ArRangeDevice::cumulativeReadingBox()). 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.
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.)
ArRobot also includes some helpful 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.
(Most 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 documentation for the ArMap class describes the format of the map file 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 port, simple construct a socket:
ArSocket sock(4040, true, ArSocket::TCP);
Or call:
ArSocket::open(4040, ArSocket::TCP);
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.
Aria/params
directory, generic, as well as individually named robot parameter files contain default and name-specific robot information that ARIA uses to characterize the robot and correctly interpret the server information that a robot sends back to the client.
Every robot has a type and subtype (e.g. "Pioneer" and "p3dx-sh") as well as a user-modifiable name, embedded in its FLASH parameters (see your robot operations manual for information about the robot's FLASH). These parameters get sent to the ARIA client right after establishment of the client-server connection, which ARIA prints to output (watch as demo
connects, for example). ARIA first loads parameters from the subtype parameter file, then from a name parameter file--setting and resetting global variables based on the contents of each file. Accordingly, subtype may add or change the settings derived from the default, and a named parameter file has the very last say over things.
ARIA has robot subtype parameter files in its params
directory. Example of parameter files are p3dx.p
(old H8 Pioneer 3 DX), p3dx-sh.p
(new SH Pioneer 3 DX), p3at-sh.p
(new SH Pioneer 3 AT), p2de.p
(Pioneer 2 DE), peoplebot-sh.p
(for new SH PeopleBot). Parameter files are also available from MobileRobots technical support (http://robots.mobilerobots.com).
To override a subtype parameter file, copy it to a new file named for your robot's name as specified in the FLASH parameter, adding the ".p" suffix, and change any parameters necessary for that specific robot. For example, ARIA uses RobotRadius
to determine the robot's turn limits in most of the obstacle avoidance routines. The default for the P2AT robot doesn't account for bumper accessories. Accordingly, you might create a new parameter file that redefines RobotRadius
for that specific robot.
ARIA uses the values in the conversion factors section of a parameter file to transform the robot-dependent server information data into normal dimensions and rates. For example, the DistConvFactor
converts the robot's position data, measured in encoder ticks, into millimeters.
ARIA consults the accessories section of a robot's parameter file to determine what accessories a robot might have that cannot be told by other means. For example, the P2 bumper values appear in the standard SIP stall values, but if a bump ring isn't connected, these values float and vacillate between on and off. An accessory definition in the parameter file clues ARIA to use or not use the bumper values.
Finally, the sonar section of the parameter file contains information about the sonar number and geometry so that ARIA can relate sonar readings with position relative to the center of the robot.
[ConvFactors]
Keywords and data are separated by one or more spaces on a single line, and may include several defining data values. Each keyword has its own behavior with how it parses the data. For example:
KeyWord data1 data2 data3 ...
Case doesn't matter for either section identifiers and keyword names. Some parameters can have multiple instances in the file. SonarUnit
is a good example of this. For example:
SonarUnit 0 73 105 90 SonarUnit 1 130 78 41
See ArConfig or ArRobotParams for additional details. ArConfig (and the same file format) may also be used by ARIA applications for other config files as well.
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.