Skip to main content

User Control Setup

How to configure user control in assembly.cpp and main.cpp

Assembly Setup

note

Using the assembly class is completely optional, there are many other ways to structure user control. In this example the robot has 1 intake motor and 1 piston.

Creating Devices

Navigate to include/assembly.h. This is what holds non drivetrain related devices. To add a devices declare it as

static vex::device_name name;

The vex devices commonly used are

vex::rotation
vex::optical
vex::distance
vex::limit

With mikLib specific devices being

mik::piston
mik::motor
mik::motor_group

For a full list of all VEX devices check out their api reference

For our robot we will create a piston and intake device.

static mik::motor intake_motor;
static mik::piston wing_piston;

Once you have your devices inside assembly.h, add functionally in robot-config.cpp by doing

vex::device_name Assembly::name(PORT12)
important

For non vex:: triport devices make sure you convert the port letter to an actual triport object using to_triport(). For mik::piston this is done automatically.

vex::limit Assembly::limit_switch(to_triport(PORT_A));
mik::piston Assembly::piston_toggle(to_triport(PORT_B));

For our example

mik::motor Assembly::intake_motor(PORT16, false, blue_6_1, "intake");
mik::piston Assembly::wing_piston(PORT_B);

User Control

Now you need a way of controlling these devices. First define functions used to control devices in assembly.h

void intake_control();
void wing_piston_control();

Then in assembly.cpp add functionally to the functions.

note

btnA_new_press fires only on the initial press, and only reactivates on release. Use this instead of .pressing() for toggles.

// Extends or retracts piston when button A is pressed, 
// can only extend or retract again until button A is released and pressed again
void Assembly::wing_piston_control() {
if (btnA_new_press(Controller.ButtonA.pressing())) {
wing_piston.toggle();
}
}

// Spins intake forward if L1 is being held, reverse if L2 is being held; stops otherwise
void Assembly::intake_control() {
if (Controller.ButtonL1.pressing()) {
intake_motor.spin(fwd, 12, volt);
} else if (Controller.ButtonL2.pressing()) {
intake_motor.spin(fwd, -12, volt);
} else {
intake_motor.stop();
}
}

Then add your functions inside of control

void Assembly::control() {
static bool initialized = false;

if (!initialized) {
init();
initialized = true;
}

intake_control();
wing_piston_control();
}

Completed Assembly Setup

// assembly.h
class Assembly {
public:
static mik::motor intake_motor;
static mik::piston wing_piston;

void init();
void control();

void intake_control();
void wing_piston_control();
};
// robot-config.cpp
mik::motor Assembly::intake_motor(PORT16, false, blue_6_1, "intake");
mik::piston Assembly::wing_piston(PORT_B);
// assembly.cpp
void Assembly::control() {
static bool initialized = false;

if (!initialized) {
init();
initialized = true;
}

intake_control();
wing_piston_control();
}

void Assembly::wing_piston_control() {
if (btnA_new_press(Controller.ButtonA.pressing())) {
wing_piston.toggle();
}
}

void Assembly::intake_control() {
if (Controller.ButtonL1.pressing()) {
intake_motor.spin(fwd, 12, volt);
} else if (Controller.ButtonL2.pressing()) {
intake_motor.spin(fwd, -12, volt);
} else {
intake_motor.stop();
}
}

Chassis Control

Navigate to main.cpp to change the control mode. The most common one is split arcade, where the left stick is the throttle, and right stick turns.

To use split arcade do

chassis.control(drive_mode::SPLIT_ARCADE);

For finer control, you can also use tank drive, with the left stick controlling the left side of the drivetrain, and right stick controlling right side.

chassis.control(drive_mode::TANK);

Control Curved

Both split arcade and tank support curved versions.

chassis.control(drive_mode::SPLIT_ARCADE_CURVED);
chassis.control(drive_mode::TANK_CURVED);

Using curved drive provides finer control and will arc while turning and driving.

Holonomic

Holonomic drivetrains can use

chassis.control(drive_mode::SPLIT_ARCADE_HOLONOMIC);
chassis.control(drive_mode::FIELD_CENTRIC_HOLONOMIC);

Field centric uses the inertial sensor to determine which direction it should go, meaning wherever you point the left stick no matter the orientation, the robot will drive in that direction.

Constants

The constants for drive modes are deadband, min_output, curve_gain, and desaturate_bias. With the scale being 0-100. Deadband applies to all drive modes, while the others only apply to curve modes.

// Each controller constant in the form of throttle, 
// turn (deadband, min_output, curve_gain), desaturate_bias.
chassis.set_control_constants(5, 10, 1.019, 5, 10, 1.019, 0.5);

With these constants, the left stick and right stick have a deadband of 5, meaning any inputs under 5 percent are 0.

Then for drive curve modes for both sticks, any output past deadband, will be at a minimum 10%, with the output following an exponential function using constant 1.019. The desaturate bias of 0.5, means that the throttle and turning have equal priority, will not exceed max speed of 100.

Completed User Control Loop

void user_control(void) {
while (chassis.calibrating) { task::sleep(50); }

enable_user_control();

chassis.set_brake_type(brakeType::coast);

while (true) {
if (!control_disabled()) {
chassis.control(drive_mode::SPLIT_ARCADE);
assembly.control();
}
task::sleep(5);
}
}