Released Functions are not working as expected

I am currently chanign my control scheme to support mutiple drivers. My Controls are split up into two classes and two files. A header file called “ControlScheme.h” and an implementation file called “ControlScheme.cpp”. Below are those files.

ControlScheme.h

class ControllerInteraction {
public:
  static void moveLeftSide();
  static void moveRightSide();
  static void pullIntake();
  static void pushIntake();
  static void liftArm();
  static void lowerArm();
  static void extendPiston();
  static void retractPiston();
  static void stopIntake();
  static void stopArm();
  static void stopPiston();
};

class Driver {
  bool running = false;

  static void nothing();

public:
  static void setDriverCieran();
  static void setDriverCharlie();
  static void setDriverAndrew();
};

ControlScheme.cpp

#include "vex.h"
// this comment is here because they auto format formats include lines by
// alphabetical order which ■■■■■ up some dependancies
#include "ControlScheme.h"

void ControllerInteraction::moveLeftSide() {
  LeftMotors.spin(fwd, Controller.Axis3.position(pct), pct);
}

void ControllerInteraction::moveRightSide() {
  RightMotors.spin(fwd, Controller.Axis2.position(pct), pct);
}

void ControllerInteraction::pushIntake() {
  // Intake Motor fwd 50% power
  IntakeMotors.spin(fwd, 50, pct);
}

void ControllerInteraction::pullIntake() {
  // Intake Motor rev 50% power
  IntakeMotors.spin(reverse, 50, pct);
}

void ControllerInteraction::liftArm() {
  // Arm Motor Forward
  ArmMotors.spin(fwd, 50, pct);
}

void ControllerInteraction::lowerArm() {
  // Arm Motor Reverse 50% power
  ArmMotors.spin(reverse, 50, pct);
}

void ControllerInteraction::extendPiston() {
  // Piston Motor Forward 50% power
  PistonMotors.spin(fwd, 50, pct);
}

void ControllerInteraction::retractPiston() {
  // Arm Motor Forward 50% power
  PistonMotors.spin(reverse, 100, pct);
}

void ControllerInteraction::stopIntake() {
  // Stopping Left Intake Motor
  IntakeMotors.stop();
}

void ControllerInteraction::stopArm() {
  // Stopping Arm Motor
  ArmMotors.stop();
}

void ControllerInteraction::stopPiston() {
  // Stopping  Piston Motor
  PistonMotors.stop();
}

void Driver::setDriverCieran() {

  // Robot Movement Setup
  // Tank Controls
  Controller.ButtonLeft.pressed(nothing);
  Controller.ButtonX.pressed(nothing);
  Controller.ButtonA.pressed(nothing);

  Controller.Screen.clearScreen();
  Controller.Screen.print("Hello Cieran!");

  // Set the left joystick Y Axis to move the left side of the robot
  Controller.Axis3.changed(ControllerInteraction::moveLeftSide);

  // Set the right joystick Y Axis to move the right side of the robot
  Controller.Axis2.changed(ControllerInteraction::moveRightSide);

  // Arm Movement Setup
  // Controls for the arm

  // Sets the left down button to lower the robot's arms
  Controller.ButtonDown.pressed(ControllerInteraction::lowerArm);
  Controller.ButtonDown.released(ControllerInteraction::stopArm);

  // Sets the right down button(B) to raise the robot's arm
  Controller.ButtonB.pressed(ControllerInteraction::liftArm);
  Controller.ButtonB.released(ControllerInteraction::stopArm);

  // Piston Control Setup
  // Controls for the piston

  // Sets the lowest front left button to lower the piston
  Controller.ButtonL2.pressed(ControllerInteraction::retractPiston);
  Controller.ButtonL2.released(ControllerInteraction::stopPiston);

  // Sets the lowest front right button to raise the piston
  Controller.ButtonR2.pressed(ControllerInteraction::extendPiston);
  Controller.ButtonR2.released(ControllerInteraction::stopPiston);

  // Intake Control Setup
  // Controls for the intake system

  // Sets the highest front left button to have the intake system pull
  // objects towards the bot
  Controller.ButtonL1.pressed(ControllerInteraction::pullIntake);
  Controller.ButtonL1.released(ControllerInteraction::stopIntake);

  // Sets the highest front right button to have the intake system push
  // objects away from the bot
  Controller.ButtonR1.pressed(ControllerInteraction::pushIntake);
  Controller.ButtonR1.released(ControllerInteraction::stopIntake);
}

void Driver::setDriverCharlie() {
  /*  TODO:
      - Get controls from charlie and update the callbacks with his desired
      control scheme
    */
  Controller.ButtonLeft.pressed(nothing);
  Controller.ButtonX.pressed(nothing);
  Controller.ButtonA.pressed(nothing);
}

