PID only returning output 1, robotpy

wpilib

#1

Using a pidcontroller for velocity the setpoint is 100 the feed forward is 12 something and yet the output is always one. The proportion is like 300. Also it does not move the arm we are trying to move. We use python.


#2

Which file is this in? All those numbers seem really high.


#3

In file arm.py and do_profile_move.py in subsystems and commands respectively Also they are really high just in case being low was the reason for the arm not moving.


#4

Sounds like a math problem somewhere, perhaps something isn’t the number you expected (or integer division is happening somewhere?). Does this issue occur on a real robot, in simulator, or both?


#5

Also, you really shouldn’t be creating a PIDController over and over again. PIDSubsystem is probably better suited for what you want to do.


#6

It happens both in sim and on the robot. Pidsubsystem is what we would have preferred to use but the lack of examples was infuriating and we were unable to get it to work.


#7

Both the PacGoat and GearsBot examples have PIDSubsystems in them. Do those no longer work? I can’t help but wonder if the reason PIDSubsystem didn’t work for you is the same reason you’re having issues with this.


#8

You’re definitely doing something weird, unfortunately I don’t really like Command based programming, so I’m not super familiar with it and can’t provide any advice. It seems like your commands are undoing the effects that the others are doing.

The reason it won’t work in simulation (besides that the code is incorrect) is that there’s nothing providing feedback to the PID loop, so even if your code was correct it wouldn’t function in simulation. You can control the feedback by adding a physics.py with the right code in it.

Here’s a physics.py that seems to work on your robot code that you provided if one makes the motors move. Obviously you’ll need to change the constants in the constructor to fit what your robot actually does.

#
# See the notes for the other physics sample
#


from pyfrc.physics import motor_cfgs, tankmodel
from pyfrc.physics.motion import LinearMotion
from pyfrc.physics.units import units


class PhysicsEngine(object):
    """
       Simulates a 4-wheel robot using Tank Drive joystick control
    """

    def __init__(self, physics_controller):
        """
            :param physics_controller: `pyfrc.physics.core.Physics` object
                                       to communicate simulation effects to
        """

        self.physics_controller = physics_controller

        # Change these parameters to fit your robot!
        bumper_width = 3.25 * units.inch

        # fmt: off
        self.drivetrain = tankmodel.TankModel.theory(
            motor_cfgs.MOTOR_CFG_CIM,           # motor configuration
            110 * units.lbs,                    # robot mass
            10.71,                              # drivetrain gear ratio
            2,                                  # motors per side
            22 * units.inch,                    # robot wheelbase
            23 * units.inch + bumper_width * 2, # robot width
            32 * units.inch + bumper_width * 2, # robot length
            6 * units.inch,                     # wheel diameter
        )
        # fmt: on

        self.encoder_idx = None

        # obviously, tune these parameters to your robot
        self.arm_motion = LinearMotion(
            "arm",
            motor_ft_per_sec=10,
            ticks_per_feet=100,
            max_position=None,
            min_position=0,
        )

    def update_sim(self, hal_data, now, tm_diff):
        """
            Called when the simulation parameters for the program need to be
            updated.
            
            :param now: The current time as a float
            :param tm_diff: The amount of time that has passed since the last
                            time that this function was called
        """

        # Simulate the drivetrain (only need one motor from each side)
        l_motor = hal_data["pwm"][3]["value"]
        r_motor = hal_data["pwm"][0]["value"]

        x, y, angle = self.drivetrain.get_distance(l_motor, r_motor, tm_diff)
        self.physics_controller.distance_drive(x, y, angle)

        # simple simulation of the arm to make it do something
        if self.encoder_idx is None:
            # robotpy's HAL doesn't have good way to find an encoder yet
            for i, enc in enumerate(hal_data["encoder"]):
                if enc["config"]["ASource_Channel"] == 0:
                    self.encoder_idx = i
                    break
            else:
                return

        # right and left motors are mirrored, so only grab the left
        try:
            left_arm_motor = hal_data["CAN"][3]["value"]
        except KeyError:
            return  # CAN not initialized yet

        # increment the encoder based on what the arm did
        hal_data["encoder"][self.encoder_idx]["count"] = self.arm_motion.compute(
            left_arm_motor, tm_diff
        )

Hopefully this helps you debug your robot in simulation!


#9

We really just didn’t understand how to implement it with our code. We looked at both those examples.


#10

Also I will try this out later, I’ve been meaning to get around to using physics.py but there have been other priorities. Thanks for the help


#11

It looks to me like your PID output is always being divided by your max_click_rate, set to 318.0, which is a huge number. That’s likely dropping your motor output to a value too low to even move the arm. That’s being done in subsystems/arm.py, when it calls click_rate_to_voltage.

It’s not clear to me what click_rate_to_voltage is for.


#12

It was intended to turn the click rate output by the pid to a -1 to 1 scale such that it could be input to motors