Uso de las clases de WPILib para conducir su robot

WPILib incluye muchas clases para ayudar a que su robot conduzca más rápido.

Chasis estándar

Robots con chasis diferencial

The wiring of a simple differential drive robot.

Estas bases de transmisión suelen tener dos o más ruedas en línea u omnidireccionales por lado (p. Ej., 6WD u 8WD) y también pueden conocerse como «skid-steer», «tank drive» o «West Coast Drive». La transmisión del kit de piezas es un ejemplo de transmisión diferencial. Estas transmisiones son capaces de conducir hacia adelante / hacia atrás y puede girar conduciendo los dos lados en direcciones opuestas causando que las ruedas patinen de lado. Estas transmisiones no son capaces de moverse de manera lateral.

Chasis mecanum

A four wheel Mecanum robot using the KOP chassis.

Chasis Mecanum es un método de conducción que utiliza ruedas especialmente diseñadas que permiten al robot conducir en cualquier dirección sin cambiar la orientación del robot. Un robot con una transmisión convencional (todas las ruedas apuntando en la misma dirección) debe girar en la dirección que se necesita conducir. Un robot mecanum puede moverse en cualquier dirección sin girar primero y se llama impulso holonómico. Las ruedas (que se muestran en este robot) tienen rodillos que causan las fuerzas de conducir para ser aplicado en un ángulo de 45 grados en lugar de en línea recta como en el caso de un accionamiento convencional.

Cuando se ve desde la parte superior, los rodillos de una transmisión mecanum deben formar un patrón de «X». Esto da como resultado los vectores de fuerza (al conducir la rueda hacia adelante) en las dos ruedas delanteras apuntando hacia adelante y hacia adentro y las dos ruedas traseras apuntando hacia adelante y hacia afuera. Girando las ruedas en diferentes direcciones, varios componentes de los vectores de fuerza se cancelan, lo que resulta en el movimiento deseado del robot. Un gráfico rápido de diferentes movimientos se proporciona a continuación, extraer los vectores de fuerza para cada uno de estos movimientos puede ayudar en entender cómo funcionan estas transmisiones. Variando las velocidades de las ruedas, además a la dirección, los movimientos se pueden combinar dando como resultado la traslación en cualquier dirección y rotación, simultáneamente.

Swerve Drive

A swerve drive robot using WCP X2i swerve modules.

Swerve drive is a method of driving using independently steerable and drivable wheels. This allows the robot to drive in any direction without changing the orientation of the robot, much like mecanum drive. However, since the wheels are steerable, they can be driven with their force vectors pointing straight forward, rather than at a 45 degree angle as in mecanum drive. This results in more efficient movement and better traction than mecanum drive.

Convenciones de clase de conducción

Inversión motora

It is the responsibility of the user to manage proper inversions for their drivetrain. Users can invert motors by calling setInverted()/SetInverted() on their motor objects. Typically for differential drive trains, one side must be inverted to avoid spinning in circles, since the forward direction of each side of the tank drive is opposite of each other.

  private final PWMSparkMax rightMotor = new PWMSparkMax(1);
  public Robot() {
    // We need to invert one side of the drivetrain so that positive voltages
    // result in both sides moving forward. Depending on how your robot's
    // gearbox is constructed, you might have to invert the left side instead.
    rightMotor.setInverted(true);
  }
  wpi::PWMSparkMax rightMotor{1};
 public:
  Robot() {
    // We need to invert one side of the drivetrain so that positive voltages
    // result in both sides moving forward. Depending on how your robot's
    // gearbox is constructed, you might have to invert the left side instead.
    rightMotor.SetInverted(true);
  }
    def __init__(self):
        """Robot initialization function"""
        super().__init__()
        right_motor = wpilib_drivers.PWMSparkMax(1)
        right_motor.set_inverted(True)

Cuadrar las entradas

Al conducir robots, a menudo es deseable manipular las entradas del joystick de modo que el robot tiene un control más fino a bajas velocidades mientras sigue usando el rango de salida completo. Una forma de lograr esto es al cuadrar la entrada del joystick y luego volver a aplicar el signo. Por defecto la Differential Drive class cuadrará las entradas. Si esto no se desea (por ejemplo, si pasa valores desde un PID Controller), utilice uno de los métodos de accionamiento con el parámetro squaredInputs y configúrelo en falso.

Salida máxima

Sometimes drivers feel that their drivetrain is driving too fast and want to limit the output. This can be accomplished with the setMaxOutput() method. This maximum output is multiplied by result of the previous drive functions like squared inputs.

Motor Safety

Motor Safety es un mecanismo en WPILib que toma el concepto de un perro guardián/watchdog y lo rompe a un perro guardián/watchdog (temporizador de seguridad del motor) para cada actuador individual. Tenga en cuenta que este mecanismo de protección es adicional al System Watchdog que es controlado por la red Código de comunicaciones y FPGA y deshabilitará todas las salidas del actuador si no recibe un paquete de datos válido para 125 ms.

The purpose of the Motor Safety mechanism is the same as the purpose of a watchdog timer, to disable mechanisms which may cause harm to themselves, people, or property if the code locks up and does not properly update the actuator output. Motor Safety breaks this concept out on a per actuator basis so that you can appropriately determine where it is necessary and where it is not. Examples of mechanisms that should have motor safety enabled are systems like drive trains and arms. If these systems get latched on a particular value they could cause damage to their environment or themselves. An example of a mechanism that may not need motor safety is a spinning flywheel for a shooter. If this mechanism gets latched on a particular value it will simply continue spinning until the robot is disabled. By default Motor Safety is enabled for DifferentialDrive and MecanumDrive objects and disabled for all other motor controllers and servos.

La característica de Seguridad del Motor opera manteniendo un temporizador que rastrea cuánto tiempo ha pasado desde que el método feed() ha sido llamado para ese actuador. El código en la clase Driver Station inicia una comparación de estos temporizadores con los valores de tiempo de espera para cualquier actuador con la seguridad activada cada 5 paquetes recibidos (100ms nominal). Los métodos set() de cada clase de controlador de motor y los métodos set() y setAngle() de la clase servo llaman a feed() para indicar que la salida del actuador ha sido actualizada.

The Motor Safety interface of motor controllers can be interacted with by the user using the following methods:

    motor.setSafetyEnabled(true);
    motor.setSafetyEnabled(false);
    motor.setExpiration(0.1);
    motor.feed();
    motor.SetSafetyEnabled(true);
    motor.SetSafetyEnabled(false);
    motor.SetExpiration(0.1_s);
    motor.Feed();
        self.motor.set_safety_enabled(True)
        self.motor.set_safety_enabled(False)
        self.motor.set_expiration(0.1)
        self.motor.feed()

By default all Drive objects enable Motor Safety. Depending on the mechanism and the structure of your program, you may wish to configure the timeout length of the motor safety (in seconds). The timeout length is configured on a per actuator basis and is not a global setting. The default (and minimum useful) value is 100ms.

Convenciones del Eje

The drive classes use the NWU axes convention (North-West-Up as external reference in the world frame). The positive X axis points ahead, the positive Y axis points left, and the positive Z axis points up. We use NWU here because the rest of the library, and math in general, use NWU axes convention.

Joysticks follow NED (North-East-Down) convention, where the positive X axis points ahead, the positive Y axis points right, and the positive Z axis points down. However, it’s important to note that axes values are rotations around the respective axes, not translations. When viewed with each axis pointing toward you, CCW is a positive value and CW is a negative value. Pushing forward on the joystick is a CW rotation around the Y axis, so you get a negative value. Pushing to the right is a CCW rotation around the X axis, so you get a positive value.

Nota

See the Coordinate System section for more detail about the axis conventions and coordinate systems.

Uso de la clase DifferentialDrive para controlar robots de accionamiento diferencial

Nota

