0

I am practicing professional C++ by building a differential drive robot that applies a Go-To-Goal Behavior.

What is I have written so far is an Agent that consumes the following interfaces:

  1. Actuators Interface
  2. Odometry Interface
  3. PID Regulator Interface

The motion of a differential drive robot is governed by the unicyle kinematics model, which is a state based model (important later) where the robot is represented in terms of its velocity and heading angle (theta). The actuation of the robot it done via another state which is the angular rotation of its wheels.

The task of the agent is the orchestration of the control loop such that:

The output of the PID is fed to the actuators (PWM motor control), and feedback is measured using optical wheel encoders (to estimate distance traveled and thus position), and fed back to the PID regulator to achieve the Go-To-Goal behavior.

I have this mostly working with some mistakes in the calculations but unit-testing should hopefully improve it.

My design goal right now has become to make the agent as well as each of the components that are exposed by those interfaces re-usable so that I can substitute more advanced kinematics or dynamic models for front wheel drive cars without any code change to the agent or unchanged components (and preferably no re-compilation).

To this effort I think the following should apply:

  1. Using shared objects instead of static linking.

  2. De-Coupling using interfaces (already had to do this for unit-testing anyways).

  3. External configuration of the components.

    1. This where I draw a blank. How can I use something like protobuf for example to make the components generic enough to be replaceable.

In summary, what I am asking the community here is the following:

  1. How can I make the Agent, Odometry and PID generic such that their communication is independent of a pre-known State implementation.
  2. Are the above 3 items helpful in achieving the re-usabiliy goal, if not, then which ones should be added/replaced.

Update

To make the question more clear, please consider the following scenario:

The factory method for the actuator needs to know which type of Command object to use when constructing the implementation of the interface, such as:

#pragma once

namespace tareeq {
  namespace control {
      template <class T, class T1>
      class Actuators {
      public:
    virtual ~Actuators() = default;

    virtual bool Init(T Config) = 0;
    virtual bool Start() = 0;
    virtual bool Stop() = 0;
    virtual bool Drive(T1 Command) = 0;
      };

      std::unique_ptr<Actuators> MakeAcutator();

  } // namespace control
} // namespace tareeq

The agent will have to know the relevant Command class to use for a differential drive robot, which is angular velocity of the two wheels, where as for a bicyle model, the actuators can range from throttle/break, to an RC car with two motors; one on the rear wheels to move the car, and another to turn the front two wheels (usually motor connected to a spring that turns the front wheels).

Another case is the communication of values between the components, for example:

The PID would have something like:

double ComputeOmega(T &target_state, T &current_state);

I think I maybe able to solve both these issues as follows:

  1. Use a pub/sub messaging model with google protobuf
  2. Use a Class-Loader that loads the .so at runtime, and this loader can be configured to load the appropriate ClassName via some external yml file.
  • 1
    1) Is the behavior of any of those classes depending on the state (i.e functions do different things depending on the state) ? or is the state just the known data about the bot (position, velocity, status of equipment, etc) ? 2) what in your current design prevent you from replacing the components behind the interfaces ? – Christophe Apr 15 at 6:43
  • @christophe state as in data about the bot. Currently the state is a c++ class that is passed to the ctr's – Sam Hammamy Apr 15 at 11:54
  • ok ! that clarifies my first point. And what about my second point ? And in addition, do you understand « interface » as an OO interface ? or more as the link between elements according to some kind of protocol stack ? – Christophe Apr 15 at 13:24
  • @Christophe an OO interface. I will update the question with a code example. I think it will clarify it much more – Sam Hammamy Apr 15 at 13:26
  • Do they communicate through this state object? The statement " How can I make the Agent, Odometry and PID generic such that their communication is independent of a pre-known State implementation." to me is either a massive miscommunication or so obvious to me that this must be a duplicate of some other question in an extremely obfuscated form. Is all that you are asking is how to have three interfaces that take as parameter an object which they don't know or care the implementation of? – opa Apr 15 at 19:22
2

The reusability graal

Achieving reusability requires lose coupling: every dependency to other classes makes the reusability more difficult because it adds more constraints. For example if reusing your actuator requires reusing your state and and your commands, which themselves may require to reuse I don't know what, and so on, it may not be so reusable after all.

How to reduce the coupling in your case ? Your (hopefully) clean interfaces is certainly the beginning. But you will need some dependency inversion as well, for example i dependency injection . This allows some kind of run-time configuration. So instead of having a class to know the command class to create new commands, you'd use an abstract command and provide to the class a command factory.

Now that we are mentionning interfaces and abstract classes, you'll also need to ensure that the deived classes behave according to the rules. And here Liskov Substitution Principle may help.

If you just follow the SOLID design principles, you get these 3 for free ;-)

Dynamic configuration

Your requirement is:

to make the agent as well as each of the components that are exposed by those interfaces re-usable so that I can substitute more advanced ... or dynamic ... without any code change to the agent or unchanged components (and preferably no re-compilation).

Of course, you can do this using templates. This has the benefit of facilitating reuse. No special constraint for T and T1 classes: just provide the required meta-interface. (But where are the requirements for T and T1 described ?)

Unfortunately templates, despite their power and flexibility, are compile-time. This does not allow run-time polymorphism, nor make dynamic loading of the right class possible.

In view of your design goals, I'd therefore recommend to get rid of the templates and opt for a polymorphic design, using an abstract Command class and an abstract State class and provide the factories to create those.

Advanced features

It is possible that your dynamic model will provide much more features than your simple abstract state. The advanced kinematics might also require some more exchanges than the basic one.

For this you could opt for a decorator pattern, to add new functionality and responsibilities. However, your agent would need to know about these. Another approach would be to use an architectural pattern that is common in games, the Entity-Component-System: here you could add advanced features as an optional component, and let your agent search in your actuator entity, for the most suitable component.

  • Thanks Christoph! Great answer! I was down the road a little this morning looking at dynamically loaded classes which register themselves with a factory. This helps narrow down the research for me quite a bit! – Sam Hammamy Apr 15 at 18:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.