setMotorTarget...WaitUntilMotorStop Doesn't always Work


#1

We are working on a program for our state competition in less than a week. We have a scenario where we are using setMotorTarget and WaitUntilMotorStop to run a series of movements for a component of our robot. The first time the code runs, it executes correctly. But the second time, we call the code with different values the robot stalls out indefinitely. Can you help us understand what is going wrong in the code and correct it? Below is the code:

void moveArm(int distance, int speed)
{
resetMotorEncoder(armmotor);
resetMotorEncoder(armmotor2);
setMotorTarget(armmotor, distance, speed);
setMotorTarget(armmotor2, distance, speed);
waitUntilMotorStop(armmotor);
resetMotorEncoder(armmotor);
resetMotorEncoder(armmotor2);
}
moveArm(-400, 100) //works correctly

moveArm(-130, 50); //program stalls out indefinitely

Thank you in advance.

Brian Severa


#2

What does stall out mean?

Is a power of 50 enough to move the arm?


#3

Yes. Power of 50 is enough to move the arm. The program executes the first command without issue, raising the arm. Then later in the program (two commands later), we run the same command but it gets stuck in the WaitUntilMotorStop command. If I give the arm a nudge, the program continues on. It’s as if it can never reach the target value entered. The strange thing is the first 3 times we ran the program, this did not occur. The program ran flawlessly. After that, it would get hung up on the WaitUntilMotorStop.


#4

OK, I was asking because the first was power 100, the second is power 50.

Can you give us all the lines between the first move and the second?


Firmware Problem?
#5

Any chance the arm isn’t able to go beyond the entire distance you’re asking it to?

If you tell the motors to go a specific distance, but they get stopped before they reach the goal you gave them, the motors will never stop trying and will never get to the next line of code.

Example: The arm is physically prevented from moving farther than 90 degrees, but you tell it to go 120 degrees.

If the arm occasionally starts in a different place, this can be the source of the randomness. Or you are trying to use too accurate of a distance, which the arm just barely makes sometimes and not others.


#6

And is all the motor and brain firmware up to date? I seem to recall noticing a bug a long time ago where motors recorded the move as complete internally, but never fed this back to the brain.

edit: Although that said, I think it only affected Modkit because the ROBOTC VM handled things differently anyway.


#7

The arm is able to go beyond the distance we are specifying. If I change the WaitUntilMotorStop to just a Wait(1, second), the move will complete and the program will move on to the next command. The motors and brain are all up to date with the latest firmware. I’ll post the code later this morning. gbr, that’s an interesting thought with the arm. It’s possible that it’s not starting in the exact same position. I’m not sure how I would control that though, to keep the position consistent. In its starting position, the arm is resting against the robot body.


#8

Have you tried to switch to stopping on armmotor2 instead?

waitUntilMotorStop(armmotor2); 

Does it do the exact same thing?


#9

Yes, I’ve tried switching the waitUntilMotorStop(armmotor2); and it has the same exact behavior.


#10

What about if you chuck it in a while loop instead? Something like:

while(getMotorEncoder(armmotor) > -130) {
setMotor(armmotor, -50);
setMotor(armMotor2, -50);
}

setMotor(armmotor, 0);
setMotor(armMotor2, 0);


#11

Below is the code from the program:

#pragma config(Sensor, port3, TouchSensor, sensorVexIQ_LED)
#pragma config(Motor, motor1, leftMotor, tmotorVexIQ, openLoop, driveLeft, encoder)
#pragma config(Motor, motor4, leftClaw, tmotorVexIQ, PIDControl, reversed, encoder)
#pragma config(Motor, motor5, rightClaw, tmotorVexIQ, PIDControl, encoder)
#pragma config(Motor, motor6, rightMotor, tmotorVexIQ, PIDControl, reversed, driveRight, encoder)
#pragma config(Motor, motor9, armmotor2, tmotorVexIQ, PIDControl, reversed, encoder)
#pragma config(Motor, motor10, armmotor, tmotorVexIQ, openLoop, encoder)
//!!Code automatically generated by ‘ROBOTC’ configuration wizard !!//

//--------------------------------------------------------
//Robot general movements - forward, backward, left, right
//--------------------------------------------------------
void turnRobotRight(int distance, int speed)
{
resetMotorEncoder(leftMotor);
setMotorTarget(leftMotor, distance, speed);
waitUntilMotorStop(leftMotor);
resetMotorEncoder(leftMotor);
}

void turnRobotLeft(int distance, int speed)
{
resetMotorEncoder(leftMotor);
setMotorTarget(leftMotor, distance, speed);
waitUntilMotorStop(leftMotor);
resetMotorEncoder(leftMotor);
}