The DifferentialDrive class handles the differential drivetrain configuration. These drive bases typically have two or more in-line traction or omni wheels per side (e.g., 6WD or 8WD) and may also be known as «skid-steer», «tank drive», or «West Coast Drive» (WCD). The Kit of Parts drivetrain is an example of a differential drive. There are methods to control the drive with 3 different styles («Tank», «Arcade», or «Curvature»), explained in the article below.

DifferentialDrive es un método proporcionado para el control de transmisiones “skid-steer” o “West Coast”, como el chasis del Kit de piezas. Crear una instancia de una unidad diferencial es tan simple como esto:

  private final PWMSparkMax leftMotor = new PWMSparkMax(0);
  private final PWMSparkMax rightMotor = new PWMSparkMax(1);
  private final DifferentialDrive robotDrive =
      new DifferentialDrive(leftMotor::setThrottle, rightMotor::setThrottle);
  wpi::PWMSparkMax leftMotor{0};
  wpi::PWMSparkMax rightMotor{1};
  wpi::DifferentialDrive robotDrive{
      [&](double output) { leftMotor.SetThrottle(output); },
      [&](double output) { rightMotor.SetThrottle(output); }};
        left_motor = wpilib_drivers.PWMSparkMax(0)
        right_motor = wpilib_drivers.PWMSparkMax(1)
        self.robot_drive = wpilib.DifferentialDrive(left_motor, right_motor)

Multi-Motor DifferentialDrive

Many FRC® drivetrains have more than 1 motor on each side. Classes derived from PWMMotorController (Java / C++ / Python) have an addFollower method so that multiple follower motor controllers can be updated when the leader motor controller is commanded. CAN motor controllers have similar features, review the vendor’s documentation to see how to use them. The examples below show a 4 motor (2 per side) drivetrain. To extend to more motors, simply create the additional controllers and use additional addFollower calls.

Class variables (e.g. in Robot.java or Subsystem):

  private final PWMSparkMax leftLeader = new PWMSparkMax(DriveConstants.LEFT_MOTOR1_PORT);
  private final PWMSparkMax leftFollower = new PWMSparkMax(DriveConstants.LEFT_MOTOR2_PORT);

  // The motors on the right side of the drive.
  private final PWMSparkMax rightLeader = new PWMSparkMax(DriveConstants.RIGHT_MOTOR1_PORT);
  private final PWMSparkMax rightFollower = new PWMSparkMax(DriveConstants.RIGHT_MOTOR2_PORT);

  // The robot's drive
  private final DifferentialDrive drive =
      new DifferentialDrive(leftLeader::setThrottle, rightLeader::setThrottle);

In Robot or Subsystem constructor:

    leftLeader.addFollower(leftFollower);
    rightLeader.addFollower(rightFollower);

    // We need to invert one side of the drivetrain so that positive voltages
    // result in both sides moving forward. Depending on how your robot's
    // gearbox is constructed, you might have to invert the left side instead.
    rightLeader.setInverted(true);
 private:
  // The motor controllers
  wpi::PWMSparkMax left1;
  wpi::PWMSparkMax left2;
  wpi::PWMSparkMax right1;
  wpi::PWMSparkMax right2;

  // The robot's drive
  wpi::DifferentialDrive drive{
      [&](double output) { left1.SetThrottle(output); },
      [&](double output) { right1.SetThrottle(output); }};

In Robot or Subsystem constructor:

  left1.AddFollower(left2);
  right1.AddFollower(right2);

  // We need to invert one side of the drivetrain so that positive voltages
  // result in both sides moving forward. Depending on how your robot's
  // gearbox is constructed, you might have to invert the left side instead.
  right1.SetInverted(true);
        self.left1 = wpilib_drivers.PWMVictorSPX(constants.LEFT_MOTOR1_PORT)
        self.left2 = wpilib_drivers.PWMVictorSPX(constants.LEFT_MOTOR2_PORT)
        self.right1 = wpilib_drivers.PWMVictorSPX(constants.RIGHT_MOTOR1_PORT)
        self.right2 = wpilib_drivers.PWMVictorSPX(constants.RIGHT_MOTOR2_PORT)

        self.left1.add_follower(self.left2)
        self.right1.add_follower(self.right2)

        # We need to invert one side of the drivetrain so that positive velocities
        # result in both sides moving forward. Depending on how your robot's
        # drivetrain is constructed, you might have to invert the left side instead.
        self.right1.set_inverted(True)

        # The robot's drive
        self.drive = wpilib.DifferentialDrive(self.left1, self.right1)

