How do I make my mecanum drive field centric?
To make a mecanum drive field centric, the translation joystick controls the robot's direction relative to the field rather than the robot's frame . This is achieved by rotating the x/y components of the joysticks counter to the robot's angle, which is provided by an Inertial Measurement Unit (IMU) .
The IMU, found in Control Hubs and older Expansion Hubs, needs to be initialized. It is recommended to use the IMU class as of SDK v8.1, as the BNO055 class is not recommended for new development .
The IMU can be initialized as follows:
// Retrieve the IMU from the hardware map
imu = hardwareMap.get(IMU.class, "imu");
// Adjust the orientation parameters to match your robot
IMU.Parameters parameters = new IMU.Parameters(new RevHubOrientationOnRobot(
RevHubOrientationOnRobot.LogoFacingDirection.UP,
RevHubOrientationOnRobot.UsbFacingDirection.FORWARD));
// Without this, the REV Hub's orientation is assumed to be logo up / USB forward
imu.initialize(parameters);
The robot's angle needs to be read in every loop, and a button to reset the angle is important to counteract drift and address potential zero changes from disconnects .
An example of resetting the yaw and getting the robot's heading is:
// This button choice was made so that it is hard to hit on accident,
// it can be freely changed based on preference.
// The equivalent button is start on Xbox-style controllers.
if (gamepad1.options) {
imu.resetYaw();
}
double botHeading = imu.getRobotYawPitchRollAngles().getYaw(AngleUnit.RADIANS);
The translation joystick values then need to be counter-rotated by the robot's heading. The formula for rotating a 2D vector is used, where x₁ and y₁ are the original vector components, beta is the angle to rotate by, and x₂ and y₂ are the resultant components .
The rotation can be implemented as:
// Rotate the movement direction counter to the bot's rotation
double rotX = x * Math.cos(-botHeading) - y * Math.sin(-botHeading);
double rotY = x * Math.sin(-botHeading) + y * Math.cos(-botHeading);
These rotated values are then used in the mecanum kinematics :
double denominator = Math.max(Math.abs(rotY) + Math.abs(rotX) + Math.abs(rx), 1);
double frontLeftPower = (rotY + rotX + rx) / denominator;
double backLeftPower = (rotY - rotX + rx) / denominator;
double frontRightPower = (rotY - rotX - rx) / denominator;
double backRightPower = (rotY + rotX - rx) / denominator;