Motors Won't Run The Same When I Use Bumpers Instead Of Joysticks

Hello Vex World! We’ve been coding a simple catapult program and have encountered a problem. It has an Intake built into it and the motors running in the catapult’s direction has dominance. However even though I tell the two motors to run at 100 percent, they won’t pull through to trigger the slip gear, even if I tell it to run way more degrees than it needs to. Then if I run a simple joystick to move the catapult at full speed, it works just fine. I’ve attached the program below and hope someone can tell me why the motors won’t run at full speed for how long I need them to.

#include "robot-config.h"


int Catapult = 0;
bool Intake = 0;

 


        ////////////////
        //   Switch   //
        ////////////////


void SwitchFunction()
{
    
        Brain.Screen.clearScreen();
        Brain.Screen.setCursor(1,1);
        Brain.Screen.print(Catapult);
        Brain.Screen.print(Intake);
        Brain.Screen.render();    
         
        if(Catapult == 0)
        {
            Controller1.rumble(".");
            Controller1.Screen.clearLine();            
            Controller1.Screen.print("Tap To Load Catapult");
            
            if(Intake == 0)
            {
            LSwitch.stop();
            RSwitch.stop();
            }
            else if(Intake == 1)
            {
            LSwitch.stop();
            RSwitch.stop();
            }
        }
        else if(Catapult == 1)
        {
            Controller1.rumble(".");
            Controller1.Screen.clearLine();
            Controller1.Screen.print("Tap To Use Intake");
            
            LSwitch.setReversed(false);
            RSwitch.setReversed(true);
            
            if(Intake == 0)
            {
                LSwitch.rotateFor(500,vex::rotationUnits::deg,100,vex::velocityUnits::pct);
                RSwitch.rotateFor(500,vex::rotationUnits::deg,100,vex::velocityUnits::pct);
            }
            else if(Intake == 1)
            {
                LSwitch.rotateFor(500,vex::rotationUnits::deg,100,vex::velocityUnits::pct);
                RSwitch.rotateFor(500,vex::rotationUnits::deg,100,vex::velocityUnits::pct);
            }        
        }
        else if(Catapult == 2)
        {
            Controller1.rumble(".");
            Controller1.Screen.clearLine();
            Controller1.Screen.print("TAP TO FIRE!");
            
            LSwitch.setReversed(true);
            RSwitch.setReversed(false);
            
            if(Intake == 0)
            {
                LSwitch.stop();
                RSwitch.stop();
            }
            else if(Intake == 1)
            {
                LSwitch.spin(vex::directionType::fwd,200,vex::velocityUnits::rpm);
                RSwitch.spin(vex::directionType::fwd,200,vex::velocityUnits::rpm);            
            } 
        }
        else if(Catapult == 3)
        {
            Controller1.rumble(".");
            Controller1.Screen.clearLine();
            Controller1.Screen.print("Tap To Load Catapult");
            
            LSwitch.setReversed(false);
            RSwitch.setReversed(true);
            
            if(Intake == 0)
            {
                LSwitch.rotateFor(90,vex::rotationUnits::deg,100,vex::velocityUnits::pct);
                RSwitch.rotateFor(90,vex::rotationUnits::deg,100,vex::velocityUnits::pct);
            }
            else if(Intake == 1)
            {
                LSwitch.rotateFor(90,vex::rotationUnits::deg,100,vex::velocityUnits::pct);
                RSwitch.rotateFor(90,vex::rotationUnits::deg,100,vex::velocityUnits::pct);
            }
        }
}    




        ///////////////////
        //     DRIVE     //
        ///////////////////


void DriveFunction() 
{
    while(true)    
    {
        //left side drive
        LMotor1.spin(vex::directionType::fwd, Controller1.Axis3.value(), vex::velocityUnits::pct);
        LMotor2.spin(vex::directionType::fwd, Controller1.Axis3.value(), vex::velocityUnits::pct);
    
        //right side drive
        RMotor1.spin(vex::directionType::fwd, Controller1.Axis2.value(), vex::velocityUnits::pct);
        RMotor2.spin(vex::directionType::fwd, Controller1.Axis2.value(), vex::velocityUnits::pct);        
    }
}
    




        ////////////////////
        //     Intake     //
        ////////////////////
      
void ChangeIntake()
{   
    ::Intake = !Intake;
    SwitchFunction();
}




        ////////////////////
        //    Catapult    //
        ////////////////////

