VEXcode, motor groups and drivetrain example

There have been quite a few requests for instructions on how to use motor groups and creating a drivetrain with more than 2 motors in VEXcode. I’m going to discuss these classes a little and provide a simple example.

What is a motor group ?
A motor group collects two or more motors together and allows control as if they were a single entity. Just about all motor class member functions (by that I mean spin, spinTo, setVelocity etc.) are available on the motor group class. We introduced motor groups with VEXcode preview 3, however, it has been improved since then and continues to be tweaked as we create each new iteration of the SDK that VEXcode uses. The code in this post is valid for VEXcode V1.0.1.

A motor group is created from instances of motors that already exist. It’s best to use global instances, we pass motors to the motor group constructor by reference (don’t worry about what that means) so if a motor is created as a local variable in a function, there’s a good change the motor group would have a reference to an object that may not exist anymore and the code will probably not do what you expect it to. VEXcode always creates global motor instances when you use the graphical configuration, and in general all the examples we have provided with VCS and VEXcode over that past year also use global instances.

A motor group can have a maximum of 16 motors.

What is a drivetrain ?
A drivetrain is another high level class we use to collect together motors and some other related parameters. A drivetrain needs to know which motors are used for the wheels on the left and right hand sides of the robot. A drivetrain does not handle complex drive systems such as X or H drives, however, it will work with a mecanum wheel based drive but you would have to add your own code for strafing.

A two wheel drivetrain only handles one motor on each side, this is what the VEXcode graphical configuration is capable of handling. With more than one motor on each side things get a little more complex. The drivetrain constructor needs a motor group provided for left and right wheels, the motors also need configuring correctly which depends on how the robot is constructed and if the wheels are mechanically coupled.

The drivetrain can also use the VEX yaw rate gyro to help in performing more accurate turns. If the gyro is used we use the smartdrive class rather than the drive trainclass.
(for the advanced programmers, a smartdrive is a sub class of drivetrain, it inherits all the class member functions that drivetrain provides and then adds some additional ones to handle turns using the gyro)

The drivetrain also needs to know the distance between left and right wheels (trackWidth), the distance between front and rear axles (wheelBase) and the wheel circumference (wheelTravel).

robot_diagram

An example program

Create a new project in VEXcode and use the graphical configuration to add four motors, a controller and (optionally) a gyro. The right side motors will generally have the reverse flag set on them. The graphical config would look as follows.

config_1

I’ve named the motors so they refer to the wheel positions, for example, MotorLf is the left front wheel motor.

Looking in robot-config.cpp we can see the motor and other device instances have been added.

// VEXcode device constructors
motor MotorLf = motor(PORT1, ratio18_1, false);
motor MotorLb = motor(PORT2, ratio18_1, false);
motor MotorRb = motor(PORT9, ratio18_1, true);
motor MotorRf = motor(PORT10, ratio18_1, true);
gyro GyroA = gyro(Brain.ThreeWirePort.A);
controller Controller1 = controller(primary);

They have also been added to robot-config.h so that they can be used in other source code files.

First we will create the left and right hand side motor groups.

Near the top of main.cpp, add a line of code to create the left side group

// left hand side of the robot has two motors
motor_group   leftDrive( MotorLb, MotorLf );

leftDrive is an instance of the motor_group class and we have initialized it with two motors. An alternate form of the constructor would look like this, which format you use is really personal preference.

// left hand side of the robot has two motors
motor_group   leftDrive = motor_group( MotorLb, MotorLf );

Create the right side in the same way, the beginning of main.cpp would now look like this.

partial main.cpp
// ---- START VEXCODE CONFIGURED DEVICES ----
// Robot Configuration:
// [Name]               [Type]        [Port(s)]
// MotorLf              motor         1               
// MotorLb              motor         2               
// MotorRb              motor         9               
// MotorRf              motor         10              
// GyroA                gyro          A               
// Controller1          controller                    
// ---- END VEXCODE CONFIGURED DEVICES ----

#include "vex.h"

using namespace vex;

/*----------------------------------------------------------------------------*/
// define the motor groups
// the motors should have been setup with correct the gear cartridge ratios
// and the reverse flag set as necessary so they rotate in the correct direction
// when commanded to more forwards

// left hand side of the robot has two motors
motor_group   leftDrive( MotorLb, MotorLf );

// right hand side of the robot has two motors
motor_group   rightDrive( MotorRb, MotorRf );

next we create the drivetrain, I’m going to create a smartdrive and use the gyro I added in graphical config.

smartdrive    robotDrive( leftDrive, rightDrive, GyroA, 12.56, 16, 16, distanceUnits::in );

