Motor brake mode not doing it's job

This used to work when I used 100% PROS, but around the same time I switched to okapilib, motors’ hold mode became weak. Kind of like brake mode.

For instance, if you set your drivetrain’s brake mode to hold and place it on the ramp it will slowly slide down, not as fast as coast mode but still insufficient braking. Earlier in the season I did this with PROS like so (and the bot held its position perfectly):

Code
if (condition) {
m_frontL.set_brake_mode(pros::E_MOTOR_BRAKE_HOLD);
m_backL.set_brake_mode(pros::E_MOTOR_BRAKE_HOLD);
m_frontR.set_brake_mode(pros::E_MOTOR_BRAKE_HOLD);
m_backR.set_brake_mode(pros::E_MOTOR_BRAKE_HOLD);
}
else {
m_frontL.set_brake_mode(pros::E_MOTOR_BRAKE_COAST);
m_backL.set_brake_mode(pros::E_MOTOR_BRAKE_COAST);
m_frontR.set_brake_mode(pros::E_MOTOR_BRAKE_COAST);
m_backR.set_brake_mode(pros::E_MOTOR_BRAKE_COAST);
}

Now its with:

Summary
if (condition) {
// XDriveTrain is an X Drive Chassis Model
XDriveTrain->setBrakeMode(okapi::AbstractMotor::brakeMode::hold);
}
else {
XDriveTrain->setBrakeMode(okapi::AbstractMotor::brakeMode::coast);
}

I have followed the okapi code of setBrakeMode all the way through to where it calls pros setBrakeMode and everything points to saying that it should function identically (that is, nothing in the code is refusing to set the brake mode that I could find).
I also was able to run getBrakeMode on individual motors, which also said hold mode was active for every one.

Any ideas?

In the code you’ve shown, you are only setting the brake mode, not actually activating it (through setVelocity(0) or other method). Please show the portion of code that activates the brake mode.

2 Likes

Here are the parts of code relevant… there is other stuff but it is irrelevant to this function.

#include "main.h"
#include <cmath>
#include <chrono>
#include <string>

using namespace okapi::literals;

pros::Imu inertial(4);

// Construct the drivetrain
std::shared_ptr<okapi::ChassisController> drive =
    okapi::ChassisControllerBuilder()
        .withMotors(
                2,
                -10,
                -11,
                20
               )
        .withDimensions(okapi::AbstractMotor::gearset::green, {{4_in, 15.5_in}, okapi::imev5GreenTPR})
        .build();

auto XDriveTrain { std::dynamic_pointer_cast<okapi::XDriveModel>(drive->getModel()) };

auto topLeft { XDriveTrain->getTopLeftMotor() };