void ChangeCatapult()
{   
    if(Catapult == 0)
    {
        Catapult = 1;
    }
    else if(Catapult == 1)
    {
        Catapult = 2;
    }
    else if(Catapult == 2)
    {
        Catapult = 3;
    }
    else if(Catapult == 3)
    {
        Catapult = 1;
    }
    SwitchFunction();
}


int main() 
{
           
    Catapult = 0;
    Intake = 0;
    
    LMotor1.setStopping(vex::brakeType::brake);
    LMotor2.setStopping(vex::brakeType::brake);
    RMotor1.setStopping(vex::brakeType::brake);
    RMotor2.setStopping(vex::brakeType::brake);
    RMotor1.setReversed(true);          
    RMotor2.setReversed(true);
    
    LSwitch.setStopping(vex::brakeType::coast);
    RSwitch.setStopping(vex::brakeType::coast);
    
    Controller1.ButtonL1.pressed(ChangeIntake);
    Controller1.ButtonR1.pressed(ChangeCatapult);
    
    vex::thread drivethread (DriveFunction);
    drivethread.detach();
    
    
 }


Gucci Bot.vex (9 KB)

I don’t see the program.

It should be there now.

Yes, it’s there now. I’m not sure I’ve spotted what you’re asking about yet, but I have found some oddities. Perhaps fixing these will do the trick.

You repeatedly use

if(Intake == 0)
            {
            }
else if(Intake == 1)
            {
            }

while placing exactly the same code inside both parts of your if statement. If you want to run that code, just do it without an if statement. But, as I suspect, if you meant to do two different things, you haven’t actually written two different things to do. Only your Catapult == 2 actually has something different in the two parts.

Another oddity is that you’re looking for Catapult == 0, but you never return to Catapult = 0. And because you increment Catapult before ever calling SwitchFunction, you’ll never have that 0 you’re looking for. Did you mean to go back to 0 inside ChangeCatapult instead of going back to 1? Also, it’s a lot shorter to code something like

if(Catapult == 3)
   Catapult = 0;
else
   Catapult++; // or if it's clearer to you Catapult = Catapult + 1;

Probably most important though, is that I don’t see anything keeping main() going. You don’t want main() to end. This is an important thing to remember when coding with events like you are. You only have to set the function for the event once, so you’re not sticking your checks for buttons inside something like while(true){}, but you still have to keep main() running to keep checking for the events.

With VCS, if main exits, other tasks will continue to run. We have the ability to change that behavior when VCS compiles the program, but that’s how it works presently, I realize it’s not typical. So the code below will allow foo to run until the program is stopped.

int foo() {
  int count = 0;
  while(1) {
    Brain.Screen.printAt( 10, 50, "Foo %d", count++ );
    // Allow other tasks to run
    this_thread::sleep_for(10);
  }
}

int main() {
  vex::thread t( foo );
}

Cool. Good to know, especially since it’s atypical. But that still brings up the question: If main() ends, do things confined to main continue to run? So if we have someButton.pressed(someFunction) in main() and we let main() end while other threads continue, will the event still trigger someFunction now that main() has ended?

I ask because I didn’t actually comment on other tasks still running, but rather things in main() and not in other tasks still running after main() is being allowed to end.

So code like this


Controller1.ButtonL1.pressed(ChangeIntake);

registers an event handler ( ChangeIntake ) on the controller buttonL1, it fires when the button is pressed.

An event handler is a function called from its own task*, the task is blocked on a semaphore waiting for the event to fire and unlock the semaphore allowing the event handler to run. The event cannot fire again until the event handler has completed. The event handler can be registered anywhere, in main, a function called by main or any task started by main or another task. Once registered, further event handlers can also be registered and they will all fire.

(had to edit this as I explained my own event handling system incorrectly :frowning: )

In addition to tasks and events, we also have a timer system where a timer can be set to fire an event in the future. The timer is a one shot action (that is, it runs the code in the timer event handler once), however, a timer event handler can re-arm itself.

There are a fixed maximum number of tasks, events, and timers that vexos can support. The number is not important and has been set sufficiently high for any practical code that may be needed to program a V5 robot.

Here is some more code that builds on what I posted earlier.

void touchHandler() {
    Brain.Screen.printAt( 10, 80, "pressed " );
}
void releaseHandler() {
    // just for fun !
    Brain.Screen.printAt( 10, 80, "released -" );
    this_thread::sleep_for(100);
    Brain.Screen.printAt( 10, 80, "released \\" );
    this_thread::sleep_for(100);
    Brain.Screen.printAt( 10, 80, "released |" );
    this_thread::sleep_for(100);
    Brain.Screen.printAt( 10, 80, "released /" );
    this_thread::sleep_for(100);
    Brain.Screen.printAt( 10, 80, "released -" );
    this_thread::sleep_for(200);
    for( int i=0;i<200;i+=10) {
      Brain.Screen.printAt( 10-i, 80, "released -  " );
      this_thread::sleep_for(40);
    }
}

