Challenge Project: Outdoor Cane Competition with Beacon Allison Connolly and Sarah Gutbrod 580.471 Principles of Biomedical Instrumentation December 4, 2009 1. Objective The purpose of our project is to design an electronic device to aid the visually impaired as they travel to a known exterior destination while avoiding moving and stationary obstacles. The device must be an improvement to the traditional cane currently used as an aid and help the user stay centered along a path as they continue towards their destination 2. Introduction The freedom to get around independently is a significant challenge for the visually impaired, especially in an external setting where moving cars, bicyclists, and other pedestrians complicate the route. Advanced obstacle detection of stationary and moving objects as well as navigational cues would be a vast improvement over traditional canes. While a simple cane can detect lower objects or obstacles directly in front of the user, there is no component to look for low hanging branches or other similar obstacles that threaten the upper body and face of the individual. It was also brought to our attention through a consultation with a visually impaired individual that it would also be extremely beneficial to know the location of the centerline of a sidewalk. With more than one million blind individuals in the United States there is a large market available for a device that increases their mobility and the confidence with which they can safely travel the streets of a city. We have designed an improved cane that couples distance detection with tactile and auditory feedback to address this concern. 3. Design Process 3.1. Sensor selection A short-range infrared sensor was chosen for low obstacle and stair detection. The sensor has a range of 3 feet or less, and outputs a voltage that varies with obstacle distance. A single sensor was positioned near the base of the cane and was used to detect both up and down stairs. This could be done by angling the sensor towards the floor, giving it an output voltage of approximately 1V. If a drop-off or down step is in range of the sensor, the output voltage falls to zero. Conversely, the output voltage jumped towards maximum when an object higher than the floor came in range of the sensor. This allowed the sensor to detect upwards stairs, curbs, or any other object a user can trip over. In order to detect objects that are farther away, either in front of or above the user, we selected to use the SRF05 ultra-sonic range finder (ultrasound transceiver and sensor). This sensor was advantageous over a long-range infrared sensor because its output voltage is digital instead of analog, making the signal processing on the microchip simpler. When a trigger pulse is input to the sensor, the ultra-sonic transmitter emits 8 bursts, and the receiver records the echo of these pulses. The on-board circuitry interprets the time delay between bursts and echo and outputs a pulse-width modulated signal whose width is dependent on the delay. Two of these sensors were used on our cane, one aimed directly in front of the user, and another pointing at an angle in front of and above the user's head. The first sensor is used to detect objects in front of the user, so he or she does not collide with stationary objects. It also has a second purpose, to detect objects approaching the user, such as joggers or bicyclists by comparing the distance of an object at time t and time t plus a short delay of 100ms. The second sensor is used to detect overhead objects. The distance threshold for detection is optimized to the height of the user, and detects objects at forehead level or below. This is an improvement over a passive cane, which can only detect low or waist-high objects, but not objects such as branches that can hit the user in the head. Based on the idea that the desired path will be a different color than the surroundings, we installed a TSL230R light intensity to frequency converter on the bottom left and right-hand side of the cane. The TSL230R sensor is an integrated circuit that uses an array of photo-diodes to detect light. The sensor then outputs a digital square wave with variable frequencies based on the intensity of the light reflected off the ground. The digital output signal simplified the analysis, which allowed more components to be programmed through the same PIC. The TSL230R also offers the ability to adjust the sensitivity and scale the output to more easily record the frequency. The circuit is also packaged in an easily integrated 8 pin DIP chip convenient for assembly. We shielded the sensors from ambient light in a dark encasing and angled the sensors towards the ground to increase their sensitivity to changes in the path. Extending nearly a foot to the left or the right the sensors will perceive a change in the color of the pathway as the cane is swept from side to side before the user steps off the desired path. This change is determined by a significant difference between the frequency outputted from the left sensor compared to the right and calculated in a manner similar to the ultrasound sensors. We chose not to rely on the absolute values read by the color sensors because the values were heavily dependent on the light conditions. The absolute reading on a cloudy day was much less than the absolute reading on a day when the sun was out. It was also heavily dependent on the time of day and made testing and calibration more difficult due to the fact that it had to be performed in the sunlight not indoor lighting. However assessing the difference between the sensors was an accurate and acceptable solution to determine the edge of the path. The sign of the difference between the sensors' reading would alert the user of the location of the edge of the path. For the purpose of this demonstration where the green grass was off the path, the sensors were calibrated so that a decrease in light intensity meant "off-path." Our design also incorporates a wireless XBEE receiver that functions as a beacon detection sensor. Set to be the same frequency as the transmitting XBEE located at the destination, the receiver picks up a signal when in range (300 ft). The pulsewidth modulated signal frequency increases when the distance between the two XBEE chips decreases. The receiving XBEE also outputs a square wave signal; the length of the positive pulse width corresponds to the strength of the received signal. Our circuit ignores the XBEE until the wireless chips are within range and then, by comparing the pulse widths at two different times, determines if the user is approaching the destination or moving away in the wrong direction. 3.2. Feedback Selection For the obstacle sensors we have selected a combination of tactile and auditory feedback mechanisms. The tactile feedback is achieved by applying a constant or pulsed voltage to a mounted shaft motor, causing it to vibrate. During testing we found that it was difficult to distinguish different vibrating locations on one hand, especially if the whole cane vibrated. Therefore we chose a variety of locations extra sensitive to tactile stimulation including the hand, forearm, and neck behind both ears to differentiate between different sensor feedback. The shaft motors were encased in flexible, cylindrical plastic housing to protect the rotating piece from interference as well as to conduct the vibrations to any shaped surface. The hand motor vibrates if an object is detected by the front ultrasound, whereas the forearm vibrates if an overhead object is detected. The left ear motor vibrates when the IR detects an edge or downstairs while the right ear piece vibrates when the IR detects up stairs. The left ear piece is longer than the right so that they are easily differentiated by the visually impaired user. There is also a beeper installed on the cane that beeps twice to signify when the XBEE is in range and beeps constantly if the XBEE perceives that the user is moving in the wrong direction. Additionally the beeper will pulse to alert the user that an object is moving at the cane. There is a servo motor embedded in the handle of the cane to alert the user when they are in close proximity of the edge of the path. The user can comfortably rest their thumb on the bracket attached to the servo motor while holding the cane. If the reading from the right color sensor is less than the left sensor, signaling off path, the motor will guide the user's thumb 45 degrees to the left to signal that the center of the path is to the left. In the same way if the left color sensor is less than the right, the motor will guide the user's thumb 45 degrees to the right. We chose to simplify the feedback to left and right and not incorporate how far left or how far right in order to make the cane more intelligible. The change in orientation and position of the thumb is easily perceived and the feedback is completely isolated from the other sensors. 3.3 Calculations and Thresholds Many of the sensor readings are dependent on initiating the internal timer of the PIC microcontroller using the following equation: frequency = 20 MHz = 20*10^6 Hz --> period = 1/(20*10^6) sec for the timer divide-by-8: each cycle has length 1.6 us t_delay (ms) = (0.0016 ms/cycle) * (no. of cycles) The following equation is used to calculate distance from the Ultrasonic range-finder output: distance (cm) = (t_delay ms) * (1000 us/ms) / (2*30 us per cm) Due to the method motion by which a moving object is determined the motion sensor had to take into account the walking motion of the user, which was determined to be an average 3ft/s. Only additional movement towards the sensor results in feedback. The following equation is used to calculate the distance from the IR sensor output: voltage (V) = adc_import_value * (5V / 255) distance (cm) 40 30 20 15 10 8 5 2 voltage (V) 0.75 0.9 1.4 1.75 2.45 2.5 1.8 0.8 The PIC microcontroller outputs a square wave to rotate the servo motor. The pulse width of the waveform determines the angle that the motor moves according to the table below. angle (deg) -90 -45 0 45 90 pulse width (usec) 600 1050 1500 1950 2400 pulse width (usec) = 1500 + (angle deg) * (10 usec/deg) Due to the fact that the color sensors rely on a difference between the left and the right signal to detect off-path it was important to establish the baseline difference in the signals. This difference was dependent on the angle and placement of the sensor relative to the ground and therefore dependent on how the user chose to hold the cane. Therefore the sensors are programmed to initialize when the cane is first turned on. However this means that the user must be relatively sure that both sensors are facing the same surface during the initialization step. The measured difference is then set to zero and a difference greater than or less than it is registered. Unfortunately it is sensitive to the way the cane is held throughout use. 3.4 Incorporating the sensors and feedback together/ PIC Selection In order to accommodate code with 16-bit variables and code of larger sizes, we chose to use the PIC18f4550 over the PIC16f877. These chips are easily interchangeable, meaning we could switch between PICs depending on our needs. In order to calculate averages and use counters above 255, we used the PIC18 because it can handle variables with range 0 to 65535. The sensor sampling occurs in series, meaning a chip can only read from one sensor at a time. If all of the sensors were on the same chip, then there could possibly be a delay of up to five seconds between readings from one sensor. This delay is too large for operation in the real world, so we split the duties between two microchips in order to cut this time in half to approximately 2 second delay. The sensors were split according to importance. The color sensors needed to be sampled most frequently, so they became the dominant sensor on PIC1. Because the servo provides feedback for these sensors, it was also placed on PIC1 to avoid any excess communication between the PICs. The XBEE beacon detector was a secondary feature for our cane, meaning it did not take up much time or space, so it could be included on PIC1. The object and motion detection sensors were placed on PIC2, along with their respective vibrating motor and sound feedback. The only separation of sensor and feedback is with the XBEE receiver, which produces a certain pattern of beeps depending on the user's proximity to the beacon. The PICs communicate through rs232 protocol. For this specific purpose, PIC1 will send a character if the XBEE needs to alert the user. PIC2 reads this character, responds that it has been read, and then performs the feedback action. Once PIC1 has received confirmation from PIC2, it continues with its normal function. In this way, there will be no missed communications between the two chips. This format can be easily adapted for future, more complex communications between the PICs. 3.5 Power and Current Concerns The device is designed to be powered by 9V batteries. Therefore it is necessary to have a 5V regulator to power the PICs and the sensors and a 3.3V regulator to power the XBEE wireless chip. When assembling the complete device and integrating the feedback and sensors we found that one battery did not supply enough current for consistent and accurate performance. The servo motor itself draws 100mA. To combat this issue we placed the 5V regulator in a heat sink to increase the current output to near 1A and added two 9V batteries in parallel to add the currents. 4. Problems 4.1. It was difficult to establish consistent communication between the XBEE wireless chips when the transmitting and receiving chip were powered by different batteries. We believe this may have been an issue with the 3.3V Regulator. The wireless communication was highly sensitive to the power source which varied significantly between our circuit and the beacon circuit. However this issue is expected due to the relatively high tolerance levels of the capacitors that are used in conjunction with the regulator. We found, by constructing multiple regulator circuits with various replacement capacitors, that the resulting output ranged from 3.3V to 3.7V. The transmitting XBEE was being powered by a supply ~3.57V, which we had to match closely in order to successfully establish communication. 4.2. Before the color sensors were shielded it was difficult to get a distinct reading from different surfaces because the signal was contaminated by ambient light. We were forced to design a physical barrier to block out peripheral light while still allowing an unobstructed view of the ground surface. In addition we had to change the parameters of the to increase the sensitivity by 100 and scale the frequency output by 10 in order to consistently perceive different values for the grass vs. the path. 4.3. Our first design included vocal feedback so that it did not require interpretation on the part of the user to understand the sensors. However, after ordering PICs that were capable of storing pre-recorded files that would then be played through an earphone, we had difficultly working with Microchip to program the PIC. We did not have access to the correct compiler and therefore had to abandon the idea and adapt our design to include tactile feedback. 4.4. We ran into difficulty when testing our device in rainy conditions. The low IR sensor responded differently to light reflected off puddles than to baseline conditions. The thresholds were no longer correct and the circuit perceived steps where they did not exist. Also we were forced to waterproof our cane, which is an important feature for external use. The servo had to be isolated from the rain and the exposed electronics had to be protected. 5. Future Work While the vibration and beeping feedback is effective, it makes the cane bulky and requires the user to focus on interpreting the vibrations. This reduces focus from other aspects of navigation, such as his own haptic feedback from feet and feeling with the cane as well as auditory feedback of his or her environment. However, almost all people can multitask to the point of holding a conversation while walking, so having voice feedback instead of vibrations would be less intrusive to the user. The voice feedback can be incorporated by using an external voice chip module or voice production board, or the microchip itself can be programmed to produce voice files from compressed storage. The latter option is ideal, as it would not add an excess circuitry and thus keep the device from becoming bulkier. This can be achieved by using a higher-level chip with sufficient memory to store the compressed sound files as well as the ability to output pulse-width-modulated signals. In order to be clinically relevant, the device must be maneuverable by all types of people. In its current state it is too heavy and too thick for a smaller person to handle. Therefore, in the next prototype, it would be important to consider size and weight concerns and aim to mimic the conditions of the current cane. This is achievable by several methods: use a single PIC, use a printed PCB board, use a single battery, use a smaller/lighter servo motor, make the overall diameter of the cane smaller. In order to reduce to a single PIC, a more sophisticated PIC with interrupts and optimized code are necessary. By optimizing the code, this will reduce the power draw on the battery. Adding solar panels to the cane, which is useful because it is aimed for outdoor use, will also reduce the power draw on the battery and allow for a longer lifespan. Based on our own field testing of the device, we encountered problems in maneuvering over rough ground due to the stopper at the end of the cane. If the cane were lighter and more balanced, the end could simply glide over bumps and cracks in the ground and would not get stuck. 6. Appendix A: PIC 1 Code /* * Allison Connolly and Sarah Gutbrod * Smart Cane for the blind - outdoor competition * November 23, 2009 * Principles of Biomedical Instrumentation * Pic 1: clock, XBEE, colorL, colorR, servo */ #include <18f4550.h> #include <stdio.h> #include <stdlib.h> #define 20_MHZ_CLOCK #use delay(clock=20000000) /* pin definitions */ #define TPIC2 PIN_A0 #define RPIC2 PIN_A1 #define RXBEE PIN_A2 #define TXBEE PIN_A4 #define RCOLOR_R PIN_B2 #define RCOLOR_L PIN_B1 #define TSERVO PIN_B4 #define SENSITIVITY_SCALE 100 #define FREQ_SCALING_LEVEL 10 /* the two pics communicate using rs232 */ #use rs232(baud=9600, XMIT=TXBEE, RCV = RPIC2, parity=N, bits=8) int in_range = 0; /* variable definitions */ /* for watch_xbee */ unsigned long XB_pulse_width = 0; /* for color sensors */ float R_freq, L_freq, CR_pulse_width, CL_pulse_width; float DIFFERENCE_THRESHOLD=0; /* read the modulated pulses from xbee * if the signal is railing 0, out of range * if the signal is railing high, at destination * otherwise, smaller pulse width means closer to destination * alert the user if go away from destination or out of range */ int watch_xbee(void) { signed long time; float temp_pulse_width; /* wait until we get an upstroke from RXBEE or timer runs out */ for ( ; ((!input(RXBEE)) && (get_timer3() < 1000)) ;) { if (input(RXBEE)) { /* XBEE upstroke triggered exit from for */ set_timer3(0); /* start timer */ } else { &nbsp; if (!in_range) return 0; /* "false" too far, XBEE out of range */ if (in_range==1) { in_range = 0; return 2; /* went out of range, should beep */ } } } /* wait until we get a downstroke from RXBEE or timer runs out */ for ( ; (input(RXBEE) && get_timer3() < 1000) ; ) { if (!input(RXBEE)) { /* XBEE downstroke triggered exit from for */ time = get_timer3(); if (in_range==0) { in_range = 1; } return 3; /* enter range, long short short beeps */ } else { if (in_range) return 1; /* "true", RXBEE railing positive, too close, at destination */ } } temp_pulse_width = (float)time * .0016; if ((temp_pulse_width - XB_pulse_width) < 0) { XB_pulse_width = temp_pulse_width; return 2; /* going away from XBEE, need to beep */ } XB_pulse_width = temp_pulse_width; } /* send out PWM signal to rotate the servo motor * to the degree passed */ void rotate_motor(signed long degree) { int j, k; for (j=0; j<50; j++) { output_high(TSERVO); for (k=0; k<10; k++) delay_us(150+degree); output_low(TSERVO); delay_ms(20); } } /* measure the frequency being read by the right color sensor * set the global variable */ void color_right(void) { float temp_pulse_width_R, time_R; temp_pulse_width_R = 0; time_R = 0; setup_timer_3(T3_INTERNAL | T3_DIV_BY_8); for ( ; !input(RCOLOR_R); ) set_timer3(0); for ( ; input(RCOLOR_R); ) time_R = get_timer3(); temp_pulse_width_R = (float)time_R*.0016; if (temp_pulse_width_R > 5) { return; } CR_pulse_width = temp_pulse_width_R; R_freq = 1/(2*temp_pulse_width_R); } /* measure the frequency being read by the left color sensor * set the global variable */ void color_left(void) { float temp_pulse_width_L=0; float time_L = 0; setup_timer_3(T3_INTERNAL | T3_DIV_BY_8); for ( ; !input(RCOLOR_L); ) set_timer3(0); for ( ; input(RCOLOR_L); ) time_L = get_timer3(); temp_pulse_width_L = (float)time_L*.0016; if (temp_pulse_width_L > 5) { return; } CL_pulse_width = temp_pulse_width_L; L_freq = 1/(2*temp_pulse_width_L); } /* compare the reading from the right sensor and the left sensor * if the difference is greater than the threshold, rotate the motor left * if the difference is less than the threshold, rotate the motor right */ void compare_color(void) { } float color_difference; for (;;) { color_right(); color_left(); color_difference = CR_pulse_width - CL_pulse_width; if (color_difference >DIFFERENCE_THRESHOLD){ rotate_motor(-45); delay_ms(10); rotate_motor(0); } if (color_difference<DIFFERENCE_THRESHOLD){ rotate_motor(45); delay_ms(10); rotate_motor(0); } } /* called when the cane is first turned on * the cane must be held still on a solid patch of ground * reads the values from the left and right sensors and averages over * many times. then sets the initial difference threshold */ float setup(void) { float temp_pulse_width_R=0, temp_pulse_width_L=0; float time_R = 0, time_L = 0; int got=0; setup_timer_3(T3_INTERNAL | T3_DIV_BY_8); delay_ms(1000); while (!got) { for ( ; !input(RCOLOR_R); ) set_timer3(0); for ( ; input(RCOLOR_R); ) time_R = get_timer3(); temp_pulse_width_R = (float)time_R*.0016; if (temp_pulse_width_R < 5) { got = 1; } } got = 0; while (!got) { for ( ; !input(RCOLOR_L); ) set_timer3(0); for ( ; input(RCOLOR_L); ) time_L = get_timer3(); temp_pulse_width_L = (float)time_L*.0016; if (temp_pulse_width_L < 5) { got = 1; } } return temp_pulse_width_R - temp_pulse_width_L; } /* the main loop. after setting up the color sensor threshold, it cycles * through reading from color sensors, and the xbee * if the xbee indicates the user needs to be notified, * this pic must communicate with the feedback pick using rs232 */ void main() { int i; float diff=0; delay_ms(1000); for (i=0; i<10; i++) { diff += setup(); } DIFFERENCE_THRESHOLD = diff / 10; for (;;) { compare_color(); i=watch_xbee(); if (i==0) {} else if (i==1) {}// at destination } } else if (i==2) { //going away //beep long while (!kbhit()) { putc('A'); } } else if (i==3) { // out of range // long short short while (!kbhit()) { putc('B'); } } 7. Appendix B: PIC 2 Code /* * Allison Connolly and Sarah Gutbrod * Smart Cane for the blind - outdoor competition * November 23, 2009 * Principles of Biomedical Instrumentation * Pic 2: clock, US_head, US_front, IR, beeper, buzzers */ #include <16F877.h> #include <stdio.h> #include <stdlib.h> #define 20_MHZ_CLOCK #use delay(clock=20000000) /* pin definitions */ #define TSERIAL PIN_A0 #define RPIC1 PIN_B1 #define TPIC1 PIN_B2 #define RIR PIN_A2 #define TSPEECH PIN_C1 #define TUS_FRONT PIN_B4 #define RUS_FRONT PIN_B5 #define TUS_HEAD PIN_B6 #define RUS_HEAD PIN_B7 /* feedback pin */ #define UP_BUZZ PIN_D4 #define DOWN_BUZZ PIN_C7 #define FRONT_BUZZ PIN_C6 #define HEAD_BUZZ PIN_C5 #define BEEP PIN_D5 /* need interrupt for receiving info from PIC1 about when to speak */ #use rs232(baud=9600, XMIT=TPIC1, RCV = RPIC1, parity=N, bits=8) /* trigger the ultrasound pulse, then wait for the pulse to be output * read in the echo from the overhead ultrasound sensor * if there is an object within ~2.5 ft (the height of our subject), * then vibrate the overhead buzzer */ int overhead_US(void) { long OH_echo_delay, OH_echo_delay_time, OH_distance; setup_timer_1(T1_INTERNAL | T1_DIV_BY_8); /* send the trigger pulse to ultrasound */ output_high(TUS_HEAD); /* Get the sensor the chance to see this */ delay_us(10); output_low(TUS_HEAD); /* wait for the upstroke of the response */ for ( ; !input(RUS_HEAD); ) set_timer1(0); /* start timer at 0 */ /* wait for the downstroke of the response */ for ( ; input(RUS_HEAD); ) OH_echo_delay = get_timer1(); /* get the delay in samples */ OH_echo_delay_time = .0016 * OH_echo_delay; /*ms, 1.6 us per sample */ if (OH_echo_delay_time >= 36) { OH_distance = 36*1000/60; // 36 ms * (2*29 us per cm) = cm /* nothing there or too far to detect */ } else { OH_distance = OH_echo_delay_time*1000 / 60; // cm /* calculate the distance from the time */ } // if something overhead if (OH_distance < 80 ) { // 30cm = 1 ft output_high(HEAD_BUZZ); delay_ms(200); output_low(HEAD_BUZZ); return 1; } return 0; } /* trigger the ultrasound pulse, then wait for the pulse to be output * read in the echo from the front ultrasound sensor * if there is an object within ~3 ft, then vibrate the front buzzer */ long front_US(void) { long M_echo_delay, M_echo_delay_time, M_distance; setup_timer_1(T1_INTERNAL | T1_DIV_BY_8); /* send the trigger pulse to ultrasound */ output_high(TUS_FRONT); /* Give the sensor the chance to see this */ delay_us(10); output_low(TUS_FRONT); /* wait for the upstroke of the response */ for ( ; !input(RUS_FRONT); ) set_timer1(0); /* start timer at 0 */ /* wait for the downstroke of the response */ for ( ; input(RUS_FRONT); ) M_echo_delay = get_timer1(); /* get the delay in samples */ M_echo_delay_time = .0016 * M_echo_delay; /*ms, 1.6 us per sample */ if (M_echo_delay_time >= 36) { M_distance = 36*1000/60; // 36 ms * (2*29 us per cm) = cm /* nothing there or too far to detect */ } else { M_distance = M_echo_delay_time*1000 / 60; // cm /* calculate the distance from the time */ } if (M_distance < 90) { output_high(FRONT_BUZZ); delay_ms(200); output_low(FRONT_BUZZ); } return M_distance; } /* read in the analog voltage value from the IR sensor * if the value is large, then there is a low object ahead, * vibrate the step up buzzer. * if the value is very small, then there is a drop off ahead, * vibrate the step down buzzer. * if the value is within the given range, then we are detecting * the floor, so no feedback. */ int IR_sensor(void) { int input; setup_adc(ADC_CLOCK_INTERNAL); setup_adc_ports(ALL_ANALOG); set_adc_channel(2); delay_us(10); input = read_adc(); if (input > 51) { output_high(UP_BUZZ); delay_ms(300); output_low(UP_BUZZ); return 1; } else if (input < 5) { output_high(DOWN_BUZZ); delay_ms(300); output_low(DOWN_BUZZ); return 1; } return 0; } /* take two measurements from the front ultrasound sensor * 100 ms apart. if the difference between the distances is * greater than the given threshold, then something is approaching * faster than walking speed. alarm the user with 2 beeps */ void motion(void) { long dist1, dist2; dist1 = front_US(); delay_ms(100); dist2 = front_US(); // walking speed 4.11 ft/sec = 0.125 cm/ms = 12.5cm/100ms if ((dist1-dist2) > 25) { output_high(BEEP); delay_ms(80); output_low(BEEP); delay_ms(80); output_high(BEEP); delay_ms(80); output_low(BEEP); } } /* output a long beep */ void beep_long(void) { output_high(BEEP); delay_ms(200); output_low(BEEP); } /* output beeps of the pattern long short short */ void beep_mixed(void) { output_high(BEEP); delay_ms(150); output_low(BEEP); delay_ms(50); output_high(BEEP); delay_ms(50); output_low(BEEP); delay_ms(50); output_high(BEEP); delay_ms(50); output_low(BEEP); } /* the main function of the program * cycle through the overhead sensor, front sensor, IR sensor, and * motion sensor. then check if PIC1 is trying to communicate. * if so, output the appropriate beeps, then feedback to PIC1 to stop * outputting and continue reading from sensors. */ void main(void) { char c; output_low(TUS_FRONT); output_low(TUS_HEAD); for ( ;; ) { // get XBEE from other pic overhead_US(); front_US(); IR_sensor(); motion(); } } if (kbhit()) { c=getc(); if (c == 'A') { putc('R'); beep_long(); } else if (c == 'B') { putc('R'); beep_mixed(); } } 8. Appendix C: Circuit Diagram QuickTime™ and a TIFF (U ncompressed) decompressor are needed to see this pi cture.