void moveRobotForwardReverse(int distance, int speed)
{
resetMotorEncoder(rightMotor);
resetMotorEncoder(leftMotor);
setMotorTarget(rightMotor, distance, speed);
setMotorTarget(leftMotor, distance, speed);
waitUntilMotorStop(rightMotor);
resetMotorEncoder(rightMotor);
resetMotorEncoder(leftMotor);

}

//--------------
//claw movements
//--------------
void moveLeftClaw(int distance, int speed)
{
resetMotorEncoder(leftClaw);
setMotorTarget(leftClaw, distance, speed);
waitUntilMotorStop(leftClaw);
resetMotorEncoder(leftClaw);
}

void moveRightClaw(int distance, int speed)
{
resetMotorEncoder(rightClaw);
setMotorTarget(rightClaw, distance, speed);
waitUntilMotorStop(rightClaw);
resetMotorEncoder(rightClaw);
}

//-------------
//arm movements
//-------------
void moveArm(int distance, int speed)
{
resetMotorEncoder(armmotor);
resetMotorEncoder(armmotor2);
setMotorTarget(armmotor, distance, speed);
setMotorTarget(armmotor2, distance, speed);
waitUntilMotorStop(armmotor);
resetMotorEncoder(armmotor);
resetMotorEncoder(armmotor2);
}

task main()
{
//Test(); - shows degrees on display

// Wait for Touch Sensor to be Pressed
waitUntil (getTouchLEDValue(TouchSensor) == true);


// clear motor encoders
resetMotorEncoder(leftMotor);
resetMotorEncoder(rightMotor);
resetMotorEncoder(leftClaw);
resetMotorEncoder(rightClaw);
resetMotorEncoder(armmotor);
resetMotorEncoder(armmotor2);

//--------------------------------
//NOTE: all movement is in degrees
//--------------------------------

// ------------------------------------------
// Phase 1: Get Yellow Hub off of Right Tower
// ------------------------------------------

// Turn toward right tower
turnRobotRight(230, 100);

// Raise Left Claw
moveLeftClaw(-90, 100);

// Move arm up
moveArm(-400,100);  //this command works

// Move forward toward right tower
moveRobotForwardReverse(470, 100);

// Lift hub off post
moveArm(-130, 50); //this command does not complete

// Back away from post
moveRobotForwardReverse(-315, 100);

// Lower arm to get under pole
moveArm(290, 100);

#12

To get syntax highlighting on all of the code, you can use fenced code blocks in posts:


#14

@jpearman The documentation for waitUntilMotorStop says
"This command tells the robot to wait until the motor has reached its target."

Which is the behavior of waitUntilMotorStop

  1. Wait until completion of the exact distance asked and never stop trying until it happens
  2. Wait until the motor stops for any reason, either completion of the distance or a physical barrier blocking the movement?

#15

Thank you. My team and I researched the command prior to implementing it. But it appears that there is some obstacle getting in the way of the code running successfully, consistently (I ran the program twice earlier today. It ran fine 2 out of 3 times. Yesterday it ran 3 times successfully, followed by 5 times unsuccessfully). As a team going to state (2nd year in a row), we’d like to go into the tournament with confidence that our program is going to run. For those teams that are consistently successful with their autonomous program, I’d be curious to know what they are doing differently that is translating into consistent successful runs,

Is there a best practice for working with motor encoders and the commands such as what appears in the program above? Would there be a better way to write the code to achieve the desired outcome consistently? Are there tricks to working with the motor encoders to ensure that the motor is completing its movement all the way to the desired target?


#16

try using waitUntilMotorMoveComplete instead.


#17

On IQ, it’s a macro

#define waitUntilMotorStop(nMotorIndex) do {sleep(100); while(!getMotorZeroVelocity(nMotorIndex)) sleep(1);} while(false)

it’s waiting for zero velocity.

these are the position based delays

//Position Based Delays
#define getMotorMoveComplete(nMotorIndex) !getMotorZeroPosition(nMotorIndex)
#define waitUntilMotorMoveComplete(nMotorIndex) do {sleep(100); while(!getMotorZeroPosition(nMotorIndex)) sleep(1);} while(false)

#18

Thanks. We did try waitUntilMotorMoveComplete as well. We got the same result. :frowning: I was tempted to use moveMotorTarget instead of setMotorTarget to see if we get different results that way.


#19

bsevera, please use the code styling.

This is code

just put three “`” before and after the code.


#20

Here is what @anon35188833 is talking about


#21

so just because I can, I had a look to see what’s going on with these commands.

From the ROBOTC side the getMotorZeroVelocity and getMotorZeroPosition calls return flags available from the motor. It looks like both zero position and velocity are triggered by the same condition, a move must be +/- 3 encoder counts from the target position. I assume the waitUntilMotorStop call blocks because, for whatever reason, the motor does not achieve the required final position. So the best solution is really to write a function that’s going to monitor the motor position error and make a decision as to when target is achieved, perhaps just relax the required accuracy to +/- 5 or +/-10 counts, only you can decide that based on the robot design.