-
Notifications
You must be signed in to change notification settings - Fork 3
Software
The Arduino micro-controller is used to monitor the status of the chamber via several sensors.
The status of the chamber and the target parameters are stored in the CurrentStatus data structure defined in datastructures.h.
The controller is always in a loop comparing the target parameters and listening for commands from the serial port.

On each iteration of the loop() function the state of the chamber and any changes from the expeced statos, according to the preferences setup for the chamber.
void loop() {
delay(100);
status_read_environment(&cs);
status_control_temperature(&cs);
status_control_light(&cs);
cs.started_up = true;
if (Serial.available() > 0) {
recvWithEndMarker(&cs);
}
if(cs.new_data){
parse_new_data(&cs);
}
}The Grove Temperature and Humidity Sensor Pro v1.3 comes with a library that converts the readings from the sensor to float values that are stored.
#include "DHT.h"
#define DHTTYPE DHT22
DHT dht(PIN_TMP_SENSOR, DHTTYPE);
void dht_setup(){
dht.begin();
}
float dht_humidity(){
return dht.readHumidity();
}
float dht_temperature(){
return dht.readTemperature();
}void status_read_environment(struct CurrentStatus * cs){
cs->humidity = dht_humidity();
cs->temperature = dht_temperature();
}When the chamber is warmer than the expected temperature, the peltier element is used to extract heat from the chamber. To improve the efficiency, we use two standard computer fans. To avoid the unnecessary execution of code, we use the next_peltier_cool_status and peltier_cool_status variables to know if the current status of the system is the same as the expected.
void status_control_temperature(struct CurrentStatus * cs){
if(cs->peltier_cool_status && cs->temperature > cs->min_tmp){
cs->next_peltier_cool_status = true;
}else{
cs->next_peltier_cool_status = cs->temperature > cs->max_tmp;
}
if( !cs->started_up || cs->peltier_cool_status != cs->next_peltier_cool_status){
if(cs->next_peltier_cool_status){
status_start_cool(cs);
}else{
status_stop_cool(cs);
}
}
}The speed of the fans are controlled by the PWM pin.
void fan_set_speed(int pwm, int f_speed){
analogWrite(pwm,f_speed);
}The relays are controlled with a digital signal that turns them on or off.
void relay_on(int port){
digitalWrite(port, HIGH);
}
void relay_off(int port){
digitalWrite(port, LOW);
}When starting or stopping the peltier element the fans attached to them are speed up to improve the heat transfer.
void status_start_cool(struct CurrentStatus * cs){
relay_on(PIN_PELTIER_1);
relay_on(PIN_PELTIER_2);
relay_on(PIN_PELTIER_3);
fan_set_speed(PIN_FAN_INSIDE, 0);
fan_set_speed(PIN_FAN_OUTSIDE, 0);
cs->peltier_cool_status = true;
}
void status_stop_cool(struct CurrentStatus * cs){
relay_off(PIN_PELTIER_1);
relay_off(PIN_PELTIER_2);
relay_off(PIN_PELTIER_3);
fan_set_speed(PIN_FAN_INSIDE, 255);
fan_set_speed(PIN_FAN_OUTSIDE, 255);
cs->peltier_cool_status = false;
}The humidity control consists on a fan to circulate air out of the chamber. The logic is similar to the temperature control, but it only turns on and off the fan that circulates air in the chamber.
void status_control_humidity(struct CurrentStatus * cs){
cs->next_humidity_fan_status = cs->humidity > cs->max_humidity;
if(cs->humidity_fan_status != cs->next_humidity_fan_status){
if(cs->next_humidity_fan_status){
relay_on(PIN_HUMIDITY_FAN);
cs->humidity_fan_status = true;
}else{
relay_off(PIN_HUMIDITY_FAN);
cs->humidity_fan_status = false;
}
}
}The light is controlled with a relay that turns on and off the lights according to the expected status.
void status_control_light(struct CurrentStatus * cs){
if(!cs->started_up || cs->next_light != cs->light){
if(cs->next_light){
status_start_light(cs);
}else{
status_stop_light(cs);
}
}
void status_start_light(struct CurrentStatus * cs){
relay_on(PIN_LIGHT);
cs->light = true;
}
void status_stop_light(struct CurrentStatus * cs){
relay_off(PIN_LIGHT);
cs->light = false;
}The Arduino microcontroller is used only to ensure that the conditions in the chamber are mantained. However, the settings of the growing condition and logs are controled from an external computer, in our prototype a Raspberry Pi. For that reason the controller is always listening to the Serial interface for commands.
void recvWithEndMarker(struct CurrentStatus * cs) {
static byte ndx = 0;
char endMarker = '\n';
char rc;
while (Serial.available() > 0 && cs->new_data == false) {
rc = Serial.read();
if (rc != endMarker) {
cs->receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}else {
cs->receivedChars[ndx] = '\0'; // terminate the string
ndx = 0;
cs->new_data = true;
}
}
}Each line is considered a command. The format is: COMAND=VALUE. The = character is used as token marker for commands with arguments.
void parse_new_data(struct CurrentStatus * cs) {
if (cs->new_data == true) {
String messageFromPC;
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(cs->receivedChars,"=");
messageFromPC = String(strtokIndx); // copy it to messageFromPC
Serial.print("{\"CMD\":\"");
Serial.print(messageFromPC);
Serial.print("\"}");
Serial.println();
Serial.flush();
int tmp_val;
if(messageFromPC == "PRINT"){
print_sensor_error(cs);
status_print(cs);
}else if(messageFromPC == "max_tmp"){
strtokIndx = strtok(NULL, ",");
cs->max_tmp = atof(strtokIndx);
cs->min_tmp = cs->max_tmp -1;
cs->started_up = false;
status_print(cs);
}else if(messageFromPC == "min_tmp"){
strtokIndx = strtok(NULL, ",");
//TODO: Add the code to the python module to control this
cs->min_tmp = atof(strtokIndx);
cs->started_up = false;
status_print(cs);
}else if (messageFromPC == "max_humidity") {
strtokIndx = strtok(NULL, ",");
cs->max_humidity = atof(strtokIndx);
cs->started_up = false;
status_print(cs);
}else if (messageFromPC == "light") {
strtokIndx = strtok(NULL, ",");
tmp_val = atoi(strtokIndx);
cs->next_light = tmp_val > 0;
cs->started_up = false;
status_print(cs);
}
else{
Serial.print("{\"ERROR\": \"Unknown command '");
Serial.print(messageFromPC);
Serial.print("'\"}");
Serial.println();
Serial.flush();
}
status_clear_in_buffer();
cs->new_data = false;
}
}The commands that are currently implemented are:
-
PRINT=Sends to the serial interface the status of the controller. The values are returned formatted asjson -
max_tmp=XX.XXSets the maximum temperature (in Centigrades). -
min_tmp=XX.XXSets the minimum temperature (in Centigrades). -
max_humidity=XX.XXSets the maximum humidity (in percentage). -
light=1|0Sets the lights as on or off.