Python Robotics Projects
上QQ阅读APP看书,第一时间看更新

Making it truly intelligent

Amazing work! We have started building things that are smarter than us by ourselves. But now we want to take it a step further and make it even smarter than us—that's what robots are here for. Not only to do what we do but to do all that in a better way. 

So, what can we improve? Well, we do not require a lot of water on a chilly winter day, but when it's summertime we need way more than what we drink in winter. The same thing happens with plants as well. 

In winter, the amount of water they need is way less. Furthermore, even the rate of evaporation of water in the soil is slower. Hence, in both the conditions, we need to supply varying amounts of water to the garden. The question is, how do we do that?

Well, firstly, to know if it's hot or cold outside we require a sensor. We will be using a sensor named DHT11. It is a cheap yet robust sensor that gives us the readings of both the temperature and humidity. The best part is, it is super cheap at a rate of around $2. 

It has four pins. But if you presume that it will work to I2C protocols, then you would be wrong. It has its own data transfer methodology. It is good to have one single protocol for all the sensors, but often you will also find that there are various sensors or devices which work on a different or an altogether new protocol. DHT11 is one such sensor. In this case, we have the choice of either understanding the entire methodology of communication or to simply get the library from the manufacturer and use it at our disposal. At present we will be opting for the latter. 

Now let's see what the pins of the DHT11 look like:

What you can see here is that there is only one signal pin which will do all the communication digitally. There are two pins for power and one of the pin is not in use. I.e. there is no significant purpose of the pin. It might be there just for soldering or for future use. This sensor works on a 5V supply and only needs a few milliamps, hence we can simply power it up by using Raspberry Pi. Now, for the data communication, we will connect the signal pin to GPIO pin number 4.

Before we start writing the code, let's first install the libraries for the communication between DHT11 and Raspberry Pi. We have done this before with the library of ADS1115, but in this one there are a few little tricks that we need to take care of. So let's get started.

Firstly, we need to make sure that the operating system of your Raspberry Pi is up to date. So connect Raspberry Pi to the internet, open the command prompt in Raspberry Pi, and type the following command:

sudo apt-get update

This command will update the raspbian OS of your Raspberry Pi automatically. Then go ahead and type in this:

sudo apt-get install build-essential python-dev python-openssl

In this command, we are installing the following packages:

  • build-essential
  • python-dev
  • python-openssl

You must be wondering why we are installing all of these. Well, to cut a long story short, these are the dependencies for the library that we are about to install for the communication of DHT11. We will not be able to use the library if these packages are not installed on Raspberry Pi.

Finally, we have to install the library; this is a generic library in which the function of communicating with the DHT11 sensor is also available. This should suffice for our needs of easy communication. Here is the command to install it:

sudo python setup.py install

All right then, we are good to go. Our system is ready to talk to DHT11. Let's first just see if what we have done up until now works the way we want. To do that, connect the DHT11 as follows; you can leave the rest of the components such as the solenoid and the soil humidity sensor connected as they are. They should not interfere. Now upload the the following code in Pi:

from time import sleep
from datetime import datetime
import RPi.GPIO as GPIO
import Adafruit_DHT
sensor = 11
pin = 4
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
while True:
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
print("Temperature: " +temperature+ "C")
print("Humidity: " +humidity+ "%")
time.sleep(2)

Once you upload this code, you will see readings of the sensor on your screen. This code is simply providing you with the raw readings of the sensor. This code is super simple and everything written here will be well understood by you, except for a few lines of the code, which are:

import Adafruit_DHT

In this line of the code, we are importing the Adafruit_DHT library in our code. This is the same library that will be used to communicate with the DHT11 sensor:

sensor = 11 

There are different versions of DHT available, such as DHT11, DHT22, and so on. We need to tell the program which sensor we are using. Hence, we have allotted a value to the variable sensor. Later, you will see how we will be using it:

pin = 4  

In this line, we are assigning the value 4 to a variable called pin. This variable will be used to tell the program on which pin of the Raspberry Pi we have connected the DHT11:

humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)

In this line, we are using a method of the Adafruit library named Adafruit_DHT.read_retry(). Now, what this does is that it reads the DHT sensor and gives the reading of the sensor to the variables humidity and temperature. One thing to note is that the DHT11 gives a reading which is updated every 2 seconds. Hence, the readings that you will be receiving will be refresh after every 2 seconds. 

