Разрабатываю детектор землетрясений, но когда он обнаруживает движение, сигнал тревоги не прекращается

Это код, который я использовал. На самом деле я использую код: для Arduino sofware и обработки программного обеспечения IDE.

Arduino Исходный код/Программа:

#include<LiquidCrystal.h> // ЖК-заголовок
LiquidCrystal lcd(7,6,5,4,3,2); // контакты для подключения ЖК-дисплея

#define buzzer 12 // штифт зуммера
#define led 13 //светодиодный контакт

#define x A0 // x_out вывод акселерометра
#define y A1 // вывод y_out акселерометра
#define z A2 // вывод z_out акселерометра

/*variables*/
int xsample=0;
int ysample=0;
int zsample=0;
long start;
int buz=0;

/*Macros*/
#define samples 50
#define maxVal 20 // максимальный предел изменения
#define minVal -20 // минимальный предел изменения
#define buzTime 5000 // зуммер вовремя

void setup()
{
    lcd.begin(16,2); //инициализация lcd
    Serial.begin(9600); // инициализация serial
    delay(1000);
    lcd.print("EarthQuake ");
    lcd.setCursor(0,1);
    lcd.print("Detector ");
    delay(2000);
    lcd.clear();
    lcd.print("Calibrating.....");
    lcd.setCursor(0,1);
    lcd.print("Please wait...");
    pinMode(buzzer, OUTPUT);
    pinMode(led, OUTPUT);
    buz=0;
    digitalWrite(buzzer, buz);
    digitalWrite(led, buz);
    for(int i=0;i<samples;i++) // взятие проб для калибровки
    {
        xsample+=analogRead(x);
        ysample+=analogRead(y);
        zsample+=analogRead(z);
    }

    xsample/=samples; // взятие среднего значения для x
    ysample/=samples; // принимая среднее значение для y
    zsample/=samples; // взятие среднего значения для z

    delay(3000);
    lcd.clear();
    lcd.print("Calibrated");
    delay(1000);
    lcd.clear();
    lcd.print("Device Ready");
    delay(1000);
    lcd.clear();
    lcd.print(" X Y Z ");
}

void loop()
{
    int value1=analogRead(x); // считывание x out
    int value2=analogRead(y); //считывание y out
    int value3=analogRead(z); //считывание z out

    int xValue=xsample-value1; // finding change in x
    int yValue=ysample-value2; // нахождение изменения в y
    int zValue=zsample-value3; // нахождение изменения в z

    /*displying change in x,y and z axis values over lcd*/
    lcd.setCursor(0,1);
    lcd.print(xValue);
    lcd.setCursor(6,1);
    lcd.print(yValue);
    lcd.setCursor(12,1);
    lcd.print(zValue);
    delay(100);

    /* comparing change with predefined limits*/
    if(xValue < minVal || xValue > maxVal || yValue < minVal
            || yValue > maxVal || zValue < minVal || zValue > maxVal)
    {
        if(buz == 0)
            start=millis(); // запуск таймера
        buz=1; // зуммер / активирован светодиодный флаг
    }
    else if(buz == 1) // активирован флаг зуммера, предупреждающий о землетрясении
    {
        lcd.setCursor(0,0);
        lcd.print("Earthquake Alert ");
        if(millis()>= start+buzTime)
            buz=0;
    }
    else
    {
        lcd.clear();
        lcd.print(" X Y Z ");
    }

    digitalWrite(buzzer, buz); // команда включения и выключения зуммера
    digitalWrite(led, buz); // led on and off command

    /*sending values to processing for plot over the graph*/
    Serial.print("x=");
    Serial.println(xValue);
    Serial.print("y=");
    Serial.println(yValue);
    Serial.print("z=");
    Serial.println(zValue);
    Serial.println(" $");
}

Обработка кода IDE/программы:

import processing.serial.*;
PFont f6,f8,f12,f10;
PFont f24;
Serial myPort; // The serial port
int xPos = 0; // horizontal position of the graph
float y1=0;
float y2=0;
float y3=0;

void setup ()
{
    // установить размер окна: и размер шрифта
    f6 = createFont("Arial",6,true);
    f8 = createFont("Arial",8,true);
    f10 = createFont("Arial",10,true);
    f12 = createFont("Arial",12,true);
    f24 = createFont("Arial",24,true);
    size(1200, 700);

    // Список всех доступных последовательных портов
    println(Serial.list());
    myPort = new Serial(this, "COM10", 9600);
    println(myPort);
    myPort.bufferUntil('\n');
    background(80);
}

