Holding motors in place

Hello, our team is starting to program the robot now, and we were wondering if there was any way we could set the motors to hold their position, and resist movement. In vex IQ, we used ‘setMotorBrakeMode (motorHold)’ which was very effective. Is there something like that we can implement? Also, are integrated encoder modules (the IEMs you stick on the back of the motors) different from ‘Integrated Encoders’, and do I need an IEM to do setMotorTarget or moveMotorTarget?
Thanks.

There is no such thing with VRC. You have to use a dreadful thing called a PID loop.

Sounds interesting. Does a PID loop need quadrature encoders? Also, does a “moveMotorTarget” need quadrature encoders too?

The IME are encoders that attach to the actual motor and are more precise than shaft encoders…however…they tend to be less accurate. I would recommend using shaft encoders (quadratic encoders) rather than the IMEs. The shaft encoders are the red square encoders where a shaft/axle goes through them.

Another option, depending on the range of motion, is a potentiometer. If you are going to have less than 270 degrees of rotation, this is usually your best option. You can use a P or PI or PID loop with any of these sensors. The coding for PID is not really all that complex but the fine tuning is where the time comes in.

There are a lot of great tutorials online with pseudo code to get you started. Good luck.

A PID loop will need some kind of sensor, including IME’s, encoders, potentiometers (those are the most common). Here is a good thread about PID’s: https://vexforum.com/t/the-fabled-pid/44119/1
And here is a great document explaining them as well: http://georgegillard.com/documents (click on the link to download the PID document)
Edit: sniped by @blatwell

@Easton Thanks for posting that thread and tutorial. I was going to look it up when I got home. You saved me some time.

@Tegicupala you will find that so long as you are willing to learn and not want someone to do everything for you, there will be a lot of help here. You asked a great question and I think you will do fine.

Also, are you using elastics on your lifts? You want to make sure your lift has “neutral buoyancy,” whether by elastics, counterweights (like elevators in buildings), etc. The idea is to counter gravity so the motors only have to deal with moving the lift, meaning they won’t need to do much to hold position. This doesn’t discount the advice above, but things won’t go well if you’re running motors heavily to hold a large load still even if you program PID beautifully.

@blatwell No problem!
And @Tegicupala good luck getting your robot arms to hold position! By the way, I think it is mentioned in the links I linked, but thought I would still tell you that if this is your first time writing a program like this (I assume it is), then you don’t have to do a whole PID loop. A simple P loop works well for many teams. Also @callen is right, elastics are a must for most lifts, here is a good example of a perfectly rubber banded lift made by @antichamber :

Thank you everyone who responded! This really clears things up for our team. We’ll get to researching about PID loops right now!

After you’ve done your research, if you’re still confused, let me know and I can post my code for you to take a look at. Good luck on this!

@The Electrobotz We think we’re getting the hang of PID commands and loops now. But honestly, it’d be really helpful if we could see some actual code to hold motors in place. We were thinking something like this:
if (vexRT(Btn7U) || vexRT(Btn7D) == 0)
{
int initialvalue = getMotorEncoder(conelift);
repeatUntil (vexRT(Btn7U) || vexRT(Btn7D) == 1)
{
if (getMotorEncoder(chainbar) < initialvalue)
{
setMotorTarget(chainbar,initialvalue,127,true);
}
if (getMotorEncoder(chainbar) > initialvalue)
{
setMotorTarget(chainbar,initialvalue,-127,true);
}

		}
	}

This doesn’t really implement PID variables or characteristics, so we were wondering how something in terms of a PID loop would look.

Or Or OR You can just have the motors go against gravity at a lower speed, low enough to not the move the arm up and fast enough to not let it fall.

for example;

if (vexRT[Btn7U])
{
motor[arm] = 127 //ur arm goes up if value is positive
{
if (vexRT[Btn7D])
{
motor[arm] = -127 //ur arm goes down if value is negative
{
else
{
motor[arm] = 10; /// This will hold ur motor in place, and won’t burn your motor since power is too low.
}

Alright, I think I found something on Robotics Stack Exchange.


void holdchainbar(int angle)
{
	int P = 2;
	int error = angle - getMotorEncoder(port4);
	motor[port4] = P * error;
}

Of course, my P value is bound to change (this was just from the example). My question now is how do I introduce/call this into my code. We were thinking something like this:


	if (vexRT[Btn7U]==1)
	{
		motor[port4] = 127;
	}
	else if (vexRT[Btn7D]==1)
	{
		motor[port4]=-127;
	}
	else
	{
		holdchainbar(getMotorEncoder(port4);
	}

However, for some reason this doesn’t seem to work. In fact, when we add this, the robot just doesn’t even function. Does anyone have any suggestions, or some sample code they have that they know works for sure?
-Thanks

My first suggestion would be to make sure your Encoder is linked in the motors and sensors setup to that motor, otherwise I would just use SensorValue instead of getMotorEncoder.

Also, think of what happens whenever you call that function. Your parameter is the encoder value, and the function subtracts the encoder value, so your error is always going to look like 0 because you’re subtracting the motor encoder’s value from itself. Instead, you should be putting the desired angle into the function.

@Mystellianne
I see what you mean with my error always being 0, and seemed to have missed that. However, I wanted something along the lines of when I don’t press anything (when my chain bar is idle), the encoder immediately sends its current position to the void (holdchainbar) function. From there, if gravity makes the chain bar move up or down, then it would correct that accordingly. In this case, I don’t really have a desired angle, I just want it to stay in place.

Have an int variable outside of your whole loop during driver control, lets call it


desiredAngle

.


if (vexRT[Btn7U]==1)
	{
		motor[port4] = 127;
                desiredAngle = getMotorEncoder(port4);
	}
	else if (vexRT[Btn7D]==1)
	{
		motor[port4]=-127;
                desiredAngle = getMotorEncoder(port4);
	}
	else
	{
		holdchainbar(desiredAngle);
	}

This way, every time you move it manually it will adjust the desired value, and whenever you’re not adjusting it, the desired value is sent to the method.

@Mystellianne
Thank you so much! I finally seem to understand the mathematics behind these PID loops. However, my chain bar seems to be doing exactly what you predicted, oscillation. I want to set the speed to about 25 (like you said), but I’m kind of unsure how to do that (first year in vex). This is more of a general question, but how do I change the speed in my void function?


void holdchainbar(int angle)
{
	int P = 1;
	int error = angle - getMotorEncoder(port4);
	motor[port4] = P * error;
}

There’s two ways you could approach this:

  1. If it’s lower than the desired value, set it to 25 to lift it up, and if it’s higher than the desired value, set it to -25 to lower it.

  2. Keep your proportional loop, but lower your P.

For something like a chainbar, I think the second option may actually be better for you, as it doesn’t just set the motor to a constant 25, it sets it higher or lower depending on how far off you are from your desired value. This allows the motors to move at a more smooth pace, which puts less strain on them.

A really simple way to fix the oscillation with a proportion (which is what you’re doing) is to just lower the P until it stops oscillating so much. Right now it’s an


int

, but you could easily just change it to a


float

so that you can make it a decimal, and just keep lowering it slightly until the oscillation goes away. Try at 0.95, 0.9. etc., and you should find a solid value that works for you :slight_smile: