Announcement

Collapse
No announcement yet.

Arduino based VDI!

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Hi everbody. I hope everyone is doing well. I'm writing this post here in order to seek help. I'm trying to merge the VDI code given by Don and VLF metal detector by following the link(https://github.com/dc42/arduino/blob...alDetector.ino), But I'm unable to get the required results. I'm to this stuff therefore, I'll be very thankful if anyone here could help me through this.

    Note:
    - I have combined the schematic uploaded by Don for VDI and https://github.com/dc42/arduino/blob.../Schematic.jpg.
    - Currently with the code given below, on my LCD i'm able to see the TID numer but it's a fixed value(not changing).


    ************************************************

    //Libraries declaration
    #define TIMER1_TOP (263)
    #define USE_3V3_AREF (1)
    #define max_ampAverage 200




    //enabling LCD
    #include <LiquidCrystal.h>
    LiquidCrystal lcd(6, 7, 10, 11, 12, 13); // Rs, En, D4, D5, D6, D7




    //Digital pins connectivity
    //arduino pins
    const int calibrationPin = 2;
    const int speaker = 3;
    const int TxPin = 5;
    const int T0InputPin = 4;
    const int T0OutputPin = 9;




    //Analog pins connectivity
    const int receiverInputPin = A0;
    int Tx = A1;
    int Rx = A2;
    //Variables initialization
    float TxValue = 0;
    float RxValue = 0;
    float y;
    int n = 0;
    int cursorClmn = 0;
    //int numSamples = 0;
    float y_total;
    float y_Avrg = 0;
    int TID = 0;




    //Declaring varaibles
    // Variables used only by the ISR
    int16_t bins[4];
    uint16_t numSamples = 0;
    const uint16_t numSamplesToAverage = 1024;
    // Variables used by the ISR and outside it
    volatile int16_t averages[4];
    volatile bool sampleReady = false;
    // Variables used only outside ISR
    int16_t calib[4];
    volatile uint8_t lastctr;
    volatile uint16_t misses = 0;
    const double halfRoot2 = sqrt(0.5);
    const double quarterPi = 3.1415927/4.0;
    const double radiansToDegrees = 180.0/3.1415927;




    //Adjust the phase error produced after setting overflow flag of timer1
    const float phaseAdjust = (45.0 * 32.0)/(float)(TIMER1_TOP + 1);




    //Sensitivity adjustment(lower = greater sensitivity(can be adjusted by using a potentiomter or a rotary encoder)
    float threshold = 7.0;




    //Setup code here runs only one time
    void setup()
    {
    lcd.begin(16, 2);
    pinMode(calibrationPin, INPUT_PULLUP);
    digitalWrite(T0OutputPin, LOW);
    pinMode(T0OutputPin, OUTPUT);
    digitalWrite(TxPin, LOW);
    pinMode(TxPin, OUTPUT);




    //Defining timers(keep track of detector oscillating Frequency
    cli();
    TCCR0A = 0;
    TCCR0B = 0;
    TIMSK0 = 0;
    TIFR0 = 0x07;
    TCNT0 = 0;
    //Setting up timer0
    TCCR0A = (1 << COM0B1) | (1 << WGM01) | (1 << WGM00);
    TCCR0B = (1 << CS00) | (1 << CS01) | (1 << CS02) | (1 << WGM02);
    OCR0A = 7;
    OCR0B = 3;
    sei();
    //Initializing timer1
    TCCR1A = 0;
    TCCR1B = 0;
    TIMSK1 = 0;
    TIFR1 = 0x07;
    TCNT1H = 0;
    TCNT1L = 0;
    //Setting up timer1
    TCCR1A = (1 << COM1A1) | (1 << WGM11);
    TCCR1B = (1 << WGM12) | (1 << WGM13) | (1 << CS10);
    TCCR1C = 0;
    OCR1AH = (TIMER1_TOP/2 >> ;
    OCR1AL = (TIMER1_TOP/2 & 0xFF);
    ICR1H = (TIMER1_TOP >> ;
    ICR1L = (TIMER1_TOP & 0xFF);
    TIMSK1 = (1 << TOIE1);

    while (!sampleReady) {}
    misses = 0;
    sampleReady = false;



    //Set up ADC to trigger and read channel 0 on timer1 overflow
    #if USE_3V3_AREF
    ADMUX = (1 << ADLAR);
    #else
    ADMUX = (1 << REFS0) | (1 << ADLAR);
    #endif
    ADCSRB = (1 << ADTS2) | (1 << ADTS1);
    ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | (1 << ADPS2);
    DIDR0 = 1;

    Serial.begin(19200);
    }




    // Timer 0 overflow interrupt -> serves 2 purposes:
    // 1. It clears the timer 0 overflow flag. If we don't do this, the ADC will not see any more Timer 0 overflows and we will not get any more conversions.
    // 2. It increments the tick counter, allowing is to do timekeeping. We get 62500 ticks/second.


    ISR(TIMER1_OVF_vect)
    {
    uint8_t ctr = TCNT0;
    int16_t val = (int16_t)(uint16_t)ADCH;
    if (ctr != ((lastctr + 1) & 7))
    {
    ++misses;
    }
    lastctr = ctr;
    int16_t *p = &bins[ctr & 3];
    if (ctr < 4)
    {
    *p += (val);
    if (*p >15000) *p = 15000;
    }
    else
    {
    *p -= val;
    if (*p < -15000) *p = -15000;
    }
    if (ctr == 7)
    {
    ++numSamples;
    if (numSamples == numSamplesToAverage)
    {
    numSamples = 0;
    if (!sampleReady)
    {
    memcpy((void*)averages, bins, sizeof(averages));
    sampleReady = true;
    }
    memset(bins, 0, sizeof(bins));
    }
    }
    }




    //Main code to run repeatedly
    void loop()
    {


    while (!sampleReady) {}


    if (digitalRead(calibrationPin) == LOW)
    {
    for (int i = 0; i < 4; ++i)
    {
    calib[i] = averages[i];
    }
    lcd.setCursor(0,0);
    lcd.print("Calibrating... ");
    }
    else
    {
    for (int i = 0; i < 4; ++i)
    {
    averages[i] -= calib[i];
    }
    const double f = 150.0;

    // Message the results to eliminate sensitivity to the 3rd harmonic, and divide by 150
    double bin0 = (averages[0] + halfRoot2 * (averages[1] - averages[3]))/f;
    double bin1 = (averages[1] + halfRoot2 * (averages[0] + averages[2]))/f;
    double bin2 = (averages[2] + halfRoot2 * (averages[1] + averages[3]))/f;
    double bin3 = (averages[3] + halfRoot2 * (averages[2] - averages[0]))/f;
    sampleReady = false; // we've finished reading the averages, so the ISR is free to overwrite them again


    double amp1 = sqrt((bin0 * bin0) + (bin2 * bin2));
    double amp2 = sqrt((bin1 * bin1) + (bin3 * bin3));
    double ampAverage = (amp1 + amp2)/2.0;

    // The ADC sample/hold takes place 2 clocks after the timer overflow
    double phase1 = atan2(bin0, bin2) * radiansToDegrees + 45.0;
    double phase2 = atan2(bin1, bin3) * radiansToDegrees;

    if (phase1 > phase2)
    {
    double Equate = phase1;
    phase1 = phase2;
    phase2 = Equate;
    }
    double phaseAverage = ((phase1 + phase2)/2.0) - phaseAdjust;
    if (phase2 - phase1 > 90.0)
    {
    if (phaseAverage < 0.0)
    {
    phaseAverage += 90.0;
    }
    else
    {
    phaseAverage -= 90.0;
    }
    }
    lcd.print(" ");


    if (ampAverage >= threshold)
    {
    if (phaseAverage < 0.0) // non-ferrous metals: -ve phase shift
    {
    first:
    TxValue = analogRead (Tx); //it will be between 0 and 1023
    RxValue = analogRead (Rx);
    //Change SensorValues below to adjust VDI sensitivity
    if (TxValue > 5) {
    if (RxValue > 5) {
    for (int n = 0 ; n < 85 ; n ++) //read Rx, Tx again in a loop 85 times
    reread:
    {
    TxValue = analogRead(Tx);
    RxValue = analogRead (Rx);
    y=RxValue / TxValue;
    if (y ==0) {
    goto reread;
    }
    y_total = y_total + y;
    }
    }
    }
    else {
    goto first;
    }
    y_Avrg = y_total/85;
    TID = ((10 - y_Avrg) * 10);
    cursorClmn = (10 - y_Avrg);
    lcd.clear();
    if (TID > 98 ) {
    lcd.clear();
    goto finish;
    }
    lcd.setCursor(0,0);
    lcd.print("TID = ");
    lcd.print (TID) ;
    lcd.setCursor(9,0);
    //if (TID = 100 ); {
    // lcd.clear();
    // goto finish;
    //}
    if ( TID > 85 ) {
    lcd.print(" A");
    goto DonePrinting;
    }
    if ( TID > 80 ) {
    lcd.print (" B");
    goto DonePrinting;
    }
    if ( TID > 71) {
    lcd.print (" C");
    goto DonePrinting;
    }
    if (TID > 39) {
    lcd.print ("D");
    goto DonePrinting;
    }
    if (TID > 0) {
    lcd.setCursor (10,0);
    lcd.print ("E");
    goto DonePrinting;
    }
    } }
    else
    {
    lcd.setCursor (10,0);
    lcd.print ("F");
    goto DonePrinting;
    }
    DonePrinting:
    lcd.setCursor(0, cursorClmn);
    lcd.print ("Detecting Metal");
    finish:
    delay (100);
    numSamples = 0;
    y_total = 0;
    y_Avrg = 0;
    y = 0;
    }
    }

    Comment


    • This code will only work for you at home on your desk because it has no ground tuning and no filters. You can be inspired by this project https://shemaforum.ru/topic/polnocen...or-na-arduino/ https://tehnodium.ru/thread-65.html

      Comment


      • Hello everyone. Is there anyone here who had designed a full metal detector using arduino with VDI?

        Comment


        • Well, they gave a link above ...

          Comment


          • Thank you for your reply. Actually above mentined links are in russian language and it's a bit difficult for me to understand. Although I have translated it but still few things are not clear. Thats why I asked if there's any link available in english.

            Comment


            • Read Don Bower's experiments:
              https://sites.google.com/site/dbcoil...di-experiments

              Comment


              • Thank you everyone for being very kind and answering my few silly questions.

                Comment


                • Friends, how is the 180 degrees calculated in this separation section? Can someone help me? vdi=x/y is not enough.

                  Comment


                  • No, no friends, I make them read ADC by doing 50 examples. Guinea doesn't work, otherwise I have to do ADC cutoff

                    Comment

                    Working...
                    X