Programming Driver Control Help

I need help with the driver control part where the control drives foreward, backward, and turns. The problem is depending on how I alter the code the forward backward part will work but then the turn will malfunction where it tries to run the code and the wheels take turns gingerly spinning but it doesn’t do what it’s meant to and vice verse. I’m wanting to know what to change so that both the forward backward part and turning part can both operate the way they are supposed to when their specific joystick is moved. Please tell me what you think. Thanks!

#pragma region VEXcode Generated Robot Configuration
// Make sure all required headers are included.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <string.h>








#include "vex.h"








using namespace vex;




// Brain should be defined by default
brain Brain;




// START V5 MACROS
#define waitUntil(condition) \
do { \
wait(5, msec); \
} while (!(condition))




#define repeat(iterations) \
for (int iterator = 0; iterator < iterations; iterator++)
// END V5 MACROS




  // Robot configuration code.
  // Robot configuration code.
  motor L1 = motor(PORT1, ratio6_1, true);


motor L2 = motor(PORT2, ratio6_1, true);


motor L3 = motor(PORT3, ratio6_1, true);


motor R1 = motor(PORT11, ratio6_1, false);


motor R2 = motor(PORT12, ratio6_1, false);


motor R3 = motor(PORT13, ratio6_1, false);


motor Catapult = motor(PORT10, ratio6_1, true);


controller Controller1 = controller(primary);
motor_group RightDriveSmart = motor_group(R3, R2, R1);
motor_group LeftDriveSmart = motor_group(L3, L2, L1);
drivetrain Drivetrain = drivetrain(LeftDriveSmart, RightDriveSmart, 319.19, 295, 40, mm, 1);


// Helper to make playing sounds from the V5 in VEXcode easier and
// keeps the code cleaner by making it clear what is happening.
void playVexcodeSound(const char * soundName) {
  printf("VEXPlaySound:%s\n", soundName);
  wait(5, msec);
}


// define variable for remote controller enable/disable
bool RemoteControlCodeEnabled = true;
// define variables used for controlling motors based on controller inputs
bool DrivetrainLNeedsToBeStopped_Controller1 = true;
bool DrivetrainRNeedsToBeStopped_Controller1 = true;


// define a task that will handle monitoring inputs from Controller1
int rc_auto_loop_function_Controller1() {
  // process the controller input every 20 milliseconds
  // update the motors based on the input values
  while (true) {
    if (RemoteControlCodeEnabled) {
      // calculate the drivetrain motor velocities from the controller joystick axies
      // left = Axis3 + Axis1
      // right = Axis3 - Axis1
      int drivetrainLeftSideSpeed = Controller1.Axis3.position() + Controller1.Axis1.position();
      int drivetrainRightSideSpeed = Controller1.Axis3.position() - Controller1.Axis1.position();
      // check if the value is inside of the deadband range
      if (drivetrainLeftSideSpeed < 5 && drivetrainLeftSideSpeed > -5) {
        // check if the left motor has already been stopped
        if (DrivetrainLNeedsToBeStopped_Controller1) {
          // stop the left drive motor
          LeftDriveSmart.stop();
          // tell the code that the left motor has been stopped
          DrivetrainLNeedsToBeStopped_Controller1 = false;
        }
      } else {
        // reset the toggle so that the deadband code knows to stop the left motor nexttime the input is in the deadband range
        DrivetrainLNeedsToBeStopped_Controller1 = true;
      }
      // check if the value is inside of the deadband range
      if (drivetrainRightSideSpeed < 5 && drivetrainRightSideSpeed > -5) {
        // check if the right motor has already been stopped
        if (DrivetrainRNeedsToBeStopped_Controller1) {
          // stop the right drive motor
          RightDriveSmart.stop();
          // tell the code that the right motor has been stopped
          DrivetrainRNeedsToBeStopped_Controller1 = false;
        }
      } else {
        // reset the toggle so that the deadband code knows to stop the right motor next time the input is in the deadband range
        DrivetrainRNeedsToBeStopped_Controller1 = true;
      }
      // only tell the left drive motor to spin if the values are not in the deadband range
      if (DrivetrainLNeedsToBeStopped_Controller1) {
        LeftDriveSmart.setVelocity(drivetrainLeftSideSpeed, percent);
        LeftDriveSmart.spin(forward);
      }
      // only tell the right drive motor to spin if the values are not in the deadband range
      if (DrivetrainRNeedsToBeStopped_Controller1) {
        RightDriveSmart.setVelocity(drivetrainRightSideSpeed, percent);
        RightDriveSmart.spin(forward);
      }
    }
    // wait before repeating the process
    wait(20, msec);
  }
  return 0;
}


