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

Thread Starter

RobotHeart

Joined Feb 21, 2010
30
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 : http://www.maxbotix.com/uploads/LV-MaxSonar-EZ1-Datasheet.pdf )
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 buzzers...no..just 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.
Rich (BB code):
//============================================================================
//   Include
//============================================================================
#include <pic.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "delay.h"
#include "delay.c"
//============================================================================
//   Configuration
//============================================================================
__CONFIG ( 0x3F32 );
//============================================================================
//   Function Prototype
//============================================================================
void ultrasonic(void);   // Find range based on input
void init(void);
void rangecal(void);
//============================================================================
//   global variable
unsigned int To=0;
unsigned int TH=0;
unsigned int value;
unsigned int distance;
unsigned int data=0;

//============================================================================
//   interrupt prototype
//============================================================================================================
static void interrupt isr(void)
{
   if(TMR0IF)         // TMR0 is overflow
   {
      TMR0IF=0;    // clear flag bit
      To+=0x100;      // count number of TMR0 overflow ( make it to 16bit TMR)
   }
}
//============================================================================
//   Main Function
//============================================================================
void main(void)
{
   init();
   ultrasonic();
}




// Initailization
// Description : Initialize the microcontroller
//============================================================================================================

void init()
{
   // Tris configuration (input or output)
   TRISA = 0b00000000;      //set PORTA as output
   TRISB = 0b00000100;      //set RB2 pin as input, other as output
   TRISC = 0b00000000;      //set PORTA as output
   
   RB4=1;   //5V to sensor
   DelayMs(250);  //sensor module power up time

   // TMR 0 configuation
   T0CS=0;                  
   PSA=0;                  
   PS2=1;                  // prescale 1:256
   PS1=1;                  //
   PS0=1;                  //
   TMR0IE=1;                  // TMR0 Interrupt
   TMR0=0;                  
      
   GIE = 1;   //global interrupt
}
//================================================================================
// FUNCTIONS
//================================================================================   
//**************************************************
//Calculate the range from the sensor depending on PWM signal input
void ultrasonic(void)      
{      
   while(1)
   {   
      if(RB2==0)               //if RB2 is high
      {
      TMR0=0;            // clear all counter involved, start new count for period of RB2 high
      To=0;
      }      
      else
      {
      TH=TMR0+To;         // RB2 is 0 mean is falling from 1 save TH, RB2 high period
      value=TH;      //value of tmr0+to
      distance=value*1.75616;   // calculate inch value per inch = 147us with 20Mhz internal clock.   
      rangecal();
      }
   }
                                                   
}

void rangecal(void)
{
   
      if(distance>100)
      {
      PORTC=0B00000001;
      }
      else if(distance>80)
      {
      PORTC=0B00000010;
      }
      else if(distance>60)
      {
      PORTC=0B00000100;
      }
      else if(distance>40)
      {
      PORTC=0B00001000;
      }
      else if(distance>20)
      {
      PORTC=0B00010000;
      }
}
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 :)
 

Thread Starter

RobotHeart

Joined Feb 21, 2010
30
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 :)
 

Thread Starter

RobotHeart

Joined Feb 21, 2010
30
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 !

anyway...my 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:

Rich (BB code):
   #include <built_in.h>
  unsigned int adc_rd;
   
  void main() {
    ANSEL  = 0x04;              // Configure AN2 pin as analog
    TRISA  = 0xFF;              // PORTA is input
    ANSELH = 0;                 // Configure other AN pins as digital I/O
    TRISC  = 0x3F;              // Pins RC7, RC6 are outputs
    TRISB  = 0;                 // PORTB is output
   
    do {
      temp_res = ADC_Read(2);   // Get 10-bit results of AD conversion
      PORTB = temp_res;         // Send lower 8 bits to PORTB
      PORTC = temp_res >> 2;    // Send 2 most significant bits to RC7, RC6
    } while(1);
  }

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
 

Markd77

Joined Sep 7, 2009
2,806
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.
 

Thread Starter

RobotHeart

