Program Issue

void tiltPID(double target)
 {    
double kp = 0.33;     
double ki = 0.0005;
double kd = 0.2;
//need to tune the constants

double proportion;
double totalError;
double integral;
double integralActiveZone = 90;       //need to tune this with the constants
double integralPowerLimit = 50 / ki;  //this will probably need to be adjusted too, depending on the velocity units
double derivative;
double finalPower;

double error = target;
double lastError = target;
vex::task::sleep(50);
while(abs(error) > 3){    // will go until tray is within 3 degrees of target;
    error = target - Tilt.rotation(rotationUnits::deg);
    error = target - Tilt2.rotation(rotationUnits::deg);
    if(error == 0){
        break;
    }
    proportion = kp * error;
    
    if(abs(error) < integralActiveZone && error != 0){
    totalError += error;
    } 
    else totalError = 0.0;
    
    if(totalError > integralPowerLimit){
        totalError = integralPowerLimit;
    }
    if(totalError < -integralPowerLimit){
        totalError = integralPowerLimit;
    }

    integral = ki * totalError;
    
    derivative = kd * (error - lastError);
    lastError = error;
    
    if(error == 0){
        derivative = 0;
    }
    finalPower = 0.5 * (proportion + integral + derivative); //.5 is the gain; can adjust that as needed
    Tilt.spin(fwd, finalPower, velocityUnits::pct);
    Tilt2.spin(fwd,finalPower, velocityUnits::pct);
    vex::task::sleep(20);
}
Tilt.stop();
Tilt2.stop();
 }
 void buttonTilt (void) {
   tiltPID(100);
 }
 


