1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

infrared Liquid level detector-SharpGP2D12

Discussion in 'Microcontrollers' started by fantabulous68, Aug 28, 2009.

  1. Mr RB

    Mr RB Well-Known Member

    Joined:
    Jul 22, 2008
    Messages:
    4,716
    Likes:
    194
    Location:
    Out there
    The calc_distance() routine you are using already decodes the measurement 00-99 into 2 values;
    cm10 (this is the TENS digit)
    cm (this is the UNITS digit)

    Then later on in oyur code in the main loop you are doign this;
    Code (text):

    //CM is higher than 09 so spilt the variable CM into 2
    cmHigh = ( ( cm >> 4 ) & 0x0F ) + 0x30;
    cmLow = ( cm & 0x0F ) + 0x30;
     
    which is bad because it has already been done in the calc_distance() function.

    All you need to do to display the distance in cm is this;
    Code (text):

    lcd_data(cm10 + '0');
    lcd_data(cm + '0');
     
    Which will display the 2 decimal digits (0-9) as 2 ascii digits ('0'-'9')
     
    • Like Like x 1
  2. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    CoooooooooooooooooooooooooooooooooooooooooooL............................

    :):):):):):):):):):):):):):):):):):):):):):):):):):):):):):):)

    its working hehehehehehehe.......

    Thanx Guys....;)

    lol now I'll have something to demo to my lecturer tomorrow...
    he wanted values on the LCD even if it was wrong lol (but he will be getting the right values:D)


    for objects<8cm away....the sensor gives crazy readings...otherwise its pretty accurate.....

    so the range is about [8-80]


    Ok this feels good...:)-its far from over though:p
    still got to integrate it with the other code to give the level of the liquid...
    and then i got to TWEAK IT(or PIMP MY RIDE as you'll would say:D)
     
    Last edited: Sep 17, 2009
  3. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    Mr.RB good find. I even forgot about that calc routine. Even in red i didnt spot it :)
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. Mr RB

    Mr RB Well-Known Member

    Joined:
    Jul 22, 2008
    Messages:
    4,716
    Likes:
    194
    Location:
    Out there

    Well I did have the unfair advantage of having seen it somewhere before... ;)
     
  6. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    i want to calculate the level of the liquid.................

    *At the moment the sensor code gives the distance to the surface of the liquid.....

    *the code allows the user to enter the "height" of container .....

    So the liquid level=height of container-distance to surface of liquid

    Now in the calc_distance function...the distance to the surface of the liquid is split into two digits..... which are displayed on a LCD.

    ie. cm(units) & cm10(tens)


    So do i need to send these 2 SPLIT digits from the calc_distance function to a NEW function that would combine them so that i can SUBTRACT it from the height of the container????


    IS there a better solution?
     
    Last edited: Sep 18, 2009
  7. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    Now with this code below there is a new variable called mathKeep.
    If you look in the calc distance function its basically a copy of the math variable before we do anything like splitting.

    Now when done using math variable we just copy our data back from the mathKeep to the math. and you can resume calculations with the math variable.

    Code (text):

    void calc_distance(void)
    {
    unsigned int mathKeep;      // [b]used for voltage calculations backup[/b]
        // from the transeiver datasheet the analog voltage is
        // the inverse of distance, so distance can be calculated
        // d = (1 / volts) then just scaled to suit the transeiver

        // load ADC value in 16bit math var
        math = ADRESH;
        math = (math * 256);
        math += ADRESL;

        // now invert it; (1 / volts) use (6050 / volts) for scaling
        math = (6050 / math);
        if(math >= 2) math -=2;     // fix linear error (-2)
        if(math > 99) math = 99;    // max limit at 99cm

        //[b]Create a copy of math for more use[/b]
        mathKeep = math;
        //LiquidLevel=height-; 

        // convert from 0-99 to 2 decimal digits, 0-99cm
        cm10=0;
        while(math >= 10)
        {
            cm10++;
            math -= 10;
        }
        cm = math;

        math = mathKeep;    //[b]Now our original data is back and can be used.[/b]
    }
     
     
    Last edited: Sep 18, 2009
  8. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    :eek::eek::eek:Very efficient...Simple method:eek::eek::eek:
     
  9. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    Could someone suggest the most suitable application for using the INFRARED LIQUID LEVEL DETECTOR???

    Where would it be useful???I want to make additional features to the project but i think it would be best if i can finalize were it is going to be useful first.

    EG if it will be used in a LAB....then knowing the volume of the liquid is important.
    and i can write code for doing that....


    the infrared detector has a range from 10cm-80cm



    And any ideas on packaging the project...........?????
     
  10. jpanhalt

    jpanhalt Well-Known Member Most Helpful Member

    Joined:
    Jun 21, 2006
    Messages:
    6,058
    Likes:
    519
    Location:
    Cleveland, OH, USA
    ONLINE
    Have you validated that it works with various liquids, including water, yet? What is its accuracy and precision? Does it need recalibration with different liquids?

    John
     
  11. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    well im trying with water now....and it gives the craziest readings:eek:

    The readings keep fluctuating!!! because of the ripples and movement on the surface...:confused:


    it measures in cm......

    im trying with various liquids now....
     
  12. Noggin

    Noggin Member

    Joined:
    Jul 21, 2003
    Messages:
    595
    Likes:
    9
    Location:
    Austin, TX
    This should help reduce fluctuations. Increase the shift value to increase noise rejection, but it will slow the response.

    Code (text):
    typdef struct filter_type
    {
       Uint16 accumulator;
       Uint16 output;
       Uint8 shift_value;
       Uint8 initialized;
    };

    filter_type adc_filter;

    void Init_Filter( filter_type *filter, Uint8 shift )
    {
       filter->initialized = FALSE;
       filter->shift_value = shift;
    }

    void Update_Filter( filter_type *filter, Uint16 new_value )
    {
       if (filter->initialized != TRUE)
       {
          filter->output = new_value;
          filter->accumulator = new_value << filter->shift_value;
          filter->initialized = TRUE;
       }
       else
       {
          filter->accumulator -= filter->output;
          filter->accumulator += new_value;
          filter->output = filter->accumulator >> filter->shift_value;
       }
    }
    Whenever you read your adc, just call Update_Filter( &adc_filter, adc_value ). Wherever you perform a calculation on the ADC value, use adc_filter.output instead.

    I haven't read your code, so I'm not positive that this is in any way helpful at all.
     
    Last edited: Sep 19, 2009
  13. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    Trouble in paradise

    :eek::eek::eek::eek::eek::eek::eek:
    The readings are fluctuating.....not very stable especially for water....

    i tried the detector on water, handy Andy (thick white liquid), oil......................................in a glass container and plastic container

    the detector is not giving the right liquid level....

    the height=height from the sensor to the base of the container

    liquid level=height-distance to surface of liquid

    so i only enter 1 input ie. height...... think i need to slow the sensor reading down.....

    Uhmmmmm what do you guys think???im going to try the sensor on paint tomorrow.....its 21:40 now.

    What can i do to improve the reading of the sensor???the most accurate reading was for handy Andy in a plastic container when it was full...

    also while varying the level of the liquid .....the readings jump about in big steps


    The sensor detects paper at an accurate level...BT i need it to work for liquids...is it perhaps(im scared to say this)

    is it perhaps the GP2 not suitable for liquids:(


    do i need to some how calibrate the sensor to enter density of different liquids and use that somewhere to improve the reading?



    Please tell me what to do to improve the readings


    Here is the code:
    Code (text):
    #include <pic.h>
    #include "pic.h"
    #include "delay.h"
    #include "math.h"
    #include <stdio.h>
    #include <stdlib.h> //

    void userMenu(char pos); //  
    void FloatToStr(float , char[]);
    void DelayMs(unsigned char);
    void lcd_cmd(unsigned char);
    void lcd_data(unsigned char);
    void lcd_clear(void);
    void lcd_puts(const char[]);
    void lcd_goto_L1(void);
    void lcd_goto_L2(void);
    void lcd_cursor(unsigned char);
    void lcd_init(void);
    void init(void);
    char WaitForInput(char expire);  
    unsigned char user_input(void);
    void home_screen(void);
    void EnterHeight(void);
    void EnterScreen(void);
    void ShowDigits(unsigned char val);
    void calc_distance(void);
    void main(void);


    unsigned char cm2LCD;
    unsigned char posneg;
    unsigned char LLHigh, LLLow;
    unsigned int LiquidLevel;


         

    #define LCD_RS RC0      //LCD RS pin
    #define LCD_EN RC1      //LCD EN pin
    #define LCD_STROBE()    LCD_EN = 1; asm("nop"); asm("nop"); LCD_EN = 0

    unsigned char cm10;     //
    unsigned char cm;       //
    unsigned int math;      // used for voltage calculations


    unsigned char NumDec;
    unsigned char NumSep[2];
       
    unsigned char i,j,k;
    //char temp[8];
    //[/b]
    unsigned char height=50;
    unsigned char range;
    unsigned char area;
    unsigned char SensorPos=10;
    //[/b] New Vars
    char input_sw;

     
    char mnuPOS;

    unsigned char MyVal;
    unsigned char MyValLCD[2];
    unsigned char MyMaxVal;
    unsigned char MyMinVal;
    unsigned long bres;     // for bresenham 2-second timer system

    unsigned char ;

    #define HOME_SW RC2             //HOME switch  
    #define INCREASE_SW RC3         //INCREASE switch
    #define DECREASE_SW RC4         //DECREASE switch
    #define ENTERSETTINGS_SW RA4    //ENTERSETTINGS switch



    ///////////////////////CONVERT FLOAT TO STRING///////////////////
    // This function was taken from the CAVR library. It was modified slightly
    // to suit our design.
    void FloatToStr(float n, char str[])
    {
    float scale;
    unsigned char d,f;
    f=0;i=0;
    if (n<0.0) {n=-n; str[f]='-'; f++;};
    n=n+0.005;
    scale=1.0;
    while (n>=scale) {scale=scale*10.0; ++i;};
    if (i==0) {str[f]='0'; f++;}
    else
    while (i--)
          {
          scale=floor(0.5+scale/10.0);
          d=(unsigned char) (n/scale);
          str[f]=d+'0';
          n=n-scale*d;
          f++;
          };

    str[f]='.';
    f++;
    for (j=0;j<=1;j++) //2 decimal points
          {
          n=n*10.0;
          d=(unsigned char) n;
          str[f]=d+'0';
          n=n-d;
          f++;
          };
    str[f]='\0';
    }
    ///////////////////END CONVERT FLOAT TO STRING///////////////////

    /////////////////////////////DELAY///////////////////////////////
    void DelayMs(unsigned char cnt)
    {
    #if XTAL_FREQ <= 2MHZ
        do {
            DelayUs(996);
        } while(--cnt);
    #endif

    #if    XTAL_FREQ > 2MHZ
        unsigned char   p;
        do {
            p = 4;
            do {
                DelayUs(250);
            } while(--p);  
        } while(--cnt);
    #endif
    }

    void DelayS(unsigned char cnt)
    {
        for (j=0; j<(cnt*10); j++)
            DelayMs(100);
    }
    ///////////////////////////DELAY END/////////////////////////////

    //////////////////////////////LCD SETUP//////////////////////////
    /* send a command to the LCD */
    void lcd_cmd(unsigned char c)
    {
        DelayMs(2); //wait for LCD to be ready shorter delay
        LCD_RS = 0;  //write instruction
        PORTB = (c & 0xF0); //load upper nibble on LCD data lines
        LCD_STROBE(); //send instruction to LCD
        PORTB = ((c << 4) & 0xF0); //load upper nibble on LCD data lines
        LCD_STROBE(); //send instruction to LCD    
    }

    /* send data to the LCD */
    void lcd_data(unsigned char c)
    {
        DelayMs(2); //wait for LCD to be ready shorter delay
        PORTB = 0x00;
        LCD_RS = 1; //write data
        PORTB |= (c & 0xF0); //load upper nibble on LCD data lines    
        LCD_STROBE(); //send instruction to LCD
        PORTB &= 0x00; //load upper nibble on LCD data lines
        PORTB |= ( (c << 4) & 0xF0);
        LCD_STROBE(); //send instruction to LCD
    }

    /*Clear the LCD*/
    void lcd_clear(void)
    {
        lcd_cmd(0x01); //command to clear LCD
    }

    /*write a string of chars to the LCD*/
    void lcd_puts(const char s[])
    {
        j = -1;
        while(s[++j]!=('\0')) // send characters until null character reached
            lcd_data(s[j]);
    }

    /*go to beginning of line 1*/
    void lcd_goto_L1(void)
    {
        lcd_cmd(0b10000000); // command to go to line 1
    }

    /*go to beginning of line 2*/
    void lcd_goto_L2(void)
    {
        lcd_cmd(0b11000000); // command to go to line 2
    }

    /*move cursor "x" positions to the right*/
    void lcd_cursor(unsigned char x)
    {
        lcd_cmd(((x)&0x7F)|0x80);
    }

    /*initialise the LCD - put into 4 bit mode*/
    void lcd_init(void)
    {
        LCD_RS = 0;
        LCD_EN = 0;
        DelayMs(20); //wait for LCD startup
        lcd_cmd(0x02);
     
        lcd_cmd(0x28);  // 4-bit mode
        lcd_cmd(0x08);  // display off
        lcd_cmd(0x01);  // clear display
        lcd_cmd(0x0C);  // disp. on, cursor off, cursor blink off
        lcd_cmd(0x06);  // entry mode
        lcd_cmd(0x80);  // initialise DDRAM address to zero
    }
    //////////////////////////LCD SETUP END//////////////////////////
       

    void init(void)
    {  
       
        // setup the PIC 16f690
        OSCCON = 0x72;          // internal osc, 8MHz


        PORTA = 0;
        TRISA = 0b10010010;     // RA7 high imp, RA3 is serial out, RA4 button input


       
        PORTB = 0;              // PORTB not used
        WPUB = 1;               // PORTB pullups ON    
        RABPU = 0;


        /* Init ADC */
        ADCON0 = 0b10000101;    // bit 7 right justify,analogue channel select bits bits5-2  0001=AN1,ADC ON, RA1 is ADC input
        ADCON1 = 0b00100000;    //bits6-4  fosc/32
        ADON=1;                 // turn on the A2D conversion module

       
        ANSEL=0x02;            //set RA1 as analog input for GP2 sensor
        ANSELH=0x00;

        T1CON = 0b00010001;     // TMR1 is ON, 1:2 prescale, =1MHz
        T2CON = 0b00000101;     // TMR2 is ON, 1:4 prescale, =1MHz



        MyVal = 0; //initializn these variables here
        MyMinVal = 0;
        MyMaxVal = 99;
     
        TRISB=0x00;
        TRISC=0xFC;
       
        lcd_init(); //call LCD initialisation

    }
    //EDITED this a bit. now if expire input is set it will leave loop with a 0
    //instead of rechecking this will be useful for display your measured data and
    //waiting for user to exit.
    char WaitForInput(char expire){
    char done;
    char temp;
    done = 0;
    temp = 0;
    while(!done){
        if(!ENTERSETTINGS_SW){
            while(ENTERSETTINGS_SW);
            temp = 1;
            done = 0xff;
        }

        if(!HOME_SW){
            while(HOME_SW);
            temp = 2;
            done = 0xff;
        }

        if(!INCREASE_SW){
            while(INCREASE_SW);
            temp = 3;
            done = 0xff;
        }

        if(!DECREASE_SW){
            while(DECREASE_SW);
            temp = 4;
            done = 0xff;
        }
        if(expire == 1) break;
    }//end of while
        DelayMs(150);    //debounce
        return temp;
    }//
    void userMenu(char pos){
        unsigned int delaytime = 100000; // 100ms CHANGE THIS FOR YOUR BELOW DELAY
        lcd_clear();
        lcd_goto_L1();

        switch(pos){
            case 0:
                lcd_puts("    HEIGHT    ");
                break;     
            case 1:
                lcd_puts("    RANGE     ");
                break;     
            case 2:
                lcd_puts(" SURFACE AREA ");
                break;                          //
            case 3:
                lcd_puts("   MEASURED   ");
                 while(WaitForInput(1) != 2){       //Wait for user to press enter to leave loop

                    // wait for 2 seconds, uses TMR1 free running at 1Mhz
                    while(!TMR1IF)          // wait for TMR1 overflow
                    TMR1IF = 0;             // clear overflow flag

                    bres += 65536;          // add 65536uS to bres value
                    if(bres >= delaytime )      // if reached 2 seconds!
                    {
                        bres -= delaytime ; // subtract 2 seconds, keep error
               
                        // read the ADC voltage RA1 (Sharp GP2 sensor)
                        GODONE=1;                   // initiate conversion on the channel 0
                        while(GODONE) continue;     // Wait convertion done
                        calc_distance();            // convert ADC value to distance

                        lcd_goto_L2();              //Only change line 2
    //
                        if(posneg == 'p')
                            lcd_data('+');
                        else
                            lcd_data('-');
    //
                        lcd_data(LLHigh);
                        lcd_data(LLLow);
                        lcd_puts(" [cm] ");         //comment this out if you want
                   }
            }
            lcd_goto_L1();
            lcd_puts(" Loading Home ");
            lcd_goto_L2();
            lcd_puts("              ");
            DelayS(1);
            break;
        }

        if(pos == 3) return;
        lcd_goto_L2();
        lcd_puts("Press Up/Down"); //home screen message (line 2)
    }

    // New Menu System
    void EnterHeight(void){
        lcd_clear();
        lcd_goto_L1();
        lcd_puts(" ENTER HEIGHT ");
        lcd_goto_L2();
        lcd_puts("Press Up/Down"); //home screen message (line 2)
    }

    void EnterScreen(void){
        lcd_clear();
        lcd_goto_L1();
        lcd_puts(" [cm] ");
    }

    void ShowDigits(unsigned char val){

        MyValLCD[0] = val /10;    //returns the quotient (if temp = 35 the result is 3)
        MyValLCD[1] = val % 10;     //Returns remainder   (if temp = 35 the result is 5)

        MyValLCD[0] += 0x30;    //to ASCII
        MyValLCD[1] += 0x30;    //to ASCII

        EnterScreen();
        lcd_goto_L2();
        lcd_data(MyValLCD[0]);  //to LCD
        lcd_data(MyValLCD[1]);  //to LCD
    }

     
    void calc_distance(void)
    {
        unsigned int tmp;
    unsigned int mathKeep;      // used for voltage calculations backup
        // from the transeiver datasheet the analog voltage is
        // the inverse of distance, so distance can be calculated
        // d = (1 / volts) then just scaled to suit the transeiver

        // load ADC value in 16bit math var
        math = ADRESH;
        math = (math * 256);
        math += ADRESL;

        // now invert it; (1 / volts) use (6050 / volts) for scaling
        math = (6050 / math);
        if(math >= 2) math -=2;     // fix linear error (-2)
        if(math > 99) math = 99;    // max limit at 99cm

        //Create a copy of math for more use
        mathKeep = math;
        //LiquidLevel=height-; 

        // convert from 0-99 to 2 decimal digits, 0-99cm
        cm10=0;
        while(math >= 10)
        {
            cm10++;
            math -= 10;
        }
        cm = math;

        math = mathKeep;    //Now our original data is back and can be used.
        //This will check if negative
        LiquidLevel=height-math;   

    //
        posneg = 'p';
            if((LiquidLevel < 0) || (LiquidLevel > 0xFF00)){
            LiquidLevel = -LiquidLevel ;
            posneg = 'n';
        }
    //
        //if below zero which will be in the 0xFFFF range i just chose any 0xFFxx number :D
          //LiquidLevel is higher than 09 so spilt the variable LiquidLevel into 2 //
          LLHigh = ( LiquidLevel / 10 ) + '0'; //
          LLLow = ( LiquidLevel % 10 ) + '0';  //
         


    }
     //
    unsigned char user_input(void)      //This will return what we want
    {
        char done = 0;
     
        MyVal = 0;          //Start on 0
        while(done == 0){
          input_sw = WaitForInput(0);
           
          switch(input_sw){
            case 1:
                done = 0xff;            //This tells us the user finished entering
                lcd_goto_L1();
                lcd_puts("      OK       "); //home screen message (line 1)
                break;
            case 3:
                if(MyVal < MyMaxVal)
                    MyVal++;
                EnterScreen();
                ShowDigits(MyVal);
                break;
            case 4:
                if(MyVal > MyMinVal)
                    MyVal--;
                EnterScreen();
                ShowDigits(MyVal);
                break;
            default:
                break;
          }
         
        }
        DelayMs(250);
        DelayMs(250);
        return MyVal;
    }

    void home_screen(void){
        mnuPOS = 0;
        lcd_clear();
        lcd_goto_L1();
        lcd_puts("INFRARED LIQUID"); //home screen message (line 1)
        lcd_goto_L2();
        lcd_puts("LEVEL DETECTOR"); //home screen message (line 2)
     
        input_sw = 0;           //Reset the value

        while(input_sw != 1)    //Wait until enter is pressed
            input_sw = WaitForInput(0);

        userMenu(0);
        DelayMs(2);             //shorter delay
        height = user_input();  //The HEIGHT var will have the myVal

        userMenu(1);
        DelayMs(2);             //shorter delay
        range = user_input();   //The HEIGHT var will have the myVal

        userMenu(2);
        DelayMs(2);             //shorter delay
        area = user_input();    //The HEIGHT var will have the myVal
    //
        userMenu(3);
        DelayMs(2);             //shorter delay
        input_sw = 0;           //Reset the value

    //Waits for user to press ENTER to show home screen
    /*
    "enter height"
    call enter/settings (which is now user input function in new code)
    height=MyVal

    "enter range"
    call user_input
    range=MyVal

    "enter surface area"
    call user_input
    area=MyVal
    */
    }
     
    //*********************************************************
    /*  Junebug_Serial4.c    RomanBlack.com 19th July 2009.

        uses "zero error 1 second timer"
        system to generate a 2 second interval, then every
        2 seconds it reads an analog voltage from a
        Sharp GP2 distance sensor and converts it to decimal
        distance, then sends that data to a LCD

        Code for MikroC, config handled by MikroC compiler;
        _INTI02_OSC_1H
        _WDT_OFF_2H
        -MCLRE_ON_3H
        _LVP_OFF_4L
        _PWRT_ON_2L
    */
    //*********************************************************

    void main(void)
    {  
        init(); // initialise I/O ports, LCD
        while(1){
        home_screen();

     /*// wait for 2 seconds, uses TMR1 free running at 1Mhz
        while(!TMR1IF)  // wait for TMR1 overflow
        TMR1IF = 0;     // clear overflow flag

        bres += 65536;          // add 65536uS to bres value
        if(bres >= 2000000)     // if reached 2 seconds!
         {
            bres -= 2000000;    // subtract 2 seconds, keep error
               
            // read the ADC voltage RA1 (Sharp GP2 sensor)
            GODONE=1;   // initiate conversion on the channel 0
            while(GODONE) continue;  // Wait convertion done
            calc_distance();        // convert ADC value to distance
        //  LiquidLevel=height-;
        //  lcd_clear();                // Using the new menu you can erase or
        //  lcd_data(cm10 + '0');
        //  lcd_data(cm + '0');
         //   lcd_goto_L2();
           // lcd_puts("[cm] ");            //comment this out if you want
    */
     
         
           
                 
     
       }
    }
     
     
    Last edited: Sep 19, 2009
  14. birdman0_o

    birdman0_o Active Member

    Joined:
    Feb 23, 2009
    Messages:
    1,370
    Likes:
    18
    Location:
    Montreal, Quebec
    This may attribute to part of the wrong readings:

    Not just V = 1/R
     
  15. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    im using the sharp GP2D12
     
    Last edited: Sep 19, 2009
  16. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    I could use a float.............what would be a good float????

    i must try that later lol MAYBE that white paper that the detector works with:D

    Any suggestions.....


    is there a better solution than a float???
     
    Last edited: Sep 19, 2009
  17. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    thanks Noggin & birdman O....
     
  18. Mr RB

    Mr RB Well-Known Member

    Joined:
    Jul 22, 2008
    Messages:
    4,716
    Likes:
    194
    Location:
    Out there
    That was already covered here (fix linear error -2)
    Code (text):

        // now invert it; (1 / volts) use (6050 / volts) for scaling
        math = (6050 / math);
        if(math >= 2) math -=2;     // fix linear error (-2)
        if(math > 99) math = 99;    // max limit at 99cm
     
    Which i hand tuned and tested for the 10-80 cm sensor. The linear error is caused by the geometry of the optics. Sicne they are on different angles in the 4-30cm sensor and the 10-80 cm sensor you need a slightly different value. However my value of 80cm -2 (its ratio) is not too different from the Sharp datasheet for the 4-30cm sensor -0.45.

    fantabulous- you've taken a couple of steps backward! You should average a number of sensor readings to smooth it out (Noggin already gave a method).

    And testing if the sensor is detecting the top or bottom of the container was what you were doing right at the start (with all the charts etc)...
     
  19. Mr RB

    Mr RB Well-Known Member

    Joined:
    Jul 22, 2008
    Messages:
    4,716
    Likes:
    194
    Location:
    Out there
    OK, I just went and dug out my connector cable Junebug and Sharp sensor. I only had the 4-30 cm sensor handy so that was the one I tested.

    I filled a big plastic jug with about 9" of water, and set the sensor looking directly downward.

    The results are a bit inconclusive. With the sensor EXACTLY perpendicular to the water surface it measures the surface. With the sensor tilted just a couple of degrees it measures the bottom of the jug (blue plastic). With the sensor almost perfect it sometimes even measures the average (distance between the top and bottom of the liquid), the sensor analog electronics must be averaging the two returned signals.

    With longer distances the sensor finds it a bit easier to measure the top of the liquid, but with the top of the liquid gets too close (ie under 10cm) it starts to give preference to the bottom of the liquid. This is inline with my earlier findings that the sharp sensor tends to ignore transparent windows if they are pretty close, which is probably a design feature since the sensors are often mounted behind plastic windows in appliances.

    So to summarise;
    1. it WILL measure the top surface of clear water if the sensor is aligned to exact perpendicular, this obviously increases the reflection strength from the surface of the water. It may be workable with a sturdy and fine adjustable sensor mount.

    2. It is much more reliable measuring the top surface of the water when that surface is further away from the sensor.

    3. Anytime the water sloshes (changes surface angle relative to the sensor) or the sensor angle changes slightly, or the water is very close to the sensor, there is a high probability of reading the bottom of the container OR an average of top/bottom of the water.

    4. I wetted a fluffy black sock and placed it in the bottom of the jug. That's about as non-reflective as you can get. No difference, if the sensor setup is perfect it reads the top surface, if not, it reads the sock (bottom) or maybe a weird average.

    I tested a couple of different water heights and some deliberate sensor angles, basically the same conclusion; if the sensor is JUST RIGHT it reads the top surface of the water accurately.

    I didn't test a light colour (white) for the jug bottom, only the blue plastic and black sock. Given the Sharp sensor's ability to negate colour differences I can't see it making any real difference, at least I saw no difference between the blue and black.
     
  20. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    Thanks ALOT MR RB:eek::eek::eek::eek: ......Sorry for inconveniencing you
    Think I must add a level eye to this design.....
     
  21. Noggin

    Noggin Member

    Joined:
    Jul 21, 2003
    Messages:
    595
    Likes:
    9
    Location:
    Austin, TX
    What if you made a floater by cutting a sheet of thin plastic with dimensions slightly smaller than the container so that it can move up and down freely? You may need to add guides by poking a few holes in it and inserting something like straightened clothes hangers. You may also find it difficult to keep it from sticking to the bottom of the container when filling it after completely empty.

    Or throw a handful of ping-pong balls in there
     

Share This Page