Modos de manejo

La clase DifferentialDrive contiene tres métodos predeterminados para controlar los robots de dirección deslizante o WCD. Tenga en cuenta que puede crear sus propios métodos para controlar la conducción del robot y hacer que llamen a tankDrive() con las entradas derivadas para los motores izquierdo y derecho.

El modo Tank Drive se usa para controlar cada lado del drivetrain de forma independiente (generalmente con un eje de joystick individual que controla cada uno). Este ejemplo muestra cómo usar el eje Y de dos palancas de mando separadas para ejecutar la transmisión en modo Tank. La construcción de los objetos ha sido omitida, para arriba drivetrain y aquí para Joystick.

El modo Arcade Drive se usa para controlar el drivetrain mediante la velocidad / aceleración y la velocidad de la rotación. Esto generalmente se usa con dos ejes de un solo joystick, o dividido en joysticks (a menudo en un solo gamepad) con el acelerador proveniente de una palanca y la rotación de otra. Este ejemplo muestra cómo usar un solo joystick con el modo Arcade. La construcción de los objetos ha sido omitida, para arriba para la construcción de drivetrain y aquí para la construcción de Joystick.

Al igual que Arcade Drive, el modo Curvature Drive se usa para controlar el drivetrain usando velocidad/aceleración y tasa de rotación. La diferencia es que la entrada de control de rotación controla el radio de curvatura en lugar de la tasa de cambio de rumbo, al igual que el volante de un automóvil. Este modo también admite girar en su lugar, que se habilita cuando el tercer parámetro boolean es verdadero.

    // Tank drive with a given left and right rates
    robotDrive.tankDrive(-driverController.getLeftY(), -driverController.getRightY());
    // Arcade drive with a given forward and turn rate
    robotDrive.arcadeDrive(-driverController.getLeftY(), -driverController.getLeftX());
    // Curvature drive with a given forward and turn rate, as well as a button for turning in-place.
    robotDrive.curvatureDrive(
        -driverController.getLeftY(),
        -driverController.getLeftX(),
        driverController.getFaceUpButton());
    // Tank drive with a given left and right rates
    robotDrive.TankDrive(-driverController.GetLeftY(),
                         -driverController.GetRightY());
    // Arcade drive with a given forward and turn rate
    robotDrive.ArcadeDrive(-driverController.GetLeftY(),
                           -driverController.GetLeftX());
    // Curvature drive with a given forward and turn rate, as well as a
    // quick-turn button
    robotDrive.CurvatureDrive(-driverController.GetLeftY(),
                              -driverController.GetLeftX(),
                              driverController.GetFaceUpButton());
def teleop_periodic(self):
    # Tank drive with a given left and right rates
    self.myDrive.tank_drive(-self.left_stick.get_y(), -self.right_stick.get_y())
    # Arcade drive with a given forward and turn rate
    self.myDrive.arcade_drive(-self.driveStick.get_y(), -self.driveStick.get_x())
    # Curvature drive with a given forward and turn rate, as well as a button for turning in-place.
    self.myDrive.curvature_drive(-self.driveStick.get_y(), -self.driveStick.get_x(), self.driveStick.getButton(1))

Por hacer

Add RLI for python example above.

Uso de la clase MecanumDrive para controlar los robots Mecanum Drive

