-2

StackOverflow fellow developers,

I am doing some Arduino coding to working with measuring Fine Dust Monitoring Device,

However, I have a question regarding with If-statement.

In the code below, I added nested-if statement in the while loop, and some reason,

    else if (9999 >= int(pm25s.getMedian()) && int(pm25s.getMedian()) >= 52) {
      pm25i = 7;
    }
    else if (9999 >= int(pm10s.getMedian()) && int(pm10s.getMedian()) >= 102) {
      pm10i = 7;
    }
      else if (pm10i == 7) {
        status = "Hazardous (7) : Health warnings of emergency conditions. People at risk should be avoided to go outside and should limit the outdoor activities to minimum. Outdoor activities are strongly discouraged.";
      }
    }

Those lines doesn't work as expected, as when pm10 or pm25 value reaches more than 100 ug / m^3, it doesn't sync with the ThingSpeak server anymore, but I don't know why it doesn't uploads any data. Interestingly rest of my source code parts work fine as expected.

However When I removed those nested-if statements it works fine. (It successfully uploads even pm10 or pm25 value reaches more than 100 ug / m^3.

Could somebody explain what's wrong with my code? and how should I fix this issue please?

Thanks.

void loop() {
  if (ss.available() <= 0) {
    Serial.println("SIGNAL STATUS : WEAK");
    s_map_x = String(map_x, 6);
    s_map_y = String(map_y, 6);
  }
  else {
    while (ss.available() > 0) {
      Serial.println("SIGNAL STATUS : GREAT");
      if (gps.encode(ss.read())) {
        Serial.println("GPS READ");
        Serial.println(ss.read());
        if (gps.location.isValid()) {
          Serial.println("LOCATION : GREAT");
          map_x = gps.location.lat();
          map_y = gps.location.lng();
          Serial.println(String(map_x, 6));
          Serial.println(String(map_y, 6));
          Serial.println(gps.satellites.value());
        }
      }
      s_map_x = String(map_x, 6);
      s_map_y = String(map_y, 6);
      yield();
    }
  }
  while (dust.available() > 0) {
    do_dust(dust.read(), got_dust);
    yield();                                          


    /* AQI (실시간 대기질 지수) 등급 분류를 위한 코드입니다.
       실시간 대기질 기준 수치는 국제 표준인 WHO 대기질 수치 기준으로 분류합니다.
       http://www.euro.who.int/__data/assets/pdf_file/0005/78638/E90038.pdf
       https://airnow.gov/index.cfm?action=aqibasics.aqi */

       
    // 초미세먼지 AQI (실시간 대기질 지수) 등급을 분류합니다.
    //   0 이상   8 이하 : 1
    //   9 이상  16 이하 : 2
    //  17 이상  26 이하 : 3
    //  27 이상  34 이하 : 4
    //  35 이상  43 이하 : 5
    //  44 이상  51 이하 : 6
    //  52 이상  ∞  이하 : 7

    if (8 >= int(pm25s.getMedian()) && int(pm25s.getMedian()) >= 0) { 
      pm25i = 1;
    }
    else if (16 >= int(pm25s.getMedian()) && int(pm25s.getMedian()) >= 9) {
      pm25i = 2;
    }
    else if (26 >= int(pm25s.getMedian()) && int(pm25s.getMedian()) >= 17) {
      pm25i = 3;
    }
    else if (34 >= int(pm25s.getMedian()) && int(pm25s.getMedian()) >= 27) {
      pm25i = 4;
    }
    else if (43 >= int(pm25s.getMedian()) && int(pm25s.getMedian()) >= 35) {
      pm25i = 5;
    }
    else if (51 >= int(pm25s.getMedian()) && int(pm25s.getMedian()) >= 44) {
      pm25i = 6;
    }
    else if (9999 >= int(pm25s.getMedian()) && int(pm25s.getMedian()) >= 52) {
      pm25i = 7;
    }


    // 미세먼지 AQI (실시간 대기질 지수) 등급을 분류합니다.
    //   0 이상   8 이하 : 1
    //   9 이상  16 이하 : 2
    //  17 이상  51 이하 : 3
    //  52 이상  68 이하 : 4
    //  69 이상  84 이하 : 5
    //  85 이상 101 이하 : 6
    // 102 이상  ∞  이하 : 7

    if (8 >= int(pm10s.getMedian()) && int(pm10s.getMedian()) >= 0) {
      pm10i = 1;
    }
    else if (16 >= int(pm10s.getMedian()) && int(pm10s.getMedian()) >= 9) {
      pm10i = 2;
    }
    else if (51 >= int(pm10s.getMedian()) && int(pm10s.getMedian()) >= 17) {
      pm10i = 3;
    }
    else if (68 >= int(pm10s.getMedian()) && int(pm10s.getMedian()) >= 52) {
      pm10i = 4;
    }
    else if (84 >= int(pm10s.getMedian()) && int(pm10s.getMedian()) >= 69) {
      pm10i = 5;
    }
    else if (101 >= int(pm10s.getMedian()) && int(pm10s.getMedian()) >= 85) {
      pm10i = 6;
    }
    else if (9999 >= int(pm10s.getMedian()) && int(pm10s.getMedian()) >= 102) {
      pm10i = 7;
    }

    /* ThingSpeak 채널 내 Status Update (상태 업데이트) 영역에 표시되는 문구이므로,  
        종합적인 정보 표현을 위해 초미세먼지와 미세먼지 등급을 비교 한 후 
        두 가지 중 높은 등급 기준으로 경고 혹은 권고메시지를 표시합니다. */

    // 분류된 초미세먼지 등급이 미세먼지 등급보다 같거나 높은 경우, 초미세먼지 등급을 기준으로 내용을 표시하기 위하여 아래의 문자열을 status 변수에 저장합니다. 
    if (pm25i >= pm10i) {
      if (pm25i == 1) {
        status = "Excellent (1) : The air quality is excellent. The air pollution pose no threat. The conditions ideal for outdoor activities.";
      }

      else if (pm25i == 2) {
        status = "Very Good (2) : Air quality is very good, and air pollution poses little or no risk. Conditions very good for outdoor activities.";
      }

      else if (pm25i == 3) {
        status = "Moderate (3) : Air quality is acceptable. however, for some pollutants there may be a moderate health concern for a very small number of people who are unusually sensitive to air pollution.";
      }

      else if (pm25i == 4) {
        status = "Satisfactory (4) : Members of sensitive groups may experience health effects, Other people should limit spending time outdoors, especially when they experience symptoms such as cough or sore throat.";
      }

      else if (pm25i == 5) {
        status = "Bad (5) : Everyone may begin to experience health effects, members of sensitive groups may experience more serious health effects. People at risk should avoid to go outside. Not recommended for outdoor activities.";
      }

      else if (pm25i == 6) {
        status = "Severe (6) : Air quality is severe. Everyone may experience more serious health effects. People at risk should be avoided to go outside and should limit the outdoor activities to minimum. Outdoor activities are discouraged.";
      }

      else if (pm25i == 7) {
        status = "Hazardous (7) : Health warnings of emergency conditions. People at risk should be avoided to go outside and should limit the outdoor activities to minimum. Outdoor activities are strongly discouraged.";
      }

    // 분류된 미세먼지 등급이 초미세먼지 등급보다 높은 경우, 미세먼지 등급을 기준으로 내용을 표시하기 위하여 아래의 문자열을 status 변수에 저장합니다.
    } else if (pm25i < pm10i) {
      if (pm10i == 1) {
        status = "Excellent (1) : The air quality is excellent. The air pollution pose no threat. The conditions ideal for outdoor activities.";
      }
      
      else if (pm10i == 2) {
        status = "Very Good (2) : Air quality is very good, and air pollution poses little or no risk. Conditions very good for outdoor activities";
      }

      else if (pm10i == 3) {
        status = "Moderate (3) :  Air quality is acceptable. however, for some pollutants there may be a moderate health concern for a very small number of people who are unusually sensitive to air pollution.";
      }

      else if (pm10i == 4) {
        status = "Satisfactory (4) : Members of sensitive groups may experience health effects, Other people should limit spending time outdoors, especially when they experience symptoms such as cough or sore throat.";
      }

      else if (pm10i == 5) {
        status = "Bad (5) : Everyone may begin to experience health effects, members of sensitive groups may experience more serious health effects. People at risk should avoid to go outside. Not recommended for outdoor activities.";
      }

      else if (pm10i == 6) {
        status = "Severe (6) : Air quality is severe. Everyone may experience more serious health effects. People at risk should be avoided to go outside and should limit the outdoor activities to minimum. Outdoor activities are discouraged.";
      }

      else if (pm10i == 7) {
        status = "Hazardous (7) : Health warnings of emergency conditions. People at risk should be avoided to go outside and should limit the outdoor activities to minimum. Outdoor activities are strongly discouraged.";
      }
    }
  }

  //Serial.println(map_x);
  //Serial.print("pm 25 : ");
  //Serial.println(int(pm25s.getMedian()));

  if (millis() > mark) {//one minute(60000) interval
    mark = millis() + 60000;
    got_interval = true;
  }

  if (got_interval) {
    got_interval = false;
    do_interval();
  }
  yield();
}
HappyBono
  • 36
  • 8
  • 2
    Wow... That's some serious `if` `else` magic you've going on there.. – Jesper Juhl Jul 06 '20 at 14:53
  • 3
    Introducing some local variables would greatly improve readability. Can you make a [mre] that shows what doesn't work? – Lukas-T Jul 06 '20 at 15:05
  • Have you tried stepping through with your debugger? If you don't know how, now is an excellent time to learn. You know what your code is supposed to do, and with your debugger you can inspect line by line to see if it's actually doing that. You want to `set a breakpoint` before the offending code, you want to `single step` through the code, and you want to `inspect your variables` at each step to make sure they match what you expect. Breaking your boolean expressions into multiple lines will help with the line-by-line debugging. – JohnFilleau Jul 06 '20 at 15:05
  • 3
    Seperating the code into smaller functions would also help. Probably the problem is some unintended modification of the flow of the program. Breaking the code into smaller pieces would help see that. – john Jul 06 '20 at 15:06
  • Does each of those calls to `getMedian` cause a hardware read? If so, then it's possible that the value will jump around between reads and you end up executing NO branches. You should sample each value once per your loop and use that same value for all conditions. Your sensor has a deadline of the start of your loop, and you won't accept any late work. It doesn't get to update the value during the loop execution. – JohnFilleau Jul 06 '20 at 15:08
  • Your code looks full of clutter. What's the sense in using `if (8 >= int(pm25s.getMedian()) && int(pm25s.getMedian()) >= 0) { pm25i = 1; } else if (16 >= int(pm25s.getMedian()) && int(pm25s.getMedian()) >= 9) { pm25i = 2; } ... ` instead of `if(pm25s.getMedian() < 9) pm25i = 1; else if(pm25s.getMedian() < 17) pm25i = 2;`?? – brc-dd Jul 06 '20 at 15:11
  • You can condense your last two warning blocks into something like `max_pmi = std::max(pm10i, pm25i)`, and then execute each of the warnings based on `max_pmi` since the messages are identical. If you do that, consider making this its own function as well `print_warning_message(int warning_level)` or something like that. – JohnFilleau Jul 06 '20 at 15:14
  • 1
    What's the return type of `getMedian`? – JohnFilleau Jul 06 '20 at 15:14
  • @JohnFilleau return type of `getMedian()` is `float`. ref: https://github.com/RobTillaart/Arduino/blob/master/libraries/RunningMedian/RunningMedian.h – brc-dd Jul 06 '20 at 15:17
  • You should call your `getMedian()` function once and store the result in a constant temporary variable. – Thomas Matthews Jul 06 '20 at 15:46
  • If you've accumulated 0 measurements, then `getMedian` will return NAN, and that conversion to int is undefined. You really need to debug your program and see what the value of `getMedian` is when you run this to understand why your branch is not executing. – JohnFilleau Jul 06 '20 at 15:50
  • Umm huh does anyone else find this hard to read, use switch statement instead?? – Yunfei Chen Jul 06 '20 at 16:10

1 Answers1

1

You may be getting unexpected behavior due to floating point comparisons or may be due to some unhandled cases, or may be because RunningMedian::getMedian() is changing on any/every condition check. Another possible reason is maybe RunningMedia::_cnt is not more than 0.

Also I would recommend updating your library to its latest version (v0.1.15).

Try putting this code inside your while loop:

float _pm25Median = pm25s.getMedian();
float _pm10Median = pm10s.getMedian();

if (isnan(_pm25Median) || isnan(_pm10Median))
    continue; // or do something else to handle this exception properly

if (_pm25Median < 9)
    pm25i = 1;
else if (_pm25Median < 17)
    pm25i = 2;
else if (_pm25Median < 27)
    pm25i = 3;
else if (_pm25Median < 35)
    pm25i = 4;
else if (_pm25Median < 44)
    pm25i = 5;
else if (_pm25Median < 52)
    pm25i = 6;
else
    pm25i = 7;

if (_pm10Median < 9)
    pm10i = 1;
else if (_pm10Median < 17)
    pm10i = 2;
else if (_pm10Median < 52)
    pm10i = 3;
else if (_pm10Median < 69)
    pm10i = 4;
else if (_pm10Median < 85)
    pm10i = 5;
else if (_pm10Median < 102)
    pm10i = 6;
else
    pm10i = 7;

if (pm25i >= pm10i) {
    switch (pm25i) {
    case 1:
        status = "Excellent (1) : The air quality is excellent. The air pollution pose no threat. The conditions ideal for outdoor activities.";
        break;
    case 2:
        status = "Very Good (2) : Air quality is very good, and air pollution poses little or no risk. Conditions very good for outdoor activities.";
        break;
    case 3:
        status = "Moderate (3) : Air quality is acceptable. however, for some pollutants there may be a moderate health concern for a very small number of people who are unusually sensitive to air pollution.";
        break;
    case 4:
        status = "Satisfactory (4) : Members of sensitive groups may experience health effects, Other people should limit spending time outdoors, especially when they experience symptoms such as cough or sore throat.";
        break;
    case 5:
        status = "Bad (5) : Everyone may begin to experience health effects, members of sensitive groups may experience more serious health effects. People at risk should avoid to go outside. Not recommended for outdoor activities.";
        break;
    case 6:
        status = "Severe (6) : Air quality is severe. Everyone may experience more serious health effects. People at risk should be avoided to go outside and should limit the outdoor activities to minimum. Outdoor activities are discouraged.";
        break;
    case 7:
        status = "Hazardous (7) : Health warnings of emergency conditions. People at risk should be avoided to go outside and should limit the outdoor activities to minimum. Outdoor activities are strongly discouraged.";
    default:
        break;
    }
} else {
    switch (pm10i) {
    case 1:
        status = "Excellent (1) : The air quality is excellent. The air pollution pose no threat. The conditions ideal for outdoor activities.";
        break;
    case 2:
        status = "Very Good (2) : Air quality is very good, and air pollution poses little or no risk. Conditions very good for outdoor activities";
        break;
    case 3:
        status = "Moderate (3) :  Air quality is acceptable. however, for some pollutants there may be a moderate health concern for a very small number of people who are unusually sensitive to air pollution.";
        break;
    case 4:
        status = "Satisfactory (4) : Members of sensitive groups may experience health effects, Other people should limit spending time outdoors, especially when they experience symptoms such as cough or sore throat.";
        break;
    case 5:
        status = "Bad (5) : Everyone may begin to experience health effects, members of sensitive groups may experience more serious health effects. People at risk should avoid to go outside. Not recommended for outdoor activities.";
        break;
    case 6:
        status = "Severe (6) : Air quality is severe. Everyone may experience more serious health effects. People at risk should be avoided to go outside and should limit the outdoor activities to minimum. Outdoor activities are discouraged.";
        break;
    case 7:
        status = "Hazardous (7) : Health warnings of emergency conditions. People at risk should be avoided to go outside and should limit the outdoor activities to minimum. Outdoor activities are strongly discouraged.";
        break;
    default:
        break;
    }
}
brc-dd
  • 10,788
  • 3
  • 47
  • 67
  • I would start with making the code more readable.... – Yunfei Chen Jul 06 '20 at 22:23
  • @YunfeiChen I already cleared much of the code, but if you wish you can further clean it by using some arrays and loops. But you'll have to consider memory constraints which is a crucial point in embedded software development. – brc-dd Jul 07 '20 at 07:19