323Z Code Help (2013-2014)

Here is goes again :smiley:

void lift(int speed)
{
	motor[LL] = speed;
	motor[LR] = speed;
}

//Arm PID Variables; change kp ki and kd to whatever is best for your robot.
float kp = .3;
float ki = 0.018;
float kd = 0.1;
int previousError = 0;
float errorSum = 0;
int motPower = 0;

//Actual PID
void LiftPID(int target)
{
  int error = target - SensorValue[LL];
  int derivative = error-previousError;
  motPower = (error*kp+errorSum*ki+derivative*kd);
  lift(motPower); //this is our function for just setting lift motors to this power.
  previousError = error;
  errorSum += error/1024.0;
}

We start the function in autonomous

while (1 == 1)
	{ 
		LiftPID(ArmBar);
	}

The lift goes straight up and doesn’t stop. I think we had this problem last year, but I don’t remember how to solve it… Anyone know why it is not stopping at the ā€œ1687ā€? Are the p, i, or d to high?

These are our variables for the lift:

//Variables
const int ArmBottom = 2463;
const int ArmBump = 2274;
const int ArmBar= 1687;
const int ArmStash= 960;

Start by only setting kP (1 is a good starting point) and setting kI and kD to 0. Your first goal should be to get a working P controller. In fact, I’ve never even had to do a full PID - I’ve found that for vex just using the P term works only marginally worse than a PID and it’s significantly easier to tune.

Another problem I see is that you should really be waiting 15 ms or so inside the while loop. Without that, your errorSum is going to add up EXTREMELY fast. In fact, if you have an error of 100 you’ll have a speed of 127 from the integral alone after only 71 loops (which occurs in a fraction of a second.)

You may also want to look into adding an if statement to prevent what’s called integral windup. Basically you make it so that the integral accumulated error should get no longer than, say, 2000. Multiplying your max error by the integral constant will tell you the max amount of motor power you’ll get from the integral term. (2000*.018=36 maximum)

James’ PID Library takes care of the windup stuff for you if you wanna try using that instead. Might make things easier. It’s what I typically use.

OK thanks. I was going to add a short wait, but didn’t do it as I was just tryint to see if the code worked. Hopefully the p, i, and d will take care of the problem.

So the function I have works correct? I just need to change some variables?

Thanks!

I agree with Daniel here, I have yet to have a true need for a PID controller in VEX. In fact, I’ve gotten away without needing to use even a P controller, although I really should start to use one :slight_smile:

If you decide to stick with the PID controller, the best method for refining your controller, if my memory serves, is to start with the P controller (and make ki and kd equal to zero) and modify kp to the point where it just slightly overshoots before returning to normal. Then, you’ll want to add on your ki value. Then, you’ll want the ki to make the controller undershoot just slightly and then return to normal. Then, you’ll adjust your kd value to make the controller slow down precisely when it needs to, so that there is a minimum ā€œbouncingā€ off the desired value.

Again, you could get away with ā€œdumberā€ controllers, like just P or using a bunch of if conditions.

So, p is 1, and it will still not stop at the right point. It wants to make a full 360 degree loop :smiley: Any other solutions?

I’ve never needed P, I, or D for my arm. I just apply a constant 16 power when I’m not operating the lift, and it stays where it’s at. The only lifts that doesn’t really work for are chain bar and back dumpers, but since you have a 6 bar, my solution should be perfectly fine.

Really no tuning needed and works really well.

If you want to set a target for your autonomous, just apply power up or down until you reach your target. I’ve never had overshoot problems with the arm. When I’m going up, gravity stops the overshoot. When I’m going down, the 16 power stops the overshoot. :stuck_out_tongue:

Could you post the entire program?

So you call a motor ā€œLLā€ and a (non-IME) sensor ā€œLLā€ so I guess you might have some conflict there… if you are using IMEs I believe the command for reading them is nMotorEncoder() or something like that (we don’t have any IMEs so I’m not too sure) instead of SensorValue().

You don’t have a loop in the function ā€œvoid LiftPID(int target)ā€ to refresh the PID values so I’m assuming that that is the loop you are using in autonomous where you call it? Just make sure that there is a loop refreshing it all somewhere or you will have one value sent to your motors and that value won’t be refreshed (I.E. it won’t slow down).

Hope that helps :slight_smile:

~George

We have a potentiometer on the lift.

//Lift

//Variables
const int ArmBottom = 2463;
const int ArmBump = 2274;
const int ArmBar= 1687;
const int ArmStash= 960;

///////////////////////////////////////////////////////////////////////////////////

void lift(int speed)
{
	motor[LL] = speed;
	motor[LR] = speed;
}

//Arm PID Variables; change kp ki and kd to whatever is best for your robot.
float kp = 1;
float ki = 0;
float kd = 0;
int previousError = 0;
float errorSum = 0;
int motPower = 0;

//Actual PID
void LiftPID(int target)
{
  int error = target - SensorValue[PL];
  int derivative = error-previousError;
  motPower = (error*kp+errorSum*ki+derivative*kd);
  lift(motPower); //this is our function for just setting lift motors to this power.
  previousError = error;
  errorSum += error/1024.0;
}
#pragma config(UART_Usage, UART2, uartVEXLCD, baudRate250000, IOPins, None, None)
#pragma config(I2C_Usage, I2C1, i2cSensors)
#pragma config(Sensor, in1,    PL,             sensorPotentiometer)
#pragma config(Sensor, in2,    PR,             sensorPotentiometer)
#pragma config(Sensor, in3,    GY,             sensorGyro)
#pragma config(Sensor, dgtl1,  ,               sensorDigitalOut)
#pragma config(Sensor, dgtl2,  ,               sensorQuadEncoder)
#pragma config(Sensor, I2C_1,  ,               sensorQuadEncoderOnI2CPort,    , AutoAssign)
#pragma config(Sensor, I2C_2,  ,               sensorQuadEncoderOnI2CPort,    , AutoAssign)
#pragma config(Motor,  port1,           IR,            tmotorVex393, openLoop, reversed)
#pragma config(Motor,  port2,           LF,            tmotorVex393HighSpeed, openLoop)
#pragma config(Motor,  port3,           RF,            tmotorVex393HighSpeed, openLoop)
#pragma config(Motor,  port4,           LM,            tmotorVex393HighSpeed, openLoop)
#pragma config(Motora,  port5,           LL,            tmotorVex393, openLoop, reversed)
#pragma config(Motor,  port6,           LR,            tmotorVex393, openLoop)
#pragma config(Motor,  port7,           RM,            tmotorVex393HighSpeed, openLoop, reversed)
#pragma config(Motor,  port8,           LB,            tmotorVex393HighSpeed, openLoop, encoder, encoderPort, I2C_2, 1000)
#pragma config(Motor,  port9,           RB,            tmotorVex393HighSpeed, openLoop, reversed, encoder, encoderPort, I2C_1, 1000)
#pragma config(Motor,  port10,          IL,            tmotorVex393, openLoop)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//

#pragma platform(VEX)

//Competition Control and Duration Settings
#pragma competitionControl(Competition)
#pragma autonomousDuration(20)
#pragma userControlDuration(120)

#include "Vex_Competition_Includes.c"   //Main competition background code...do not modify!
#include "Drive.c" //Drive Functions
#include "Lift.c" //Lift Functions
#include "Intake.c" //Intake Functions

/////////////////////////////////////////////////////////////////////////////////////////
//
//                          Pre-Autonomous Functions
//
// You may want to perform some actions before the competition starts. Do them in the
// following function.
//
/////////////////////////////////////////////////////////////////////////////////////////

void pre_auton()
{
	// Set bStopTasksBetweenModes to false if you want to keep user created tasks running between
	// Autonomous and Tele-Op modes. You will need to manage all user created tasks if set to false.
	bStopTasksBetweenModes = true;

	// All activities that occur before the competition starts
	// Example: clearing encoders, setting servo positions, ...
}



/////////////////////////////////////////////////////////////////////////////////////////
//
//                                 Autonomous Task
//
// This task is used to control your robot during the autonomous phase of a VEX Competition.
// You must modify the code to add your own robot specific commands here.
//
/////////////////////////////////////////////////////////////////////////////////////////

task autonomous()
{
	Turn(180, 64);
}

