Wait Statement Within While Loop?

I am trying to make a program that moves a motor until a bump sensor is pressed or the motor will stop after 3 seconds. This is my sample code.


while (SensorValue(bump) < 1 || wait1Msec(3000))
  {
    motor[port1] = 127;
  }
  motor[port1] = 0;

There is an error that says:


**Error**:Internal failure in expression evaluation for 'wait1Msec'

Is what I am doing possible? What am I doing wrong? Thanks for the help!

wait1Msec(3000) is a command rather than a comparison.

I would recommend using an actual timer, like t1, t2, etc, and then compare
the timer value.

  • Sunny

wait1Msec doesn’t return a value since it’s a built-in void function
As Sunny mentioned, use a timer that returns a value
RobotC syntax is ClearTimer(T1); then time1[T1] to retrieve the value, if I remember correctly
You can also use time100[T1] and wait for 30 tenths of a second, since your value doesn’t seem to require high precision

OK so now the timer works, BUT the bumper is not working. I tested the bumper without the wait statement together, so the bumper is working. What is the problem this time? This is my current code:

#pragma config(Sensor, in2,    bump,                sensorDigitalIn)
task main ()
{
ClearTimer(T1);
while (SensorValue[bump] < 1 || time100[T1] < 500)
  {
    motor[port1] = 127;
  }
  motor[port1] = 0;
}

When running the code there is no error, it just doesn’t respond when I press the button.

If that is your whole program, unless you are holding the bumper in when you start the bot it is just going to exit. You need to put the whole thing inside another while (true) { } loop to keep it going and going. Additionally, I think the bump sensor is only going to do anything while it is pressed. And since the timer starts at the beginning, I think it will keep moving at the beginning via the timer and not the bumper.


#pragma config(Sensor, in2,    bump,                sensorDigitalIn)
task main ()
{
  while (true)
  {
    ClearTimer(T1);
    while (SensorValue[bump] < 1 || time100[T1] < 500)
    {
      motor[port1] = 127;
    }
    motor[port1] = 0;
  }
}

So if this is your entire bot, you should be fairly safe… but I personally don’t like using while loops because then you get stuck in a bit of code and can’t respond to anything else. For a 1 motor, 1 sensor bot this may not be a big deal. Instead, you can make use of the time still but not use a while loop.

The below code is a bit over complicated for the simple task above (and it probably doesn’t work right because I only compiled it, I didn’t test it), but should be easier to expand and allow you to do other things at the same time. The main benefit (to me) is it gives you better information about the buttons. The SensorValue[bump] reads that value instantly, so putting it inside an if or while statement means it will only run when the button is physically held down. By watching for the button state and storing a few values, you can instead see when the button is down (held down), that it was pressed and then released and keep track of how many times it was pressed. And by using if statements with timers (or something else) that finish immediately instead of getting stuck inside a loop, you can continue to act on other things.

I also use this sort of code to use the 4 back buttons on the controller as buttons, which can be useful for a variety of things :slight_smile:


#pragma config(Sensor, in2,    bump,                sensorDigitalIn)

// A struct to store button press details
typedef struct {
  int Counter;
  bool Down;
  bool Pressed;
}button;

button bumper;

void initButtons();

task main ()
{
  bVexAutonomousMode = false;
  initButtons();

  // Clear timer the first time to get started
  ClearTimer(T1);
  motor[port1] = 0;

  while (true)
  {
    // Detect a press of bumper
    if (SensorValue[bump])
    {
      bumper.Down = true;
    }

    // Detect a release of bumper
    if (bumper.Down && !SensorValue[bump])
    {
      bumper.Pressed = true;
      bumper.Counter +=1;
      bumper.Down = false;
    }

    // A button press and release was detected
    if (bumper.Pressed)
    {
      motor[port1] = 127;
      // We've dealt with the button being pressed, so unpress it
      bumper.Pressed = false;
    }

    // The timer has expired
    if (time100[T1] < 500)
    {
      motor[port1] = 127;
    }
  }
}

void initButtons()
{
  bumper.Counter = 0;
  bumper.Down = false;
  bumper.Pressed = false;
}

I tried both of your programs and neither seemed to give me any help. The first program responded in the same way that my other program did, by running until the 50 seconds were up without doing anything when the button was pressed.
The second program just didn’t respond at all and didn’t do anything. Was there something I was supposed to add to it?
Thanks for the help so far!

Sorry, I didn’t mean to imply that either of them would actually work :wink:

If it were me, I’d fiddle around. You can’t break anything, so feel free to poke around. I’d run it with the device hooked up (RobotC right?) and see what values the different variables have and what they are doing. Try stepping through the program one line at a time, see where it does what you expect and where it doesn’t.