int myTask() {
  int count = 0;

  while(1) {
    Brain.Screen.printAt( 10, 50, "myTask %d", count++ );
    // Allow other tasks to run
    this_thread::sleep_for(10);
  }
}

void myEvent() {
    static int count = 0;
    Brain.Screen.printAt( 10,100, "myEvent %d", count++ );

    // re-arm
    timer().event( myEvent, 1000 );
}

int main() {
  // add thread
  vex::thread t1( myTask );

  // add a couple of event handlers
  Brain.Screen.pressed( touchHandler );
  Brain.Screen.released( releaseHandler );
  
  // create an event to be called in 2 seconds
  // event is static method
  timer().event( myEvent, 2000 );
  
  // main exits but everything else still runs
  // it's preferable to add while loop with sleep
  // at this point as it makes code clearer and would be more portable.
}

*task and thread are more or less interchangeable

Based on what you said,


int main()
{
Controller1.ButtonL1.pressed(ChangeIntake);
}

would theoretically run forever. So some earlier examples of code people showed that kept main() running really didn’t need to, right?

So, @9409Robotics , ignore my suggestion to keep main() running, but look at the other two suggestions.

It’s not that main runs forever, it’s the event handler that runs forever.

Now, I’m not recommending this is the preferred way of working, all our examples will use a loop at the end of main. I’m also not sure what happens with RobotMesh, it’s using a mostly compatible API to VCS but I forget where we are on the issue of main exiting.

Right. I meant the program would run forever, not main run forever.

Hi, I’m the guy who programmed this and just got my account approved so I can actually partake in this, YAY! Anyways, It’s not the problem of the code not running, it’s that once I set the motors to “rotateFor” a certain amount of degrees, it won’t run at 100% power as I specified for it to do even though the cortex says they are running at 100% power. And then once I just link any button straight up to the motors but do not use a “rotateFor” function and instead I use the “spin” function, it runs at 100% power just fine. So could you find why it might be doing that (cutting power) specifically?

Can you attach the VCS program (the .vex file) that does not work so I don’t have to re-enter all the motor config etc.

ya sure, here ya go I will also give you a simplified updated version of the code as well.


vex::brain Brain;

vex::motor LMotor1 = vex::motor(vex::PORT1,vex::gearSetting::ratio18_1);
vex::motor LMotor2 = vex::motor(vex::PORT2,vex::gearSetting::ratio18_1);
vex::motor RMotor1 = vex::motor(vex::PORT9,vex::gearSetting::ratio18_1);
vex::motor RMotor2 = vex::motor(vex::PORT10,vex::gearSetting::ratio18_1);
vex::motor LSwitch = vex::motor(vex::PORT4,vex::gearSetting::ratio18_1);
vex::motor RSwitch = vex::motor(vex::PORT7,vex::gearSetting::ratio18_1);

vex::controller Controller1 = vex::controller();
vex::controller Controller2 = vex::controller(vex::controllerType::partner);

#include "robot-config.h"


int Catapult = 0;
bool Intake = 0;

 


        ////////////////
        //   Switch   //
        ////////////////


