Aibo Telepathy

Technical details

Usage

Subscribing to remote events:

You can subscribe to events on a remote AIBO using any of the addRemoteListener functions in EventRouter. These functions are used the same way as the addListener functions, except with an extra parameter for the host. The EventRouter::stringToIntIP function can be used to convert a string IP to an int for this parameter. The signatures are:

void addRemoteListener(EventListener* el, int host,
                       EventBase::EventGeneratorID_t egid);

void addRemoteListener(EventListener* el, int host,
                       EventBase::EventGeneratorID_t egid, unsigned int sid);

void addRemoteListener(EventListener* el, int host,
                       const EventBase& e);

void addRemoteListener(EventListener* el, int host,
                       EventBase::EventGeneratorID_t egid, unsigned int sid,
                       EventBase::EventTypeID_t etid);

No action is required on the server dog, EventRouter automatically starts listening for incoming requests when it starts up.

Once a behavior is subscribed to a remote event, the behavior's processEvent method will be called when the event occurs on the remote robot, just as it would for a local event. The event passed to processEvent now contains a host field which allows the user to determine whether the event is coming from a local or remote robot.

Note: both AIBO's must be on and connected to the network before starting the behavior that calls addRemoteListener.

Example behavior using a remote listener (video)

This behavior listens for back button presses on remoteDog and walks forward, backward, or stops according to which button is pressed.

in doStart:

erouter->addRemoteListener(this,
                           remoteDog,
                           EventBase::buttonEGID,
                           RobotInfo::FrontBackButOffset,
                           EventBase::activateETID);

erouter->addRemoteListener(this,
                           remoteDog,
                           EventBase::buttonEGID,
                           RobotInfo::MiddleBackButOffset,
                           EventBase::activateETID);

erouter->addRemoteListener(this,
                           remoteDog,
                           EventBase::buttonEGID,
                           RobotInfo::RearBackButOffset,
                           EventBase::activateETID);

in processEvent:

if (event.getHostID() == remoteDog && event.getGeneratorID() == EventBase::buttonEGID) {
     switch (event.getSourceID()) {
          case RobotInfo::FrontBackButOffset:
               MMAccessor(walk_id)->setTargetVelocity(100, 0, 0);
               break;

          case RobotInfo::MiddleBackButOffset:
               MMAccessor(walk_id)->setTargetVelocity(0, 0, 0);
               break;

          case RobotInfo::RearBackButOffset:
               MMAccessor(walk_id)->setTargetVelocity(-100, 0, 0);
               break;
      }
}

Obtaining remote state information:

State information can be requested from a remote dog using the EventRouter::requestRemoteStateUpdates function:

void requestRemoteStateUpdates(int host, RemoteState::StateType type, unsigned int interval = 500);

This will send a request to the host dog to send the specified type of state updates every 'interval' ms. When remote state information is received, the RemoteRouter will post a DataEvent<RemoteState *> with an EGID of remotestateEGID. The source ID will be the type of state that was updated.

Example behavior using remote state information (video):

in doStart:

erouter->requestRemoteStateUpdates(remoteDog, RemoteState::OutputState, 150);

in processEvent:

    if (event.getGeneratorID() == EventBase::remoteStateEGID) {
        const float *j = NULL;
        const DataEvent<const RemoteState *> &de =
            dynamic_cast<const DataEvent<const RemoteState *>&>(event);
        
        j = de.getData()->outputs;
        MMAccessor<HeadPointerMC>(hp_id)->
            setJoints(j[HeadOffset+TiltOffset],
                      j[HeadOffset+PanOffset],
                      j[HeadOffset+NodOffset]);
        
    }

Implementation details

Subscribing to remote events:

The EventRouter creates and maintains a RemoteRouter instance on the client robot which communicates with the host robot. When addRemoteListener is called, the RemoteRouter connects to the host and requests to listen for a specific event. It also creates a listener on the client robot for the event. The EventProxy on the host robot creates a listener for the specified events. When the events occur, EventProxy calls saveBinaryBuffer on the event and forwards it to the client robot. The RemoteRouter receives the event and uses loadBinaryBuffer to decode it, then forwards it to the EventRouter, which handles it like it would handle a local event.

Obtaining remote state information:

When the client calls erouter->requestRemoteStateUpdates() the host EventProxy subscribes itself to a timer. Whenever a timer event occurs, it sends the data to the client dog's remote router and posts a remoteState event. The data can then be accessed on the client using erouter->getRemoteState().