MecanumDrive es un método proporcionado para el control de transmisiones holonómicas con ruedas Mecanum, como el chasis del kit de piezas con el kit de actualización de la transmisión mecanum, como se muestra arriba. Crear una instancia de MecanumDrive es tan simple como esto:

  private static final int FRONT_LEFT_CHANNEL = 0;
  private static final int REAR_LEFT_CHANNEL = 1;
  private static final int FRONT_RIGHT_CHANNEL = 2;
  private static final int REAR_RIGHT_CHANNEL = 3;
  private final MecanumDrive robotDrive;
  public Robot() {
    PWMSparkMax frontLeft = new PWMSparkMax(FRONT_LEFT_CHANNEL);
    PWMSparkMax rearLeft = new PWMSparkMax(REAR_LEFT_CHANNEL);
    PWMSparkMax frontRight = new PWMSparkMax(FRONT_RIGHT_CHANNEL);
    PWMSparkMax rearRight = new PWMSparkMax(REAR_RIGHT_CHANNEL);

    // Invert the right side motors.
    // You may need to change or remove this to match your robot.
    frontRight.setInverted(true);
    rearRight.setInverted(true);

    robotDrive =
        new MecanumDrive(
            frontLeft::setThrottle,
            rearLeft::setThrottle,
            frontRight::setThrottle,
            rearRight::setThrottle);
  }
  static constexpr int FRONT_LEFT_MOTOR_PORT = 0;
  static constexpr int REAR_LEFT_MOTOR_PORT = 1;
  static constexpr int FRONT_RIGHT_MOTOR_PORT = 2;
  static constexpr int REAR_RIGHT_MOTOR_PORT = 3;
  wpi::PWMSparkMax frontLeft{FRONT_LEFT_MOTOR_PORT};
  wpi::PWMSparkMax rearLeft{REAR_LEFT_MOTOR_PORT};
  wpi::PWMSparkMax frontRight{FRONT_RIGHT_MOTOR_PORT};
  wpi::PWMSparkMax rearRight{REAR_RIGHT_MOTOR_PORT};
  wpi::MecanumDrive robotDrive{
      [&](double output) { frontLeft.SetThrottle(output); },
      [&](double output) { rearLeft.SetThrottle(output); },
      [&](double output) { frontRight.SetThrottle(output); },
      [&](double output) { rearRight.SetThrottle(output); }};
  Robot() {
    // Invert the right side motors. You may need to change or remove this to
    // match your robot.
    frontRight.SetInverted(true);
    rearRight.SetInverted(true);
  }
    FRONT_LEFT_CHANNEL = 0
    REAR_LEFT_CHANNEL = 1
    FRONT_RIGHT_CHANNEL = 2
    REAR_RIGHT_CHANNEL = 3
    IMU_MOUNT_ORIENTATION = wpilib.OnboardIMU.MountOrientation.FLAT
    def __init__(self) -> None:
        """Robot initialization function"""
        super().__init__()

        self.imu = wpilib.OnboardIMU(self.IMU_MOUNT_ORIENTATION)
        self.joystick = wpilib.Joystick(self.JOYSTICK_PORT)

        front_left = wpilib_drivers.PWMSparkMax(self.FRONT_LEFT_CHANNEL)
        rear_left = wpilib_drivers.PWMSparkMax(self.REAR_LEFT_CHANNEL)
        front_right = wpilib_drivers.PWMSparkMax(self.FRONT_RIGHT_CHANNEL)
        rear_right = wpilib_drivers.PWMSparkMax(self.REAR_RIGHT_CHANNEL)

        front_right.set_inverted(True)
        rear_right.set_inverted(True)

        self.robot_drive = wpilib.MecanumDrive(
            front_left, rear_left, front_right, rear_right
        )

Modos de manejo mecanum

Nota

Las convenciones del eje de accionamiento son diferentes de las convenciones comunes del eje del joystick. Ver las convenciones del eje anteriores para más información.