void draw ()
{
    serial();
}

void serial()
{
    String inString = myPort.readStringUntil('$'); // чтение даты включения из последовательного
    if (inString != null)
    {
        // извлечение всех необходимых значений всех трех осей:
        int l1=inString.indexOf("x=")+2;
        String temp1=inString.substring(l1,l1+3);
        l1=inString.indexOf("y=")+2;
        String temp2=inString.substring(l1,l1+3);
        l1=inString.indexOf("z=")+2;
        String temp3=inString.substring(l1,l1+3);

        //сопоставление значений x, y и z с размерами графика
        float inByte1 = float(temp1+(char)9);
        inByte1 = map(inByte1, -80,80, 0, height-80);
        float inByte2 = float(temp2+(char)9);
        inByte2 = map(inByte2,-80,80, 0, height-80);
        float inByte3 = float(temp3+(char)9);
        inByte3 = map(inByte3,-80,80, 0, height-80);
        float x=map(xPos,0,1120,40,width-40);

        //окно построения графика, единица измерения
        strokeWeight(2);
        stroke(175);
        Line(0,0,0,100);
        textFont(f24);
        fill(0,00,255);
        textAlign(RIGHT);
        xmargin("EarthQuake Graph (SESMIOGRAPH)",200,100);

        fill(100);
        strokeWeight(100);
        line(1050,80,1200,80);

        strokeWeight(1);
        textAlign(RIGHT);
        fill(0,0,255);
        String temp="X:"+temp1;
        Text(temp,100,95);

        fill(0,255,0);
        temp="Y:"+temp2;
        Text(temp,100,92);

        fill(255,0,0);;
        temp="Z:"+temp3;
        Text(temp,100,89);


        //нанесение значений x y и z на график
        strokeWeight(2);
        int shift=40;

        stroke(0,0,255);
        if(y1 == 0)
            y1=height-inByte1-shift;
        line(x, y1, x+2, height-inByte1-shift) ;
        y1=height-inByte1-shift;

        stroke(0,255,0);
        if(y2 == 0)
            y2=height-inByte2-shift;
        line(x, y2, x+2, height-inByte2-shift) ;
        y2=height-inByte2-shift;

        stroke(255,0,0);
        if(y2 == 0)
            y3=height-inByte3-shift;
        line(x, y3, x+2, height-inByte3-shift) ;
        y3=height-inByte3-shift;

        xPos+=1;

        if (x >= width-30) // вернитесь к началу
        {
            xPos = 0;
            background(80);
        }
    }
}

void Line(int x1, int y1, int x2, int y2)
{
    float xx1=map(x1,0,100,40,width-40);
    float xx2=map(x2,0,100,40,width-40);
    float yy1=map(y1,0,100,height-40,40);
    float yy2=map(y2,0,100,height-40,40);

    line(xx1,yy1,xx2,yy2);
    xx2=map(100,0,100,40,width-40);
    yy2=map(0,0,100,height-40,40);
    line(xx1,yy1,xx2,yy2);

    strokeWeight(1);
    for(int i=1;i<21;i++)
    {
        yy2=map(i*10,0,200,height-40,40);
        yy1=yy2;
        line(xx1,yy1,xx2,yy2);
    }
    yy2=map(100,0,100,height-40,40);
    yy1=map(0,0,100,height-40,40);
    for(int i=1;i<41;i++)
    {
        xx1=map(i*5,0,200,40,width-40);
        xx2=map(i*5,0,200,40,width-40);
        line(xx1,yy1,xx2,yy2);
    }

    textAlign(RIGHT); // 100 градусов
    // результат+=yy1;
    fill(255);
    strokeWeight(1);
    textFont(f12);
    for(int i=-10;i<11;i++)
    {
        String result="";
        result+=5*i;
        ymargin(result, x1,y1);
        y1+=5;
    }

    x1=0;
    y1=0;
    strokeWeight(1);
    textFont(f10);
    for(int i=0;i<41;i++)
    {
        String result="";
        result+=28*3*i;
        xmargin(result, x1,y1);
        x1+=5;
    }

    textAlign(RIGHT);
    textAlign(RIGHT);
}

void ymargin(String value, int x1, int y1)
{
    float xx1=map(x1,0,100,40,width-40);
    float yy1=map(y1,0,100,height-40,40);
    text(value,xx1-5,yy1+5);
}

void xmargin(String value, int x1, int y1)
{
    float xx1=map(x1,0,200,40,width-40);
    float yy1=map(y1,0,100,height-25,25);
    text(value,xx1+7,yy1);
}

