Alright, get ready for the math I'm about to throw.
On my SAGAR robots, I have 39cm circumference wheels. That means my robot has traveled 39cm with one wheel rotation.
My motors have a 19:1 gear ratio.
My encoders give me 32 'clicks' per motor shaft rotation. That means i get 608 (32 * 19) clicks per wheel rotation.
Therefore I get about 16 (608 / 39) clicks per cm traveled.
Now my PID controller works with clicks, not cm. So whenever my motor controller gets a command for speed. (We will say 200 cm/sec for example) it has to translate that into clicks. so 200 cm * 16 =3200 clicks per second.
My PID loop runs at a rate of 35Hz, that means it adjusts wheel speed 35 times a second. so now our goal of 3200clicks/sec has to be divided by 35 to create a click goal for each PID loop. 3200/35 = about 91 clicks per PID loop.
The max speed for my motors is 325 cm/sec. That means the range of clicks per PID loop goes from 0 to 150. Actually, it's -150 to 150 since anything negative just means it spins in reverse.
All this was to demonstrate that the input range of my motor controller's PID is -150 to 150. The output is a PWM duty cycle from 0-255 where 255 is full on. Again, it's actually -255 to 255 with negative meaning power in reverse.
So for -150 to 150 input and -255 to 255 output, my PID gains are:
K_P .8 //porpotional control Gain
K_I .4 //Integral Control Gain
K_D 5 //Derivitave control gain
I_LIMIT 2.5 //to prevent I wind-up
My new controller is actually more complicated, as it has a state machine per wheel, it can be either under power with the PID controller above, braking x hard using a second PID controller, or in constant current mode with a third PID controller if a motor is drawing too much current and is still being asked to go faster.