Update on March 2014:

Mechaphytum Animus is getting complicated... Now she has a fan to control temperature and a humidifier to control environmental humidity... I took this recent pic to show that she is alive... A camera and wifi is the next on the todo list...

At last I managed to complete the design of watering system which is controlled by the soil sensor connected to relay 1... I used the air pump of a faulty blood pressure meter from my garbage bin to pressurize an enclosed beverage bottle which sends water to the plant housing by the help of some aquarium pipe...the system is designed as safe as possible from water spills because we all know that water and electronics is not a good combination...

Update on Feb 2014:

This is the Mechaphytum Animus V1... Still working on problematic Jansen legs, I decided to build my plantoid without legs as V1... It has a recycled body borrowed from an old stereo rack cabin, a sun tracker circuit aligning the plant to the max lighting conditions on a turntable, soil, capacitive and galvanic response sensors as well as environmental temperature and humidity sensors... All electronics are placed in front of the cabin for easy access, the Arduino, a relay board and mood led, a 4post usb hub for future connections such as camera and wifi... 12v 5amp regulated power supply is placed inside the cabin...

I also retired my Hoya Carnosa which was too big and the new candidate plantoid plant is a Kalanchoe which is smaller and has big succulent leaves for sensor attachment...

As a robotics fan and botanical hobbyist I decided to work on Plantoids... the wonderful work of DJUltis and GroG inspired me to work on this project... As a start, I made a datalogging setup for monitoring one of my plants, a Hoya Carnosa ( randomly selected among my hundreds of plants just for her closeness to my working environment)... the data is collected with many sensors, mainly environmental and plant signalling... I made a simple resistive sensor sticking EKG electrodes to both sides of a leaf and reading with Arduino. I had a soil humidity sensor and connected that to the pot too. A temp sensor reads the environmental temperature ( had all kinds of temp sensors but selected DS18B20 because it is digital, accurate and easy to use)... I have a RTC module, air humidity sensors and BMP85 barometric sensor too but will add them later... As a broke hobbyist I made a diy datalogger from one of my micro-sd card readers lying around. the setup can be seen from the above pic... while carrying out this datalogging I learned much about how the plant reacts to her environment... 

GroG just reminded me of the ThingsSpek service of  MRL and will be integrating that to my project soon... so anyone interested can monitor my plant's health remotely... Just in case anyone may be interested the software side, i am attaching here my datalogging Arduino sketch for reference...

/*Read DS18B20 Temp sensor for plant signal datalogging
* Dincer Hepguler 2013
* DS18B20 code from: sheepdogguides.com/arduino/ar3ne1tt.htm
* Code lightly adapted from code from nuelectronics.com
*/
 
#include <SD.h>
// Pin definitions - attaches a variable to a pin.
// On the Ethernet Shield, CS is pin 4. Note that even if it's not
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
// 53 on the Mega) must be left as an output or the SD library
// functions will not work.
const int chipSelect = 10;
const int LeafSensor = A2; // A2 pin is used to read the value of the Leaf Sensor
int LeafState;
const int SoilSensor = A0; // A0 pin used to read val of soil sensor
int SoilState;
int NumReadings = 20; //number of readings per avarage 
//float Deg;
#define TEMP_PIN  3 //D3 pin for ds18b20 signal line
 
void OneWireReset(int Pin);
void OneWireOutByte(int Pin, byte d);
byte OneWireInByte(int Pin);
 
void setup() {
    digitalWrite(TEMP_PIN, LOW);
    pinMode(TEMP_PIN, INPUT);      // sets the digital pin as input (logic 1)
    pinMode(LeafSensor, INPUT); //defines A2 pin as input
    pinMode(10, OUTPUT); //make sure the chip select pin10 is set to output
Serial.begin(9600);
    while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  Serial.print("Initializing SD card...");
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
    delay(100);
    Serial.print("Leaf:   Soil:   Temp:\n");
}
 