task rc_auto_loop_task_Controller1(rc_auto_loop_function_Controller1);


#pragma endregion VEXcode Generated Robot Configuration


////////////////////////////////////////////////////////
There is code inbeteween the top section and bottom section but it is irrelevant so I removed it. The code missing is preauton and auton stuff, I didn't want to make this overly long.
////////////////////////////////////////////////////
void userControl(void) {
  Brain.Screen.clearScreen();
  // place driver control in this while loop
  while (true) {


    // "when driver control" hat block


    if (Controller1.Axis3.position() > 10) {
      L1.spin(forward, Controller1.Axis3.position(), volt);
      L2.spin(forward, Controller1.Axis3.position(), volt);
      L3.spin(forward, Controller1.Axis3.position(), volt);
      R1.spin(forward, Controller1.Axis3.position(), volt);
      R2.spin(forward, Controller1.Axis3.position(), volt);
      R3.spin(forward, Controller1.Axis3.position(), volt);
    }


    // "when driver control" hat block
    else if (Controller1.Axis1.position() > 10) {
      L1.spin(reverse, Controller1.Axis1.position(), volt);
      L2.spin(reverse, Controller1.Axis1.position(), volt);
      L3.spin(reverse, Controller1.Axis1.position(), volt);
      R1.spin(forward, Controller1.Axis1.position(), volt);
      R2.spin(forward, Controller1.Axis1.position(), volt);
      R3.spin(forward, Controller1.Axis1.position(), volt);
    } else {
      L1.stop();
      L2.stop();
      L3.stop();
      R1.stop();
      R2.stop();
      R3.stop();
    }
    // "when driver control" hat block
    Brain.Screen.clearScreen();


    if (Controller1.ButtonX.pressing()) {
      Catapult.spin(forward);
      waitUntil(Controller1.ButtonA.pressing());
    } else {
      Catapult.stop();
    }


    // Start the driver control tasks....


    wait(20, msec);
  }
}


int main() {
  // create competition instance
  competition Competition;


  // Set up callbacks for autonomous and driver control periods.
  Competition.autonomous(autonomous);
  Competition.drivercontrol(userControl);


  // Run the pre-autonomous function.
  preAutonomous();


  // Prevent main from exiting with an infinite loop.
  while (true) {
    wait(100, msec);
  }
}

Just in case you somehow don’t know, (don’t take offense in either situation) you should be able to set up a drivetrain in your sidebar.
Otherwise, I don’t think I’m too fit to help with this.
Also, some tips:

  • Show relevant code spot only to make things more concise
  • Elaborate on issue
  • Note more things you’ve already tried

Also, what are you trying to accomplish with this? A smoother version of a regular drivetrain? X/Mecanum Drive?

I’m not sure if I myself can give a solid answer or not, but I would like to help.

They’re using a 6 motor drivetrain, which you can’t do with the config in the sidebar

But to answer your question, I can see a couple problems in your code. First of all, it seems like you have two different functions which are trying to control the drivetrain, one called rc_auto_loop_function_Controller1 and one called userControl. If they are both trying to control the robot at the same time they will be sending conflicting messages to the motors. Also, in userControl, your drive and turn commands are conflicting with each other too. Here’s the relevant part of the code:

if (Controller1.Axis3.position() > 10)
{
    L1.spin(forward, Controller1.Axis3.position(), volt);
    L2.spin(forward, Controller1.Axis3.position(), volt);
    L3.spin(forward, Controller1.Axis3.position(), volt);
    R1.spin(forward, Controller1.Axis3.position(), volt);
    R2.spin(forward, Controller1.Axis3.position(), volt);
    R3.spin(forward, Controller1.Axis3.position(), volt);
}
else if (Controller1.Axis1.position() > 10)
{
    L1.spin(reverse, Controller1.Axis1.position(), volt);
    L2.spin(reverse, Controller1.Axis1.position(), volt);
    L3.spin(reverse, Controller1.Axis1.position(), volt);
    R1.spin(forward, Controller1.Axis1.position(), volt);
    R2.spin(forward, Controller1.Axis1.position(), volt);
    R3.spin(forward, Controller1.Axis1.position(), volt);
}
else
{
    L1.stop();
    L2.stop();
    L3.stop();
    R1.stop();
    R2.stop();
    R3.stop();
}

because the code for drivetrain controls is in an if else if like this, you can only turn if you are not driving. It would be best if you can turn and drive at the same time so you don’t have to constantly stop moving. You also can’t drive backwards or turn left because the conditions for the if statements require the values to be greater then 10, and negative numbers are less then 10. Here’s the way joystick controls are usually done:

