Writing Your First MotionCommand

This document will walk you through the creation of your first MotionCommand.  MotionCommands provide reusable motion primitives which are combined and controlled by a Behavior to accomplish a task.  This guide will show you how to write a MotionCommand to make three of the legs to mirror the position of the fourth leg.

Prerequisites

  1. You should complete the "Writing your first Behavior" guide before doing this since we will use the SampleBehavior class here.

  2. Read through the Doxygen documentation on the MotionCommand class, we will be inheriting from it.

  3. If you're new to C++, or just rusty, there is a C++ review available.

The Generic MotionCommand

  1. Create a file named SampleMC.h (or whatever you want to call it) in your project directory.

    • By convention, we've been ending the names of our MotionCommands with MC to make it clear what they are.

  2. Set up the usual C++ boilerplate for a class which inherits from the MotionCommand class.  The functions are described below.

    SampleMC.h
    //-*-c++-*-
    #ifndef INCLUDED_SampleMC_h_
    #define INCLUDED_SampleMC_h_

    #include "Motion/MotionCommand.h"

    class SampleMC : public MotionCommand {
    public:
    // Constructor
    SampleMC() : MotionCommand() {}

    // Abstract functions:
    // These must be defined by every MotionCommand
    virtual int updateOutputs() {}
    virtual int isDirty() {}
    virtual int isAlive() {}
    };

    #endif
  3. This isn't quite valid yet - several of the required functions have return codes which we are ignoring.  But first, a brief description of the functions:

    • updateOutputs() is called once per "cycle".  It should return the number of "dirty" outputs. ("dirty" means outputs which have changed since the last cycle.) Currently the return value is unused, but in the future MotionManager may use this information to avoid redundant calculations.  If this would be expensive to calculate precisely, at least be sure to return a non-zero value if there are any dirty outputs.

      SampleMC.h
        virtual int updateOutputs() {
      //by convention, return the number of dirty joints
      //(or non-zero if unknown)
      return NumLegJoints;
      }

      We are using the legs, so a nice way to say that is to use the constants defined in the RobotInfo namespace.  Since we're going to be using all of the leg joints, we return NumLegJoints.

    • isDirty() is not called at present, but should return the same value as updateJointCmds().  But just for this example, we'll always return true.

      SampleMC.h
        virtual int isDirty() {
      return true;
      }
    • isAlive() should return true as long as the MotionCommand is active.  If this returns false and the MotionCommand is set to autoprune, MotionManager will remove it.  This is handy for "throw away" motion primitives.

      SampleMC.h
        virtual int isAlive() {
      return true;
      }

      Our MotionCommand never really reaches an end condition, so we'll always return true.

    After adding these lines, the MotionCommand should be valid, although it doesn't do anything.

  4. Now lets add SampleMC to the SampleBehavior.h so you can test it out.  Not that it will do anything yet, but you will be able to test incremental changes from now on.

    First, include the header file and create a new MotionPtr<SampleMC> member variable, initialize it, and then activate it in DoStart

    SampleBehavior.h
    // [...]
    #include "SampleMC.h"

    class SampleBehavior : public BehaviorBase {
    protected:
    // [...]
    MotionPtr<SampleMC> mirror;

    public:
    SampleBehavior() : BehaviorBase("SampleBehavior"),
    // [...]
    mirror() // initializer
    {}

    DoStart() {
    // [...]
    addMotion(mirror); // activate as soon as the behavior runs
    }
    // [...]
    };

    And that's it!  From this point we customize what we want SampleMC to do that makes it unique.

    Note that if your MotionCommand has a definite stopping point and uses isAlive() to reflect this status, you may instead wish to use addPrunableMotion(), and skip removeMotion().  If you do this and care to know when the MC has finished, you can listen for the appropriate deactivate event from motmanEGID.

Further Exercises

Part 2: Adding MotionCommand Functionality will show you how to control the joints.
back to top

developer resources

Last modified: 2010-01-10