void Driver::setDriverAndrew() {
  Controller.ButtonLeft.pressed(nothing);
  Controller.ButtonX.pressed(nothing);
  Controller.ButtonA.pressed(nothing);

  Controller.Screen.clearScreen();
  Controller.Screen.print("Hello Andrew!");

  // Set the left joystick Y Axis to move the left side of the robot
  Controller.Axis3.changed(ControllerInteraction::moveLeftSide);

  // Set the right joystick Y Axis to move the right side of the robot
  Controller.Axis2.changed(ControllerInteraction::moveRightSide);

  // ~~~ Arm Movement Setup ~~~

  // sets the down buttons pressed and released functions
  Controller.ButtonDown.pressed(ControllerInteraction::lowerArm);
  Controller.ButtonDown.released(ControllerInteraction::stopArm);

  // Sets the right down button(B) to raise the robot's arm
  Controller.ButtonB.pressed(ControllerInteraction::liftArm);
  Controller.ButtonB.released(ControllerInteraction::stopArm);

  // Piston Control Setup
  // Controls for the piston

  // Sets the highest front left button to have the intake system pull
  // objects towards the bot
  Controller.ButtonL1.pressed(ControllerInteraction::pullIntake);
  Controller.ButtonL1.released(ControllerInteraction::stopIntake);

  // Sets the lowest front left button to lower the piston
  Controller.ButtonL2.pressed(ControllerInteraction::retractPiston);
  Controller.ButtonL2.released(ControllerInteraction::stopPiston);

  // Sets the highest front right button to have the intake system push
  // objects away from the bot

  Controller.ButtonR1.pressed(ControllerInteraction::pushIntake);
  Controller.ButtonR1.released(ControllerInteraction::stopIntake);

  Controller.ButtonR2.pressed(ControllerInteraction::extendPiston);
  Controller.ButtonR2.released(ControllerInteraction::stopPiston);
}

Then in the userControl function within the main.cpp file I set the driver based on button input.

void usercontrol(void) {
  // User control code here, inside the loop
  Brain.Screen.render(true);
  if (Controller.ButtonX.pressing()) {
    Driver::setDriverAndrew();
  } else if (Controller.ButtonLeft.pressing()) {
    Driver::setDriverCieran();
  } else if (Controller.ButtonA.pressing()) {
    Driver::setDriverCharlie();
  }

  while (1) {
    wait(20, msec); // Sleep the task for a short amount of time to
                    // prevent wasted resources.
  }
}

Everything in this code works but the released functions. I am fairly sure that Button.pressed(callback) creates an event and does not need to be in a while loop but I could be incorrect. I am able to switch drivers but when I start a motor it does not stop on release. If anyone could help out it would be greatly appreciated.

I just tested on the armMotor and it seems to work, add some printf statements to help debug like this.

void ControllerInteraction::liftArm() {
  // Arm Motor Forward
  printf("liftArm\n");
  ArmMotors.spin(fwd, 50, pct);
}

void ControllerInteraction::stopArm() {
  printf("stop arm\n");
  // Stopping Arm Motor
  ArmMotors.stop();
}

5 Likes

there was a download issue with the brain after a firmware update everything is working fine now. Sorry about that.

One issue you may face is that you may end up with multiple events as userControl may run more than once as you connect to the field and also when the task is started by field control. You may also end up with no control at all if you forget to hold a button down as userControl starts, I would have a backup solution for that situation.

5 Likes

thank you for pointing that out I will try to make a backup for that! I am having an issue using the printf function. Do you happen to know the correct import for that? I thought it was stdio.h but I am wrong.

1 Like

printf is in stdio.h (or cstdio), but that should already be in vex.h
you could also use std::cout, the C programmer in me just always reverts to printf.
(and terminal window may not actually be working on windows, we had a bug there for the last couple of releases, I forgot about that)

5 Likes

Oh alright I wonder why it is giving a no matching function error. Thanks for your help.

see above, if you are on windows the terminal tab is broken anyway so printf won’t show its output. On Mac it works.
sigh, unless you use it wirelessly through the controller, then it is working, sorry should have given full explanation.

5 Likes

Oh that actually explains a lot I thought I was messing up really basic output to a terminal. It is kind of odd that it works through the controller. I know this is unrelated but when I am grabbing encoder values from motors and printing it to the screen the value is either 0, 1717986918, -1717986918 or 858993459. The encoders are being reset in pre_auton


  while (1) {
    Controller.Screen.setCursor(1, 0);
    Controller.Screen.clearLine(1);
    Controller.Screen.print("L1: %d", leftWheelMotor.rotation(deg));
    Controller.Screen.setCursor(2, 0);
    Controller.Screen.clearLine(2);
    Controller.Screen.print("R1: %d", rightWheelMotor.rotation(deg));
    wait(20, msec); // Sleep the task for a short amount of time to
                    // prevent wasted resources.
  }
2 Likes

rotation(deg) returns double, use %.3f or something like that.

not really, the data goes via a completely different path to get the VEXcode.

5 Likes

I want to do multiple driver controls like @Zurtar did.

Can I put if-elses setting controls for multiple people into the while loop of user control to make it more robust?

Does old callback get erased when I set new callback function?

1 Like

If you want to learn more about button callbacks you can look into these topics:

Yes, if you put this into the while loop then you can change driver setting during the user control period. Just make sure you call the function only once per button press event.

I am not sure that I fully understand your question, but I assume that when you set another callback function for the button, an old event pointer gets replaced by the pointer to the new function and it will not call the old function.

If you no longer want callback function called you can set an event to a callback function with an empty body. Also, while never tested myself, I remember reading somewhere that if you sett callback to a nullptr it will no longer call original callback.

Edit: my assumption was sadly incorrect.

3 Likes

No, callbacks for an event should only be registered once, registering an additional callback will cause both to fire, registering a null pointer will not free resources.

5 Likes