Now it's time to combine paths with the motion profiles from earlier. Road Runner calls this composition a trajectory. Trajectories take time values and output the corresponding field frame kinematic state (i.e., real positions, velocities, and acceleration). This state can be transformed to the robot frame and fed directly into the feedforward component of the controller.
Here's a sample for planning a
Trajectory from a
TrajectoryVelocityConstraint velConstraint = new MinVelocityConstraint(Arrays.asList(new TranslationalVelocityConstraint(20),new AngularVelocityConstraint(1)));TrajectoryAccelerationConstraint accelConstraint = new ProfileAccelerationConstraint(40);Trajectory traj = TrajectoryGenerator.generateTrajectory(path, velConstraint, accelConstraint);
val velConstraint = MinVelocityConstraint(listOf(TranslationalVelocityConstraint(20.0),AngularVelocityConstraint(1.0)))val accelConstraint = ProfileAccelerationConstraint(40.0)val traj = TrajectoryGenerator.generateTrajectory(path, velConstraint, accelConstraint)
As indicated by their names, the constraints limit translational velocity, angular velocity, and profile acceleration. It's common to replace the translational velocity constraint with a stronger constraint that limits wheel velocities. These constraints are named according to the drive types (e.g.,
Once a trajectory is finally generated, one of the
TrajectoryFollowers can be used to generate the actual
DriveSignals that are sent to the
Drive class. The PIDVA followers are usually suitable, although
RamseteFollower has noticeably better performance for tank drives.
Following a trajectory is as simple as creating a follower, calling
TrajectoryFollower.followTrajectory(), and repeatedly querying
PIDCoefficients translationalPid = new PIDCoefficients(5, 0, 0);PIDCoefficients headingPid = new PIDCoefficients(2, 0, 0);HolonomicPIDVAFollower follower = new HolonomicPIDVAFollower(translationalPid, translationalPid, headingPid);follower.followTrajectory(traj);// call in loopDriveSignal signal = follower.update(poseEstimate);
val translationalPid = PIDCoefficients(5.0, 0.0, 0.0)val headingPid = PIDCoefficients(2.0, 0.0, 0.0)val follower = HolonomicPIDVAFollower(translationalPid, translationalPid, headingPid)follower.followTrajectory(traj)// call in loopval signal = follower.update(poseEstimate)