La clase MecanumDrive contiene dos modos predeterminados diferentes para conducir los motores de su robot.

  • driveCartesian: los ángulos se miden en sentido horario desde el eje X positivo. La velocidad de los robots es independiente de su ángulo o velocidad de rotación.

  • drivePolar: los ángulos se miden en sentido antihorario desde el frente. La velocidad a que el robot conduce (traslación) es independiente de su ángulo o velocidad de rotación.

    // Use the joystick Y axis for forward movement, X axis for lateral
    // movement, and Z axis for rotation.
    robotDrive.driveCartesian(-joystick.getY(), -joystick.getX(), -joystick.getZ());
    // Drive at 45 degrees relative to the robot, at the speed given by the Y axis of the joystick,
    // with no rotation.
    robotDrive.drivePolar(-joystick.getY(), Rotation2d.fromDegrees(45), 0);
    // Drive using the X, Y, and Z axes of the joystick.
    robotDrive.DriveCartesian(-joystick.GetY(), -joystick.GetX(),
                              -joystick.GetZ());
    // Drive at 45 degrees relative to the robot, at the speed given by the Y
    // axis of the joystick, with no rotation.
    robotDrive.DrivePolar(-joystick.GetY(), 45_deg, 0);
def teleop_periodic(self):
    # Drive using the X, Y, and Z axes of the joystick.
    self.robot_drive.drive_cartesian(-self.stick.get_y(), -self.stick.get_x(), -self.stick.get_z())
    # Drive at 45 degrees relative to the robot, at the speed given by the Y axis of the joystick, with no rotation.
    self.robot_drive.drive_polar(-self.stick.get_y(), Rotation2d.from_degrees(45), 0)

Por hacer

Add RLI for python example above.

Conducción con orientación del campo

A 4th parameter can be supplied to the driveCartesian(double ySpeed, double xSpeed, double zRotation, double gyroAngle) method, the angle returned from a Gyro sensor. This will adjust the rotation value supplied. This is particularly useful with mecanum drive since, for the purposes of steering, the robot really has no front, back, or sides. It can go in any direction. Adding the angle in degrees from a gyro object will cause the robot to move away from the drivers when the joystick is pushed forwards, and towards the drivers when it is pulled towards them, regardless of what direction the robot is facing.

El uso de la conducción orientada al campo a menudo hace que el robot sea mucho más fácil de conducir, especialmente en comparación con un sistema de accionamiento «orientado al robot» donde los controles se invierten cuando el robot se enfrenta a los conductores.

Solo recuerde obtener el ángulo giroscópico cada vez que se llame a driveCartesian().

Nota

A muchos equipos también les gusta ramificar las entradas de los mandos en el tiempo para promover una aceleración suave y reducir las sacudidas. Esto se puede conseguir con un Limitador de velocidad de giro.

Swerve Drive SW

WPILib does not have a default class for controlling swerve drive. The WPILib swerve drive kinematics classes can be used to help with the math for controlling a swerve drive. See the Swerve Drive Kinematics section for more information on the kinematics of swerve drive and how to use the WPILib swerve drive kinematics classes. See the Odometría para un Swerve Drive section for more information on the odometry of swerve drive and how to use the WPILib swerve drive odometry classes. These are used in the SwerveBot (Java, C++, Python) and SwerveDrivePoseEstimator (Java, C++) examples.

Third Party Swerve Drive Libraries

There are also third party libraries for controlling swerve drive. These libraries typically include classes for controlling the swerve modules and the drivetrain as a whole, and may also include features such as odometry and path following. See the vendor’s documentation for more information on how to use these libraries.

AdvantageKit Swerve: Thare are templates provided by AdvantageKit for controlling swerve drive robots for users of the AdvantageKit library.

CTRE Swerve Project Generator: This is a tool provided by CTRE to generate swerve drive code for their motor controllers, encoders, and gyro.

Rev Max Swerve Template: This is a template provided by REV Robotics for controlling their MAX Swerve drive system.

Thrifty Swerve Generator: This is a tool provided by ThriftyBot to generate swerve drive code for their motor controllers and encoders.

Yet Another Mechanism System (YAMS): This is a generic mechanism library that includes support for swerve drive.