void opcontrol() { 

while(true) {
XDriveTrain->xArcade(
                controller.getAnalog(okapi::ControllerAnalog::leftX),
                controller.getAnalog(okapi::ControllerAnalog::leftY),
                controller.getAnalog(okapi::ControllerAnalog::rightX),
                0.05); 

      //Tilt Lock
        static bool tilted { false };
        int roll = std::abs(inertial.get_roll());
        if (!tilted && roll >= 10 && roll < 1000) { // Going from flat to tilted enable hold
            std::cout << "triggered tiltbrake\n";
            XDriveTrain->setBrakeMode(okapi::AbstractMotor::brakeMode::hold);
            tilted = !tilted;
        }
        else if (tilted && roll < 10) { //going from tilted to flat disable hold
            XDriveTrain->setBrakeMode(okapi::AbstractMotor::brakeMode::coast);
            tilted = !tilted;
        }
pros::delay(10);
}

You aren’t activating the brake mode. If we look at the okapi docs for XDriveModel::xArcade here, then we’ll see the note that says “Uses voltage mode”. When you let off the joysticks, the drivetrain motors will be commanded to 0 volts, not 0 velocity. 0 volts is effectively the same thing as coast, hence why you saw similar behavior to coast. In order to actually activate the brake mode, you will need to command the drive motors to 0 velocity, either through the use of a method specific to the drive model class (e.g. XDriveModel::stop()), or through some other method. In your specific example, that would probably mean implementing a deadband yourself, rather than relying on the ithreshold parameter.

5 Likes

Thanks for the answer
To be sure, there’s no way to have velocity mode with XDriveModel::xArcade? I used to use velocity mode with PROS, so that would explain it.

So I got the motors to use velocity mode (and braking works great) by creating a derived class with an extra function:

Code
#include "main.h"
#include <cmath>
#include <chrono>
#include <string>

using namespace okapi::literals;

class cXDriveModel : public okapi::XDriveModel {
  public:
    void xArcadeVel(const double ixSpeed,
                          const double iforwardSpeed,
                          const double iyaw,
                          const double ithreshold) {
      double xSpeed = std::clamp(ixSpeed, -1.0, 1.0);
      if (std::abs(xSpeed) < ithreshold) {
        xSpeed = 0;
      }

      double forwardSpeed = std::clamp(iforwardSpeed, -1.0, 1.0);
      if (std::abs(forwardSpeed) < ithreshold) {
        forwardSpeed = 0;
      }

      double yaw = std::clamp(iyaw, -1.0, 1.0);
      if (std::abs(yaw) < ithreshold) {
        yaw = 0;
      }

      topLeftMotor->moveVelocity(
        static_cast<int16_t>(std::clamp(forwardSpeed + xSpeed + yaw, -1.0, 1.0) * maxVelocity));
      topRightMotor->moveVelocity(
        static_cast<int16_t>(std::clamp(forwardSpeed - xSpeed - yaw, -1.0, 1.0) * maxVelocity));
      bottomRightMotor->moveVelocity(
        static_cast<int16_t>(std::clamp(forwardSpeed + xSpeed - yaw, -1.0, 1.0) * maxVelocity));
      bottomLeftMotor->moveVelocity(
        static_cast<int16_t>(std::clamp(forwardSpeed - xSpeed + yaw, -1.0, 1.0) * maxVelocity));
    }
};

pros::Imu inertial(4);

// Construct the drivetrain
std::shared_ptr<okapi::ChassisController> drive =
    okapi::ChassisControllerBuilder()
        .withMotors(
                2,
                -10,
                -11,
                20
               )
        .withDimensions(okapi::AbstractMotor::gearset::green, {{4_in, 15.5_in}, okapi::imev5GreenTPR})
        .build();

auto cXDriveTrain { std::static_pointer_cast<cXDriveModel>(drive->getModel()) };

void opcontrol() { 

while(true) {
cXDriveTrain->xArcadeVel(
                controller.getAnalog(okapi::ControllerAnalog::leftX),
                controller.getAnalog(okapi::ControllerAnalog::leftY),
                controller.getAnalog(okapi::ControllerAnalog::rightX),
                0.05); 

      //Tilt Lock
        static bool tilted { false };
        int roll = std::abs(inertial.get_roll());
        if (!tilted && roll >= 10 && roll < 1000) { // Going from flat to tilted enable hold
            std::cout << "triggered tiltbrake\n";
            cXDriveTrain->setBrakeMode(okapi::AbstractMotor::brakeMode::hold);
            tilted = !tilted;
        }
       else if (tilted && roll < 10) { //going from tilted to flat disable hold
            cXDriveTrain->setBrakeMode(okapi::AbstractMotor::brakeMode::coast);
            tilted = !tilted;
        }
pros::delay(10);
}

I don’t know why, but if instead of

auto cXDriveTrain { std::static_pointer_cast<cXDriveModel>(drive->getModel()) };

I say this:

auto cXDriveTrain { std::dynamic_pointer_cast<cXDriveModel>(drive->getModel()) };

The program will crash with this in console:

Error
DATA ABORT EXCEPTION

CURRENT TASK: User Operator Control (PROS)
REGISTERS AT ABORT
 r0: 0x00000000  r1: 0x00000008  r2: 0x00000000  r3: 0x00000000  r4: 0x038000dc  r5: 0x00000000  r6: 0x06060606  r7: 0x07070707
 r8: 0x08080808  r9: 0x09090909 r10: 0x10101010 r11: 0x11111111 r12: 0x00000011  sp: 0x03ae3f88  lr: 0x07801134  pc: 0x07800300

BEGIN STACK TRACE
	0x7800300
	0x7801134
END OF TRACE
HEAP USED: 7448 bytes
STACK REMAINING AT ABORT: 4233247881 bytes

Maybe there is a c++ guru out there who will know why.
I think its weird because

auto XDriveTrain { std::dynamic_pointer_cast<okapi::XDriveModel>(drive->getModel()) };

has no problem.

1 Like