void SwitchFunction()
{
    
        Brain.Screen.clearScreen();
        Brain.Screen.setCursor(1,1);
        Brain.Screen.print(Catapult);
        Brain.Screen.print(Intake);
        Brain.Screen.render();    
         
        if(Catapult == 0)
        {
            Controller1.rumble(".");
            Controller1.Screen.clearLine();            
            Controller1.Screen.print("Tap To Load Catapult");
            
            LSwitch.stop();
            RSwitch.stop();
        }
        else if(Catapult == 1)
        {
            Controller1.rumble(".");
            Controller1.Screen.clearLine();
            Controller1.Screen.print("Tap To Use Intake");
            
            LSwitch.setReversed(false);
            RSwitch.setReversed(true);

            LSwitch.rotateFor(500,vex::rotationUnits::deg,100,vex::velocityUnits::pct);
            RSwitch.rotateFor(500,vex::rotationUnits::deg,100,vex::velocityUnits::pct);
            
            Catapult = 2;
        }
        else if(Catapult == 2)
        {
            Controller1.rumble(".");
            Controller1.Screen.clearLine();
            Controller1.Screen.print("TAP TO FIRE!");
            
            LSwitch.setReversed(true);
            RSwitch.setReversed(false);
            
            if(Intake == 0)
            {
                LSwitch.stop();
                RSwitch.stop();
            }
            else if(Intake == 1)
            {
                LSwitch.spin(vex::directionType::fwd,200,vex::velocityUnits::rpm);
                RSwitch.spin(vex::directionType::fwd,200,vex::velocityUnits::rpm);            
            } 
        }
        else if(Catapult == 3)
        {
            Controller1.rumble(".");
            Controller1.Screen.clearLine();
            Controller1.Screen.print("Tap To Load Catapult");
            
            LSwitch.setReversed(false);
            RSwitch.setReversed(true);

            LSwitch.rotateFor(90,vex::rotationUnits::deg,100,vex::velocityUnits::pct);
            RSwitch.rotateFor(90,vex::rotationUnits::deg,100,vex::velocityUnits::pct);
            
            Catapult = 0;
        }
}    




        ///////////////////
        //     DRIVE     //
        ///////////////////


void DriveFunction() 
{
    while(true)    
    {
        //left side drive
        LMotor1.spin(vex::directionType::fwd, Controller1.Axis3.value(), vex::velocityUnits::pct);
        LMotor2.spin(vex::directionType::fwd, Controller1.Axis3.value(), vex::velocityUnits::pct);
    
        //right side drive
        RMotor1.spin(vex::directionType::fwd, Controller1.Axis2.value(), vex::velocityUnits::pct);
        RMotor2.spin(vex::directionType::fwd, Controller1.Axis2.value(), vex::velocityUnits::pct);        
    }
}
    




        ////////////////////
        //     Intake     //
        ////////////////////
      
void ChangeIntake()
{   
    ::Intake = !Intake;
    SwitchFunction();
}




        ////////////////////
        //    Catapult    //
        ////////////////////

void ChangeCatapult()
{   
    if(Catapult == 3)
    {
        Catapult = 1;
    }
    else
    {
        Catapult++;
    }
    SwitchFunction();
}


int main() 
{
           
    Catapult = 0;
    Intake = 0;
    
    LMotor1.setStopping(vex::brakeType::brake);
    LMotor2.setStopping(vex::brakeType::brake);
    RMotor1.setStopping(vex::brakeType::brake);
    RMotor2.setStopping(vex::brakeType::brake);
    RMotor1.setReversed(true);          
    RMotor2.setReversed(true);
    
    LSwitch.setStopping(vex::brakeType::coast);
    RSwitch.setStopping(vex::brakeType::coast);
    
    Controller1.ButtonL1.pressed(ChangeIntake);
    Controller1.ButtonR1.pressed(ChangeCatapult);
    
    vex::thread drivethread (DriveFunction);
    drivethread.detach();
    
    
 }

ok, so I don’t know exactly what your robot looks like, but I assume that LSwitch and RSwitch are perhaps two motors mechanically connected together. When you have code like this.

 
LSwitch.rotateFor(500,vex::rotationUnits::deg,100,vex::velocityUnits::pct);
RSwitch.rotateFor(500,vex::rotationUnits::deg,100,vex::velocityUnits::pct);

you are asking the LSwitch motor to move to 500 deg followed by the RSwitch, the LSwitch motor needs to complete its move before the RSwitch motor will start as the rotateFor call is blocking. Try changing those lines of code to this form


 LSwitch.rotateFor(500,vex::rotationUnits::deg,100,vex::velocityUnits::pct, false);
 RSwitch.rotateFor(500,vex::rotationUnits::deg,100,vex::velocityUnits::pct);
 

The additional parameter to the first call tells the rotateFor call not to wait for the motor to get to the requested position, that allows both motors (more or less) to move at the same time.

I also see a couple of unneeded calls, for example this is probably not needed

Brain.Screen.render();

That’s a call that is only needed when updating many different areas of the screen quickly, it reduces flicker from screen redraw.

I will attach a revised version I modified slightly.

int Catapult = 0;
bool Intake = 0;

 
        ////////////////
        //   Switch   //
        ////////////////

int debugTask() {
  while(1) {
    Brain.Screen.printAt( 10, 100, "LSwitch Pos: %5.2f vel: %5.2f     ", LSwitch.rotation(rotationUnits::deg), LSwitch.velocity( velocityUnits::rpm ) );
    Brain.Screen.printAt( 10, 120, "RSwitch Pos: %5.2f vel: %5.2f    ", RSwitch.rotation(rotationUnits::deg), RSwitch.velocity( velocityUnits::rpm ) );
    this_thread::sleep_for(50);
  }
  
  return(0);
}