void loop(){
  // make a string for assembling the data to log:
  String dataString = "";
  LeafState = analogRead(LeafSensor);  // reads LeafSensor and stores to LeafState variable
  LeafState = map(LeafState, 0,1023,0,255);
  dataString += String(LeafState);
  dataString += "\t";
  SoilState = ReadSensorAvg();
  SoilState = map(SoilState, 0,1023,0,255);
  dataString += String(SoilState);
  dataString += "\t";
  
  int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;
  
  OneWireReset(TEMP_PIN);
  OneWireOutByte(TEMP_PIN, 0xcc);
  OneWireOutByte(TEMP_PIN, 0x44); // perform temperature conversion, strong pullup for one sec
 
  OneWireReset(TEMP_PIN);
  OneWireOutByte(TEMP_PIN, 0xcc);
  OneWireOutByte(TEMP_PIN, 0xbe);
 
  LowByte = OneWireInByte(TEMP_PIN);
  HighByte = OneWireInByte(TEMP_PIN);
  TReading = (HighByte << 8) + LowByte;
  SignBit = TReading & 0x8000;  // test most sig bit
  if (SignBit) // negative
  {
    TReading = (TReading ^ 0xffff) + 1; // 2's comp
  }
  Tc_100 = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25
 
  Whole = Tc_100 / 100;  // separate off the whole and fractional portions
  Fract = Tc_100 % 100;
  //float Deg = Tc_100 * 0.01;
  dataString += String(Whole);
  dataString += ",";
  dataString += String(Fract);
  if (SignBit) // If its negative
  {
     Serial.print("-");
  }
  //LeafState = analogRead(LeafSensor);  // reads LeafSensor and stores to LeafState variable
  //delay(1);
  
  //Serial.print(Whole);
  //Serial.print(".");
  //if (Fract < 10)
  //{
  //   Serial.print("0");
  //}
  //Serial.print("Temp:");
  //Serial.print(Fract);
  //Serial.print("\t");
  //Serial.print(Deg);
  //Serial.print("\t");
  //Serial.print("LeafState:");
  //Serial.print(LeafState);
  //Serial.print("\n");
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile = SD.open("datalog.txt", FILE_WRITE);
 
  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
    Serial.println(dataString);
  }  
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  } 
  delay(1000);      // 5 second datalog delay.  Adjust as necessary
}
 
void OneWireReset(int Pin) // reset.  Should improve to act as a presence pulse
{
     digitalWrite(Pin, LOW);
     pinMode(Pin, OUTPUT); // bring low for 500 us
     delayMicroseconds(500);
     pinMode(Pin, INPUT);
     delayMicroseconds(500);
}
 
void OneWireOutByte(int Pin, byte d) // output byte d (least sig bit first).
{
   byte n;
 
   for(n=8; n!=0; n--)
   {
      if ((d & 0x01) == 1)  // test least sig bit
      {
         digitalWrite(Pin, LOW);
         pinMode(Pin, OUTPUT);
         delayMicroseconds(5);
         pinMode(Pin, INPUT);
         delayMicroseconds(60);
      }
      else
      {
         digitalWrite(Pin, LOW);
         pinMode(Pin, OUTPUT);
         delayMicroseconds(60);
         pinMode(Pin, INPUT);
      }
 
      d=d>>1; // now the next bit is in the least sig bit position.
   }
 
}
 
byte OneWireInByte(int Pin) // read byte, least sig byte first
{
    byte d, n, b;
 
    for (n=0; n<8; n++)
    {
        digitalWrite(Pin, LOW);
        pinMode(Pin, OUTPUT);
        delayMicroseconds(5);
        pinMode(Pin, INPUT);
        delayMicroseconds(5);
        b = digitalRead(Pin);
        delayMicroseconds(50);
        d = (d >> 1) | (b<<7); // shift d to right and insert b in most sig bit position
    }
    return(d);
}
int ReadSensorAvg(){   //subroutine for reading sensor n times and avarage
  int i=0;
  int SoilState=0;
  for (i=0; i < NumReadings; i++){
    SoilState = SoilState + analogRead(SoilSensor);  //read sensor n times 
  delay(10);         //delay between reads for more stability
  }
  SoilState = SoilState / NumReadings;            //avarage
  return SoilState;
}  

 

 

borsaci06

11 years ago

I tried to add MRL ThingSpeak service to my datalogging process.. loaded the py script of the service and made necessarry adjustments... tried to poll A2 pin with no luck.. just received a max number and blocked there... later tried a digital poll with D3 pin which is attached to a PIR sensor and the system worked.... couldnt see the realtime graph on the ThingSpeak site at first but later when i stopped the service the graphs were updated to new logged data... system is Worky!!!.. at least to some extent... :)the screen captures are here as you can see... However there is a bug in saving the py scripts in MRL... if you save the script from the py tab unpredicted changes occur during saving... my saved scripts doesnt work.. so i first copy and paste the script to Notepad++ and save it from there ...

