OkapiLib icon indicating copy to clipboard operation
OkapiLib copied to clipboard

Rosserial Integration

Open CanyonTurtle opened this issue 7 years ago • 2 comments

Is your feature request related to a problem? Please describe.

Problem: Integrating a ROS serial connection with VEX hardware is possible with rosserial for V5 alone, but requires user configuration for lots of hardware-specific setup, such as setting up publishers for sensor data, moving the robot based on commands, etc...

Describe the solution you'd like

The OkapiLib API can act as a schema for mapping ROS objects into abstractions, e.g. chassis, that ROS can control via standardized ROS messages, e.g. Twist command velocity messages for that chassis.

Describe alternatives you've considered

Using rosserial with vex hardware is still possible (example), but the OkapiLib abstractions can provide control systems built-in, which will allow the ROS messages to be a more intelligent control interface, with minimal user requirement.

Versions

PROS: 3.0.6 OkapiLib: recent

Additional context

This issue is intended to be a running discussion about integrating rosserial and OkapiLib.

CanyonTurtle avatar Jul 19 '18 22:07 CanyonTurtle

Some additional summary of our initial discussion @Octogonapus:

Design of Adaptation Layer as Registry / Class Wrappers

There are a few ways to make some sort of adaptation layer for rosserial bindings ontop of the OkapiLib classes.

1 - Create a registry class that accepts OkapiLib objects.

The registry class assigns the required publishers/subscribers to track the OkapiLib with publishers and subscriber callbacks. The registry would presumably have an overridden method for "register" for each supported OkapiLib class that would be the mechanism for writing the ROS binding behavior.

rosserial::Registry rosManager; 

void opcontrol(void) {
  // set up loop thread to publish sensor data from all registered objects
  rosManager.start(20);
  
  // Normal OkapiLib object definition
  // ...
  okapi::ChasisController chassis(model);
  // ...

  // every 20 milliseconds, sensor array published on topic , e.g. "/myDrive/sensors/"
  // AND subscriber callbacks are set for another topic, e.g. "myDrive/cmd_vel/"
  // Note: these names are all just placeholders
  rosManager.register(chassis, "myDrive");
  // the above requires implementation of 
  // void rosserial::Registry::register(okapi::ChassisController, const char*);
  // AND
  // void rosserial::Registry::ChassisControllerCallback(const geometry_msgs::Twist&);
}

1 PROS (no pun intended):

  • Don't have to make new class for every time we want to wrap one from OkapiLib
  • Straightforward way for the user to bind the parts he wants.

1 CONS

  • lots of stuff in the Registry class
  • explicit declaration of a manager and of registering

2 - Create rosserial subclasses of OkapiLib objects.

There would be one subclass for every supported OkapiLib class that extends the original with the ROS functionality.

void opcontrol(void) {
  
  // Normal OkapiLib object definition
  okapi::ChasisController chassis(model);

  // every 20 milliseconds, sensor array published on topic , e.g. "/myDrive/sensors/"
  // AND subscriber callbacks are set for another topic, e.g. "myDrive/cmd_vel/"
  rosserial::wrappers::ChassisController rosChassis(chassis, "myDrive");
  // the class has the pub/sub logic from before, but in the class
}

2 PROS:

  • behavior per-subsystem will clearly associate in a respective class

2 CONS:

  • User API more diverse. More to know?
  • setting up publishers and subscribers probably requires a dedicated singleton thread anyway (workaround: multiple inheritance, so the rosserial subclasses inherit from the OkapiLib class, and a single ROS class with a method to set up publishers in that singleton thread).

These approaches are similar in nature, after all. I think that the first way has a cleaner interface.

Configuration for Registered objects

When an OkapiLib object is registered, additional configuration should be provided. At least:

  • the name of the object, as will be visible via ROS topics
  • maybe, publish rate? V5 is fast enough to do everything at 100hz, we could just use the publishing loop to decide how fast the whole system will go.
  • What to publish / subcribe: I actually think these don't need to be parameters. A given system should have fixed publishers / subscribers, that will be implemented in the respective register() function, and can be documented to show how to interface over ROS with that subsystem.

Additional notes

This architecture makes it very straightforward how to handle the API: every supported object has a correspondingregister() override in the Registry class, everyget() has a publisher constantly firing in that registry's loop thread, and every set() has a subscriber callback waiting for a ros message to pass parameters. Possibly, an option in registering to make some parts of a system silent might be good. Or, forcing the user to supply which messages to send/recieve could reduce unnecessary messages.

CanyonTurtle avatar Jul 20 '18 17:07 CanyonTurtle

As I had said before, I prefer the first option. Others are welcome to share their opinions.

Octogonapus avatar Jul 20 '18 18:07 Octogonapus