Help Needed: Controlling a motor using ultrasonic sensor and IR sensor

Discussion in 'Embedded Systems and Microcontrollers' started by RobotHeart, Feb 21, 2010.

  1. RobotHeart

    Thread Starter Member

    Feb 21, 2010
    Hello everyone

    I'm actually a new member here as i wish i can get the help i need, and also try to help others.
    I'm doing my final year project which is an assistance aid that helps blind people avoid obstacles while walking.

    in this topic i want to seek help while im doing my software part.
    at the FIRST part...What im going to do is that i want to control a vibration motor (rotation in 1 direction only) depending on the output of ultrasonic sensor which is Maxbotix EZ1 (datasheet : )
    this sensor got digital output (PWM), and an input of 5V with a detection distance that can reach to 6m. in this project im going to use the PWM output.

    the process will be:
    - if there is a far obstacle the vibration motor should rotate slowly.
    - if there is a medium distance obstacle the vibration motor should rotate at normal speed.
    - if there is a near obstacle the vibration motor should rotate fast.

    Im going to use PIC16F876A microcontroller which has an internal ADC and other sufficient features.
    there is no display LCD or as simple as that (thats for FIRST part) and as im pretty weak in programming , i'll need your full help.

    at start i want to control the ultrasonic sensor...i've found a source code in the Maxbotix supplier (Cytron) forums, the code does control the ultrasonic, but for different output purposes which can be adjusted easily.
    Code ( (Unknown Language)):
    1. //============================================================================
    2. //   Include
    3. //============================================================================
    4. #include <pic.h>
    5. #include <stdlib.h>
    6. #include <string.h>
    7. #include <stdio.h>
    8. #include "delay.h"
    9. #include "delay.c"
    10. //============================================================================
    11. //   Configuration
    12. //============================================================================
    13. __CONFIG ( 0x3F32 );
    14. //============================================================================
    15. //   Function Prototype
    16. //============================================================================
    17. void ultrasonic(void);   // Find range based on input
    18. void init(void);
    19. void rangecal(void);
    20. //============================================================================
    21. //   global variable
    22. unsigned int To=0;
    23. unsigned int TH=0;
    24. unsigned int value;
    25. unsigned int distance;
    26. unsigned int data=0;
    28. //============================================================================
    29. //   interrupt prototype
    30. //============================================================================================================
    31. static void interrupt isr(void)
    32. {
    33.    if(TMR0IF)         // TMR0 is overflow
    34.    {
    35.       TMR0IF=0;    // clear flag bit
    36.       To+=0x100;      // count number of TMR0 overflow ( make it to 16bit TMR)
    37.    }
    38. }
    39. //============================================================================
    40. //   Main Function
    41. //============================================================================
    42. void main(void)
    43. {
    44.    init();
    45.    ultrasonic();
    46. }
    51. // Initailization
    52. // Description : Initialize the microcontroller
    53. //============================================================================================================
    55. void init()
    56. {
    57.    // Tris configuration (input or output)
    58.    TRISA = 0b00000000;      //set PORTA as output
    59.    TRISB = 0b00000100;      //set RB2 pin as input, other as output
    60.    TRISC = 0b00000000;      //set PORTA as output
    62.    RB4=1;   //5V to sensor
    63.    DelayMs(250);  //sensor module power up time
    65.    // TMR 0 configuation
    66.    T0CS=0;                  
    67.    PSA=0;                  
    68.    PS2=1;                  // prescale 1:256
    69.    PS1=1;                  //
    70.    PS0=1;                  //
    71.    TMR0IE=1;                  // TMR0 Interrupt
    72.    TMR0=0;                  
    74.    GIE = 1;   //global interrupt
    75. }
    76. //================================================================================
    77. // FUNCTIONS
    78. //================================================================================  
    79. //**************************************************
    80. //Calculate the range from the sensor depending on PWM signal input
    81. void ultrasonic(void)      
    82. {      
    83.    while(1)
    84.    {  
    85.       if(RB2==0)               //if RB2 is high
    86.       {
    87.       TMR0=0;            // clear all counter involved, start new count for period of RB2 high
    88.       To=0;
    89.       }      
    90.       else
    91.       {
    92.       TH=TMR0+To;         // RB2 is 0 mean is falling from 1 save TH, RB2 high period
    93.       value=TH;      //value of tmr0+to
    94.       distance=value*1.75616;   // calculate inch value per inch = 147us with 20Mhz internal clock.  
    95.       rangecal();
    96.       }
    97.    }
    99. }
    101. void rangecal(void)
    102. {
    104.       if(distance>100)
    105.       {
    106.       PORTC=0B00000001;
    107.       }
    108.       else if(distance>80)
    109.       {
    110.       PORTC=0B00000010;
    111.       }
    112.       else if(distance>60)
    113.       {
    114.       PORTC=0B00000100;
    115.       }
    116.       else if(distance>40)
    117.       {
    118.       PORTC=0B00001000;
    119.       }
    120.       else if(distance>20)
    121.       {
    122.       PORTC=0B00010000;
    123.       }
    124. }
    for this code, the user used PIC16F877 (which has an internal OSC)

    at first, i tried compiling the code just for checking but the following errors occurred:

    can't open include file #include <pic.h>
    can't open include file #include <stdlib.h>
    can't open include file #include <string.h>
    can't open include file #include <stdio.h>
    can't open include file #include "delay.h"
    can't open include file #include "delay.c"

    the compiler that im using is MikroC PRO (& MikroC)....i think there are some missing files if im not mistaken, i tried simply to delete those lines but of course 10s of errors occured.

    any idea what should i do to compile this code successfully ?

    i need some attention for this topic please as this is my final year project.

    thank you :)
  2. BMorse

    Senior Member

    Sep 26, 2009
  3. RobotHeart

    Thread Starter Member

    Feb 21, 2010
    thank you for replying...
    well that project can be useful in developing my project after finishing mine, specially that i don't like taking others 'exact' job...have to put my own touch :)
    thanks alot :)
  4. BMorse

    Senior Member

    Sep 26, 2009
    well, it is just a "guide" on how you can accomplish certain tasks for your project....

    B. Morse
  5. RobotHeart

    Thread Starter Member

    Feb 21, 2010
    for the previous problem i had to use HI-TECH C-Compiler and also delete the delay lines (although i got the delay.h file but still wont work ! ). maybe i'll have to do some empty loops if i want to do delay later on ! problem now is that i want to convert the analog voltage coming from the IR sensor to digital and then back to analog again by using PIC16F877A.

    the following code convert from analog to digital:

    Code ( (Unknown Language)):
    2.    [FONT=&quot]#include <built_in.h>[/FONT]
    3.   [B][FONT=&quot]unsigned int[/FONT][/B][FONT=&quot] adc_rd;[/FONT]
    4.   [FONT=&quot] [/FONT]
    5.   [B][FONT=&quot]void[/FONT][/B][FONT=&quot] main() {[/FONT]
    6.   [FONT=&quot]  ANSEL  = 0x04;              [I]// Configure AN2 pin as analog[/I][/FONT]
    7.   [FONT=&quot]  TRISA  = 0xFF;              [I]// PORTA is input[/I][/FONT]
    8.   [FONT=&quot]  ANSELH = 0;                 [I]// Configure other AN pins as digital I/O[/I][/FONT]
    9.   [FONT=&quot]  TRISC  = 0x3F;              [I]// Pins RC7, RC6 are outputs[/I][/FONT]
    10.   [FONT=&quot]  TRISB  = 0;                 [I]// PORTB is output[/I][/FONT]
    11.   [FONT=&quot] [/FONT]
    12.   [FONT=&quot]  [B]do[/B] {[/FONT]
    13.   [FONT=&quot]    temp_res = ADC_Read(2);   [I]// Get 10-bit results of AD conversion[/I][/FONT]
    14.   [FONT=&quot]    PORTB = temp_res;         [I]// Send lower 8 bits to PORTB[/I][/FONT]
    15.   [FONT=&quot]    PORTC = temp_res >> 2;    [I]// Send 2 most significant bits to RC7, RC6[/I][/FONT]
    16.   [FONT=&quot]  } [B]while[/B](1);[/FONT]
    17.   [FONT=&quot]}[/FONT]

    the previous code convert the analog voltage and send it to portB and portC as a binary number...lets say we have an input of 1V >> 1V/.00489 >> 205 decimal = 11001101 in binary.

    now i don't want the binary output as the final result...i want to get an analog output from 1 pin.
    lets say the input coming from IR sensor and going to microcontroller is as following:
    0.5V, 1V, 1.5V, 2V, 2.5V, 3V

    the conversion needed from input to the final output is as following

    0.5V >> ADC >> 5V
    1V >> ADC >> 3V
    1.5V >> ADC >> 2.5V
    2V >> ADC >> 1V
    2.5V >> ADC >> 0.5V
    3V >> ADC >> 0V

    note that the output values at the right side are supposed to be analog.

    so the question is, what is the code modification needed to get analog values instead of the binary output given by ADC ?

    i tried my best to make it as clear as possible, now i need your help :)

    thank you
  6. Markd77

    Senior Member

    Sep 7, 2009
    For motor control the PWM output of the PIC would be best. It's not strictly analog but it is excellent for motor control.
    Your input output chart isn't exactly linear. I'm not sure if you just want these 6 values with a step change in between. If you do then a lookup table would be fine.
    If you want a smooth response a linear relationship would be easier and close enough.
    Your input has a 2.5V range and the output range is 5V so you would just subtract the input from 3V and multiply by 2.
    It will have to be scaled to match the range of your ADC and the PWM generator but that should be easy enough.
  7. RobotHeart

    Thread Starter Member

    Feb 21, 2010
    well i did mention that im weak in programming :) ....thats why i choosed the input values i've wrote previously...but if the linear relationship is easy enough for a newbie, it will be great !
    so as u said, in my case i have to substract the input from 3V and then multiply by 2

    lets say:

    Code ( (Unknown Language)):
    2. output_value = ( temp_res - 3 )* 2
    4. PortB.2 = output_value
    is that somehow partialy correct ?

    please guide me to write this code as i really need to come up with something that works properly.

    thank you :)
  8. Markd77

    Senior Member

    Sep 7, 2009
    Not quite:

    Just using the high byte of the left shifted ADC result, 3V would be (3/5)*255=153

    output_value = ( 153-temp_res )* 2

    This will give you a value of 0-255 which you will have to send to the PWM peripheral. I don't really understand C so you would have to find some example. I'm sure there are plenty out there.
    I'm also not sure if in C the above line uses only the higher byte of temp_res, if someone could check....
    Last edited: Mar 10, 2010
  9. symqwerty


    Feb 22, 2010
    first of all, I believe that pic16f877 DONT have internal oscillator...

    if you want to use some C function like above, you MUST make sure that *.h file EXIST.(when compiling, compiler will look for THAT files)
    MikroC have tons of built-in functions such as 'delay' and etc. So, you dont have to include that header file.

    Bear in mind that you are programming MCU in C environment. Dont expect to have full function/features like what has been defined in ANSI C. Read MikroC manual regarding ANSI C support.

    For the sensor, i recommend you to use CCP module(plus interrupt) in order to read PWM signal.
    you can use analog as an input instead of pulse since you have 3 options the read the output from the sensor. Anyway, choose what you like:)

    For ADC part(your IR sensors), you must set the Vref. Are you sure that your IR sensor will output max 5V analog?By default, the Vref tied to Vcc of the MCU( i assume that you know abt this ). Then, after get the digital val, you can do the math to manipulate the readings.:)
  10. RobotHeart

    Thread Starter Member

    Feb 21, 2010
    so ur saying the equation:
    output_value = ( 153-temp_res )* 2
    will get the value that will be sent to the output port ?
    but why it is sent to the PWM ? i need an analog output...i mean PWM gives a pulse as i know so far, so how can i control a motor by a pulse that doesn't change in amplitude ? i know there's something here im missing..hope u tell me what it is :)
  11. RobotHeart

    Thread Starter Member

    Feb 21, 2010
    - ya i knew that and used an external 20MHZ oscillator :)
    - ya i also tried that, someone gave me the delay file (delay.h)...ried to past is into the MikroC system file called Include which include all the libraries...didn't work for the delay file...but worked for other !
    - about the ultrasonic sensor...i've uploaded the previous software and been able to calculate the distance using the PWM...but still couldn't send the result to a single output pin to have an analog "linear" output...instead...various pins were toggled to represent the output as shown on the last lines of the previous code.
    - the IR maximum output that goes to MCU is 3V....does that mean the Vref should be changed to 3V ??
  12. symqwerty


    Feb 22, 2010
    I think your method should be revised. You want to output the reading in analog form, right? There are 3 ways to implement it.

    1. Since you have "digital" value after you, what you could do is to buy an DAC chip..pass all the 8bit or 10-bit value to DAC to convert it to analog. There are 2 type of DAC IC, parallel or serial input. Parallel input means that single pin represent single bit.Thus, if you have 10 bit value, it is equal to 10 pin must be connected to the chip(each way). The
    serial require one pin only but you must know how to use SPI or I2C:)

    2. Using PWM..You can generate analog output using PWM. The method is the same as before but instead of reading, you generate the PWM based on the reading you have. It's something like a 'low-cost' DAC.

    3. The simplest method. The sonar sensor itself has 3 types of output, uart, analog(this is what u want) and pulse(PWM). Why dont you just take the output from the sensor(it's in analog form).

    May i ask you a question? Why you want to convert it to analog form?

    For ADC portion, Vref will affect your ADC sensitivity. Why? If you maximum input is 3V, but your Vref tied to 5V, then,

    1-bit = 5/(2^10)V = 4.88mV >>>> maximum digital val @3V = 614.4 or 614

    but if Vref=3.0

    1-bit = 3/(2^10)V = 2.93mV >>>> max dig val @3 = 1024 = 2^10:)
  13. RobotHeart

    Thread Starter Member

    Feb 21, 2010
    thank u for the reply
    first of all...i think i should've explained how my sensors work and what types do i have.
    i have 3 types of sensors with a total number of 5 sensors:

    1\ EZ1 maxbotix Ultrasonic sensor:
    - used to detect objects on the front side of the device.
    - input voltage: 5V
    - output voltage: analog, PWM (digital), etc
    - analog output voltage range: 0V to 5V
    - range of detection: 6m
    - the required range in my project: 2m
    - the relationship between analog output voltage and distance: proportional (means when the distance of the obstacle increase the voltage increase too)
    - the output used to be connected to MCU: PWM (digital).

    2\ Standard Ultrasonic sensor module (quantity = 2)
    - used to detect objects on left and right sides.
    - input voltage = 5V
    - output voltage: Analog only
    - analog output voltage range: 0V to 4.5V
    - range of detection: 3m
    - the required range in my project: 1 to 1.5m
    - the relationship between analog output voltage and distance: proportional (means when the distance of the obstacle increase the voltage increase too, the required relation is the opposite...thats why im using a MCU to give the reverse output )
    - the relationship between digital output and distance: the PWM width increase when the object goes far...but after using the distance equation the relationship becomes non-proportional (voltage increase when object come closer).
    - the output used to be connected to MCU: Analog.

    3\ SHARP IR sensor (quantity = 2)
    - used to detect holes and low objects .
    - input voltage = 5V
    - output voltage: Analog only
    - analog output voltage range: 0V to 3V (can be amplified to 5V)
    - range of detection: 1m
    - the required range in my project: 10cm to 1m
    - the relationship between analog output voltage and distance: non-proportional ( means when the object comes near...the output voltage increases, so one of the 2 sensors will be directly connected to the motor, the other sensor (hole detection) will be connected through MCU to get the reveres relation).
    - the output used to be connected to MCU: Analog.

    so....all of the sensor (except for the hole detection sensor) will be connected to the MCU...and all of those which r connected to the MCU (except the EZ1 maxbotix Ultrasonic sensor) will have a reveres relation in order to make the motors rotate faster when the obstacles come nearer.

    1\ using DAC will be a good idea...but only for the EZ1 maxbotix ultrasonic sensor since its the only one having (connected to MCU) a non-proportional relation.

    2\ i think using the PWM is the best way...although im not good in programming...but i trust you guyz on teaching me how to do it :)
    please show me how.

    3\ well...i have a small problem trying to make a conclusion from the calculation u have just made
    Code ( (Unknown Language)):
    1. 1-bit = 5/(2^10)V = 4.88mV >>>> maximum digital val @3V =  614.4 or 614
    3. but if Vref=3.0
    5. 1-bit = 3/(2^10)V = 2.93mV  >>>> max dig val @3 = 1024 =  2^10
    but i think i should amplify the 3V to 5V (coming from the IR sensor to the MCU) in order for all sensors to have the same Vref without complications.

    im very sorry for the long explanation :)
  14. RobotHeart

    Thread Starter Member

    Feb 21, 2010
    waiting for is really needed !
  15. symqwerty


    Feb 22, 2010
    Yup, you could do it either way..using opamp would help you w/o affecting Vref.

    It's hard to discuss about generating analog from PWM w/o diagram here but i have some article for you..

    The basic idea is:

    Let's assume that you have a pwm signal(with FIXED period) @50Hz

    so, the period is 1/50Hz = 20ms

    Logic high = VCC / 5V
    logic Low = GND

    at DC=100%; Vo = 5v
    at DC=50%; Vo = 2.5v
    at DC=10%; Vo = 0.5V

    or (Vlogic/100)*DC or (Vcc/period)*(time@logic high)

    *remember, pwm freq will affect the output
  16. RobotHeart

    Thread Starter Member

    Feb 21, 2010
    thank you for replying...almost lost hope :)
    So basically the PWM will be converted to analog signal using a LP filter...ok first of using PIC16F877A...does it have a PWM output pin ? which one is it ? is it the CCP1 and CCP2 ??

    and what is the code that can be used to apply the equations u mentioned and do i still have to apply the equations mentioned in previous replies (output_value = ( 153-temp_res )* 2 ) ?

    i need an explanation in terms of steps if possible, because things are getting slightly mixed up here :)

    p.s. always note that there are outputs that have proportional relation with the input, and outputs that have a non-proportional relation with the input, so i guess 2 different types of equations are needed in my case.
  17. symqwerty


    Feb 22, 2010
    It's up to you either to use CCP1 or CCP2..That PIC have 2 PWM output.
  18. RobotHeart

    Thread Starter Member

    Feb 21, 2010
    can you show me what are the steps on using CCP1 for example ?
  19. symqwerty


    Feb 22, 2010
  20. aneeshmp200745

    New Member

    Feb 24, 2010
    add delay files ..