Using a set of switches to detect and avoid obstacles
|
Concepts
Since we know how a SPST switch can be used to start a program, let's expand on that concept and use it to detect when the robot hits a wall. Since a momentary switch will always be in the same state (in this case open) when not pressed, we can set up the use the state of the switch to detect if the robot has hit an object and closed the switch. With a little extra code, we can even make the robot backup and avoid the wall.
Setup
To demonstrate how this works, we will be building our own switches called whiskers. All the parts you will need are included with the Parallax kit.
First, we will build the electronics circuit. You will need the two 3-pin male headers, two 10kΩ resistors (Brown-Black-Orange), two 220Ω resistors (Red-Red-Brown), and two jumper wires.
Plug the components into the bread board so it looks like the following:
Now we need to work on the mechanical "Switch". You will need 2x 1/2" metal standoffs, 2x plastic washers, 2x metal whiskers, and 2x screws (longer) for the mechanical part of the switch.
You will need to swap out the small screws holding the shield near the breadboard with the whiskers. In the end it should look like the image below.
How it works
When the robot is in an open area and the whiskers are not touching anything, the switch is open. This means that the circuit is providing the digital input pin with a high logic level.
However, when the robot starts to drive into a wall, the whiskers get pushed in towards the pins in the breadboard. Once the whiskers have been push far enough, the whiskers contacnt the pins and thus close the switch. Since the whiskers are connected to the BoeBot frame, which is in turn connected to ground, the whiskers bring the digital input pin to ground and a low logic level.
Programming
Since the Robot has 2 switches we need to configure both of them. Since we are controlling the motors we will need to configure them as well.
- Parallax Boe Shield
- digital pin 7 as a Digital High Impedance named "leftSwitch"
- digital pin 8 as a Digital High Impedance named "rightSwitch"
- servo_10 as a Continuous Rotation Servo named "leftServo"
- servo_11 as a reversed Continuous Rotation Servo named "rightServo"
One that is done, your program should have the following code at the top.
#pragma config(CircuitBoardType, typeCktBoardUNO) #pragma config(PluginCircuitBoard, typeShieldParallaxBoeBot) #pragma config(UART_Usage, UART0, uartSystemCommPort, baudRate200000, IOPins, dgtl1, dgtl0) #pragma config(Sensor, dgtl7, leftSwitch, sensorDigitalHighImpedance) #pragma config(Sensor, dgtl8, rightSwitch, sensorDigitalHighImpedance) #pragma config(Motor, servo_10, leftServo, tmotorServoContinuousRotation, openLoop, IOPins, dgtl10, None) #pragma config(Motor, servo_11, rightServo, tmotorServoContinuousRotation, openLoop, reversed, IOPins, dgtl11, None) //*!!Code automatically generated by 'ROBOTC' configuration wizard !!*// |
Now that everything is configured, it is time to plan the behavior. We want the robot to start of driving forward at speed 20. If the robot detects a wall via the whiskers, then it will back up for 0.5 seconds, make a left point turn for 0.5 seconds, then resume driving forward. The robot should do this indefinitely so we know that we will need a while loop. However, how do we make the code change what it is doing based on sensor inputs? To do this we need to use what is called an 'If' statement. There are several forms of If statements, but for this code we will be using the most basic form:
if (condition) { //code to run if condition is true } |
By placing an if statement inside the while loop and checking the whisker states, we can program the robot to respond to a whisker detecting a wall. However, we have 2 whiskers, so we have to check the state of both inside of the if statements' condition. We do this by using 'Boolean logic'. There are several Boolean logic operators, but for this program all we we are going to utilize is the 'or' operator "||". The or operator will return a logical 'true' if one OR both of its conditions evaluate to true.
task main() { while(true) { //if either the left OR the right switch is closed if (SensorValue[leftSwitch] == 0 || SensorValue[rightSwitch] == 0) { //code to avoid the wall } //drive forward at speed 20 motor[leftServo] = 20; motor[rightServo] = 20; } } |
Now we just place the "Avoid Wall" code inside the If statement, and we get the following code.
#pragma config(CircuitBoardType, typeCktBoardUNO) #pragma config(PluginCircuitBoard, typeShieldParallaxBoeBot) #pragma config(UART_Usage, UART0, uartSystemCommPort, baudRate200000, IOPins, dgtl1, dgtl0) #pragma config(Sensor, dgtl7, leftSwitch, sensorDigitalHighImpedance) #pragma config(Sensor, dgtl8, rightSwitch, sensorDigitalHighImpedance) #pragma config(Motor, servo_10, leftServo, tmotorServoContinuousRotation, openLoop, IOPins, dgtl10, None) #pragma config(Motor, servo_11, rightServo, tmotorServoContinuousRotation, openLoop, reversed, IOPins, dgtl11, None) //*!!Code automatically generated by 'ROBOTC' configuration wizard !!*// task main() { while(true) { //if either the left OR the right switch is closed if (SensorValue[leftSwitch] == 0 || SensorValue[rightSwitch] == 0) { //drive backwards at speed 20 for 0.5 seconds motor[leftServo] = -20; motor[rightServo] = -20; wait1Msec(500); //left point turn at speed 20 for 0.5 seconds motor[leftServo] = -20; motor[rightServo] = 20; wait1Msec(500); } //drive forward at speed 20 motor[leftServo] = 20; motor[rightServo] = 20; } } |