How to adjust speed of drivetrain with a button?

I am trying to make our robot speed adjustable if we click on a button. For example, If I were to click X, it should go to 100% speed and if I were to click B, it should go to 50% speed. I am using the standard arcade control code. Whenever I run my program, it ends up downloading perfectly fine, but the button for changing the speed to 50% speed doesn’t work.

Here is my code that I am trying to get to work:

if(Controller1.ButtonX.pressing()){
    int y = (1);
}
else if(Controller1.ButtonB.pressing()){
    int y = (2);
}
    else {
}
leftFront.spin(directionType::rev, (Controller1.Axis3.position() + Controller1.Axis4.position())/y, velocityUnits::pct); //(Axis3+Axis4)/2
leftRear.spin(directionType::rev, (Controller1.Axis3.position() + Controller1.Axis4.position())/y, velocityUnits::pct); //(Axis3+Axis4)/2
rightRear.spin(directionType::fwd, (Controller1.Axis3.position() - Controller1.Axis4.position())/y, velocityUnits::pct);//(Axis3-Axis4)/2
rightFront.spin(directionType::fwd, (Controller1.Axis3.position() - Controller1.Axis4.position())/y, velocityUnits::pct);//(Axis3-Axis4)/2

i’m not a programmer but should you put the if else things in a while loop?

Oh ya I forgot to add, there is a while loop in the program. I forgot to put it in the snip.

If your going for one press and not holding it used the pressed command. However, you need to create a callback and stuff and I have no idea how to do it. Maybe someone else does?

To directly answer your question, you can employ button edge detection to correct detect when a button changes states. PROS and OkaipiLib have this built in, but it should be relatively easy to implement in alternative environments (I’m on my phone rn, but you can DM later if you want more info)

However, If I’m understanding correctly, what you’re really trying to do is allow yourself times when you need greater precision over controlling your chassis, while still having times when you can use the full power of your chassis.

The most common way I’ve seen solve this issue is using a logistic or sinusoidal curve on their drive control. Basically, you run your joystick input through a specific function (in the mathematical sense) to give yourself greater control.

For example, I use a logistic curve to modify my joystick values. When I put my joystick to 50%, my drivetrain only moves at about 30% velocity. When I put it at 100%, the motor still go 100%, but I am afforded greater levels of control.

The general idea is that there are many many cases when you need fine motor control between 0 and 50% (for example), but there are very few cases where you want, say 70% over just 100%.

4 Likes

If you could help me set up a logistic curve that would be a huge help. You don’t have to do it know, but when you have time any kind of guide or something would be great.

Sure. What you want to do is define a pure function in your code that implements your curve of choice. When I was experimenting with this, I used a demo similar to this to experiment with modifying the main variables.

Once you know your constants, you’ll want to implement a logistic function in your environment. For reference, here’s my implementation of a logistic curve in C++ (PROS, but this is portable enough to work on VexCode as well)

double logistic(double step, double max, double growth, double midpoint, double deadband)
{
    // Sanity deadbands, because a perfect logistic curve is impossible
    if (abs(step) < abs(deadband))
        return 0.0;
    if (abs(step) > 1.0 - deadband)
        return 1.0;

    return max * sgn(step) / (1.0 + exp(-growth * (abs(step) - midpoint)));
}

Then, in your driver control loop, you’ll want to run your joystick values through this function before setting motor velocity.

double forward = logistic(
            controller.getAnalog(ControllerAnalog::rightX),
            1, 7.3, 0.5, 0.1);

double turn = logistic(
            controller.getAnalog(ControllerAnalog::leftY),
            1, 7.3, 0.5, 0.1);

drive::arcade(forward, turn);
2 Likes

Edge detection should have no bearing on what you are trying to do (all you are doing is setting an int’s value, repeating that action should change nothing). I believe your real problem is that “y” is out of scope from where you set the motor’s speeds. However I can’t be sure without seeing the rest of your program.

The basic idea is that anything inside a set of brackets cannot be accessed outside of those brackets. And since your two variables y and y are both in separate scopes (the two if()'s), they are treated as two separate variables. Your motor.spin() call is also outside of the scope of the if statements containing the variables, so the motor.spin() call can’t access the y variable. If you make the declaration outside of the if() statements though, it should bring your y variable back into scope. You can read more about scope here. I would also advise naming your variable something that relates more to its function like “reduction” or something. Naming them all single letters will get confusing (and letters will eventually run out).

Also what MayorMonty said is true. You should probably use a math function (equation) to modify your joystick values to something easier to control instead of using speed reduction buttons (you want all the speed and power you can get to win).

1 Like

Edge detection is relevant for toggling a state in a single button (for example, an enable slow mode function).

1 Like

Thank you very much!

This is the extent of my programming knowledge too

I am a little bit confused…would you please explain this to me in layman’s terms?

guess were all making things up along the way