Joined Feb 21, 2010
30
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:

Rich (BB code):
output_value = ( temp_res - 3 )* 2
 
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 :)
 

Markd77

Joined Sep 7, 2009
2,806
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:

symqwerty

Joined Feb 22, 2010
31
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 : http://www.maxbotix.com/uploads/LV-MaxSonar-EZ1-Datasheet.pdf )
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 buzzers...no..just 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.
Rich (BB code):
//============================================================================
//   Include
//============================================================================
#include <pic.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "delay.h"
#include "delay.c"
//============================================================================
//   Configuration
//============================================================================
__CONFIG ( 0x3F32 );
//============================================================================
//   Function Prototype
//============================================================================
void ultrasonic(void);   // Find range based on input
void init(void);
void rangecal(void);
//============================================================================
//   global variable
unsigned int To=0;
unsigned int TH=0;
unsigned int value;
unsigned int distance;
unsigned int data=0;

//============================================================================
//   interrupt prototype
//============================================================================================================
static void interrupt isr(void)
{
   if(TMR0IF)         // TMR0 is overflow
   {
      TMR0IF=0;    // clear flag bit
      To+=0x100;      // count number of TMR0 overflow ( make it to 16bit TMR)
   }
}
//============================================================================
//   Main Function
//============================================================================
void main(void)
{
   init();
   ultrasonic();
}




// Initailization
// Description : Initialize the microcontroller
//============================================================================================================

void init()
{
   // Tris configuration (input or output)
   TRISA = 0b00000000;      //set PORTA as output
   TRISB = 0b00000100;      //set RB2 pin as input, other as output
   TRISC = 0b00000000;      //set PORTA as output
   
   RB4=1;   //5V to sensor
   DelayMs(250);  //sensor module power up time

   // TMR 0 configuation
   T0CS=0;                  
   PSA=0;                  
   PS2=1;                  // prescale 1:256
   PS1=1;                  //
   PS0=1;                  //
   TMR0IE=1;                  // TMR0 Interrupt
   TMR0=0;                  
      
   GIE = 1;   //global interrupt
}
//================================================================================
// FUNCTIONS
//================================================================================   
//**************************************************
//Calculate the range from the sensor depending on PWM signal input
void ultrasonic(void)      
{      
   while(1)
   {   
      if(RB2==0)               //if RB2 is high
      {
      TMR0=0;            // clear all counter involved, start new count for period of RB2 high
      To=0;
      }      
      else
      {
      TH=TMR0+To;         // RB2 is 0 mean is falling from 1 save TH, RB2 high period
      value=TH;      //value of tmr0+to
      distance=value*1.75616;   // calculate inch value per inch = 147us with 20Mhz internal clock.   
      rangecal();
      }
   }
                                                   
}

void rangecal(void)
{
   
      if(distance>100)
      {
      PORTC=0B00000001;
      }
      else if(distance>80)
      {
      PORTC=0B00000010;
      }
      else if(distance>60)
      {
      PORTC=0B00000100;
      }
      else if(distance>40)
      {
      PORTC=0B00001000;
      }
      else if(distance>20)
      {
      PORTC=0B00010000;
      }
}
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 :)
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)
OR
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.
OR
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.:)
 

Thread Starter

RobotHeart

Joined Feb 21, 2010
30
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....
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 :)
tq
 

Thread Starter

RobotHeart

Joined Feb 21, 2010
30
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)
OR
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.
OR
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.:)
- 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 ??
tq
 

symqwerty

Joined Feb 22, 2010
31
- 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 ??
tq
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:)
 

Thread Starter

RobotHeart

Joined Feb 21, 2010
30
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. 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:)
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
Rich (BB code):
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
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 :)
 

symqwerty

Joined Feb 22, 2010
31
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..
http://ww1.microchip.com/downloads/en/AppNotes/00538c.pdf

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
 

Thread Starter

RobotHeart

Joined Feb 21, 2010
30
thank you for replying...almost lost hope :)
So basically the PWM will be converted to analog signal using a LP filter...ok first of all..im 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.
 
Top