/////////////////////////////////////////////////////////////////////////////////////////
//
//                                 User Control Task
//
// This task is used to control your robot during the user control phase of a VEX Competition.
// You must modify the code to add your own robot specific commands here.
//**//
/////////////////////////////////////////////////////////////////////////////////////////

task usercontrol()
{
	// User control code here, inside the loop

	while (true)
	{
		motor[LF] = vexRT[Ch3]; //Left joystick drives left side
		motor[LM] = vexRT[Ch3]; //Left joystick drives left side
		motor[LB] = vexRT[Ch3];
		motor[RF] = vexRT[Ch2]; //Left joystick drives left side
		motor[RM] = vexRT[Ch2]; //Left joystick drives left side
		motor[RB] = vexRT[Ch2];

	  motor[port5] = vexRT[Ch3Xmtr2];
		motor[port6] = vexRT[Ch3Xmtr2];

		motor[IL] = (vexRT[Btn8DXmtr2] - vexRT[Btn8UXmtr2])*127;
		motor[IR] = (vexRT[Btn8DXmtr2] - vexRT[Btn8UXmtr2])*127;

		//motor[LL] = (vexRT[Btn5U] - vexRT[Btn5D])*127;
		//motor[LR] = (vexRT[Btn5U] - vexRT[Btn5D])*127;

		//motor[IL] = (vexRT[Btn6U] - vexRT[Btn6D])*127;
		//motor[IR] = (vexRT[Btn6U] - vexRT[Btn6D])*127;

	}
}

There is our lowly code :slight_smile: Let me know if you see any problems.

@Tabor.
So you can still say ā€œGo to position Nā€ and it will go there. You have a little power going to it all the time right?

I don’t see you calling liftPID anywhere in that code. Am I missing something?

ahaha woops.

Here:

#pragma config(UART_Usage, UART2, uartVEXLCD, baudRate250000, IOPins, None, None)
#pragma config(I2C_Usage, I2C1, i2cSensors)
#pragma config(Sensor, in1,    PL,             sensorPotentiometer)
#pragma config(Sensor, in2,    PR,             sensorPotentiometer)
#pragma config(Sensor, in3,    GY,             sensorGyro)
#pragma config(Sensor, dgtl1,  ,               sensorDigitalOut)
#pragma config(Sensor, dgtl2,  ,               sensorQuadEncoder)
#pragma config(Sensor, I2C_1,  ,               sensorQuadEncoderOnI2CPort,    , AutoAssign)
#pragma config(Sensor, I2C_2,  ,               sensorQuadEncoderOnI2CPort,    , AutoAssign)
#pragma config(Motor,  port1,           IR,            tmotorVex393, openLoop, reversed)
#pragma config(Motor,  port2,           LF,            tmotorVex393HighSpeed, openLoop)
#pragma config(Motor,  port3,           RF,            tmotorVex393HighSpeed, openLoop)
#pragma config(Motor,  port4,           LM,            tmotorVex393HighSpeed, openLoop)
#pragma config(Motora,  port5,           LL,            tmotorVex393, openLoop, reversed)
#pragma config(Motor,  port6,           LR,            tmotorVex393, openLoop)
#pragma config(Motor,  port7,           RM,            tmotorVex393HighSpeed, openLoop, reversed)
#pragma config(Motor,  port8,           LB,            tmotorVex393HighSpeed, openLoop, encoder, encoderPort, I2C_2, 1000)
#pragma config(Motor,  port9,           RB,            tmotorVex393HighSpeed, openLoop, reversed, encoder, encoderPort, I2C_1, 1000)
#pragma config(Motor,  port10,          IL,            tmotorVex393, openLoop)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//

#pragma platform(VEX)

//Competition Control and Duration Settings
#pragma competitionControl(Competition)
#pragma autonomousDuration(20)
#pragma userControlDuration(120)

#include "Vex_Competition_Includes.c"   //Main competition background code...do not modify!
#include "Drive.c" //Drive Functions
#include "Lift.c" //Lift Functions
#include "Intake.c" //Intake Functions

/////////////////////////////////////////////////////////////////////////////////////////
//
//                          Pre-Autonomous Functions
//
// You may want to perform some actions before the competition starts. Do them in the
// following function.
//
/////////////////////////////////////////////////////////////////////////////////////////