For me to get this working like you want, I’d have to set up my vex doodads and tinker around. I’d work on getting the first one to behave as you want since it is far, far simpler. If you are feeling adventurous, you can probably use what you learn to make the second style work too.

Edit: Also, I always forget what motor values are valid in RobotC. Is it -127 to 127? Or is it 0 to 255? I think the first, but am not sure :slight_smile:

Also, what happens if you hold down the bumper button after the 50s are up with the first program?

It is -127 to 127, and I will go try some of your suggestions thanks!

I know in easyC there is a command to retrieve the sensor value, is there something like that in robotC that I have just completely looked over? The code I posted was actually just a shortened code of my whole test program to test using two different conditions and “or” inside a while loop. I want to use this type of code in an autonomous mode for competition. My entire test code is:

Sorry, I find it hard to read code w/o formatting :wink:

Blech, a ton of my comments are wrong because I thought ‘sensorRotation’ was the potentimeter, but I just realized it is obviously the rotation encoder :wink:

If you read the below, ignore those parts. Sorry, I might have a look at this later when I can.


#pragma config(Sensor, in1, coder, sensorRotation)
#pragma config(Sensor, in2, bump, sensorDigitalIn)
//*!!Code automatically generated by 'ROBOTC' configuration wizard !!*//

// You aren't looping inside of main, so this program will run once then exit
task main ()
{
  // This will only run *while* the sensor 'bump' is pressed down *OR* when 
  // the sensor 'coder' is lower than 900
  // Having to hold the button in is very unlikely to be what you want to do.  
  while(SensorValue[bump] < 1 || SensorValue(coder) < 900)
  {
    motor[port1] = -127;
  }
  
  // Immediately after the above conditions are done being met (you twist the 
  // know past 900 or let go of the button).  Your motor on port1 will stop.  
  // If the knob was *already* past 900 when you started *or* you were 
  // not holding the button when the robot was turned on, you'll just get 
  // here and nothing will have happened. 
  motor[port1] = 0;
  wait1Msec(1000);

  // Now you are trying to set a sensor to a value, which I don't think is valid.
  SensorValue[coder] = 0;

  ClearTimer(T1);

  // Again, this will *ONLY* fire when the sensor 'bump' is held down *OR* it 
  // is less than 500 what evers since you cleared the timer.
  // And since your program only runs once *and* you clear the timer 
  // immediately before... the bump sensor will actually have no effect at all.
  while (SensorValue[bump] < 1 || time100[T1] < 500)
  {
    motor[port1] = 127;
  }
  // The above should have run for ~500 what evers, but this will of course stop it.
  motor[port1] = 0;
  // Setting a value on a sensor again, I don't think that is valid.
  SensorValue[coder] = 0;
  ClearTimer(T2);
  // This should run for 600 what evers, since your program only runs once 
  // I don't think the bump will have any effect
  while (time100[T2] < 600 || SensorValue[bump] < 1)
  {
    motor[port2] = 127;
  }
  motor[port2] = 0;
}

Yeah sorry I didn’t format my code, I know it can be very difficult without it :wink:

#pragma config(Sensor, in1,    coder,               sensorRotation)
#pragma config(Sensor, in2,    bump,                sensorDigitalIn)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//
//yes I just want it to run once
task main ()
{
  //I had meant for the program to stop when I either pressed the button OR the motor 
  //caused the rotation encoder(coder) to rotate 900 ticks.
  while(SensorValue[bump] > 0 || SensorValue(coder) < 900)
  {
    motor[port1] = -127;
  }
  //then I would like the motor to stop once either of those happens.
  motor[port1] = 0;
  //wait a second just to let me see what is happening easier
  wait1Msec(1000);
  //I have had trouble figuring out how to reset a rotation encoder back to 0. 
  // from what I was able to find, this is what I am supposed to do, but it has 
  // not seemed to work well, even though it doesn't matter in this program because
  //I never use the encoder again in the program. but if you do know a way to reset an 
  //encoder that would be helpful.
  SensorValue[coder] = 0;
  //then I clear the timer so it starts counting from 1
  ClearTimer(T1);
 
  //for this part I hope that it would drive the motor until the timer is no longer 
  //less than 50 seconds OR I press the button. Is this the correct way to write it?...
  while (SensorValue[bump] > 0 || time100[T1] < 500)
  {
    motor[port1] = 127;
  }
  //then the motor stops
  motor[port1] = 0;
  //clear a second timer
  ClearTimer(T2);
  //and finally, it runs for 60 seconds OR stops when I press the button. but, from what
  //you said it sounds like it does not re-check the value of the button over and over
  //while running the loop. Is there a "check motor value" command that I could put 
  //inside the loop to continuously check the motor?
  (time100[T2] < 600 || SensorValue[bump] > 0)
  {
    motor[port2] = 127;
  }
  motor[port2] = 0;
}

