Master project, Make a plate vibrate according to the Co2 level

Hi,

I'm in second year of Master in Fine arts and for my degree show piece i have a project which implies Arduino and a Co2 sensor MHZ19.

My project is to have a MHZ19 Co2 sensor on and connected to the arduino, which will mesure the value of Co2 due to the amount of visitor in the gallery. According to the data, the arduino will set a vibrating motor on or off to make the sculpture vibrate.

I have wrote the code, but it's not working, it is writing the value on the serial monitor but that's it, i don't know it communicating the value and i have no idea why, i'm a bit lost maybe there is a mistake there but i can't be sure.

Would love to have a bit of help if possible,
Thanks

Eleonore

#include <SoftwareSerial.h>
SoftwareSerial co2Serial(7, 6); // define MH-Z19 RX TX
unsigned long startTime = millis();

int ledpin = 4;
 
void setup() {
  Serial.begin(9600);
  co2Serial.begin(9600);
  pinMode(9, INPUT);
  pinMode(4, OUTPUT);
}
 
void loop() {
  Serial.println("------------------------------");
  Serial.print("Time from start: ");
  Serial.print((millis() - startTime) / 1000);
  Serial.println(" s");
  int ppm_uart = readCO2UART();
  int ppm_pwm = readCO2PWM();
  delay(5000);
}

int readCO2UART(){
  byte cmd[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79};
  byte response[9]; // for answer

  Serial.println("Sending CO2 request...");
  co2Serial.write(cmd, 9); //request PPM CO2

  // clear the buffer
  memset(response, 0, 9);
  int i = 0;
  while (co2Serial.available() == 0) {
//    Serial.print("Waiting for response ");
//    Serial.print(i);
//    Serial.println(" s");
    delay(1000);
    i++;
  }
  if (co2Serial.available() > 0) {
      co2Serial.readBytes(response, 9);
  }
  // print out the response in hexa
  for (int i = 0; i < 9; i++) {
    Serial.print(String(response[i], HEX));
    Serial.print("   ");
  }
  Serial.println("");

  // checksum
  byte check = getCheckSum(response);
  if (response[8] != check) {
    Serial.println("Checksum not OK!");
    Serial.print("Received: ");
    Serial.println(response[8]);
    Serial.print("Should be: ");
    Serial.println(check);
  }
  
  // ppm
  int ppm_uart = 256 * (int)response[2] + response[3];
  Serial.print("PPM UART: ");
  Serial.println(ppm_uart);

  // temp
  byte temp = response[4] - 40;
  Serial.print("Temperature? ");
  Serial.println(temp);

  // status
  byte status = response[5];
  Serial.print("Status? ");
  Serial.println(status); 
  if (status == 0x40) {
    Serial.println("Status OK"); 
  }
  
  return ppm_uart;
}

byte getCheckSum(char *packet) {
  byte i;
  unsigned char checksum = 0;
  for (i = 1; i < 8; i++) {
    checksum += packet[i];
  }
  checksum = 0xff - checksum;
  checksum += 1;
  return checksum;
}

int readCO2PWM() {
  unsigned long th, tl, ppm_pwm = 0;
  do{

    th = pulseIn(9, HIGH, 1004000) / 1000;
    tl = 1004 - th;
    ppm_pwm = 5000 * (th-2)/(th+tl-4);
   } while (th == 0);
  Serial.print("PPM PWM: ");
  Serial.println(ppm_pwm);
  return ppm_pwm;


    if ("ppm_uart" > 1400 ) ( ledpin = HIGH);
    if ("ppm_uart" < 1400 ) ( ledpin = LOW);
}

(I know if the details of my project is understable, if not let me know.)

There's nothing in your code that would control a motor. I'd assume that you'll need to use digitalWrite() to control the pin that the motor is driven from:

I see you might have made an attempt to control pin 4:

Eleonore258:

    if ("ppm_uart" > 1400 ) ( ledpin = HIGH);

if ("ppm_uart" < 1400 ) ( ledpin = LOW);

However, that is not the correct way to do it. Please spend some time studying the digitalWrite() documentation I linked above, as well as this tutorial:
https://www.arduino.cc/en/Tutorial/Blink

Defining a variable for the pin numbers is a good idea:

Eleonore258:

int ledpin = 4;

but then you don't use it here:

Eleonore258:

  pinMode(4, OUTPUT);

You should use the variable name everywhere you reference the pin. Imagine if this was part of some complex code and you decided to move the LED to a different pin. If you only changed the definition of ledpin and missed the places where you didn't use ledpin, that would result in a very confusing bug!

Eleonore258:

  pinMode(9, INPUT);

You should also give this pin a descriptive name. 9 means nothing to us but a good variable name would make the code much easier to understand.