Nice Borsaci! It's great you got it working so quickly. I have the bug of "saving" scripts on my list...

I'm excited to see your project develop. DJ and you are making an excellent team.. great to see new ideas and species evolve

borsaci06

11 years ago

thx DJUltis... wish me luck.... :)

borsaci06

10 years 10 months ago

Wanted to share with you part of tonight's datalogging results... its very cold outside here at minus degrees and its snowing outside. my Hoya is near the terrace door and a little cold surrounding... after few hrs of datalogging i saw that green led on soil sensor is lit, indicating that the soil is dry... so i watered the plant while datalogging and saw some changes in the log window.

then i tried to increase the surrounding temp blowing with a hot air hair dryer for a while. then stopped the torture on the plant and graphed the log file to post here... you can see the part of the log below with some explanations...

Edit on 13.Dec.2013:

Still working on datalogging and better plant response tracking... Trying to create a good interface between the plant and the robot, i need a reliable and usable sensor setup between them... actually the datalogging process taught me a lot in the last few days but i have to improve sensor and data quality... As you can see from the below datalog session that the plant is giving realtime responses to environmental changes but the sensor data from the resistive sensor attached to the plant leaf is not reliable... the relative plant response can be read clearly but the data structure is not consistent enough to be used in a software... The sensor displays a different scale everytime its powered on, values decaying for a while to stabilize in the end...

So I decided to carry on with a new approach to improve data reliability... I know that plants are good conductives and receptors as living tissue... In order to read in-plant activity I made a different sensor reading in a new way... it is a simple antenna signal meter consisting of a small coil, a Germanium diode and a trimer, small enough to attach to the plant stem... So it now reads the signals more reliable via the same Arduino analog port... will display my results in the next few days...

 

GroG

10 years 10 months ago

Interested how your new plantoid will evolve...   Will it use mrl or are you going with straight Arduino sketch only in the v1 / v2 version?

This version runs with std Arduino sketch which I wrote but will be adding MRL into the project as soon as I add the camera and wifi... Until now I havent worked on the Plantoid service and dont know how it works and what it does... May have some questions to you while adding MRL to the Plantoid...

Here is my controlling Arduino sketch for V1:

/*Read hum&temp from DHT11 for plant signalling.
 * Only 3 wires are involved:Vcc, Gnd and a single data line. 
 * Read soil, cap and leaf sensors and assign to variables.
 * Control a mood led according to variables.
 * Control 4 relays to take care of the plant.
 * Dincer Hepguler 2013
*/
 
int r=0;             // red mood               
int g=0;             //green mood              
int b=255;           // blue mood
 
int RelayPin1 = 10;   //watering
int RelayPin2 = 11;   //humidifier
int RelayPin3 = 12;   //fan
int RelayPin4 = 13;
 
 
const int LeafSensor = A2; // A2 pin is used to read the value of the Leaf Sensor
int LeafState;
const int CapSensor = A1;  // A1 pin used to read capacitive sensor
int CapState;
const int SoilSensor = A0; // A0 pin used to read val of soil sensor
int SoilState;
int NumReadings = 20; //number of readings per avarage 
int StresState;
 
#define dht_dpin 2 // Set equal to channel sensor is on,
                   //where if dht_dpin is 14, sensor is on digital line 14, aka analog 0
                   //Other digital lines can be used, e.g. D2
 
byte bGlobalErr;//for passing error code back from complex functions.
byte dht_dat[5];//Array to hold the bytes sent from sensor.
 
void setup(){
 pinMode(LeafSensor, INPUT);   //defines A2 pin as input
 pinMode(CapSensor, INPUT);    //defines A1 pin as input 
 pinMode(RelayPin1, OUTPUT);   //defines relay pins as output
 pinMode(RelayPin2, OUTPUT);
 pinMode(RelayPin3, OUTPUT);
 pinMode(RelayPin4, OUTPUT);
InitDHT();                    //Does what's necessary to prepare for reading DHT
Serial.begin(9600);
delay(300);                   //Let system settle
Serial.println("Leaf:   Soil:   Cap:   Stres:   Hum%:   TempC:\n");
delay(700);                  //Wait rest of 1000ms recommended delay before reading DHT11
  
}
 
