Hi,
I'm working on an air quality visualization project for school and have no idea how to reference my Struct data. I'm an Architectural Design student, with some biotech background and used to teach kids coding classes but this is beyond anything I have experience with.
TL;DR:
How do I reference data in my Struct, such as <particles_03um>, and utilize as a function to control the speed of a motor?
#include <PMS.h>
#include <SoftwareSerial.h>
SoftwareSerial pmsSerial(10, 11);
void setup() {
// our debugging output
Serial.begin(115200);
// sensor baud rate is 9600
pmsSerial.begin(9600);
}
struct pms5003data {
uint16_t framelen;
uint16_t pm10_standard, pm25_standard, pm100_standard;
uint16_t pm10_env, pm25_env, pm100_env;
uint16_t particles_03um, particles_05um, particles_10um, particles_25um, particles_50um, particles_100um;
uint16_t unused;
uint16_t checksum;
};
struct pms5003data data;
// structures ((pms3003data)) into data to be addressed in data.xxxxx format
int particles_03um = data.particles_03um;
int particles_05um = data.particles_05um;
int particles_10um = data.particles_10um;
int particles_25um = data.particles_25um;
int particles_50um = data.particles_50um;
int particles_100um = data.particles_100um;
// sets each particle size as individually adressable variable
void loop() {
if (readPMSdata(&pmsSerial)) {
// reading data was successful!
Serial.println();
Serial.println("---------------------------------------");
Serial.println("Concentration Units (standard)");
Serial.print("PM 1.0: "); Serial.print(data.pm10_standard);
Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_standard);
Serial.print("\t\tPM 10: "); Serial.println(data.pm100_standard);
Serial.println("---------------------------------------");
Serial.println("Concentration Units (environmental)");
Serial.print("PM 1.0: "); Serial.print(data.pm10_env);
Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_env);
Serial.print("\t\tPM 10: "); Serial.println(data.pm100_env);
Serial.println("---------------------------------------");
Serial.print("Particles > 0.3um / 0.1L air:"); Serial.println(data.particles_03um);
Serial.print("Particles > 0.5um / 0.1L air:"); Serial.println(data.particles_05um);
Serial.print("Particles > 1.0um / 0.1L air:"); Serial.println(data.particles_10um);
Serial.print("Particles > 2.5um / 0.1L air:"); Serial.println(data.particles_25um);
Serial.print("Particles > 5.0um / 0.1L air:"); Serial.println(data.particles_50um);
Serial.print("Particles > 10.0 um / 0.1L air:"); Serial.println(data.particles_100um);
Serial.println("---------------------------------------");
}
}
boolean readPMSdata(Stream *s) {
if (! s->available()) {
return false;
}
// Read a byte at a time until we get to the special '0x42' start-byte
if (s->peek() != 0x42) {
s->read();
return false;
}
// Now read all 32 bytes
if (s->available() < 32) {
return false;
}
uint8_t buffer[32];
uint16_t sum = 0;
s->readBytes(buffer, 32);
// get checksum ready
for (uint8_t i=0; i<30; i++) {
sum += buffer[i];
}
/* debugging
for (uint8_t i=2; i<32; i++) {
Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", ");
}
Serial.println();
*/
// The data comes in endian'd, this solves it so it works on all platforms
uint16_t buffer_u16[15];
for (uint8_t i=0; i<15; i++) {
buffer_u16[i] = buffer[2 + i*2 + 1];
buffer_u16[i] += (buffer[2 + i*2] << 8);
}
// put it into a nice struct :)
memcpy((void *)&data, (void *)buffer_u16, 30);
if (sum != data.checksum) {
Serial.println("Checksum failure");
return false;
}
// success!
return true;
}
So my PM sensor has 9 outputs, 3 of which can be read as environmental or standard units, for a total of 12 value outputs. I want to select 5 of those Struct values (0.3um, 1.0um, 2.5um, 5.0um, 10.0um), assign them as a function, and control the speed of the independent servos assigned to digital pins 3-7.
In an ideal scenario, I'd want to reparametrize the values of the PM data. the value difference between each are significant (a few hundred units ambiently, a few thousand if I create an event by burning incense or cooking), so my thought (based off of reparametrizing curves in grasshopper for rhino) is to create a 0-1 function, where 0 = min speed, 1 = max speed. Where the value of the PM sensor is defined first by a set range of the sensor values (for 0.3um particles for instance: a range of 0-5500, reparametrized, so that if the real time reading is 3300, it's read as a value of 0.6. If the reading is 250, it's read as a value of 0.04545, etc. and sets a constant motor 'sweep' at that defined speed.
How could I go about this? what resources would you suggest to understand this process in C++?
Hardware:
Arduino Uno
PlanTower PMS5003 Particulate matter sensor with break out board (x 1)
SG90 Servo Motor (x 5)
http://www.ee.ic.ac.uk/pcheung/teaching/DE1_EE/stores/sg90_datasheet.pdf
Note: I'd like to use 3-5 servos inevitably, but just would like to connect 1 data output to control 1 motor to start.
Wring:
PMS5003
(TXD) -> D10
(GND) -> GND
(VCC) -> 5V
SG90s
PWM(1) -> D3
PWM(2) -> D4
PWM(3) -> D5
PWM(4) -> D6
PWM(5) -> D7
VCC/GND -> 5v/GND, Respectively
Many Thanks!