One thing that always confuses me is when you have multiple versions of variables e.g.

  int ppm_uart = readCO2UART();
  int ppm_pwm = readCO2PWM();

// and later

  int ppm_uart = 256 * (int)response[2] + response[3];
//
  unsigned long th, tl, ppm_pwm = 0;

// in this case you've redefined ppm_pwm as a different type from the original version

Steve

Hi, Thank you for your reply!!!
I will have a look on all of this and post my new version of the code, following your suggestions.

:slight_smile:
Eleonore

Hi again,

here is my code with the changes but it still doesn't work, i have put a relay module to see the on and off movement, i have red all documentation and arduino book and now i have no clue why it is not working.

Would super great to have a bit of help here ! :slight_smile:

Do you think there is something wrong with the code? I have test the relay module and the Co2 device separately it's working.

Also here is attached a picture of the wiring.

Thanks

#include <SoftwareSerial.h>
SoftwareSerial co2Serial(7, 6); // define MH-Z19 RX TX
unsigned long startTime = millis();

int ledpin = 4;
 
void setup() {
  Serial.begin(9600);
  co2Serial.begin(9600);
  pinMode(9, INPUT);
  pinMode(4, OUTPUT);
}
 
void loop() {
  Serial.println("------------------------------");
  Serial.print("Time from start: ");
  Serial.print((millis() - startTime) / 1000);
  Serial.println(" s");
  int ppm_uart = readCO2UART();
  int ppm_pwm = readCO2PWM();
  delay(5000);
}

int readCO2UART(){
  byte cmd[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79};
  byte response[9]; // for answer

  Serial.println("Sending CO2 request...");
  co2Serial.write(cmd, 9); //request PPM CO2

  // clear the buffer
  memset(response, 0, 9);
  int i = 0;
  while (co2Serial.available() == 0) {
//    Serial.print("Waiting for response ");
//    Serial.print(i);
//    Serial.println(" s");
    delay(1000);
    i++;
  }
  if (co2Serial.available() > 0) {
      co2Serial.readBytes(response, 9);
  }
  // print out the response in hexa
  for (int i = 0; i < 9; i++) {
    Serial.print(String(response[i], HEX));
    Serial.print("   ");
  }
  Serial.println("");

  // checksum
  byte check = getCheckSum(response);
  if (response[8] != check) {
    Serial.println("Checksum not OK!");
    Serial.print("Received: ");
    Serial.println(response[8]);
    Serial.print("Should be: ");
    Serial.println(check);
  }
  
  // ppm
  int ppm_uart = 256 * (int)response[2] + response[3];
  Serial.print("PPM UART: ");
  Serial.println(ppm_uart);

  // temp
  byte temp = response[4] - 40;
  Serial.print("Temperature? ");
  Serial.println(temp);

  // status
  byte status = response[5];
  Serial.print("Status? ");
  Serial.println(status); 
  if (status == 0x40) {
    Serial.println("Status OK"); 
  }
  
  return ppm_uart;
}

byte getCheckSum(char *packet) {
  byte i;
  unsigned char checksum = 0;
  for (i = 1; i < 8; i++) {
    checksum += packet[i];
  }
  checksum = 0xff - checksum;
  checksum += 1;
  return checksum;
}

int readCO2PWM() {
  unsigned long th, tl, ppm_pwm = 0;
  do{

    th = pulseIn(9, HIGH, 1004000) / 1000;
    tl = 1004 - th;
    ppm_pwm = 5000 * (th-2)/(th+tl-4);
   } while (th == 0);
  Serial.print("PPM PWM: ");
  Serial.println(ppm_pwm);
  return ppm_pwm;


    if ("PPM UART" > 1400 )  digitalWrite (ledpin , HIGH);
    if ("PPM UART" < 1400 )  digitalWrite (ledpin , LOW);
}

but it still doesn't work

What does it do?
What do the serial prints show?

yes the serial monitor print the value ppm uart/ppm pwm and temperature as it should do.

If the program prints everything that you expect it to then will you need to explain EXACTLY what is it not doing and when.

    if ("PPM UART" > 1400 )  digitalWrite (ledpin , HIGH);
    if ("PPM UART" < 1400 )  digitalWrite (ledpin , LOW);

These 2 lines are doing nothing because a) they are after the return statement so never executed and b) comparing a String constant like "PPM_UART" to an integer like 1400 is pointless.

Steve

  return ppm_pwm;


    if ("PPM UART" > 1400 )  digitalWrite (ledpin , HIGH);
    if ("PPM UART" < 1400 )  digitalWrite (ledpin , LOW);
}

.Code after an unconditional return is never executed, so there is little point on having that nonsense there.
Comparing a string literal to a numeric literal makes very little sense

What is the problem with your code?

Acceptable answers do not include "it doesn't work"