A flywheel model only has one pole, so the only way to make it oscillate is to undersample the dynamics or introduce a bunch of measurement delay. Adding K_d in those situations doesn’t help. I’ll try to explain why you only need K_p (steady-state error due to feedforward modeling error notwithstanding).

PID controllers typically control voltage to a motor in FRC independent of the equations of motion of that motor. For position PID control, large values of K_p can lead to overshoot and K_d is commonly used to reduce overshoots. Let’s consider a flywheel controlled with a standard PID controller. Why wouldn’t K_d provide damping for velocity overshoots in this case?

##
Flywheel model derivation

Our simple motor model hooked up to a mass is

\begin{align}
V &= IR + \frac{\omega}{K_v} \\
\tau &= I K_t \\
\tau &= J \frac{d\omega}{dt}
\end{align}

First, we’ll solve for \frac{d\omega}{dt} in terms of V.

\begin{align}
V &= IR + \frac{\omega}{K_v} \nonumber \\
V &= \left(\frac{\tau}{K_t}\right) R + \frac{\omega}{K_v} \nonumber \\
V &= \frac{\left(J \frac{d\omega}{dt}\right)}{K_t} R + \frac{\omega}{K_v}
\nonumber \\
V &= \frac{J \frac{d\omega}{dt}}{K_t} R + \frac{\omega}{K_v} \nonumber \\
V - \frac{\omega}{K_v} &= \frac{J \frac{d\omega}{dt}}{K_t} R \nonumber \\
\frac{d\omega}{dt} &= \frac{K_t}{JR} \left(V - \frac{\omega}{K_v}\right)
\nonumber \\
\underbrace{\frac{d\omega}{dt}}_{\dot{\mathbf{x}}} &=
\underbrace{-\frac{K_t}{JRK_v}}_{\mathbf{A}} \underbrace{\omega}_{\mathbf{x}} +
\underbrace{\frac{K_t}{JR}}_{\mathbf{B}} \underbrace{V}_{\mathbf{u}}
\end{align}

##
Flywheel pole locations

Poles are the eigenvalues of the differential equation above, which in this case is just A. Poles can be real numbers or imaginary. Since this is a continuous model, the figure below shows the various impulse responses for different pole locations.

There’s one stable open-loop pole at -\frac{K_t}{JRK_v}. It’s a real number, so it’s on the real axis and doesn’t oscillate. Let’s try adding a simple P controller.

\begin{align*}
\mathbf{u} &= \mathbf{K} (\mathbf{r} - \mathbf{x}) \\
V &= K_p (\omega_{goal} - \omega)
\end{align*}

Closed-loop models have the form

\dot{\mathbf{x}} = (\mathbf{A} - \mathbf{B}\mathbf{K})\mathbf{x} + \mathbf{B}\mathbf{K}\mathbf{r}.

Therefore, the closed-loop poles are the eigenvalues of \mathbf{A} - \mathbf{B}\mathbf{K}.

\begin{align*}
\dot{\mathbf{x}} &= (\mathbf{A} - \mathbf{B}\mathbf{K})\mathbf{x} + \mathbf{B}\mathbf{K}\mathbf{r}
\\
\dot{\omega} &= \left(\left(-\frac{K_t}{JRK_v}\right) -
\left(\frac{K_t}{JR}\right)(K_p)\right)\omega +
\left(\frac{K_t}{JR}\right)(K_p)(\omega_{goal}) \\
\dot{\omega} &= -\left(\frac{K_t}{JRK_v} + \frac{K_t K_p}{JR}\right)\omega +
\frac{K_t K_p}{JR}\omega_{goal}
\end{align*}

This closed-loop flywheel model has one pole at -\left(\frac{K_t}{JRK_v} + \frac{K_t K_p}{JR}\right). It therefore only needs one P controller to place that pole anywhere on the real axis, and no value of K_p will cause it to leave the real axis.

A derivative term is unnecessary on an ideal flywheel. It may compensate for unmodeled dynamics such as accelerating projectiles slowing the flywheel down, but that effect may also increase recovery time; K_d drives the acceleration to zero in the undesired case of negative acceleration as well as well as the actually desired case of positive acceleration.

##
Discrete systems and sample delay

If we consider a discrete system instead of a continuous one (periodic updates), one pole can oscillate if there’s undersampling of the dynamics or sample delay (I won’t go into the discrete pole unit circle here because this post is already long). The only options in that case are to reduce K_p to slow down the response or fix the source of the sample delay.