Making a robot stop and hold it's position [SOLVED]

Hi, I have a bi-ped robot that I am trying to make go into a squatted position and stay in that position until an input changes. The robot uses a Pixy cam for color detection and a IR sensor for distance detection. The rest of the code works fine so the robot will track and walk to certain colors. if the IR sensor values suggest a wall or furniture is in front of it the robot will turn to avoid it and if the Pixy cam does see the correct color and the IR sensor detects an object the robot will go into a squatted position. However, it immediately goes from a squatted position back to walking and scanning for objects. I'm trying to make the robot go to a certain object and when it gets to it squat and wait until the object moves before it moves again.

I have tried more combinations of code than I can remember. I focused mostly on a state machine and different while statements neither of which provided good results. Here is my current code that does get the robot to do everything other than hold it's position.

void loop()
{
  read_Ir();
  ScanForBlocks();
  camera();

  while (ir > Middle && (millis() - lastBlockTime < 200))
  {
    Rest();
    read_Ir();
    ScanForBlocks();
  }
  if (panLoop.m_pos < RCS_CENTER_POS && ir > Middle && (millis() - lastBlockTime > 200))
  {
    Turn_Right(200);
  }
  else if (panLoop.m_pos > RCS_CENTER_POS && ir > Middle && (millis() - lastBlockTime > 200))
  {
    Turn_Left(200);
  }
}

After the while statement I also tried polling the IR sensor different ways than it's showing here.

Thank you for your time and any help.

Scott

What goes wrong?

It won't stay in the rest(); position. In the rest position the robot is squatted down, like it's taking a break. Currently it moves to that position, then immediately goes back to walking and scanning for more objects. I'd like it to stay still in that position until the object in front of it moves again.

Another way to word my issue that may paint a picture would be using delay(); for an unspecified amount of time. If I write in a delay the robot holds it's position the way I want but that's obviously only as long as I write the delay.

Delay won’t work, because it stops the computer from doing anything else. You need to be continuously sampling the input sensors and making a decision.

Take a look at the “blink without delay” example that comes with the IDE, to see how to pause a particular action without holding up anything else.

I realize that. I had to use delay when I was writing the code for rest(); I used it to test the servo movements since that was the only way I could get it to stay in the rest position long enough to check the servo angles and make code adjustments.

I'm familiar with blink without delay but I don't understand how that would help.

I'm familiar with blink without delay but I don't understand how that would help.

The example shows you how to avoid using delay. Learn from it, and your life will be immensely richer.

Thank you for your reply and your time, I do appreciate it and I am trying to learn.

I shouldn't have even mentioned the use of delay.

From my understanding delay simply stops the program from running until a specified time has passed. And blink without delay using millis lets the program run and checks the inputs after a specified time has passed. I'm trying to avoid any specified time. I'm looking to stop the movement of the robot during the loop() for an infinite amount of time when a certain condition exists.

To clarify in my simple mind I can use delay to stop everything from executing for let's say 2000 ms. Or I can use blink without delay (millis) and recheck the values after 2000 ms. I'm confused how that would stop the robot from moving for any where between 2 seconds to 15 minutes.

I apologize if I'm difficult. I'm just trying to figure this out.

"I'm looking to stop the movement of the robot during the loop() for an infinite amount of time when a certain condition exists."

while (condition exists){ // such as digitalRead(pinX) == LOW
// hang out
}
// continue

Thank you for your input as well CrossRoads. In my code posted above am I on the right path with the while statement?

while (ir > Middle && (millis() - lastBlockTime < 200))

You want it to continue when either becomes false? i.e. ir <= Middle OR >=200 mS have elapsed?

No, I want it to stay still when both of those are true. Meaning when the IR is greater than Middle and the last block time (last time the camera saw red) is less than 200.

I also have it programed to turn and avoid objects if the camera hasn't seen red in over 200 and IR is greater than middle. That works perfectly.

Thank you again.

I apologize! Yes! I stepped away from the computer and realized what you meant. Exactly, stay still when both are true or continue when either are false. Thanks again.