float driveSpeed = axis3.position();
float turnSpeed = axis1.position();

leftDrivetrain.spin(driveSpeed + turnSpeed);
rightDrivetrain.spin(driveSpeed - turnSpeed);

This code is not actual C++ code, and will not work if you just copy-paste it into your code. It’s your job to turn it into functioning code in your program. The code combines the turn and drive joystick inputs so that you can do both at the same time, and also allows you to move in every direction and takes up less lines.

Lastly, I’d recommend using a sensor to detect if the catapult should stop instead of having to time it with a button. It would also be better if you can drive the robot while the catapult is spinning, instead of having to stop it to drive. Maybe you can move the stop command out of the else, and instead make another if to control stopping? I’ll leave that to you to figure out.

4 Likes

What @iseau395 side is very good advice. if you want to use volts as your units you will need to convert them as volts go -12 to 12 on the motors whereas position from the joysticks goes from -100 to 100. To fix this, you could change the units to percent or convert the position value to be between -12 and 12.

3 Likes

Correct me if i’m wrong, but can’t you somehow set up a 2 motor AND a 4 motor drivetrain and just do some extra code to make it 6 motor? Or am i completely wrong?

Thank you iseau395 for your helpful input. I implemented what you suggested and this is what my code looks like now:

void userControl(void) {
  Brain.Screen.clearScreen();
  // place driver control in this while loop
  while (true) {


rc_auto_loop_function_Controller1();
  bool RemoteControlCodeEnabled = true;
  while (RemoteControlCodeEnabled){
    float driveSpeed = Controller1.Axis3.position();
    float turnSpeed = Controller1.Axis1.position();

  LeftDriveSmart.spin(forward,driveSpeed + turnSpeed,volt);
RightDriveSmart.spin(forward,driveSpeed - turnSpeed,volt);
  }

    if (Controller1.ButtonX.pressing()) {
      Catapult.spin(forward);
      waitUntil(Controller1.ButtonA.pressing());
       Catapult.stop();
    } 

    // Start the driver control tasks....
 wait(20, msec);
  }
}

Would this make sense to get the turning and driving to work simultaneously?
Also with this, would usercontrol and rc_auto_loop_function_Controller1 still conflict with eachother or not because of the callback?

Also you said that you would reccomend changing the code so the I don’t have to stop the catapult to drive. I’ve been thinking about it a lot and I don’t know how to get it that way, but for now that’s ok with me because I only intend to use the catapult while stationairy.

I would recommend removing rc_auto_loop_function_Controller1 entirely, because it looks like it is an auto-generated function which you don’t need if you can make your own version. Also, it looks like you have two while loops inside of each other, but you only need one. As it is right now, your catapult code will never run because it is outside of the inner while loop which runs forever. Basically you should remove these three lines:

rc_auto_loop_function_Controller1();
bool RemoteControlCodeEnabled = true;
while (RemoteControlCodeEnabled) {

and the curly bracket after the drivetrain commands. I would also recommend doing what @EcstaticPilot said and scale the inputs from the controller from being from -100 to 100 to instead being from -12 to 12. You can do this by dividing the joystick values by 100 then multiplying them by 12 before you tell the motor to move at that speed. Other then that though, your drivetrain control code looks good.

As for the catapult code, how I would do it is I would split the stop and spin parts into seperate ifs, and remove the waitUntil. This way you would have a separate “if button X pressing then spin catapult” bit and a “if button A pressing then stop catapult” bit. Here’s some pseudocode:

if (buttonX) {
    spinCatapult();
}

if (buttonA) {
    stopCatapult();
}

You could, but that also makes it harder to use in the long run because you need to send commands to both the 2 motor and 4 motor drivetrains instead of sending them to just the one 6 motor drive. Imo it’s a lot simpler to not use the GUI config and just use text configuration for devices once you know how to do it.

1 Like

Thank you for all your help! My code now looks like this:

void userControl(void) {
  Brain.Screen.clearScreen();
  // place driver control in this while loop
  // Start the driver control tasks....
  while (true) {

    float driveSpeed = (Controller1.Axis3.position()/ 100.0) * 12.0;
    float turnSpeed = (Controller1.Axis1.position() / 100.0) * 12.0;

  LeftDriveSmart.spin(forward,driveSpeed + turnSpeed,volt);
RightDriveSmart.spin(forward,driveSpeed - turnSpeed,volt);
  

    if (Controller1.ButtonX.pressing()) {
    Catapult.spin(forward);
}
    if (Controller1.ButtonA.pressing()) {
    Catapult.stop();
}

 wait(20, msec);
  }
}

This looks right to me, just checking to make sure it looks good.
Thanks again!

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.