void loop(){
  // make a string for assembling the data to log:
  String dataString = "";
  LeafState = ReadLeafAvg();  // reads LeafSensor and stores to LeafState variable
  //LeafState = map(LeafState, 0,1023,0,255);
  g = map(LeafState, 0,1023,0,255);
  dataString += String(LeafState);
  dataString += "\t";
  SoilState = ReadSoilAvg();
  SoilState = map(SoilState, 0,1023,0,255);
    if (SoilState > 50)
{
  digitalWrite(RelayPin1, HIGH);   // sets the Relay1 on for watering
}
  else
{
  digitalWrite(RelayPin1, LOW);    // sets the relay off
}
  dataString += String(SoilState);
  dataString += "\t";
  CapState = analogRead(CapSensor);  // reads CapSensor and stores to CapState variable
  CapState = map(CapState, 0,1023,0,255);
  //r = min(CapState, 255);
  r =255-(CapState+SoilState);
  dataString += String(CapState);
  dataString += "\t";
  StresState = LeafState + CapState;
    if (StresState > 100)
{
  digitalWrite(RelayPin1, HIGH);   // sets the relay LEDs on
  digitalWrite(RelayPin2, HIGH);
  digitalWrite(RelayPin3, HIGH);
  digitalWrite(RelayPin4, HIGH);
  delay(1000);                     // waits for a second
  digitalWrite(RelayPin1, LOW);    // sets the LEDs off
  digitalWrite(RelayPin2, LOW);
  digitalWrite(RelayPin3, LOW);
  digitalWrite(RelayPin4, LOW);
  delay(1000);                     // waits for a second
}
  dataString += String(StresState);
  dataString += "\t";
  
  ReadDHT();
  
  switch (bGlobalErr){
    case 0:
//Serial.print("Current humidity = ");
//Serial.print(dht_dat[0], DEC);
//Serial.print(".");
//Serial.print(dht_dat[1], DEC);
//Serial.print("%  ");
//Serial.print("temperature = ");
//Serial.print(dht_dat[2], DEC);
//Serial.print(".");
//Serial.print(dht_dat[3], DEC);
//Serial.println("C  ");
        dataString += String(dht_dat[0], DEC);
        dataString += ",";
        dataString += String(dht_dat[1], DEC);
        //dataString += "% ";
          if (dht_dat[0] < 30)
{
  digitalWrite(RelayPin2, HIGH);   // sets the Relay2 on for humidifier
}
  else
{
  digitalWrite(RelayPin2, LOW);    // sets the relay off
}
        dataString += "\t";
        dataString += String(dht_dat[2], DEC);
        dataString += ",";
        dataString += String(dht_dat[3], DEC);
        //dataString += "C ";
        if (dht_dat[2] > 30)
{
  digitalWrite(RelayPin3, HIGH);   // sets the Relay3 on for fan
}
  else
{
  digitalWrite(RelayPin3, LOW);    // sets the relay off
}
        break;
     case 1:
        Serial.println("Error 1: DHT start condition 1 not met.");
        break;
     case 2:
        Serial.println("Error 2: DHT start condition 2 not met.");
        break;
     case 3:
        Serial.println("Error 3: DHT checksum error.");
        break;
     default:
        Serial.println("Error: Unrecognized code encountered.");
        break;
      }          //end "switch"
     //b = SoilState + dht_dat[0];
  Serial.println(dataString);   
  delay(1000);     //Don't try to access too frequently... 
  rgb(r,g,b);      // mood led status. yellowish-green=good, reddish=bad          
}                  // end loop()
 
 
void InitDHT(){
        pinMode(dht_dpin,OUTPUT);
        digitalWrite(dht_dpin,HIGH);
}//end InitDHT
 
