Tray P Control

Hey I was going trying to add some p control to my code and I was wonder how you get the rotation in degree output from the v5 motors. I was told that they have encoders built into them here.

This is what I had don’t make fun of me if its wrong.

if ( TrayPusher.rotation(degrees) < 500) { TrayPusher.setVelocity( 30 , percent );
} else if ( TrayPusher.rotation(degrees) < 600) { TrayPusher.setVelocity( 25 , percent );
} else if ( TrayPusher.rotation(degrees) < 700) { TrayPusher.setVelocity( 20 , percent );
} else if ( TrayPusher.rotation(degrees) < 800) { TrayPusher.setVelocity( 15 , percent );
} else if ( TrayPusher.rotation(degrees) < 900) { TrayPusher.setVelocity( 10 , percent );
} else { TrayPusher.setVelocity( 25 , percent ); };

Thanks, 7157A

uhh I would just make a ratio

power = 100*1-(TrayPusher.rotation(degrees)/900)

replace 900 with your targeted end rotation value.

You have less control over each step but there are more stepdowns.

you might need parentheses around 1-(TrayPusher.rotation(degrees)/900) because, well order of operations dictates that you multiply first then subtract. unless VexCode completely ignores PEMDAS.

tbh I don’t really understand exactly what you mean, im kinda new to text so if you wouldn’t mind explaining it in depth that would be nice.

That is not a P control, thats a bunch of if statements that also use VEX’s internal PID due to “setVelocity”.
If you want a P control do something along the lines of

double kP = 0.001;
int error = 0;
int targetValue = 900;


error = TrayPusher.rotation(degrees) -  targetValue;

TrayPusher.spin( directionType::fwd, error * kP, voltageUnits::volt );


Using voltage would be better, so you have more control of how you operate the motor. You may need to switch things around so the P control loop works.


ok thank you, ill try that

1 Like

Sounds good! Just for a heads up voltage ranges between -12.0 to 12.0, where 0.0 is not spinning. That means its a double value so you can be very precise in how you operate the motor. Change the value of kP to tune it.

I’d change the while condition to something like

while(abs(error) > 10)

This gives you some threshold if you never reach the target. Obviously tune the constant to your needs. I wouldn’t go over 50-60 ticks cause then you’ll see noticeable inaccuracy (depending on your gear ratio as well).

1 Like

Just a thought, but there are lots of line fitting applications that can make you a smooth curve for a range of values. So I have 100 degrees with 100%, 300 degrees with 50%, etc… You could do it however you want.


1 Like

I got rid of the while condition and in my case I was setting it up with the button L2 pressing.

int error = 0;
int targetValue = 1012;
double kP = 0.014;

if ( Controller1.ButtonL1.pressing()) {
TrayPusher.spin( directionType::fwd, error * kP, voltageUnits::volt );
error == TrayPusher.rotation(degrees) - targetValue;


One approach I’ve seen work well is to have your velocity model the cosine function as you approach the target. Specifically, a scaled version of the cosine function below:

y(x) = 0.5(cos(pi * x) + 1)

The point of inflection at x = 0.5 really helps to minimize the effects of the momentum of the tray arm

1 Like

My code is assuming that the code is in driver control.

That would not work if you do not have a while loop. I was assuming that you would figure out that what is inside the while loop is inside the while loop of your code, and what is outside the while loop is outside the while loop of your code.


Even if it is in driver control, you need a condition in the loop that exits or else you’ll get an infinite loop. How about the program only enters the loop when a button is pressed and while a condition is met.

while( buttonPressed && (abs(error) > 10))

This way the tilter will only move if the button is being pressed and if the error is above a threshold. You still want to be able to exit the loop to be able to access other driver control functions and you don’t want the robot to be immobile while in the loop so have the condition based on user input and the tray’s real-time position.


I don’t like to clutter up the driver control function. Instead, I create other functions that are usable in other parts of my code. This means my driver control is just a list of function headers and the functions are all located with their respective subsystem (chassis, lift, etc). This is just preference but it makes organizing your project a lot easier and efficient.

1 Like

yes I put it in the usercontrol