Falcons "brake" unexpectedly

So we’re tuning our velocity PID on our shooter, running two Falcon 500’s, one Talon FX following the other, and when we stop driving the shooter it brakes for a few seconds and then, at a consistent (Velocity units)/100ms of about 5000 (green plot), it suddenly coasts–and our gearbox makes a not-so-fun noise in the process.

The motors are set to Coast in code, the red lights in back are not on, and they are set to Coast in Phoenix Tuner as well.

This happens regardless whether we run them with our code, with Phoenix Tuner in Percent Control mode, or with Phoenix Tuner in Velocity Control mode, but if we disable the robot while at full speed it coasts as normal.

Any thoughts on what could be causing this, and what to do about it? Thanks!

1 Like

As you can see, the blue and purple show that the motor is outputting current and is not being set to brake or coast mode.

The motor goes into brake or coast mode when the output is 0% and it’s not 0% in this case.

Keep in mind that setting the desired velocity to 0 units/100ms does not mean setting the output to 0%. It’s going to run its PID loop to try and get the velocity back down to 0 as quick as it is configured to do.

In our code, when our subsystem is commanded to go to 0 RPM, we just set the PercentOutput to 0 and have the motor coast its way back down to 0 RPM. There’s no reason for us to use the PID loop to slow it down.

1 Like

I would try the following tests:

  • Same thing, but without PID turned off (go from a percent output that should be close to where you are in your test down to 0). There could be something going on with the PID causing it
  • Test with some different values. Does the same thing happen if you start at half speed? What happens if you go from full speed to half speed to stopped?

Okay, I think that’s likely it–what we thought we were doing was not what we were actually doing. (Go figure, robots try to do what you tell them to, not what you meant to tell them to.)

Jon, it happens at any speed above ~5000 velocity units / 100 ms.

Thanks, folks, we think that’s enough for us to get the right behavior from here on out. I’ll be back if we can’t figure it out!

2 Likes

This. To just let the wheel coast down to a stop, use code like the following:
talon0.set(ControlMode.PercentOutput, 0.0);

I suspect you’re probably instead doing the below in your code:
talon0.set(ControlMode.Velocity, 0.0);

1 Like

Hookay, so my programmers went home, so this is now just me trying to look through the code, and I’m, like, well, not a programmer…

We’re trying to use RobotContainer.shoot_Motor.set(ControlMode.PercentOutput, 0.0) but the problem persists.

In our Shoot_Motor.java command, could the line

public boolean isRunning()
{
return m_lead_motor.getControlMode() == ControlMode.Velocity;
}

be overriding that command? Shoot is part of a command group that is controlled by a WhileHeld, and ShooterStop is triggered by a WhenReleased on the same button, but even when it’s no longer held, well, the problem persists.

Rather than have a “whileHeld” command and a “whenReleased” command attached to the same button, I’d suggest doing the actions that you want to take place “whenReleased” in the end() method of the whileHeld command.

Depending upon the details, it may be the case that the whenReleased command is actually getting initiated before the end method of the whileHeld command. As a result, the end() of the whileHeld command may be getting called after the whenReleased command is getting initiated, meaning it may be undoing what is done in the whenReleased command.

1 Like

That’s what we tried first. :confused:

No. That line wouldn’t change the value. = assigns value while == is a relational operator (checks if they are equal and returns true or false).

Hey Pat,

This is a bit hard to diagnose without a full code sample. I’d be happy to take a look through it on Sunday to see if I can spot anything if you want to send me a copy of the repository.

Justin

If we can’t figure it out today, I’ll definitely take you up on that, thanks!

1 Like

No luck so far.

We dropped our commands and subsystems at github.com/pfreivald/1551-2020-Code/tree/master

Clearly we need to organize it into file folders, but if you’d be willing to take a look that would be great.

The shoot command is Shoot_Motor_Command_Group.java, which is a SequentialCommandGroup consisting first of a ParallelRaceGroup to aim the robot and spin up the shooter, which works fine, then a second ParallelRaceGroup to continue with shooter spin-up and run our feed motor when it’s up to speed, which works fine, followed finally by the ShooterStop command to set the PercentOutput to 0.0, which doesn’t work.

I suspect that in this line of code it’s never getting to the ShooterStop, because with the trigger button held it hangs on the second ParallelRaceGroup–which it should–and once released it kicks out of the Command Group and never even sees the ShooterStop command. Seems reasonable.

So we’ve tried a few things, including:

  1. Having a RobotContainer.shoot_Motor.set(SetControlMode.PercentOutput, 0) in the end() of our Shoot command. We thought this would be all that was necessary in the first place. No dice.

  2. Explicitly calling the ShooterStop command at the end of the Shoot_Motor_Command_Group (as noted above). No dice.

  3. Explicitly calling the ShooterStop command with a WhenReleased on the same trigger in RobotContainer. No dice.

  4. Setting ShooterStop to an entirely different WhenPressed button, releasing the trigger that is the WhileHeld for the Shoot_Motor_Command_Group and then pressing that entirely different button to set the motors to PercentOutput 0… No dice.