void pre_auton()
{
	// Set bStopTasksBetweenModes to false if you want to keep user created tasks running between
	// Autonomous and Tele-Op modes. You will need to manage all user created tasks if set to false.
	bStopTasksBetweenModes = true;

	// All activities that occur before the competition starts
	// Example: clearing encoders, setting servo positions, ...
}



/////////////////////////////////////////////////////////////////////////////////////////
//
//                                 Autonomous Task
//
// This task is used to control your robot during the autonomous phase of a VEX Competition.
// You must modify the code to add your own robot specific commands here.
//
/////////////////////////////////////////////////////////////////////////////////////////

task autonomous()
{
	LiftPID(ArmBar);
}

/////////////////////////////////////////////////////////////////////////////////////////
//
//                                 User Control Task
//
// This task is used to control your robot during the user control phase of a VEX Competition.
// You must modify the code to add your own robot specific commands here.
//**//
/////////////////////////////////////////////////////////////////////////////////////////

task usercontrol()
{
	// User control code here, inside the loop

	while (true)
	{
		motor[LF] = vexRT[Ch3]; //Left joystick drives left side
		motor[LM] = vexRT[Ch3]; //Left joystick drives left side
		motor[LB] = vexRT[Ch3];
		motor[RF] = vexRT[Ch2]; //Left joystick drives left side
		motor[RM] = vexRT[Ch2]; //Left joystick drives left side
		motor[RB] = vexRT[Ch2];

	  motor[port5] = vexRT[Ch3Xmtr2];
		motor[port6] = vexRT[Ch3Xmtr2];

		motor[IL] = (vexRT[Btn8DXmtr2] - vexRT[Btn8UXmtr2])*127;
		motor[IR] = (vexRT[Btn8DXmtr2] - vexRT[Btn8UXmtr2])*127;

		//motor[LL] = (vexRT[Btn5U] - vexRT[Btn5D])*127;
		//motor[LR] = (vexRT[Btn5U] - vexRT[Btn5D])*127;

		//motor[IL] = (vexRT[Btn6U] - vexRT[Btn6D])*127;
		//motor[IR] = (vexRT[Btn6U] - vexRT[Btn6D])*127;

	}
}

George is on the right track, you are not reading the pot but whatever is on analog 5 (LL == port5 == 4)

I missed this the first time… I think I see the problem, it’s really simple. I saw the code above and noticed something was a bit funny. Your potentiometer is on backwards, I.E. a high value is a low height, a low value is a high height. So, when you are lifting the arm up, normally you’d expect the potentiometer value to increase, causing the error to shrink, but in this case the pot reading is decreasing, so the error is increasing as you lift the arm up. I’ll let you think about this and come up with a solution :wink: you can either do it in code or just flip your potentiometer the ā€œrightā€ way :stuck_out_tongue:

~George

I believe that he corrected that in post 9.

If there is still an issue, it’s probably the reversed pot like George said.

I corrected that, and I will flip the potentiometer. That makes a lot of sense :wink: Thanks, and I will let you know tomorrow if it worked!

Yes, I was just a bit slow hitting ā€œsubmitā€. I see more problems if the code you have posted is actually what you are using. Are you using the PID in both autonomous and driver control ?

And don’t forget to add in a while! Otherwise it won’t keep updating the value.

task autonomous()
{
	while(1)
	{
		LiftPID(ArmBar);
		wait(5);
	}
}

Just Autonomous.

Yep. I added it after I posted the code on here :wink:

Once you get the function working, you should convert it to a task and use a global variable for the desired arm position the PID is looking for. That way you can move the base and the arm at the same time.

One tip on using the task, initialize the global variable to the current sensor value so the PID does not do something weird right off the bat.

But one thing at a time… (there’s a bad pun in there I think)

  1. set the global variables to where they are right now
  2. start the arm PID task (and position PID and claw PID if you have them)
  3. set desired positions for each task
  4. loop around until you are the target range of each PID are satisfied
  5. set the next targets

This way you can do more complex moves at the same time and shave off time in those 15 seconds to do more stuff.

Oh yes! We had planned on doing that. Right now we are just making sure all of our functions work. We will be putting then in tasks to save on time. Thank you!