Using hubs to group objects

Now, suppose that, for our previous example, we can speed things up by sending all the servomotor commands at the same time, using the method setPositions (int count, int *ids, double * positions) that takes two arrays of ids and positions. A hub is the perfect way to handle this task. The UObject header stays the same. We add a hub declaration:

class servohub : public urbi::UObjectHub
{
public:
  //the class must have a single constructor taking a string
  servohub (const std::string&);

  // called periodically
  virtual int update ();

  // called by servo
  void addValue (int id, double val);

  int* ids;
  double* vals;
  int size;
  int count;
};

servo::update becomes a call to the addValue method of the hub:

int
servo::update()
{
  ((servohub*)getUObjectHub ("servohub"))->addValue (id, (double)val);
};

The following line can be added to the servo init methdd, although it has no use in our specific example:

URegister(servohub);

Finaly, the implementation of our hub methods is:

servohub::servohub (const std::string& s)
  : UObjectHub (s),
    ids   (0),
    vals  (0),
    size  (0),
    count (0)
{
  // setup our timer
  USetUpdate (1);
}

int
servohub::update ()
{
  // called periodically
  setPositions (count, ids, vals);

  // reset position counter
  count = 0;

  return 0;
}

void
servohub::addValue (int id, double val)
{
  if (count + 1 < size)
  {
    // allocate more memory
    ids = (int*)realloc (ids, (count + 1) * sizeof (int);
    vals = (double*)realloc (vals, (count + 1) * sizeof (double);
    size = count + 1;
  }
  ids[count] = id;
  vals[count++] = val;
}

UStartHub (servohub);

Periodically, the update method is called on each servo instance, which adds commands to the hub arrays, then the update method of the hub is called, actually sending the command and resetting the array.

Alternate implementation

Alternatively, to demonstrate the use of the members hub variable, we can entirely remove the update method in the servo class (and the USetUpdate() call in init), and rewrite the hub update method the following way:

int servohub::update()
{
  //called periodically
  for (UObjectList::iterator it = members.begin ();
       it != members.end ();
       it++)
  {
    addValue (((servo*)*it)->id,
              (double)((servo*)*it)->val);
  }
  setPositions(count, ids, vals);
  // reset position counter
  count=0;

  return 0;
}