ros-mobile-robots / diffbot

DiffBot is an autonomous 2wd differential drive robot using ROS Noetic on a Raspberry Pi 4 B. With its SLAMTEC Lidar and the ROS Control hardware interface it's capable of navigating in an environment using the ROS Navigation stack and making use of SLAM algorithms to create maps of unknown environments.
https://ros-mobile-robots.com
BSD 3-Clause "New" or "Revised" License
297 stars 86 forks source link

PID Controller #35

Open PaddyCube opened 3 years ago

PaddyCube commented 3 years ago

Hello, could you please explain the values of PID controller? What is f, antiwindup, i_clampmin and i_clampmax good for? I tried different values with no luck so far. Acceleration seems to work but when I stop the robot with a velocity of 0m/s, it starts to oscillate back and forth endless

fjp commented 3 years ago

Hi @PaddyCube

anti-windup is to preventing the integral error from growing too much. Put in a simple python example this is how the integral error is clamped (in this example between -2 and 2):

e_int = max(min(e_int,2),-2)

F is the feedforward term and used to reach the set point faster.

Which hardware and "version" of diffbot are you using? The reason I am asking is because there are basically two approaches, where to put the PID controller:

  1. Having the PID controller in the high level hardware interface - found in 0.0.2.
  2. Running the PID controller on the low level firmware source code - implemented in noetic-devel, which is implemented on tag 1.0.0 .

Recently, I made a major code change regarding where to put the PID controller. Option 2 is currently my preferred method and implemented in the latest commits of noetic-devel, because the behaviour seems to be more stable. Using option 2 also means that the dynamic reconfigure parameters (F, P, I, D and anti-windup feature) in the high level hardware interface are not used anymore. I didn't remove the code however, to allow/show both methods, but this might change in the future.

With option 1 you have the comfort of dynamic reconfigure to tune the (F)PID controller but for me definetely the second option feels more stable. To tune the PID values with the second option you need to change the values in code. I am planning to use dynamic reconfigure however, and send topics to the low level firmware running on the Teensy mcu.

In general I cannot recommend which option to choose but for me definitely option 2 worked better so far.

To tune the PID controller, this youtube video might help. It gives some insights what the PID parameters influence. Regarding the F term, I would start setting it to zero.

darld commented 3 years ago

Is possible to disable the PID, so the robot wouldn't oscillate during the teleops?

fjp commented 3 years ago

@darld disabling the PID is not directly possible, since you would create an open loop without feedback from the velocity error. Therefore, I would first suggest to tune the PID correctly to avoid the oscillations. This way you can leverage all the features from ROS Controls diff_drive_controller.

However, in case you don't want to use this controller, you could also try to update the write() method of the base_controller that is running on the low level microcontroller:

https://github.com/ros-mobile-robots/diffbot/blob/ece43cb345dbee6d622b083e9a8b630b492a5b24/diffbot_base/scripts/base_controller/lib/base_controller/base_controller.h#L501-L510

This is where the PID is used to compute the PWM motor signals from the velocity error. Instead of calling the PID you would have to translate the commanded velocity (from the diff_drive_controller) to a PWM signal, for example using a simple mapping. Then you also have to make sure that the commanded velocities from the diff_drive_controller are actually applied on the motors. Otherwise the error can grow and you produce an open loop.

darld commented 3 years ago

Not sure whether I can just set the error_ = 0, therefore no error compute in the open loop. https://github.com/ros-mobile-robots/diffbot/blob/ece43cb345dbee6d622b083e9a8b630b492a5b24/diffbot_base/src/pid.cpp#L35-L39

fjp commented 3 years ago

Please note that this is the "old" PID controller that was running in the high level hardware interface, as I mentioned in my comment previously. If you flashed the script/base_controller on your microcontroller, tuning these PID parameters with dynamic reconfigure or even setting the error_ = 0 won't have any effect. If you want to work with the high level PID you should flash the source code found in the scripts/encoders folder:

image

However, I would suggest you try to use the base_controller firmware. The PID values which you then have to tune are found in the diffbot_base_config.h here:

https://github.com/ros-mobile-robots/diffbot/blob/ece43cb345dbee6d622b083e9a8b630b492a5b24/diffbot_base/scripts/base_controller/lib/config/diffbot_base_config.h#L18-L20

The drawback of this method is that you currently have to re-flash the microcontroller every time you change the PID values. However, I am planning to add a topic to change these values for a better tuning experience.

fjp commented 3 years ago

Regarding the tuning process. You mentioned oscillations, which might happen because of a too high proportional gain. So I would start the tuning by setting these values:

P = something small until no oscillations are observable I = 0 D = 0

Only increase the I and D gains once you see stable results with a P value not equal to zero.

Setting the error_ = 0 is definitely not what you want, because then the commuted output command from the PID will be always zero (u(t) = 0 in the formula below).

image