/* * Copyright 2013-2015 Cel Skeggs * Copyright 2014 Alexander Mackworth (single joystick) * Copyright 2015 Aidan Smith (mecanum) * * This file is part of the CCRE, the Common Chicken Runtime Engine. * * The CCRE is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * The CCRE is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with the CCRE. If not, see <http://www.gnu.org/licenses/>. */ package ccre.ctrl; import ccre.channel.DerivedUpdate; import ccre.channel.FloatInput; import ccre.channel.FloatOutput; import ccre.verifier.SetupPhase; /** * Contains various presets for driving the robot. * * Provided types of drive: * * Tank drive is where two joystick axes are used to control two motors, * respectively. * * Extended tank drive adds another joystick axis that is added to both motors' * outputs, so that direct forward and backward movement is easy. * * Single joystick drive, aka Arcade drive, is where one joystick is used to * control a robot in rotation and movement. * * Mecanum drive only works with a special kind of wheel, and allows strafing in * addition to normal movement and rotation. * * Other types to come later. * * @author skeggsc */ public class Drive { /** * Run tank drive on the given two FloatInputs and FloatOutputs. * * @param leftIn the left control axis. * @param rightIn the right control axis. * @param leftOut the left motor. * @param rightOut the right motor. * @see Drive */ @SetupPhase public static void tank(FloatInput leftIn, FloatInput rightIn, FloatOutput leftOut, FloatOutput rightOut) { leftIn.send(leftOut); rightIn.send(rightOut); } /** * Run extended tank drive on the given three FloatInputs and FloatOutputs. * * @param leftIn the left control axis. * @param rightIn the right control axis. * @param forward the forward control axis. * @param leftOut the left motor. * @param rightOut the right motor. * @see Drive */ @SetupPhase public static void extendedTank(FloatInput leftIn, FloatInput rightIn, FloatInput forward, FloatOutput leftOut, FloatOutput rightOut) { leftIn.plus(forward).send(leftOut); rightIn.plus(forward).send(rightOut); } /** * Run arcade drive on the given two FloatInputs and FloatOutputs. * * @param joystickXAxis the joystick's x-axis. * @param joystickYAxis the joystick's y-axis. * @param leftOut the left motor. * @param rightOut the right motor. * @see Drive */ @SetupPhase public static void arcade(FloatInput joystickXAxis, FloatInput joystickYAxis, FloatOutput leftOut, FloatOutput rightOut) { joystickYAxis.plus(joystickXAxis).send(leftOut); joystickYAxis.minus(joystickXAxis).send(rightOut); } /** * Run arcade drive on the given Joystick. * * @param joystick the joystick. * @param leftOut the left motor. * @param rightOut the right motor. * @see Drive */ @SetupPhase public static void arcade(Joystick joystick, FloatOutput leftOut, FloatOutput rightOut) { arcade(joystick.axisX(), joystick.axisY(), leftOut, rightOut); } /** * When the returned EventInput is fired, run Mecanum drive on the given * FloatInputs and FloatOutputs. * * @param forward the forward movement axis. * @param strafe the strafing axis. * @param rotate the rotation axis. * @param leftFrontMotor the left front motor. * @param leftBackMotor the left back motor. * @param rightFrontMotor the right front motor. * @param rightBackMotor the right back motor. * @see Drive */ @SetupPhase public static void mecanum(final FloatInput forward, final FloatInput strafe, final FloatInput rotate, final FloatOutput leftFrontMotor, final FloatOutput leftBackMotor, final FloatOutput rightFrontMotor, final FloatOutput rightBackMotor) { // TODO: Optimize this? new DerivedUpdate(forward, strafe, rotate) { @Override protected void update() { float distanceY = forward.get(); float distanceX = strafe.get(); float rotationspeed = rotate.get(); double speed = Math.sqrt(distanceX * distanceX + distanceY * distanceY); if (speed > 1) { speed = 1; } double angle = Math.atan2(distanceY, distanceX) - Math.PI / 4; double sin = speed * Math.sin(angle), cos = speed * Math.cos(angle); double leftFront = sin - rotationspeed; double rightBack = sin + rotationspeed; double leftBack = cos - rotationspeed; double rightFront = cos + rotationspeed; double normalize = Math.max(Math.max(Math.abs(leftFront), Math.abs(rightFront)), Math.max(Math.abs(leftBack), Math.abs(rightBack))); double mul; if (normalize > 1) { mul = 1 / normalize; } else if (normalize < speed) { mul = speed / normalize; } else { mul = 1; } rightFrontMotor.set((float) (rightFront * mul)); leftFrontMotor.set((float) (leftFront * mul)); rightBackMotor.set((float) (rightBack * mul)); leftBackMotor.set((float) (leftBack * mul)); } }; } private Drive() { } }