I have seen many robots at competitions that have the ability to make their tray move up fast at first and when it is about to reach the optimal stacking position, it slows down to make the stacking more accurate. I wanted to implement this on our robot but I do not know-how. Any help with this would be greatly appreciated.
I’m going to guess that you built your tilted something like a 4-bar. What you want to do is reposition the attachment so that when the tray is straight, the “pusher” angle is very close to 180
Our robot is kind of like that. Our robot is a robot with a dr4b mounted on the robot and a titler mounted on the robot but they are 2 separate mechanisms.( So out robot is like every other tray bot but with a dr4b attached to it). I wanted more clarification on your solution. I dont understand how the robot tilter will slow down when it reaches that optimal position with your solution.
Try using sensors (Potentiometer) to help you know where your tray currently is. If you don’t have them or can’t use them, use the v5 built in encoders. The way my team slows down the tray is by using a remap function that takes your sensor range:
[tray down pos, tray up pos]
and converts it to [motor start speed, motor end speed]
by using this formula: (x - a) * [(c - d)/(a - b)] + c
where x is your current sensor pos, a is your down tray pos, b is your up tray point and c and d are your start and end motor speeds.
On the other hand, you could use a pid loop, which is more complicated, and have a low kP and some kI and kD to make your system work.
Good luck!
I made a function that makes the tilter speed a function of degrees rotated by the motor.
I think your function would work great. I made a sample of your fucntion below and i just wated to know if i was on the right path. (Sorry i am kind of new no vex and c++).
void tilterSpeed(double trayFinal){ // degrees of final position
double CurrentPosition = Tilter.position(degrees); // the current position
double motorSpeed = 0.0; // just defining the motor speed
while (CurrentPosition < trayFinal ){ // a while loop that converts the motor speed to the current position in degrees
double CurrentPosition = Tilter.position(degrees);
motorSpeed += CurrentPosition;
Tilter.spin(fwd, motorSpeed, velocityUnits::pct); // make the motors move based on the new motor speed made
}
}
/*---------------------------------------------------------------------------*/
/* */
/* Autonomous Task */
/* */
/* This task is used to control your robot during the autonomous phase of */
/* a VEX Competition. */
/* */
/* You must modify the code to add your own robot specific commands here. */
/*---------------------------------------------------------------------------*/
void autonomous(void) {
tilterSpeed(100); // calling the fucntion
The general concept behind this is known as Motion Profiling (defining your velocity as a function of your position)
I personally use a cosine motion profile, something like this:
velocity = cos(pi/2 * progress)
As progress goes to 1, velocity goes to zero, and the Point of Inflection of the cosine function helps to mitigate the intertia of the stack
Or, you could do something very simple –– a proportional loop.
First find the difference between the target position and current position so you can scale the voltage (i.e. proportion)
error = targetPos - currentPos;
Then set that value to the voltage or velocity of the motor (your choice, it’s a bit arbitrary), and also scale the value down so that it aligns with the units used in the motor so you can see a change in speed.
setMotorSpeed(error*scaler);
Lastly, throw the above code into a while loop
while(buttonPressed && !target){
error = targetPos - currentPos;
setMotorSpeed(error*scalar);
delay(20);
}
The scalar should be a small value. Start with .5
and work up or down depending if the target is ever reached or if it’s still too fast at the end of the movement.
What I just explained is called a p-loop. I used scalar
instead of Kp
as a name because it should make more intuitive sense. It’s really just a convention of standard to use Kp
. All error
is is the difference between the target and current position of the tilter which changes over time (i.e. gets smaller and smaller, and so does the velocity of the motor over time).
I hope this makes intuitive sense, I tried to explain it as simple as I could.
Thank You so much. Your solution is very well explained and i understand it really well. I only had one clarification question. Would i define the variables outside of the while loop for user contol or inside the while loop for user control.
Like This:
void usercontrol(void) {
// User control code here, inside the loop
while (1) {
int targetPos = 10.0;
int tilterPosition = Tilter.position(degrees);
double scalar = 0.0;
while( ButtonR1 && !targetPos){
error = targetPos - tilterPosition;
Tilter.spin(forward,(error*scalar) , voltageUnits::volt);
vex::task::sleep(20);
}
Or like this:(with the variables in between user control and while button is pressed)
void usercontrol(void) {
// User control code here, inside the loop
int targetPos = 10.0;
int tilterPosition = Tilter.position(degrees);
double scalar = 0.0;
while (1) {
while( ButtonR1 && !targetPos){
error = targetPos - tilterPosition;
Tilter.spin(forward,(error*scalar) , voltageUnits::volt);
vex::task::sleep(20);
}
Thank You so much for your help. I feel like I actually understand now!
It’s generally good practice to declare variables outside of the loop because otherwise you’d continually re-instantiate and declare those variables. I’m not sure what behavior this would cause or how it impacts anything because I’ve never done it. Also throw the whole while loop and variable declarations into a function like this:
void pLoop (){
//all your code
}
And then put that function header into the user control loop instead.
void usercontrol(void){
pLoop();
}
This will make your code cleaner and easy to read. Again, not necessary, but optimizing code is something you should be working towards. I’m glad you understood my explanation!