Programming Issues

Hi everyone. Even though my season is over, I have been trying (slowly and lazily) to figure out some of the issues that we had during the season that I was never able to figure out. The first problem was inside of a hold arm function inside user control. Here is the code:


void holdArmPos(int pos) {

	if(pos > 500) { //make sure that it isn't running if it is on the ground
		int errorL = pos - SensorValue[leftTowerPot]; //calculate error as target position subtracted from the SensorValue
		int errorR = pos - SensorValue[rightTowerPot];
		int tolerance  = 100; //allow a small amount of tolerance
		if(abs(errorL) > tolerance || abs(errorR) > tolerance) {
			float kp = .1;
			int armHoldSpeedL = errorL * kp;
			int armHoldSpeedR = errorR * kp;

			motor[LeftCatapult1] = motor[LeftCatapult2] = -1 * armHoldSpeedL;
			motor[RightCatapult1] = motor[RightCatapult2] = -1* armHoldSpeedR;
		}
	}
	else {
		motor[LeftCatapult1] = motor[LeftCatapult2] = 0;
		motor[RightCatapult1] = motor[RightCatapult2] = 0;
	}
}

if(vexRT[Btn5U] == 1) {
			motor[LeftCatapult1] = motor[LeftCatapult2] = 127;
			motor[RightCatapult1] = motor[RightCatapult2] = 127;
			TowerPot = ((SensorValue[leftTowerPot] + SensorValue[rightTowerPot]) / 2);
		}
		else if(vexRT[Btn5D] == 1) {
			motor[LeftCatapult1] = motor[LeftCatapult2] = -127;
			motor[RightCatapult1] = motor[RightCatapult2] = -127;
			TowerPot = ((SensorValue[leftTowerPot] + SensorValue[rightTowerPot]) / 2);
	}
		else if(vexRT[Btn8U] == 1) {
			holdArmPos(1200);
		}
		else if(vexRT[Btn8L] == 1 || vexRT[Btn8R] == 1) {
			holdArmPos(1000); used to move the arm to a designated spot (we never actually used this)
		}


		else {
			holdArmPos(TowerPot); //call the function to hold arm
		}

The issue with this is that the inertia of the arm carries it farther than when the button is released. As a result, the variable towerPot is different from where the arm wants to stop with inertia. This caused the arm to kind of bounce whenever we moved it and made it harder to drive. Any advice on how to prevent this from happening and account for the inertia would be appreciated. Even a suggestion for a completely different approach on a holdArm is welcome.
EDIT: I just added some comments to the code to make it easier to read. I understand how much effort all the forum users go through to help others and really appreciate it.
Notes:

  1. I already tried adding or subtracting a small number when it is set to try and ease the effect of inertia but that didn’t help.
  2. I also don’t think it would work to have TowerPot re update outside of the if and just regularly in the while loop because as the arm falls, TowerPot would just change to become that new value.

Thanks everyone and Good Luck to all of you competing at VEX Worlds 2017.

Trying to go from high angular momentum to no angular momentum in minimal time requires a lot of torque. On top of that, because it’s drifted past where you want, you’re trying to past zero to the opposite direction. Even if your motors can handle that much torque, you must actually get it externally, meaning from gravity and the floor. You cannot get enough that way, which is why your robot rocks. The solution is to require less torque, which means trying to make this transition more gently.

Try this general approach:

  1. Check the buttons as normal.
  2. If the move button (5U or 5D) is pressed, run power as normal, but also set an integer to record the recent power and set that to the power you’re setting for the motor. Grab the position as normal here, too.
  3. If the hold button (8U) is pressed, don’t just try to stop the motor there. Instead, check the recent power. If it’s at full that means you just switched the button. Start decrementing the recent power integer and set the motor to it. Once it’s low enough, just drop it to 0. If, however, the recent power is 0, then you know you’ve intentionally stopped over some time (keeping the hold button down a while) and now you can go through the code of getting the arm to the position you recorded (as you’d planned before).

Thank you very much. This makes a lot of sense and I will try it out when I get some time. I randomly got another possible solution though. What if before the holdArmPos() function is called there was a condition checking the velocity of the arm. If the velocity of the arm is still very large, it would wait to grab the target position until it reaches a lower velocity to reduce the rock. It wouldn’t wait until it reaches 0 of course because that is a very low chance, but just enough so when the arm locks up in that position, it wouldn’t cause any rock.

I also have another question. How would I pass a string as a parameter to a function. I set it up something like this and it gave me an error. This isn’t the function that I am using it for, but this is exactly how it is set up:


