acmerobotics / road-runner-quickstart Goto Github PK
View Code? Open in Web Editor NEWFTC quickstart for https://github.com/acmerobotics/road-runner
License: BSD 3-Clause Clear License
FTC quickstart for https://github.com/acmerobotics/road-runner
License: BSD 3-Clause Clear License
It isn't 100% clear how to use the StandardTrackingWheelLocalizer. I have read issue #24 and I have gone through the examples and the documentation. However, I am still not sure on a few things.
getWheelPositions
, DriveConstants.TICKS_PER_REV
, DriveConstants.WHEEL_RADIUS
, etc.Also, in my situation we are not able to install our lateral odometery wheels inline. In our case they are offset from the center line of the robot. What measurements should I use to utilize this configuration?
Thank you for any help you can provide.
I am wondering if there is some way to quantify a sane MaxJerk range. If you have maxVelocity=50 and maxAcceleration=20 what is a sane way to think about the MaxJerk value? Can we consider it a relation to the maxAcceleration?
The reason I am asking is that I started with a very small value (.01) and have tried a few things without success. I just don't quite understand what makes sense.
I am not sure this is the right place to ask this. If it is not, I will post to one of the other GitHub repos for the applicable related library.
It seems like the code to retrieve the expansionhub is "flaky". If we deploy new code, the app crashes, etc. you can no longer find the expansionhub unless you restart the robot and app.
Is there something we are doing wrong or is it just the cost of being able to do "bulk reads"?
See #5. This is a low priority feature request.
I know this is not exactly a question about road runner but it seems like a basic we need to fully understand and set correctly before properly start tuning road runner. We have a mecanum chassis with 40:1 Rev Hex motors.
I am getting incorrect and inconsistent results from the track width tuner. I use a 4 wheel drive with traction in the back, and omnis in the front. When I ran the default configuration, the tuner gave a result of 13.09. The actual width is 16.25. I tried adjusting the track width to provide accurate turns. I got accurate results at a track width of 22.5. I also tried different combinations of motor power and number of turns in the track width (listed below).
Motor power | Number of turns | Output track width |
---|---|---|
(default ) 0.3 | 4 | 13.09 |
0.3 | 2 | 15.73 |
0.3 | 6 | 12.2 |
0.3 | 12 | 11.46 |
0.5 | 4 | 13.17 |
0.7 | 4 | 13.36 |
The Kv should assume around 5000 rpm bare motor speed similar to the ExH. Perhaps the ExH assumes 25% lower max? Either way the current Kv doesn't get you up to speed correctly.
Folks,
I'm new to RoadRunner, still learning the various APIs and integration model. One of the test I was trying to run was to build a simple trajectory (go straight for 48") using the GUI plugin and run it as autonomous. The YAML file seems to load fine, I think, but the robot doesn't go anywhere. Any suggestions on how best to diagnose and resolve this issue? Thank you! By the way, love the toolkit.
Sample code:
@autonomous(group = "drive")
public class TrajectoryTest extends LinearOpMode {
private static final String TRAJECTORY_FILE = "MyTest";
@Override
public void runOpMode() throws InterruptedException {
SampleMecanumDriveBase drive = new SampleMecanumDriveREV(hardwareMap);
Trajectory traj = null;
try {
traj = AssetsTrajectoryLoader.load(TRAJECTORY_FILE);
} catch (IOException e) {
throw new InterruptedException("Trajectory Error.");
}
waitForStart();
if (isStopRequested()) return;
if (traj != null) {
drive.followTrajectorySync(traj);
}
}
}
startPose:
x: 0.0
y: 0.0
heading: 0.0
startHeading: 0.0
steps:
In the DriveVelocityPIDTuner opmode the velocities are calculated. This calculation results in a lot of noise and random spikes. The motor class and bulk read classes provide more accurate velocity estimates to make tuning easier.
I have a very simple question: does this library work with Modern Robotics too? I've tried a modified quickstart and the robot did not move at all. Now I'm unsure whether this is a problem of our code or if it doesn't work at all in general with MR stuff since changing PID Coefficients is not possible with it.
So we can use the GoBilda motor that is added there.
It seems that the dashboard is included at two different versions in this project. I think that the dashboard should also be updated to 0.2.2
in FtcRobotController's build.release.gradle
.
We have read the Pid-Tuning document already.
Heading PID is being really annoying to get right. We are just strafing left and right 60 in to tune.
This image is our P:5, I:0, D:0.03
We find that if I or D are greater than 0.05, the robot shakes a lot near the end of the strafe.
Error appears to stay up and then drop back down
The switch from positive to negative and vice versa is in every combination we have tested so far and is always near the end of the trajectory.
The current Heading PID is a little better in straight test (2 to -2 deg) but more spiky.
StraightTestOpMode
's body is an exact copy of TurnTestOpMode
. In other words, the trajectory followed in StraightTestOpMode
is:
Trajectory trajectory = drive.trajectoryBuilder() .turnTo(Math.PI / 2) .build();
Should be an easy fix.
The optimized REV drive classes are currently both broken pending upstream changes in RevExtension2. More specifically, RE2 is not compatible with FTC SDK v4.x, and there is a minor issue with the signs of bulk read encoder values. Both of these issues should be fixed in the next release. In the interim, the other drive classes should work fine.
This is a conceptual question: what is the role of the drivetrain PID loop?
We understand that the process of tuning the drivetrain PID coefficients with DriveVelocityPIDTuner
is matching the measured velocities of each wheel to the target velocity according to the motion profile.
We read that the built-in velocity PID (RUN_USING_ENCODER
) tries to match the motor shaft's rotational velocity to the input power given ("In the DcMotor.RunMode.RUN_USING_ENCODER
mode, the controller uses an onboard velocity PID controller, and the power is instead a scaled velocity.").
Since the wheel velocities are themselves calculated from the encoder readings on the drive wheels, we are wondering why the internal PID cannot handle it, and we need a separate closed loop for the drivetrain (i.e., if the built-in velocity PID makes the motors turn at the right rotational velocity, what more needs to be done?). Of course our past experience suggests that this is not true, but we just cannot think it through. Any explanation would be of great help to our team!
For TrackWidthTuner
, we are trying to implement a localizer that updates only heading using the internal REV IMU (the imu
initialized in all sample mecanum drive subclasses).
We read here that:
the robot has a heading defined as the angle \theta between the front of the robot and the global axis
And implemented the following logic in our localizer:
public class NaiveHeadingOnlyLocalizer implements Localizer {
private Pose2d poseEstimate;
private SampleMecanumDriveREVOptimized drive;
public NaiveHeadingOnlyLocalizer(SampleMecanumDriveREVOptimized drive) {
this.drive = drive;
}
@NonNull
@Override
public Pose2d getPoseEstimate() {
return poseEstimate;
}
@Override
public void setPoseEstimate(@NonNull Pose2d pose2d) {
this.poseEstimate = pose2d;
}
@Override
public void update() {
poseEstimate = new Pose2d(0.0,0.0, getProcessedHeading());
// no Vector2d position
}
public double getProcessedHeading() {
if (drive.getRawExternalHeading() < 0) {
return 2 * Math.PI + drive.getRawExternalHeading();
} else {
return drive.getRawExternalHeading();
}
}
}
The headings do show up as we expect them to be on the dashboard. However, the effective track width returned seems very off, and we wonder if we have understood something wrong. Any help is appreciated!
I was trying to program my own autonomous by referencing MecanumSplineFollower.java. I noticed that in the lines
builder .splineTo(new Pose2d(48, 48, Math.PI / 2), new ConstantInterpolator(0)) .splineTo(new Pose2d(0,0,Math.PI), new LinearInterpolator(Math.PI / 2, Math.PI));
after the splineTo coordinates are created, there are various interpolators that can be used. My question is, what is the use of each interpolator, and when do we use them? Going through the javadoc, I noticed there are about 7 different interpolators.
We have been trying to debug the following issue: Unexpected heading error behavior, and have some speculations regarding its cause:
Since heading error seems to be correct when following a trajectory, we decided that it may be a problem only affecting the drive's in the TURN mode. It appears that in SampleMecanumDriveBase
the turnController
used in this mode is separate from the trajectory follower:
private PIDFController turnController;
. . .
follower = new HolonomicPIDVAFollower(TRANSLATIONAL_PID, TRANSLATIONAL_PID, HEADING_PID);
Since the heading control in FOLLOW_TRAJECTORY
seems to work, we are interested in how headingController
in the follower is different from turnController
in the drive. They are both PIDFController
s that have the target position set to zero by default.
/**
* Target position (that is, the controller setpoint).
*/
var targetPosition: Double = 0.0
In the HolonomicPIDVAFollower
, error seems to be set to the PIDFController
s by setting setpoint = error (actually right in the comments)
// you can pass the error directly to PIDFController by setting setpoint = error and position = 0
axialController.targetPosition = poseError.x
lateralController.targetPosition = poseError.y
headingController.targetPosition = poseError.heading
But it seems to us that targetPosition
seems to be never set to and therefore remains 0, and subsequent error calculations seem to be based on it. The debugger output seems to confirm this, as well as the behavior of the heading error (starting at 0, becoming increasingly negative as the counterclockwise turn is executed) we experienced in
Issue #35.
We created a pull request that addresses the problem for us: #37.
So we see that setDrivePower
is used in LocalizationTest
that enables gamepad controlled drive:
drive.setDrivePower(new Pose2d(
-gamepad1.left_stick_y,
-gamepad1.left_stick_x,
-gamepad1.right_stick_x
));
drive.update();
We noticed that the translational and angular velocities cannot seem to be controlled simultaneously. Would this be the expected behavior due to some physical constraints?
When using the DriveFFTuningOpMode with a SampleMecanumDriveREV base, it moves less than a foot forward (and also turns slightly). The phone telemetry suggests it should move closer to 100 in. forward - is this unexpected behavior/do you know why this might be? If so, it would suggest that the kV (and kA/kStatic) that are given are incorrect. Subsequently, the StraightTestOpMode drives at about a 10 degree angle instead of straight and seems to get more off-track as time progresses. I've set my other DriveConstants accurately (I believe). I'm also using RevRobotics20HdHexMotor. Thank you!
This happens when an opMode using FTCDashboard is run:
Stacktrace:
E/fi.iki.elonen.NanoHTTPD: Communication with the client broken, or an bug in the handler code java.lang.IllegalArgumentException: Infinity is not a valid double value as per JSON specification. To override this behavior, use GsonBuilder.serializeSpecialFloatingPointValues() method. at com.google.gson.Gson.checkValidFloatingPoint(Gson.java:324) at com.google.gson.Gson$2.write(Gson.java:292) at com.google.gson.Gson$2.write(Gson.java:278) at com.google.gson.Gson.toJson(Gson.java:669) at com.google.gson.Gson.toJsonTree(Gson.java:562) at com.google.gson.Gson.toJsonTree(Gson.java:541) at com.google.gson.internal.bind.TreeTypeAdapter$GsonContextImpl.serialize(TreeTypeAdapter.java:155) at com.acmerobotics.dashboard.config.variable.ConfigVariableSerializer.serialize(ConfigVariableSerializer.java:22) at com.acmerobotics.dashboard.config.variable.ConfigVariableSerializer.serialize(ConfigVariableSerializer.java:12) at com.google.gson.internal.bind.TreeTypeAdapter.write(TreeTypeAdapter.java:81) at com.google.gson.internal.bind.TreeTypeAdapter.write(TreeTypeAdapter.java:74) at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69) at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:208) at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:145) at com.google.gson.Gson.toJson(Gson.java:669) at com.google.gson.Gson.toJsonTree(Gson.java:562) at com.google.gson.Gson.toJsonTree(Gson.java:541) at com.google.gson.internal.bind.TreeTypeAdapter$GsonContextImpl.serialize(TreeTypeAdapter.java:155) at com.acmerobotics.dashboard.config.variable.ConfigVariableSerializer.serialize(ConfigVariableSerializer.java:22) at com.acmerobotics.dashboard.config.variable.ConfigVariableSerializer.serialize(ConfigVariableSerializer.java:12) at com.google.gson.internal.bind.TreeTypeAdapter.write(TreeTypeAdapter.java:81) at com.google.gson.internal.bind.TreeTypeAdapter.write(TreeTypeAdapter.java:74) at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69) at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:208) at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.write(MapTypeAdapterFactory.java:145) at com.google.gson.Gson.toJson(Gson.java:669) at com.google.gson.Gson.toJsonTree(Gson.java:562) at com.google.gson.Gson.toJsonTree(Gson.java:541) at com.google.gson.internal.bind.TreeTypeAdapter$GsonContextImpl.serialize(TreeTypeAdapter.java:155) at com.acmerobotics.dashboard.config.variable.ConfigVariableSerializer.serialize(ConfigVariableSerializer.java:22) at com.acmerobotics.dashboard.config.variable.ConfigVariableSerializer.serialize(ConfigVariableSerializer.java:12) at com.google.gson.internal.bind.TreeTypeAdapter.write(TreeTypeAdapter.java:81) at com.google.gson.internal.bind.TreeTypeAdapter.write(TreeTypeAdapter.java:74) at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:125) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:243) at com.google.gson.Gson.toJson(Gson.java:669) at com.google.gson.Gson.toJson(Gson.java:648) at com.google.gson.Gson.toJson(Gson.java:603) at com.google.gson.Gson.toJson(Gson.java:583) at com.acmerobotics.dashboard.FtcDashboard.toJson(FtcDashboard.java:612) at com.acmerobotics.dashboard.DashboardWebSocket.send(DashboardWebSocket.java:72) at com.acmerobotics.dashboard.FtcDashboard.addSocket(FtcDashboard.java:814) at com.acmerobotics.dashboard.DashboardWebSocket.onOpen(DashboardWebSocket.java:34) at fi.iki.elonen.NanoWSD$WebSocket$1.send(NanoWSD.java:87) at fi.iki.elonen.NanoHTTPD$HTTPSession.execute(NanoHTTPD.java:964) at fi.iki.elonen.NanoHTTPD$ClientHandler.run(NanoHTTPD.java:192) at java.lang.Thread.run(Thr EventLoopManager state is EMERGENCY_STOP
It may well be that we configured something wrong. Any help is greatly appreciated!
Our phones have 2+ seconds of initialization normally and when the imu problem message pops up, 5+ seconds. This is a big problem for competition and the switch from auto to teleop.
Our robot moves only in the tuning OpModes, but not in the test ones. We have set the hardware names and imu.
I cannot seem to find a proper localization method for TrackWidthtTuner. I am using encoders, I think I did VelocityPIDTuner and StraightTest ok and in the code it says to set a localization method that does not rely on encoders for determining position.As I saw StandardTrackingWheelLocalizer relies on encoders and if I use a basic Localizer, I do not know how to implement the three methods (getPoseEstimate, setPoseEstimate and update). Any help would be extremely much appreciated.
This opmode conflicts zero power (caused by updating the drive class while in IDLE mode with the zero drive signal) with its expected teleop style controls. This can be fixed by disabling update but that somewhat defeats the purpose of the opmode.
During testing we discover one issue: the follower often finishes following a trajectory with quite some positional error in the end. In the dashboard we can see that error is being still reduced by the PID controllers when the following stopped.
Looking at HolonomicPIDVAFollower
and TrajectoryFollower
, we think that admissibleError
and timeout
should be set to address this issue. Since they are by default zero, we wonder if there might be other considerations that we are overlooking. Advice on best practices will be great!
Shouldn't be too difficult to add. Would also be nice to know how controlling linear movement (i.e. moving up a lift) is different PID-wise than rotary movement (i.e. rotating an arm).
We are wondering if there is a reason that the same PID coefficients are set for all motors on the drivetrain (for example setPIDCoefficients
in SampleMecanumDriveREVOptimized
). It seems to us that on our drivetrain each motor/wheel has a different error and should be tuned separately?
When putting in the locations of the three tracking (dead) wheels, do we put in lateral distance of the outside, middle, or inside of the left and right wheels.
I||---------||I (outside distance),
|I|---------|I| (middle distance),
||I---------I|| (inside distance),
I attempted to Modify the StandardTrackingWheelLocalizer to use a Gyro for heading. After getting everything setup, it gives an error that "The specified configuration cannot support full localization". What am I doing wrong?
To aid in tuning, a higher frequency graph is often helpful. Increasing the telemetry interval here would make high frequency oscillations more apparent.
I don't know if we are doing something really bizarre or not but with the DriveVelocityPIDTuner changing the distance on the dashboard makes no difference. (but changing it in the code does)
We are hesitant to tune the PID values if this makes no difference.
The heading error is the least when it should be the greatest, and vice versa. This happened to us while testing TrackWidthTuner
and FollowerPIDTuner
. The heading value itself is correct, and the dashboard output is as followed:
Translational error seems to be correct. We definitely made a mistake in our configurations. Would appreciate any pointers!
We’re struggling with tuning our robot to predictably turn when doing a turn sync.
I am getting inaccurate and inconsistent results from the track width tuner. I am using a 4 wheel drive, with traction in the back and omnis in the front. The default settings of the tuner give me a result of 13.09. Using this track width gives me really inaccurate turns. The actual track width of the drivetrain (measured) is 16.5. I tried adjusting the track width manually to provide accurate turns. I got accurate results at a width of 22.5". I tested multiple combinations of motor power and number of turns (listed below).
motor power | number of turns | output track width |
---|---|---|
0.3 | 4 | 13.09 |
0.3 | 2 | 15.73 |
0.3 | 6 | 12.2 |
0.3 | 12 | 11.46 |
0.5 | 4 | 13.17 |
0.7 | 4 | 13.36 |
I am unable to get the FTC dashboard variable configuration to show anything. I'm not sure what I did wrong as everything appears to be defined. It doesn't work in any of the Op Modes included.
I wrote this simple program to try to isolate the issue but it still doesn't work. Telemetry does though.
package org.firstinspires.ftc.teamcode;
import com.acmerobotics.dashboard.FtcDashboard;
import com.acmerobotics.dashboard.config.Config;
import com.acmerobotics.dashboard.telemetry.MultipleTelemetry;
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
@TeleOp
@Config
public class dashboardTest extends LinearOpMode {
static public double theBegining = 0;
static public int theEnd = 0;
@Override
public void runOpMode() {
FtcDashboard dashboard = FtcDashboard.getInstance();
telemetry = new MultipleTelemetry(telemetry, dashboard.getTelemetry());
theBegining = 1;
theEnd = 4;
dashboard.updateConfig();
waitForStart();
while(!isStopRequested()) {
telemetry.addData("theBegining", theBegining);
telemetry.addData("theEnd", theEnd);
telemetry.update();
}
}
}
Hi there,
When attempting to run the LocalizationTest.java in the quickstart project, the code threw the LynxFirmwareVersionException
error. It says that our attached lynx modules have outdated firmware, and that the minimum version was 1.8.2.
How can we update this firmware?
Seems silly but I have to ask... when running each test in the tuning process for the road runner quickstart it wasn't clear to me if we should be focused on the telemetry in the dashboard or the physical results. For instance, in "StraightTest" should we be looking at what the telemetry is telling us about how close the robot landed to the target or should we be measuring with a tape measure how far the robot traveled and comparing with the target?
I'm currently trying to implement three-wheel tracking into the quickstart but I don't exactly know what to do. In SampleMechanumDriveREV it says // TODO: if desired, use setLocalizer() to change the localization method
How do I go about doing this? I've tried putting this line of code setLocalizer(StandardTrackingWheelLocalizer);
there but it doesn't seem to be working. What do I need to do?
What is the difference between followTrajectory and and followTrajectorySync? And was turnTo and turn in TrajectoryBuilder changed to turnSync/turn under the SampleMecanumDriveBase class?
We read in the comments to StandardTrackingWheelLocalizer that "Note: this could be optimized significantly with REV bulk reads", which we are trying to do.
We wonder if they best practice would be implementing a getTrackingWheelPositions
in the drive class, then set the values to a List<Double>
of the localizer, which is returned when the localizer's getWheelPositions()
is called. If this is not the ideal way of doing it, we hope our question may be helpful to other teams.
We have our robot tuned in fairly well. Our only remaining issue is when we add motions in two directions. Doing this create inconsistent profiles. I believe this is because there is some assumption that we can move max velocity in both directions at the same time, which we can't. Is this a valid concern?
Trajectory complexMove = drive.trajectoryBuilder()
.lineTo(new Vector2d(40, 19), new LinearInterpolator(0, 0))
.lineTo(new Vector2d(80.5, 32), new LinearInterpolator(0, 0))
.build();
drive.followTrajectorySync(complexMove);
My expectation is that this will create a "triangle" motion. Which it does, but we never really reach the correct Y. This issue becomes worse the more we increase our max velocity. It seems like the only solution is to greatly reduce the max velocity significantly.
Should we be thinking about this differently?
Do you plan on writing examples using the new features in the FTC SDK 4.0?
We have been having an issue where a program that just calls a simple strafeTo()
followTrajectorySync(trajectoryBuilder().strafeTo(new Vector2d(25, 25)).build());
When the program is run, the robot just sits there for a few seconds and then runs, not getting the the target position. In a few other cases, the robot runs immediately but overshoots the target a lot. We have verified that initialization has finished.
This issue is very random, sometimes it works, sometimes it doesn't. Lately, it's been on the not working side.
As the title states. Occasionally, when the OpMode is stopped, a nullpointerreferenceexception with respect to the revbulkdata is thrown
The trajectory followers are controllers that compute the robot's velocity and acceleration from the current trajectory and current position (they fall into the category of reference trackers). Some of the followers in Road Runner use PID with VA feedforward terms (the holonomic PIDVA trajectory follower source is pretty readable and understandable at a high level) while others use more sophisticated techniques.
Originally posted by @rbrott in #25 (comment)
Thank you, this is incredibly clarifying. The feedforward concept in HolonomicPIDVAFollower
seems quite understandable, but we are a bit confused by the comment where correctedVelocity
is calculated and applied:
// note: feedforward is processed at the wheel level; velocity is only passed here to adjust the derivative term
Additionally, we want to make sure if the goals of FollowerPIDTuner
is to tune TRANSLATIONAL_PID
and HEADING_PID
in SampleMecanumDriveBase
? It was not completely clear in the docs but made sense to us. I thought that this should become a separate issue so that more people can find it.
It is not clear on how to use FollowerPIDTuner to tune the TRANSLATIONAL_PID and HEADING_PID found inside of MecanumDriveBase. It is also not clear on what these PID variables do and how it effects the movement of the robot. Help would be appreciated. Thanks
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.