The smartdrive I created is called “robotDrive”. I set the wheel travel at 12.56 inches (4" wheels), the track width and wheel base are set at 16 inches. A drivetrain without using the gyro would look like this.

drivetrain    robotDrive( leftDrive, rightDrive, 12.56, 16, 16, distanceUnits::in );

Now we add some code to main.cpp to control the drive. A command to rotate the drive would be.

// tell drivetrain to rotate 90 deg
robotDrive.turnFor( 90, degrees );

but you can also directly control the motors on the left and right hand sides by using spin and other methods.

leftDrive.spin( forward, leftSpeed, percent );
rightDrive.spin( forward, rightSpeed, percent );

you can access individual motors as well.

Brain.Screen.print( "  MotorLb    speed: %4.0f   position: %6.2f", MotorLb.velocity( percent ), MotorLb.position( rev ) );

The full contents of main.cpp for this little example is as follows. It’s a bit more complex than the typical examples included with VEXcode as it does start an additional task (thread) to display some of the motor properties.

main.cpp
/*----------------------------------------------------------------------------*/
/*                                                                            */
/*    Module:       main.cpp                                                  */
/*    Author:       james                                                     */
/*    Created:      Sat Nov 02 2019                                           */
/*    Description:  V5 project                                                */
/*                                                                            */
/*----------------------------------------------------------------------------*/

// ---- START VEXCODE CONFIGURED DEVICES ----
// Robot Configuration:
// [Name]               [Type]        [Port(s)]
// MotorLf              motor         1               
// MotorLb              motor         2               
// MotorRb              motor         9               
// MotorRf              motor         10              
// GyroA                gyro          A               
// Controller1          controller                    
// ---- END VEXCODE CONFIGURED DEVICES ----

#include "vex.h"

using namespace vex;

/*----------------------------------------------------------------------------*/
// define the motor groups
// the motors should have been setup with correct the gear cartridge ratios
// and the reverse flag set as necessary so they rotate in the correct direction
// when commanded to more forwards

// left hand side of the robot has two motors
motor_group   leftDrive( MotorLb, MotorLf );

// right hand side of the robot has two motors
motor_group   rightDrive( MotorRb, MotorRf );

/*----------------------------------------------------------------------------*/
// define the drivetrain
// this one is a smart drive which uses the gyro
// gyro and all motors were defined using graphical config
// we have 4 inch wheels
// drive is 16 inches wide between the wheels
// drive has a 16 inch wheelbase (between fron and back wheel axles)
//
smartdrive    robotDrive( leftDrive, rightDrive, GyroA, 12.56, 16, 16, distanceUnits::in );
// this is how the above definition would be if no gyro is used
//drivetrain    robotDrive( leftDrive, rightDrive, 12.56, 16, 16, distanceUnits::in );


/*----------------------------------------------------------------------------*/
//
// A task that just displays motor velocity and position
// The motors that are part of a motor group and/or drivetrain can still be accessed
// directly.
//
int displayTask() {
    while(1) {
      // display some useful info
      Brain.Screen.setCursor(2,1);
      Brain.Screen.print( "  MotorLb    speed: %4.0f   position: %6.2f", MotorLb.velocity( percent ), MotorLb.position( rev ) );
      Brain.Screen.newLine();
      Brain.Screen.print( "  MotorLf    speed: %4.0f   position: %6.2f", MotorLf.velocity( percent ), MotorLf.position( rev ));
      Brain.Screen.newLine();
      Brain.Screen.print( "  MotorRb    speed: %4.0f   position: %6.2f", MotorRb.velocity( percent ), MotorRb.position( rev ));
      Brain.Screen.newLine();
      Brain.Screen.print( "  MotorRf    speed: %4.0f   position: %6.2f", MotorRf.velocity( percent ), MotorRf.position( rev ));
      Brain.Screen.newLine();
      Brain.Screen.newLine();

      // motor group velocity and position is returned for the first motor in the group
      Brain.Screen.print( "  leftDrive  speed: %4.0f   position: %6.2f", leftDrive.velocity( percent ), leftDrive.position( rev ));
      Brain.Screen.newLine();
      Brain.Screen.print( "  rightDrive speed: %4.0f   position: %6.2f", rightDrive.velocity( percent ), rightDrive.position( rev ));
      Brain.Screen.newLine();
      Brain.Screen.newLine();

      // drivetrain velocity is the average of the motor velocities for left and right
      Brain.Screen.print( "  robotDrive speed: %4.0f", robotDrive.velocity( percent ) );
      Brain.Screen.newLine();

      // no need to run this loop too quickly
      wait( 20, timeUnits::msec );
    }

    return 0;
}

/*----------------------------------------------------------------------------*/
//
// main program entry and drive control
//
int main() {
    // Initializing Robot Configuration. DO NOT REMOVE!
    vexcodeInit();

    // set 10 second timeout for robot drive movements
    robotDrive.setTimeout(10, seconds);

    // set the speed used for drive turns
    robotDrive.setTurnVelocity(50, percent);

    // start the display task
    task displayTaskInstance( displayTask );

    // loop forever
    while( true ) {
      // Buitton A is used to rotate drive 90 degrees
      if( Controller1.ButtonA.pressing() ) {
        // tell drivetrain to rotate 90 deg
        robotDrive.turnFor( 90, degrees );
        // wait for it to be done
        while( robotDrive.isMoving() )
          wait( 10, timeUnits::msec );
      }
      else {
        // not rotating, then we can drive using controller

        // read percent from controller axis
        int leftSpeed  = Controller1.Axis3.position();
        int rightSpeed = Controller1.Axis2.position();
        // deadband
        if( abs(leftSpeed)  < 10 ) leftSpeed  = 0;
        if( abs(rightSpeed) < 10 ) rightSpeed = 0;

        // send to motors
        leftDrive.spin( forward, leftSpeed, percent );
        rightDrive.spin( forward, rightSpeed, percent );
      }
          
      // no need to run this loop too quickly
      wait( 20, timeUnits::msec );
    }

    return 0;
}

The VEXcode project is attached

v5code-project-ForumMotorGroup.zip
(14.5 KB)

16 Likes

How do you set a max speed for a drivetrain?

1 Like

Hi Lucky - not sure what you mean but ‘set maximum velocity’ As a rule of thumb you can set velocity either statically
leftDrive.setVelocity(100, percent )
or when moving:
leftDrive.spin( forward, 100, percent );

The V5 API website & included examples can be excellent reference - although much isn’t explained it may help w/all the different commands/syntax

1 Like