Summer Robotics Project #10 – Collision Avoidance

With the compass sorted, we could finally start working on the collision avoidance. First, we downloaded a library which we would need in order to be able to easily receive values from our HC-SR04 sensor. As this is a double sensor, using the Ping example on the Arduino IDE was not an option, and we outsourced a library called Ultrasonic and the relevant CPP file, the source of which I can’t remember. The download had an example sketch, which we used to create our sketch for Collision Avoidance. This was kept pretty simple; we just wanted the sensor to be able to print the values to the Serial Monitor/LCD, and print a phrase when the sensor was too close.

float checkFrontSensor(){
    return ultrasonic.Ranging(CM);
}

void collisionAvoidance(){
    if(checkFrontSensor() < collisiondistance){
        Serial.println("Too Close");
    }
 
    else{
        Serial.print(checkFrontSensor());
        Serial.println(" cm");
    }
}

The library contains a function called Ranging, which prompts the sensor to read the distance to an obstacle in front. Using this function, a function for the collision avoidance was written (but of course these two functions can be written as together as one function). The function collisionAvoidance() takes the values from the sensor, and if they are less than a preset maximum distance, collisiondistance, it will print “Too Close” in the serial monitor. We ran this code, and there is a slight glitch in the code when the distance reaches about 13cm, where the sensor prints values such as 2cm and 3cm instead. However when the obstacle is 10cm or closer, which was our preset distance, it printed “Too Close”, as it should, so we are keeping this as it is, as for now, that’s all we need it to do.

The next task was now to get this to work with, not only our motors, but also our problematic compass. We copied this sketch into our main sketch for the robot, and changed up collisionAvoidance() to return bool values, and so that it could stop the motors using our stopMotor() function. (A delay was also added in to give it sufficient time to understand what has been returned):

bool collisionAvoidance(){
    if(checkFrontSensor() > collisiondistance){
        return true;
    }
    
    else{
        stopMotor();
        return false;
        delay(500);
    }
 }

We then proceeded to put a ‘while’ loop inside our main loop, and removed any turn functions for the time being:

void loop(){
    while(collisionAvoidance()){
        delay(10000);
        forward(70);
        delay(1000);
    }
 }

But when we ran the code, the robot wouldn’t stop when faced with an obstacle. As we had no other function aside from forward in our loop, we decided to inspect our forward function guessing something in the code may have been overlooking the collision avoidance. And we were right ..sort of. As we had written this in a ‘while’ loop, collisionAvoidance would be run once, at the start (at which point there is no obstacle and so it would return true), and then run the forward function, which would run as if there was no collisionAvoidance function. Once it had finished the loop once, it would run it again, and only then would it take the next reading for collision avoidance. In short, collisionAvoidance wasn’t being properly incorporated into the loop. To overcome this issue, we simply called collisionAvoidance inside the ‘if’ statement in our forward function. The forward function now looked like this:

void forward(float distance){
    enctarget = (360/ (PI * wheelDiameter)) * distance;
    
    if (abs(encoder1()) < enctarget && collisionAvoidance()){
        setMotorSpeed(100, 100);
        forward(distance);
    }
 
    else {
        stopMotor();
        encodeReset();
    }
 }

We ran this code, and we managed to get the robot to stop when an obstacle was within the preset distance. However, we wanted the robot to be able to continue with it’s manoeuvre as soon as the obstacle was removed. This function failed to do that, and the robot would just reset and start the loop from the top, which would be an issue when more functions are added later on. We initially thought this was to do with calling forward(distance) inside the ‘if’ statement, but then realised that it was due to the encodeReset() being in the ‘else’ statement; the encoders would reset before the robot entered the ‘if’ statement again. We also added forward(distance) into the ‘else’ statement. This would ensure the robot would run the forward function on a loop until the distance had been covered; the encoders would have not yet reset and would still have the value for the distance covered by the robot before the obstacle.

Now that we were able to get the sensors to work with one function in the loop, we wanted to try it with a turn command as well. We ran the code after adding a turn and to our dismay, the robot ignored the prompt to turn, but it did travel forward the right distance. Yet again, it was the forward function that was causing the issue. The addition of the extra ‘forward(distance)’ in the ‘else’ loop was causing the robot to be stuck in the ‘if’ statement – it would read that the distance had been covered, would jump to the ‘else’ statement which stops the motors, and then go back to the start of the ‘if’ statement; This would repeat over and over, causing it to never reach the turn command. To overcome this, we changed the existing ‘else’ statement to an ‘else if’ statement, and added a new ‘else’ statement which would stop the motors and reset the encoders.

void forward(float distance){
    enctarget = (360/ (PI * wheelDiameter)) * distance;

    if (abs(encoder1()) < enctarget && collisionAvoidance()){ 
        setMotorSpeed(100, 100);
        forward(distance);
    }
 
    else if (abs(encoder1()) < enctarget && collisionAvoidance() == false){
        stopMotor();
        delay(1000);
        forward(distance);
    }
 
    else {
        stopMotor();
        encodeReset();
    }
}

We had initially written – else if (abs(encoder1()) < enctarget && !collisionAvoidance()) – but after testing, we noticed that the ! might not have been working, as the robot would skip the ‘else if’ statement, go into the ‘else’ statement and then execute the turn without completing the forward manoeuvre. We changed this to collisionAvoidance() == false, which did the trick. Now the function runs the motors, if the distance hasn’t been reached and there are no obstacles within close proximity. But if an obstacle is detected, it will stop the motors until the obstacle is cleared, and will resume from where it left off. Once the distance has been achieved, the motors will stop and reset, ready for the next command.

We also edited the collisionAvoidance function slightly so that it no longer has a stopMotor() command in it (as this is already in the forward function). We ran this with a turn function in the main loop and it executed it perfectly, so we are proud to have made so much progress in a matter of hours. We don’t intend on calling the collisionAvoidance function in the turn function, as we would need side facing sensors, or on any future functions for Eurobot, as the robot will either be stationary while executing these, or will be running them alongside the forward function, which already has collisionAvoidance in it.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s