void driveForward(int number, string text) {
//code
}

It is called like this:


driveForward(52, "someOtherText");

When compiled, it produces this error:
Error:‘const’ expressions does not fit. Call to ‘drive’. Parameter: ‘unsigned string & accuracyLevel’ is ‘“medium”’ of type ‘string’.”

What would you set the motor to in the meantime? If you don’t do anything it looks like it will still be ±127 because you have no options other than 127 or holdArmPos(). So if you just wait instead of setting it to a new value, won’t it stay at ±127?

I see what you are saying. Let’s ignore buttons 8U and 8L for a minute. Maybe setting the motors immediately to 0 when the buttons 5U and 5D are released, the having the condition would work. Inside the condition will be the function call.


boolean targetGrabbed=false;
if(vexRT[Btn5U] == 1) {
			motor[LeftCatapult1] = motor[LeftCatapult2] = 127;
			motor[RightCatapult1] = motor[RightCatapult2] = 127;
			targetGrabbed=false;
		}
		else if(vexRT[Btn5D] == 1) {
			motor[LeftCatapult1] = motor[LeftCatapult2] = -127;
			motor[RightCatapult1] = motor[RightCatapult2] = -127;
			targetGrabbed=false;
	}
else { 
if(targetGrabbed==false) { //this is to make sure that it doesn't set the motors to 0 every time through the loop, only when the buttons have been pressed.
motor[LeftCatapult1] = motor[LeftCatapult2] = 0;
			motor[RightCatapult1] = motor[RightCatapult2] = 0;
}
if(/*velocity check*/) {
TowerPot = ((SensorValue[leftTowerPot] + SensorValue[rightTowerPot]) / 2);
targetGrabbed=true;

}
if(targetGrabbed==true) {
holdArmPos();
}
}

Try it out. I’m not sure about the specific behavior with the motors set to 0 versus something non-zero along with back-EMF. You may well still find things shake a lot dropping right to 0, as you presumably have a lot of angular momentum with four motors running at 127 to rotate the arm and your prior comments on the issue. If it works, great. If not, try slowing down more gradually.

Ok thank you so much. I will try this out and see if it works better and if I need to will try the gradual slow down.

PID

Ok thanks for all your responses. Now I have another question. How would I pass a string as a parameter to a function. I set it up something like this and it gave me an error. This isn’t the function that I am using it for, but this is exactly how it is set up:


void driveForward(int number, string text) {
//code
}

It is called like this:


driveForward(52, "someOtherText");

When compiled, it produces this error:
Error:‘const’ expressions does not fit. Call to ‘drive’. Parameter: ‘unsigned string & accuracyLevel’ is ‘“medium”’ of type ‘string’.”

Also, I am confused on how the getMotorVelocity() function works. The inbuilt one that uses IME’s. This function accepts one parameter, but I am not sure what data type that parameter is. After all, C is not object-oriented, so there is not Motor class or anything that would allow you to pass a string value that is read as a motor. So how would you recreate this manually?

Thanks for all your help everyone.

I’ve been coding in PROS. I suspect you’re using RobotC. So I was hoping someone more knowledgeable about RobotC might reply.

A quick look at strings in RobotC reveals they are all set to a length of 20 in RobotC because of the screen size. I cannot say if this is the issue or not. I also don’t know if there is some #include you need to use with strings in RobotC. Or maybe the issue is what you’re doing with the string inside of driveForward(). Are you trying to stick a string in where something else should go?

As for getMotorVelocity(), it takes a port. The type is tMotor, which I would assume is a port number. What you could do with a word is to use #define to replace that word with a value. Then you can see the word while actually just passing an integer or whatever that port number (tMotor) is.

Anyway, hopefully someone who knows RobotC and is familiar with a few of these issue will chime in.

That code looks fine, but RobotC != ANSI C, so who knows.

Generally it’s a bad idea to pass strings for performance reasons. I know it’s not really an issue here but having read a lot of books on game engine design, for game developers using strings for data passing is probably the #1 sin.

May I suggest making an error enum and passing that?

Try this and see if it resolves your problem.

void driveForward(int number, char* text) {
//code
}

driveForward(52, “someOtherText”);

Ok thanks. What is enum? I guess I’ll try to avoid using strings though.

So by this you mean:


void getMotorVelocity(tMotor motor _name) {
//code
}

Right? This way tMotor is the data type for the parameter. Or am I misunderstanding?

@The Electrobotz if you want me to explain what enums are and look at your problem in more detail, we can certainly do so over Skype / Hangouts.