So either ShooterStop isn’t doing what I think it should be doing (which seems unlikely–it’s a pretty obvious command), it’s never getting called in the first place (also seems unlikely, given the several ways we’ve tried to call it), or something in the rest of the code is overriding it (seems most likely, but I can’t for the life of me figure out what that would be.)

What’s your Falcon FX’s firmware version? Need be updated. The manufacture firmware version may cause the issue you described

My recommendation to your programmers would be to put prints in the places that you set the control mode of that motor to see if your code is setting it in some weird way. If you debug the code with simple System.out.println()s, you’ll be able to see exactly what’s being called. And if you’re brave enough to learn how to use VS Code’s debugger, that might be helpful as well.

On a separate note, in Shoot_Motor you configure the voltage saturation to 12.5 after you enable voltage compensation, which I don’t think will get you the desired results because the enableVoltageCompensation() method says you should call it AFTER you call configVoltageCompSaturation(). This won’t solve your problem, but I thought I’d point that out.

Well, we thought we’d isolated the issue to a bad TalonFX, but after swapping it out we still have the same problem.

Very perplexing.

All firmware is up to date.

Looking at your code, I think the cause of your problem is the setRampRate() feature. When you suddenly command the motor to ControlMode.PercentOutput, 0.0, the controller won’t go immediately to zero, but will ramp down to zero, which is what you are seeing. That is true whether the motor is in ControlMode.Velocity or ControlMode.PercentOutput. Disabling the robot will cause an immediate setting to zero, and won’t obey the ramp.

Getting rid of all of the setRampRate() calls in your code, except an initial setRampRate(false) command in the Shoot_Motor.java constructor would be one way to do this. Note that you have some of these calls in Shoot.java

To test my theory, I would suggest changing line 40 in Shoot_Motor.java from the below

   // setRampRate(true);

to instead being as below:

   setRampRate(false);

Also, for the time being change the setRampRate calls in Shoot.java, at line 33 (in the initialize method) to be setRampRate(false):

  public void initialize() {
      RobotContainer.shoot_Motor.setRampRate(true);
      System.out.println("===================");
  }

The code that you have at Shoot.java lines 44-46 is what is causing the change in behavior at 5000 native units. (Given your constants, 1500rpm ~ 5000 native units). While debugging, I would comment out / remove those lines, too.

Also a few other incidental things I noticed when looking at the code:

In “Shoot_Motor.java” you have a pair of lines commented out at lines 23-24.

 // m_lead_motor.configFactoryDefault();
 // m_follow_motor.configFactoryDefault();

These are best to leave in as a best practice, so that the controllers are always configured correctly when the robot program runs and don’t have any parameters left over from prior usage (such as when replaced due to a hardware failure, or with parameters left over from another application, such as PhoenixTuner).

Lines 30 and 31 should be reversed, as mentioned by another user.

    m_lead_motor.enableVoltageCompensation(true);
    m_lead_motor.configVoltageCompSaturation(12.5);
3 Likes

Patrick, have you been in contact with CTRE?

@ozrien

I don’t think I’ve narrowed down to a single thing, but some concerns I have:

  1. You may be converting units wrong. I don’t know. I’m not immediately sure what the 10 * 60 is supposed to represent in encoder -> RPM conversions (because I don’t know your gearbox either). Maybe its too early in the morning. I tried digging through Javadocs trying to find a way to natively convert units so that you don’t have to do it, but I couldn’t find anything obvious.

  2. I would take off the ramp rate. Make sure you aren’t just commenting it out. I’m not sure if the Falcon will remember a ramp rate of 1 between settings (which is a very high value anyway - try going much lower - I think 2791 2018 dt had a ramp rate of 0.05), but you should explicitly set it to zero. Instead, I’d put a current limit of like 30A on it.

  3. I would take what you can find for a barebones closed loop velocity controller on the system, taking all other robot code off. Start a completely fresh project and try to copy paste in stuff from CTRE example code, but I spent an hour looking for TalonFX example code and didn’t really find anything.

  4. You have this line in the Shoot::execute function:

      if (RobotContainer.shoot_Motor.getRPM() > 1500){
          RobotContainer.shoot_Motor.setRampRate(false);
      }

which scares me. The current limit as I mentioned in 2 will do what I think you are trying to achieve here.


Looks like Ken mostly beat me to it.

We aren’t using Falcons on our shooter so I can’t give you our shooter code to copy-paste to check if it works, but I can give you our NEO-based code as maybe a vague template you can throw Falcon code at: https://gist.github.com/tervay/1241905d5af46aaafe63e0000c3760ff

1 Like

For any others following along, the unit conversion in question is in the following snippet of code:

public double getRPM() {
    return (m_lead_motor.getSelectedSensorVelocity() * 10 * 60 / Constants.SHOOTER_PULSES_PER_ROTATION);
}

which converts from CTRE Phoenix native units (which are in counts / 100 msec) for a Falcon.

Basically, the conversion from CTRE Phoenix native units is as follows:

Starting with N (in native units, which is counts / 100msec),
multiply by 10 (in 100msec / second)
multiply be 60 (in seconds / minute)
divide by 2048 (in counts / rotation).

If one keeps track of the units in the above calculation, the counts cancel, the 100msecs cancel, the seconds cancel, and one ends up with rotations / minute (RPM).

3 Likes