001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package org.wpilib.math.kinematics; 006 007import static org.wpilib.units.Units.Meters; 008 009import org.wpilib.math.geometry.Twist2d; 010import org.wpilib.math.kinematics.proto.DifferentialDriveKinematicsProto; 011import org.wpilib.math.kinematics.struct.DifferentialDriveKinematicsStruct; 012import org.wpilib.math.util.MathSharedStore; 013import org.wpilib.units.measure.Distance; 014import org.wpilib.util.protobuf.ProtobufSerializable; 015import org.wpilib.util.struct.StructSerializable; 016 017/** 018 * Helper class that converts a chassis velocity (dx and dtheta components) to left and right wheel 019 * velocities for a differential drive. 020 * 021 * <p>Inverse kinematics converts a desired chassis velocity into left and right velocity components 022 * whereas forward kinematics converts left and right component velocities into a linear and angular 023 * chassis velocity. 024 */ 025public class DifferentialDriveKinematics 026 implements Kinematics< 027 DifferentialDriveWheelPositions, 028 DifferentialDriveWheelVelocities, 029 DifferentialDriveWheelAccelerations>, 030 ProtobufSerializable, 031 StructSerializable { 032 /** Differential drive trackwidth in meters. */ 033 public final double trackwidth; 034 035 /** DifferentialDriveKinematics protobuf for serialization. */ 036 public static final DifferentialDriveKinematicsProto proto = 037 new DifferentialDriveKinematicsProto(); 038 039 /** DifferentialDriveKinematics struct for serialization. */ 040 public static final DifferentialDriveKinematicsStruct struct = 041 new DifferentialDriveKinematicsStruct(); 042 043 /** 044 * Constructs a differential drive kinematics object. 045 * 046 * @param trackwidth The trackwidth of the drivetrain in meters. Theoretically, this is the 047 * distance between the left wheels and right wheels. However, the empirical value may be 048 * larger than the physical measured value due to scrubbing effects. 049 */ 050 public DifferentialDriveKinematics(double trackwidth) { 051 this.trackwidth = trackwidth; 052 MathSharedStore.reportUsage("DifferentialDriveKinematics", ""); 053 } 054 055 /** 056 * Constructs a differential drive kinematics object. 057 * 058 * @param trackwidth The trackwidth of the drivetrain in meters. Theoretically, this is the 059 * distance between the left wheels and right wheels. However, the empirical value may be 060 * larger than the physical measured value due to scrubbing effects. 061 */ 062 public DifferentialDriveKinematics(Distance trackwidth) { 063 this(trackwidth.in(Meters)); 064 } 065 066 /** 067 * Returns a chassis velocity from left and right component velocities using forward kinematics. 068 * 069 * @param wheelVelocities The left and right velocities. 070 * @return The chassis velocity. 071 */ 072 @Override 073 public ChassisVelocities toChassisVelocities(DifferentialDriveWheelVelocities wheelVelocities) { 074 return new ChassisVelocities( 075 (wheelVelocities.left + wheelVelocities.right) / 2, 076 0, 077 (wheelVelocities.right - wheelVelocities.left) / trackwidth); 078 } 079 080 /** 081 * Returns left and right component velocities from a chassis velocity using inverse kinematics. 082 * 083 * @param chassisVelocities The linear and angular (dx and dtheta) components that represent the 084 * chassis' velocity. 085 * @return The left and right velocities. 086 */ 087 @Override 088 public DifferentialDriveWheelVelocities toWheelVelocities(ChassisVelocities chassisVelocities) { 089 return new DifferentialDriveWheelVelocities( 090 chassisVelocities.vx - trackwidth / 2 * chassisVelocities.omega, 091 chassisVelocities.vx + trackwidth / 2 * chassisVelocities.omega); 092 } 093 094 @Override 095 public ChassisAccelerations toChassisAccelerations( 096 DifferentialDriveWheelAccelerations wheelAccelerations) { 097 return new ChassisAccelerations( 098 (wheelAccelerations.left + wheelAccelerations.right) / 2, 099 0.0, 100 (wheelAccelerations.right - wheelAccelerations.left) / trackwidth); 101 } 102 103 @Override 104 public DifferentialDriveWheelAccelerations toWheelAccelerations( 105 ChassisAccelerations chassisAccelerations) { 106 return new DifferentialDriveWheelAccelerations( 107 chassisAccelerations.ax - trackwidth / 2 * chassisAccelerations.alpha, 108 chassisAccelerations.ax + trackwidth / 2 * chassisAccelerations.alpha); 109 } 110 111 @Override 112 public Twist2d toTwist2d( 113 DifferentialDriveWheelPositions start, DifferentialDriveWheelPositions end) { 114 return toTwist2d(end.left - start.left, end.right - start.right); 115 } 116 117 /** 118 * Performs forward kinematics to return the resulting Twist2d from the given left and right side 119 * distance deltas. This method is often used for odometry -- determining the robot's position on 120 * the field using changes in the distance driven by each wheel on the robot. 121 * 122 * @param leftDistance The distance measured by the left side encoder in meters. 123 * @param rightDistance The distance measured by the right side encoder in meters. 124 * @return The resulting Twist2d. 125 */ 126 public Twist2d toTwist2d(double leftDistance, double rightDistance) { 127 return new Twist2d( 128 (leftDistance + rightDistance) / 2, 0, (rightDistance - leftDistance) / trackwidth); 129 } 130 131 @Override 132 public DifferentialDriveWheelPositions copy(DifferentialDriveWheelPositions positions) { 133 return new DifferentialDriveWheelPositions(positions.left, positions.right); 134 } 135 136 @Override 137 public void copyInto( 138 DifferentialDriveWheelPositions positions, DifferentialDriveWheelPositions output) { 139 output.left = positions.left; 140 output.right = positions.right; 141 } 142 143 @Override 144 public DifferentialDriveWheelPositions interpolate( 145 DifferentialDriveWheelPositions startValue, 146 DifferentialDriveWheelPositions endValue, 147 double t) { 148 return startValue.interpolate(endValue, t); 149 } 150}