Kinematics
Last updated
Last updated
Tank drive kinematics are often overlooked in part due to their surface simplicity. Intuitively, for a tank drive, everyone knows that you provide the same voltage to both sides to go forward and opposite voltages to spin. Nevertheless, it's instructive to derive this formally and similar techniques can be applied to mecanum and swerve drives where intuition starts to fail.
Consider the following configuration of a tank robot traveling with constant forward and angular velocity. Throughout this discussion, we will assume that the drive has one wheel per side (this is generally accurate although certain drivetrains may have significant scrub/friction).
For better pose estimation, some robots have unactuated tracking wheels (sometimes called dead wheels) dedicated to odometry measurements. Three wheels are necessary to compute the full pose. These three wheels are commonly placed in the standard configuration shown below.
Road Runner provides built-in localizers for tracking wheels. This configuration is implemented with the following code.
You can replace the default localizer of a Drive
instance with Drive#setLocalizer()
.
Here the forward velocity is and the angular velocity is . The length in the picture is called the track width; it's defined as the distance between the wheels (point of contact is assumed to be in the middle of the wheels). First, the circumference of the circle is which implies the robot takes time to complete a single revolution. Now, we can calculate the wheel velocities: and . However, we still aren't quite done. In one revolution around the circle, the robot itself also completes one spin relative to the global frame. Thus . Substituting, we are left with and .
Now we have all the ingredients for our trajectory feedforward. The trajectory itself gives the field-centric velocities of the robot. Applying a coordinate frame transform, these velocities are turned into robot-centric velocities. For a tank drive, the robot-centric velocities are and . The equations derived in the previous paragraph turn and into the wheel velocities and which are sent to the motor controller.
As it turns out, the same equations can be used to determine how the robot moved with wheel encoder data. Solving the system for and gives (as you should verify) and . To make the odometry computations tractable, we will split the robot motion into several time segments and assume constant velocity over each segment. The change in position over a given segment is just the velocity multiplied by time. The relationship between the position changes is and . These position changes are accumulated over time with an initial pose to produce the current pose. In Road Runner, this process is performed incrementally with Kinematics.relativeOdometryUpdate()
.