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).
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.
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)