void ReadDHT(){
/*Uses global variables dht_dat[0-4], and bGlobalErr to pass
  "answer" back. bGlobalErr=0 if read went okay.
  Depends on global dht_dpin for where to look for sensor.*/
bGlobalErr=0;
byte dht_in;
byte i;
  // Send "start read and report" command to sensor....
  // First: pull-down I/O pin for 23000us
digitalWrite(dht_dpin,LOW);
delay(23);
/*aosong.com datasheet for DHT22 says pin should be low at least
  500us. I infer it can be low longer without any]
  penalty apart from making "read sensor" process take
  longer. */
//Next line: Brings line high again,
//   second step in giving "start read..." command
digitalWrite(dht_dpin,HIGH);
delayMicroseconds(30);//keep line high 20-40us 
//Next: Change Arduino pin to an input, to
//watch for the 80us low explained a moment ago.
pinMode(dht_dpin,INPUT);
delayMicroseconds(40);
 
dht_in=digitalRead(dht_dpin);
 
if(dht_in){
   bGlobalErr=1;//dht start condition 1 not met
   return;
   }//end "if..."
delayMicroseconds(80);
 
dht_in=digitalRead(dht_dpin);
 
if(!dht_in){
   bGlobalErr=2;//dht start condition 2 not met
   return;
   }//end "if..."
 
/*After 80us low, the line should be taken high for 80us by the
  sensor. The low following that high is the start of the first
  bit of the forty to come. The routine "read_dht_dat()"
  expects to be called with the system already into this low.*/
delayMicroseconds(80);
//now ready for data reception... pick up the 5 bytes coming from
//   the sensor
for (i=0; i<5; i++)
   dht_dat[i] = read_dht_dat();
 
//Next: restore pin to output duties
pinMode(dht_dpin,OUTPUT);
 
//Next: Make data line high again, as output from Arduino
digitalWrite(dht_dpin,HIGH);
 
//Next see if data received consistent with checksum received
byte dht_check_sum =
       dht_dat[0]+dht_dat[1]+dht_dat[2]+dht_dat[3];
/*Condition in following "if" says "if fifth byte from sensor
       not the same as the sum of the first four..."*/
if(dht_dat[4]!= dht_check_sum)
   {bGlobalErr=3;}//DHT checksum error
};//end ReadDHT()
 
byte read_dht_dat(){
//Collect 8 bits from datastream, return them interpreted
//as a byte. I.e. if 0000.0101 is sent, return decimal 5.
 
  byte i = 0;
  byte result=0;
  for(i=0; i< 8; i++){
      //We enter this during the first start bit (low for 50uS) of the byte
      //Next: wait until pin goes high
      while(digitalRead(dht_dpin)==LOW);
            //signalling end of start of bit's transmission.
 
      //Dataline will now stay high for 27 or 70 uS, depending on
            //whether a 0 or a 1 is being sent, respectively.
      delayMicroseconds(30);//AFTER pin is high, wait further period, 
        
 
      //Next: Wait while pin still high
      if (digitalRead(dht_dpin)==HIGH)
    result |=(1<<(7-i));// "add" (not just addition) the 1
                      //to the growing byte
    //Next wait until pin goes low again, which signals the START
    //of the NEXT bit's transmission.
    while (digitalRead(dht_dpin)==HIGH);
    }//end of "for.."
  return result;
}//end of "read_dht_dat()"
 
int ReadSoilAvg(){     //subroutine for reading soil sensor n times and avarage
  int i=0;
  int SoilState=0;
  for (i=0; i < NumReadings; i++){
    SoilState = SoilState + analogRead(SoilSensor);  //read sensor n times 
  delay(1);         //delay between reads for more stability
  }
  SoilState = SoilState / NumReadings;            //avarage
  return SoilState;
}  
 
int ReadLeafAvg(){     //subroutine for reading leaf sensor n times and avarage
  LeafState = 0;
  for (int i=0;i< NumReadings;i++) {
    LeafState = LeafState + analogRead(LeafSensor);
  delay(1);
  } 
  LeafState = LeafState / NumReadings;
  return LeafState;
}
 
// mood led setup. shows state of the plant.
void rgb(int r, int g, int b) {
  analogWrite(9,b);
  analogWrite(5,r);
  analogWrite(6,g);  
}

GroG

10 years 9 months ago

Borsaci, thanks for the update !

It is getting more complicated !   TURNTABLE !!!  75 rpm ?  How are you managing such slow turning?

Does music make a difference in mood ?

borsaci06

10 years 9 months ago

Thx Grog,

I am still working on her... The turntable is the reason that I borrowed the chassis from an old stereo rack lying around... I replaced the main axis with a hollow metal pipe through which I managed to pass the 8 necessary wires for connections between the plant and the processor... I also used the belt system to slow down the motion of the tracking mechanism... Nowadays I am working on the watering system which I am designing... I am using the air pumping part of a faulty blood pressure meter from my garbage bin for the purpose... It will be an insulated close enclosure for safety purposes... We all know that water and electronics together is not a good mix... :)

I hope music makes a difference in the mood of the plant.... Hehe... :)