void usercontrol(void) {
Controller1.ButtonUp.pressed(buttonTilt);



  int LISpeedPCT=100;
  int RISpeedPCT=100;
  int ArmSpeedPCT=100;
  int RightaSpeedPCT=100;
  int TiltSpeedPCT=50;
  


  while (true) {

     int RSpeed = Controller1.Axis2.position();
int LSpeed = Controller1.Axis3.position(); 
RR.spin(directionType::fwd, RSpeed, velocityUnits::pct);
LR.spin(directionType::fwd, LSpeed, velocityUnits::pct);

    
    
    if(Controller1.ButtonR1.pressing()) {
      RI.spin(directionType::fwd, RISpeedPCT, velocityUnits::pct);
      LI.spin(directionType::fwd, LISpeedPCT, velocityUnits::pct);

    }

    else if(Controller1.ButtonR2.pressing()) {
      RI.spin(directionType::rev, RISpeedPCT, velocityUnits::pct);
      LI.spin(directionType::rev, LISpeedPCT, velocityUnits::pct);
    }
    else{
      LI.stop(brakeType::hold);
      RI.stop(brakeType::hold);
    }

    if(Controller1.ButtonL1.pressing()) {
      Arm.spin(directionType::fwd, ArmSpeedPCT, velocityUnits::pct);
      Righta.spin(directionType::fwd, RightaSpeedPCT, velocityUnits::pct);
    }


    else if(Controller1.ButtonL2.pressing()) {
      Arm.spin(directionType::rev, ArmSpeedPCT, velocityUnits::pct);
      Righta.spin(directionType::rev, RightaSpeedPCT, velocityUnits::pct);
    }

    else{
      Arm.stop(brakeType::hold);
      Righta.stop(brakeType::hold);
    }

    if(Controller1.ButtonRight.pressing()) 
     { Tilt.spin(directionType::fwd, TiltSpeedPCT, velocityUnits::pct);
     Tilt2.spin(directionType::fwd, TiltSpeedPCT, velocityUnits::pct);
     RI.setStopping(coast);
     LI.setStopping(coast);
    }

    else if(Controller1.ButtonLeft.pressing()) {
      Tilt.spin(directionType::rev, TiltSpeedPCT, velocityUnits::pct);
      Tilt2.spin(directionType::rev, TiltSpeedPCT, velocityUnits::pct);
      RI.setStopping(coast);
     LI.setStopping(coast);
    }

    else{
      Tilt.stop(hold);
      Tilt2.stop(hold);
    }
   

 
  }

edit: mods added code tags, please try and use them in future.

will check in the morning when I have robot near me.

1 Like

ok thank you. We just want to see if we can make stacking a little bit easier.

bad idea to try and control motors from two different tasks (ie. main and an event handler)

4 Likes

event handler?

Im sorry i am new to programming.

The problem is that you have two different paths that Tilter.stop() will get called. While this may not be technically what happens, but when you press ButtonUp, essentially a task gets created to run the call-back (buttonTilt in this case). So now buttonTilt and usercontrol are running at the same time (really not true, but the OS provides the illusion this is the case). Now, buttonTilt is trying to move the Tilter motor. At the same time, un usercontrol, assuming neither ButtonLeft nor ButtonRight are being pressed, the control of that if statement falls thru to Tilt.stop().

TL;DR - You have two things fighting for control over issuing commands to the Tilt motor - one trying to move it while the other tries to stop it.

5 Likes

so i should put the button up command above the user control? and get rid of the manual if statements for the tilter?

My goal was to use the loop for a 9 stack but i can also self stack stuff

1 Like

Most likely what you’ll want is some way to indicate within usercontrol whether buttonTilt is currently executing. If it is executing, it shouldn’t call Tilt.stop(). One possible solution would be to use a global variable for this purpose.

4 Likes

pressed is an event, i.e… something happens.
buttonTilt is your “event handler” it does the work when the event happens

4 Likes

Ohhhh, So tilt stop is in the if else if statements and when that up button is pressed, it is also programmed to stop the motors until left or right are pressing?

, can i just do the pressed Up statement as my Else on the driver control so it shows no stop? Or do i need a stop so the tilters dont make it move?

And how will a global varible work.

ok that makes sense now.

Here is something to try to get your code working without too much changes. If this doesn’t work you can put all your tilt code into a single task. tiltPID can still be a function but called from that task (sleep() usage would probably need to change).

Anyway here is something to try.
You usually want user control to override the automated control. So for that inside the while of the callback you want to add a return if either user tilt button is pressed.

// if user wants control, immediately return from tiltPID 
if (Controller1.ButtonRight.pressing() || Controller1.ButtonLeft.pressing()){
 return;
}

then you need to make sure that opcontrol is not always stopping the tilt motors when not pressing a button as this code does.

else { 
  Tilt.stop(hold); 
  Tilt2.stop(hold);
 }

so you only want to call stop(hold) only one time after releasing the tilt buttons

 int tiltActive = 1; // control when stop is called. 1 = initialize tilt motors to stop(hold)

 while (true) { 
  // your other code

    if(Controller1.ButtonRight.pressing())   {
     tiltActive=1;
     Tilt.spin(directionType::fwd, TiltSpeedPCT, velocityUnits::pct);
     Tilt2.spin(directionType::fwd, TiltSpeedPCT, velocityUnits::pct);
     RI.setStopping(coast);
     LI.setStopping(coast);
    }
    else if(Controller1.ButtonLeft.pressing()) {
      tiltActive = 1;
      Tilt.spin(directionType::rev, TiltSpeedPCT, velocityUnits::pct);
      Tilt2.spin(directionType::rev, TiltSpeedPCT, velocityUnits::pct);
      RI.setStopping(coast);
      LI.setStopping(coast);
    }
    else if (tiltActive) {  // this else gets called once after the operator releases the above button(s)
      tiltActive=0; // when tilt is not active, don't keep telling the motor to stop
      Tilt.stop(hold);
      Tilt2.stop(hold);
    }
   
6 Likes

Ok awesome. Thank you very much.

And just a quick question, Can i stack any height of cubes?

My builder wants to know if I can use that PID loop to stack any height of cubes like a 9 or 10 stack without changing anything?

Sorry about all these questions.

I have limited PID experience so hopefully others can help you more with that. However, I would start with ki and kd set to 0 and get kp tuned first. Then tune kd. If that works I’d leave ki at 0.

Since tuning can be time consuming it might be a good idea to have buttons to increment and decrement the constant value so you don’t have to recompile each test. I’d also display that value to the controller.

Note, you may need different values for the constants for different heights of cubes.

Good Luck.

ed. I just look over your i-term and you cannot modify that on the fly since you are saving the error and not ki*error. So if you change ki it will apply to all prior errors which can cause a bump in the output. But like i said you probably can/should leave ki=0.

3 Likes

Ok. I will just use this for our 9 stack since that is a good stack for a normal match and just manually stack for the 11 or below. Thanks

When we press Up. the tilter barely moves but then no other button moves.

When we press Left or right,it goes but wont stop

Nevermind. We figured it out. thank you all

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