Exercise: Setting Up a MotionCommand to Cycle the LEDs
We will use a LedMC to make some LEDs blink, and increase the rate
when a button is pressed. On the AIBO will use the face LEDs; for the
Qwerkbot we'll use all the LEDs. First, we must create a data member
to store the MC_ID of the MotionCommand we'll be creating, and
initialize it in the DstBehavior constructor.
#include "Behaviors/StateMachine.h"
$nodeclass ButtonFlash : public StateNode : leds_id(MotionManager::invalid_MC_ID) {
MotionManager::MC_ID leds_id; // id number for the MotionCommand
...
|
We use the global variable motman to access the
MotionManager. doStart() instantiates a LedMC using the
SharedObject<LedMC> constructor. It sets the LedMC's parameters
to blink with a 1000 msec period, by calling its
cycle(...) method. Then it adds the LedMC to the
MotionManager's active list. Note that leds_mc is a local variable
that will be lost when doStart() returns. That's okay because the
actual MotionCommand is sitting in shared memory and is protected by a
reference counter. The variable leds_mc is just a smart pointer to
the shared memory region. The MotionCommand itself will not be
deleted until it is removed from the MotionManager's active list and
its reference count goes to zero.
virtual void doStart() {
cout << getName() << " is starting up." << endl;
erouter->addListener(this,EventBase::buttonEGID);
SharedObject<LedMC> leds_mc;
leds_mc->cycle(RobotInfo::FaceLEDMask, 1000, 100.0);
leds_id = motman->addPersistentMotion(leds_mc);
}
|
The expresion leds_mc->cycle(...) above hides a
syntactic trick: the cycle() function belongs to the nameless LedMC
instance, not to the SharedObject stored at leds_mc. SharedObject
overloads the -> operator and passes the call on to
the LedEnging::cycle() function for the actual LedMC instance. Note:
the variable RobotInfo::FaceLEDMask passed to cycle is
defined in several model-specific namespaces, such as ERS210Info,
ERS220Info, and ERS7Info. To write model-independent code, you can
limit yourself to identifiers defined across all models, and refer to
the generic RobotInfo namespace to automatically get the version
appropriate to the model you're compiling for. Use
RobotInfo::AllLEDMask to activate all the LEDs on a
robot; this is a good choice for the Qwerkbot.
doStop() removes the LedMC instance from the Motion Manager's active
list.
virtual void doStop() {
motman->removeMotion(leds_id);
std::cout << getName() << " is shutting down." << endl;
}
|
Inside doEvent, we will change the parameters of the running
LedMC to alter its blink rate. To do this safely, we must first
instantiate an MMAccessor, which we'll call leds_acc, using leds_id.
This locks down the MotionCommand. Then we use the accessor to call
the LedEngine::cycle method to change the blink period to 250
milliseconds for rapid blinking, or 1000 milliseconds to go back to
slow blinking. The blink amplitude of 100.0 causes the LEDs to jump
from full off to full on, or vice versa, instead of fading up or down
gradually. (The cycle() function computes a sine wave. The LED
amplitudes are bounded between 0 and 1.0, so multiplying the sine wave
by 100.0 means the positive half of the wave will hit the 1.0 limit
very quickly, producing a step function.)
Once again we are using a bit of syntactic sugar: MMAccessor overloads
the -> operator to provide for method invocation,
since we have no direct pointer to the LedMC instance which is sitting
in shared memory. We do not have to explicitly unlock the
MotionCommand: this happens automatically when we exit the block and
leds_acc's destructor function is called.
virtual void doEvent() {
switch ( event->getGeneratorID() ) {
case EventBase::buttonEGID: {
cout << getName() << " got event: " << event->getDescription() << endl;
MMAccessor<LedMC> leds_acc(leds_id);
leds_acc->cycle(RobotInfo::FaceLEDMask, int(1000-750*event->getMagnitude()), 100.0);
break; }
default:
cout << "Unexpected event:" << event->getDescription() << endl;
}
}
} // end of $nodeclass
REGISTER_BEHAVIOR(ButtonFlash);
|
Compile this code and boot the robot. Unpause it, and then activate
ButtonFlash. The MotionCommand you created is now active, but no
lights should be blinking because the default LedMC parameters tell it
to do nothing. Now press a button and the call to cycle
will update the parameters and cause the lights to blink at a rapid
rate. Release the button and the lights should blink at a slower
rate. Deactivate the Behavior and the MotionCommand will be removed
from the active list.
|