A different way to solve this: Dont look at your speed, but look at your position.

First determine how far each motor has to run and in how fast you want the motors to run.

Say 3000 degrees 50 degrees per second.

Now take a variable "step" and load it with the actual encoder value.

Go into a loop:

Let "step" count up with a speed of 50 degrees per second every loopcycle until you reach the setpoint.

This variable contains the value you want the motor to be every loopcycle.

Every loopcycle you compare the actual encoder value with "step". There will be a small difference between them. This difference will be the new setspeed for the motor.

I use this theory a lot and it works pretty good. It can be used up to 3 motors the same time and synched.

It does not have a ramp up and down, but is pretty easy to integrate (just left it out to keep things more clear)

in pseudo

As soon setpoint is reached the motor stops automatically, because the error will reach 0.

the internal PID wil run the motors.

The looptime is something to play with, since the motor output power is set every cycle. this resets the PID

Sometimes 25 ms works best. other times 100ms

Hope i made it clear a little