void SwitchFunction()
{
        static int count = 1;
        Brain.Screen.printAt(10, 120, "SwitchFunction %d", count++ );
        
        //Brain.Screen.clearScreen();
        Brain.Screen.setCursor(1,1);
        Brain.Screen.print(Catapult);
        Brain.Screen.print(Intake);
        //Brain.Screen.render();    
         
        if(Catapult == 0)
        {
            Controller1.rumble(".");
            Controller1.Screen.clearLine();            
            Controller1.Screen.print("Tap To Load Catapult");
            
            LSwitch.stop();
            RSwitch.stop();
        }
        else if(Catapult == 1)
        {
            Controller1.rumble(".");
            Controller1.Screen.clearLine();
            Controller1.Screen.print("Tap To Use Intake");
            
            LSwitch.setReversed(false);
            RSwitch.setReversed(true);

            LSwitch.rotateFor(500,vex::rotationUnits::deg,100,vex::velocityUnits::pct, false);
            RSwitch.rotateFor(500,vex::rotationUnits::deg,100,vex::velocityUnits::pct);
            
            Catapult = 2;
        }
        else if(Catapult == 2)
        {
            Controller1.rumble(".");
            Controller1.Screen.clearLine();
            Controller1.Screen.print("TAP TO FIRE!");
            
            LSwitch.setReversed(true);
            RSwitch.setReversed(false);
            
            if(Intake == 0)
            {
                LSwitch.stop();
                RSwitch.stop();
            }
            else if(Intake == 1)
            {
                LSwitch.spin(vex::directionType::fwd,200,vex::velocityUnits::rpm);
                RSwitch.spin(vex::directionType::fwd,200,vex::velocityUnits::rpm);            
            } 
        }
        else if(Catapult == 3)
        {
            Controller1.rumble(".");
            Controller1.Screen.clearLine();
            Controller1.Screen.print("Tap To Load Catapult");
            
            LSwitch.setReversed(false);
            RSwitch.setReversed(true);

            LSwitch.rotateFor(90,vex::rotationUnits::deg,100,vex::velocityUnits::pct, false);
            RSwitch.rotateFor(90,vex::rotationUnits::deg,100,vex::velocityUnits::pct);
            
            Catapult = 0;
        }
}    




        ///////////////////
        //     DRIVE     //
        ///////////////////


void DriveFunction() 
{
    while(true)    
    {
        //left side drive
        LMotor1.spin(vex::directionType::fwd, Controller1.Axis3.value(), vex::velocityUnits::pct);
        LMotor2.spin(vex::directionType::fwd, Controller1.Axis3.value(), vex::velocityUnits::pct);
    
        //right side drive
        RMotor1.spin(vex::directionType::fwd, Controller1.Axis2.value(), vex::velocityUnits::pct);
        RMotor2.spin(vex::directionType::fwd, Controller1.Axis2.value(), vex::velocityUnits::pct);        
    }
}
    




        ////////////////////
        //     Intake     //
        ////////////////////
      
void ChangeIntake()
{   
    Intake = !Intake;
    SwitchFunction();
}




        ////////////////////
        //    Catapult    //
        ////////////////////

void ChangeCatapult()
{   
    if(Catapult == 3)
    {
        Catapult = 1;
    }
    else
    {
        Catapult++;
    }
    SwitchFunction();
}


int main() 
{
    Catapult = 0;
    Intake = 0;
    
    LMotor1.setStopping(vex::brakeType::brake);
    LMotor2.setStopping(vex::brakeType::brake);
    RMotor1.setStopping(vex::brakeType::brake);
    RMotor2.setStopping(vex::brakeType::brake);
    RMotor1.setReversed(true);          
    RMotor2.setReversed(true);
    
    LSwitch.setStopping(vex::brakeType::coast);
    RSwitch.setStopping(vex::brakeType::coast);
    
    Controller1.ButtonL1.pressed(ChangeIntake);
    Controller1.ButtonR1.pressed(ChangeCatapult);
    
    vex::thread drivethread (DriveFunction);
    vex::thread db( debugTask );
 }

It didn’t seem to work :confused: It’s still doing the same as before. When reeling back the catapult it still stops and is trying to keep spinning. I don’t understand why. And it’s not as if the degrees fall short either because once we turn it by hand it fires and continues to turn for a little bit.