So my main problems are resetting the encoder(coder) back to zero and getting the program to recheck the bumper value(bump) over and over within the while loop.
Thanks for the continued help!

Are you using a quad encoder or the older type? Does it have 1 or 2 sets of wires? Your program looks setup for the older 1 set of wires type.

This is the program I am using to test what you want.

bump1 advances to the next test
bump2 is used inside a test for various purposes

Between each test it will zero out everything (timers, button presses/counters, rotation encoder)

There are no while loops (well, except the main one to keep it going) so it doesn’t get stuck anywhere and you can always do anything you want.

Test 0: Just sits there, waits for you to press button 1
Test 1: If you press and hold button 2, it will run the motor
Test 2: The motor runs until you press button 2 then does nothing
Test 3: The motor runs until either you press button 2 OR the encoder ticks 900 forward or back (assumes the motor is connected to the encoder of course)
Test 4: The motor runs until either you press button 2 OR 10 seconds elapses on the timer


#pragma config(Sensor, in1,    pot1,                sensorPotentiometer)
#pragma config(Sensor, in3,    rot1,                    sensorQuadEncoder, int3)
#pragma config(Sensor, in15,   bump2,               sensorTouch)
#pragma config(Sensor, in16,   bump1,               sensorTouch)
#pragma config(Motor,  port1,           motor1,        tmotorNormal, openLoop)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//

// A simple struct I use to make buttons more powerful
typedef struct {
  int Counter;
  bool Held;
  bool Pressed;
}button;

// Will use bump1/bumper1 to advance through the tests
button bumper1;
// Will use bump2/bumper2 to do actions inside a test
button bumper2;

// Start all the buttons with the right values
void initButtons();

task main()
{
  // Initialize all button values
  initButtons();
  // TestSection controls where we are in testing, default is 0
  int TestSection = 0;

  // Lets go forever
  while(true)
  {
    // bumper1
    if (SensorValue[bump1])
    {
      bumper1.Held = true;
    }
    if (bumper1.Held && !SensorValue[bump1])
    {
      bumper1.Pressed = true;
      bumper1.Counter +=1;
      bumper1.Held = false;
    }

    // bumper2
    if (SensorValue[bump2])
    {
      bumper2.Held = true;
    }
    if (bumper2.Held && !SensorValue[bump2])
    {
      bumper2.Pressed = true;
      bumper2.Counter +=1;
      bumper2.Held = false;
    }

    // Catch button 1 press to advance test section
    if (bumper1.Pressed)
    {
      TestSection+=1;
      // We want to clear button state every time we advance.
      initButtons();
      // And stop the motor;
      motor[motor1] = 0;
      // And reset the rotation sensor
      SensorValue[rot1] = 0;
      // And reset the timer
      ClearTimer(T1);
    }

    // Right now there are only 2 sections, so after 1 we wrap to 0
    if (TestSection > 4)
    {
      TestSection = 0;
    }

    switch (TestSection)
    {
    case 0:
      wait10Msec(1);
      break;

    case 1:
      // If bumper2 is held in, run the motor otherwise stop it
      if (bumper2.Held)
      {
        motor[motor1] = 15;
        } else {
        motor[motor1] = 0;
      }
      break;

    case 2:
      // Run the motor until bumper2 is pressed.
      if (bumper2.Pressed)
      {
        motor[motor1] = 0;
        } else {
        motor[motor1] = 15;
      }
      break;
    
    
    case 3:      
      // Run the motor until bumper2 is pressed *or* encoder hits 900 ticks
      if (bumper2.Pressed || abs(SensorValue[rot1]) > 900)
      {
        motor[motor1] = 0;
      } else {
        motor[motor1] = -15;
      }
      break;
      
    case 4:
      // Run the motor until bumper2 is pressed *or* 10 seconds has passed
      if (bumper2.Pressed || time100[T1] > 100)
      {
        motor[motor1] = 0;
      } else {
        motor[motor1] = 15;
      }
      break;
    
    }   
    // Wait a little to save cpu
    wait1Msec(10);
  }
}

void initButtons()
{
  bumper1.Counter = 0;
  bumper1.Held = false;
  bumper1.Pressed = false;

  bumper2.Counter = 0;
  bumper2.Held = false;
  bumper2.Pressed = false;
}