Hi I am going build a pick and place robot which can detect the object and place in a appropriate place so can I get the code for it or if I get the corrected code of your project "Making a robot stop and hold it's position" It will be helpful for me

Sameer_Shaikh: Hi I am going build a pick and place robot which can detect the object and place in a appropriate place so can I get the code for it or if I get the corrected code of your project "Making a robot stop and hold it's position" It will be helpful for me

I don't really understand your reply.

CrossRoads: while (ir > Middle && (millis() - lastBlockTime < 200))

You want it to continue when either becomes false? i.e. ir <= Middle OR >=200 mS have elapsed?

Is that how I should write the second part of the while statement? Or is the while statement not my best option here? I played with a case and switch before. But that caused all kinds of goofy behavior. Thanks again.

I think while ( ) { } is your best option, you just need to figure out the logic you need. I would guess that (millis() - lastBlockTme) won't be true very long; 200mS is not a long amount of time when mechanical stuff is involved.

  while ( (ir > Middle) && ( (millis() - lastBlockTime) < 200) )
  {
    Rest();
    read_Ir();
    ScanForBlocks();
  }

(added a couple more ( ) to make the tested parts more clear) and nothing in your code appears to update last BlockTime, so it won't be in that while hold time for long no matter what ir does. Is that really what you want?

I'll add in the extra () that you did and try that. I could definitely go to 500mS and maybe even 1000 but 1000 may give it some false positives. I'll try increasing the mS until I get behavior I don't want. You are also right about the last block time, thank you for catching that error. I think I need to replace ScanForBlocks(); with Camera();. The Camera(); loop produces the lastBlockTime.

I'll give all of that a try and see what happens. Thank you again.

Now some interesting things are happening. I tried quite a few changes that didn’t yield any results. One thing I did try was increasing the 200mS to 500mS, 1000mS and all the way to 5000mS. That in itself didn’t change anything when the robot was looking at a red object (which is what the camera is programed to look for and produces the lastBlockTime). However, if I showed the robot a red object then quickly swapped it out for another object the robot would hold it’s rest(); position for approximately 5 seconds. I’ve got to think this out a little.

Whoa! It works! I adjusted the millis all the way up to 50000. I correctly assumed that would cause it to go into rest(); if the IR sensor detected something during that time even if the red object wasn't in front of the camera. meaning if a wall or furniture was detected within the Middle range of the IR it would go into Rest(); To fix that I increased the distance the IR sensor will cause the robot to turn and avoid an object if it doesn't see red. 50,000 millis wouldn't be enough time to hold the position so I upped it again to 500,000. I only poll the IR in the while statement now. Now the robot will hold it's position for a maximum of 8 minutes (which should be enough time). Most importantly, if the object moves during that time it will go back to scanning for the object or tracking it appropriately. It seems like the battery is getting low from all this use so I'm going to charge it and recheck all it's motions before I tag this as solved. Below is what the current loop looks like right now.

void loop()
{
  read_Ir();
  ScanForBlocks();
  camera();

  while ((ir > Middle) && (millis() - lastBlockTime < 500000))
  {
    Rest();
    read_Ir();
  }
  if ((panLoop.m_pos < RCS_CENTER_POS) && ir > Far && (millis() - lastBlockTime > 500))
  {
    Turn_Right(200);
  }
  else if ((panLoop.m_pos > RCS_CENTER_POS) && Far > Middle && (millis() - lastBlockTime > 500))
  {
    Turn_Left(200);
  }
}

A very big thank you to you guys for your input so far. Any other advice is always appreciated.

Scott

Thank you very much to the Arduino forum especially CrossRoads. The robot does for the most part exactly as I had wished for. It does stop and hold in the rest() position when appropriate. It also can still roam the house avoiding walls and furniture. I had to make a few minor adjustments in the turn left and turn right obstacle avoidance to avoid false positives (bring the mills - lastBlockTime > back down to 200). I need to do more fine tuning of the IR values and perhaps speed up the pan servo proportional gain to make it run flawlessly. But that wasn't what the topic was about. The robot does stop and hold it's position now until the object moves. Next up is fine tuning adjustments and adding the sound back to it!

Thank you again for your help.

Scott

Glad you got it working.