Once this code is through, then we can be sure that the sensor is working the way we want. Finally, the time has come to integrate all of the sensors together and make an entirely intelligent robot. As the solenoid, humidity sensor, and temperature sensors are already connected, all we need to do is to upload the code over to Pi and see the magic:

from time import sleep
from datetime import datetime
import RPi.GPIO as GPIO
import Adafruit_ADS1x15
import Adafruit_DHT
water_valve_pin = 23
sensor = 11
pin = 4
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(water_valve_pin, GPIO.OUT)
Channel =0
GAIN = 1
adc = Adafruit_ADS1x15.ADS1115()
def check_moisture(m):
adc.start_adc(channel, gain=GAIN)
moisture_value = adc.get_last_result()
moisture_value = int(moisture_value/327)
print moisture_value
if moisture_value < m:
GPIO.output(water_valve_pin, GPIO.HIGH)
sleep(5)
GPIO.output(water_valve_pin, GPIO.LOW)
else:
GPIO.output(water_valve_pin, GPIO.LOW)
while True:
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
H = datetime.now().strftime(‘%H’)
M = datetime.now().strftime(‘%M’)
if H == ‘07’ and M <= ‘10’:
if temperature < 15:
check_moisture(20)
elif temperature >= 15 and temperature < 28:
check_moisture(30)
elif temperature >= 28:
check_moisture(40)
if H == ‘17’ and M <= ‘10’:
if temperature < 15:

check_moisture(20)
elif temperature >= 15 and temperature < 28:
check_moisture(30)
elif temperature >= 28:
check_moisture(40)

Pretty long code, right? It might look so, but once you write it line by line, you will certainly understand that it might be longer than all the code we have written so far, but it's anything but complex. You might have understood most of the program, however let me explain a few new things that we have used here:

def check_moisture(m):
adc.start_adc(channel, gain = GAIN)

moisture_value = adc.get_last_result()
moisture_value = int(moisture_value / 327)
print moisture_value

if moisture_value < m:
GPIO.output(water_valve_pin, GPIO.HIGH)
sleep(5)
GPIO.output(water_valve_pin, GPIO.LOW)
else :
GPIO.output(water_valve_pin, GPIO.LOW)

In this line, we are defining a function named check_moisture(). Previously, if you remember, while we were making the function check_moisture, we were basically checking if the moisture value was either more or less than 20%. What if we have to check the moisture for 30%, 40%, and 50%? Would we make a separate function for that?

Obviously not! What we do is we pass an argument to the function,  an argument is basically a variable placed within the brackets of the function. Now we can assign values to this variable for, for example, check_moisture(30)—now the value of the m will be 30 during the time that function is executing. Then again, if you call it as check_moisture(40) then the value of that m would be 40

Now, as you can see, we are comparing values of m throughout the function:

   if moisture_value < m:

The if statement will be checking the value of the m which is assigned while calling the function. This makes our job very easy and simple. 

Let's see what the rest of the program is doing:

            if temperature < 15:
check_moisture(20)

Every time the desired time is reached it will go ahead and check for the temperature. If the temperature is less than 15 it will call the function check_moisture  with the value of the argument as 20. Hence, if the moisture is less than 20%, then the water will be fed to the garden:

 elif temperature >= 15 and temperature < 28:
check_moisture(30)

The elif or the else if statement is used after an if statement. This in common words means that if the previous if statement is not true, then it will check for this if statement. So, in the preceding line it will check if the temperature is between 15 and 28 degrees Celsius. If that is true, then it will check the moisture of the soil. The argument to the function is 30 in this line. Hence, it will check if the moisture is less than 30. If so, then it will supply the water to the garden:

 elif temperature >= 28:
check_moisture(40)

Similarly, in this line of code we are checking the temperature, and if it is equal to or more than 28 degrees Celsius then it will pass the value 40 as an argument to the function check_moisture. Hence this time it will check for moisture if it is 28 or more than that.

As you can see, now the system will be checking the ambient temperature and, based on that, the amount of water to the plants is regulated. The best part is that it is consistent and will provide the right amount of water needed by the plants. 

The values mentioned in this entire chapter are simply assumed values. I would strongly recommend to tweak it based on where you live and what kind of plants you have in your garden to get the best out of the system.