void Text(String value, int x1, int y1)
{
    float xx1=map(x1,0,100,40,width-40);
    float yy1=map(y1,0,100,height-25,25);
    text(value,xx1,yy1);
}

, 👍2


3 ответа


2

Я не вижу в вашем коде ничего, что могло бы быть причиной такого поведения. Так что, возможно, причина кроется вне кода.

Как вы имитируете землетрясение? Я предполагаю, что вы каким-то образом вручную перемещаете датчик . Вполне может случиться так, что после перемещения он не установится точно в той же ориентации, что и раньше. Когда это произойдет, ускорение силы тяжести будет немного в другом направлении, и ваша калибровка больше не будет действительной. Вы можете проверить это условие, наблюдая за отображаемыми значениями: если они соответствуют чему-то почти постоянному, но большому (более 20 по абсолютной величине), то именно это и происходит.

Если это так, то возможным решением было бы повторить калибровку через пару секунд после обнаружения землетрясения. Я бы предложил метод, который, на мой взгляд, более элегантен: калибровать непрерывно, то есть обновлять калибровку каждые несколько микросекунд.

Идея состоит в том, что вместо того, чтобы вычислять набор смещений раз и навсегда, вы фильтруете нижние частоты необработанных показаний и используете эти сглаженные показания в качестве смещений. Когда вы вычитаете смещения из показаний, вы реализуете, по сути, фильтр высоких частот.

Вот примерная реализация этой идеи. Я сделал показания периодическими, чтобы иметь некоторый контроль над постоянной времени фильтра. На практике вам придется адаптировать постоянную времени к требованиям вашего эксперимента:

// Константы, подлежащие корректировке, время в микросекундах.
const uint32_t readingPeriod   = 10e3;  // 10e3 us = 10 мс
const float filterTimeConstant = 10e6;  // 10e6 us = 10 с
const float filterConstant = readingPeriod / filterTimeConstant;

// Периодически обновляемые отфильтрованные ускорения.
float accelX, accelY, accelZ;

// Внутреннее состояние фильтра.
uint32_t lastTimeReading = 0;
float offsetX, offsetY, offsetZ;

// Вызовите это из setup()
void initializeOffsets() {
    offsetX = analogRead(x);
    offsetY = analogRead(y);
    offsetZ = analogRead(z);
}

// Вызовите это из цикла()
void updateAccelerations() {
    // Берите показания только каждый период чтения у нас.
    if (micros() - lastTimeReading < readingPeriod)
        return;
    lastTimeReading += readingPeriod;

    // Считайте показания датчиков.
    int readingX = analogRead(x);
    int readingY = analogRead(y);
    int readingZ = analogRead(z);

    // Обновите смещения.
    offsetX += filterConstant * (readingX - offsetX);
    offsetY += filterConstant * (readingY - offsetY);
    offsetZ += filterConstant * (readingZ - offsetZ);

    // Обновите отфильтрованные ускорения.
    accelX = readingX - offsetX;
    accelY = readingY - offsetY;
    accelZ = readingZ - offsetZ;
}
,

Большое вам спасибо. Я попробую ваше предложение., @Christian Marasigan

В какую часть моего кода я должен поместить ваш код?, @Christian Marasigan

@ChristianMarasigan: Это написано в комментариях. Пожалуйста, не копируйте это просто так, не понимая хотя бы общего принципа. Посмотрите на комментарии. Если что-то не имеет смысла, спросите., @Edgar Bonet


2

Я бы преобразовал выходные данные в целые числа из Double и посмотрел, все ли еще "звонит".

Описание предполагает, что он создает петлю обратной связи (критически затухающую), и вы должны установить нижний предел тех значений, которые также выключают устройство.

Итак, если вы в данный момент читаете точность < 0.00001 ( по любой оси), добавьте разрыв в программу.

Большая старая догадка, но удачи тебе.

,

Спасибо. Я попробую это сделать., @Christian Marasigan


1

Просто предположение, но достаточно ли сильна вибрация от зуммера, чтобы вызвать акселерометр? Если это так, то как только зуммер прозвучит после обнаружения землетрясения, он может просто продолжать срабатывать сам по себе.

Чтобы исправить это, вам, вероятно, нужно взять несколько образцов показаний акселерометра, чтобы увидеть, насколько сильны вибрации зуммера по сравнению с сигналом от землетрясения. Затем вы можете изменить калибровку или попытаться отфильтровать сигнал от зуммера.

Кроме того, вам может потребоваться физически изолировать зуммер от акселерометра.

,