Skip to content

Commit f7e7e52

Browse files
Merge pull request #1340 from arduino/benjamindannegard/mkr-zero-tutorial-import
[MKC-1158] MKR zero tutorial import
2 parents da5a812 + 41a5d53 commit f7e7e52

File tree

12 files changed

+370
-0
lines changed

12 files changed

+370
-0
lines changed
Lines changed: 370 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,370 @@
1+
---
2+
title: 'Home Gardening Automation with MKR Zero'
3+
difficulty: intermediate
4+
compatible-products: [mkr-zero]
5+
description: "Do you like home gardening but you've never had a green thumb? This could be the right solution for you!"
6+
tags:
7+
- Automation
8+
- Gardening
9+
author: 'Arduino'
10+
hardware:
11+
- hardware/01.mkr/01.boards/mkr-zero
12+
software:
13+
- ide-v1
14+
- ide-v2
15+
- web-editor
16+
---
17+
18+
Gardens are a way to contribute to contrast the global warming. Maybe you don't have a backyard, but you have a balcony or a windowsill, in which you could put some plants!
19+
20+
Of course you have to take care of them, and here I am. Even if you don't have a green thumb (like me), you can successfully grow plants thanks to this project: an HGA, aka "Home Gardening Automation" system!
21+
22+
## Hardware & Software Needed
23+
24+
- [Arduino IDE](https://www.arduino.cc/en/software)
25+
- [Arduino MKR Zero](https://store.arduino.cc/products/arduino-mkr-zero-i2s-bus-sd-for-sound-music-digital-audio-data)
26+
- Seeed Grove Moisture Sensor
27+
- Seeed Grove - Relay
28+
- Seeed Seed - Grove - Oled Display 0.96"
29+
- Seeed Seed - Grove - Water Sensor
30+
- Seeed GROVE - HIGH PRECISION BAROMETRIC PRESSURE SENSOR (DPS310)
31+
- Seeed Grove - I2C Hub
32+
- Arduino MKR Connector Carrier (Grove compatible)
33+
- Arduino USB cable type A male to micro type B male
34+
35+
### Circuit
36+
37+
This project is based on the Arduino MKRZERO, and few other Grove components ready-to-use; the BOM is the following:
38+
39+
- The Arduino MKRZERO itself
40+
41+
- The Arduino MKR Connector Carrier, that is used to connect easily to the Arduino board any of the hundreds Grove modules!
42+
43+
- The Grove Moisture sensor, used to measure the humidity level on the ground (connected to A0)
44+
45+
- The Grove Water sensor, used to check the water availability in the tank (connected to D0)
46+
47+
- The Grove relay module, used to activate the water pump - or if you prefer, you can drive an electronic valve (connected to D1)
48+
49+
- The Grove Barometric sensor, used to check the pressure and temperature (connected to TWI port with the Grove I2C Hub)
50+
51+
- The Grove OLED display, used to show all the values retrieved from the sensors, and other info (connected to TWI port with the Grove I2C Hub)
52+
53+
![Image of components for the project](assets/component-image.jpg)
54+
55+
Then you have to add to the recipe:
56+
57+
- A pump or an electronic valve to water the plant(s)
58+
59+
- 12v power supply for Arduino and pump/valve powering
60+
61+
- last but not least: a vase with your plant
62+
63+
Of course you can reach the same setup using a breadboard, floating wires, spare components and a few time more!
64+
65+
## Programming the Board
66+
67+
To use the MKRZERO board, there are 2 options. Either using the Arduino Web Editor or using the Arduino IDE. You can find more information on the Web Editor and IDE setup for the MKRZERO at [this link](https://docs.arduino.cc/hardware/mkr-zero).
68+
69+
After connecting your Arduino to the usb port, be sure to have selected the right board and the right port.
70+
71+
Let's start sketching!
72+
73+
## Sketch #1: Water Level Sensor
74+
75+
The water sensor is connected to pin D0 and it works like a switch: it there water on its surface (or touching both the wire ends), then it will be read like a pressed switch.
76+
77+
So we can start with a simple sketch, to test the sensor!
78+
79+
```arduino
80+
const int waterSensor = 0;
81+
void setup() {
82+
Serial.begin(9600);
83+
pinMode(waterSensor, INPUT);
84+
}
85+
void loop() {
86+
int waterStatus = digitalRead(waterSensor);
87+
Serial.prinln(waterStatus);
88+
delay(500);
89+
}
90+
```
91+
92+
Now open the Monitor (or Serial Monitor if you are working on the IDE) and you'll see a column of "1".
93+
94+
If you touch the surface of the sensor with a wet finger, you'll see the number changing to "0".
95+
96+
So, the value in case of water presence, is LOW (0)!
97+
98+
```arduino
99+
void loop() {
100+
int waterStatus = digitalRead(waterSensor);
101+
//the Water Sensor gives 0 when it measure water presence
102+
Serial.println(waterStatus);
103+
if (waterStatus == LOW) {
104+
//system ok
105+
}
106+
delay(500);
107+
}
108+
```
109+
110+
Save the code, and go on with the next step.
111+
112+
### Water Sensor Hacking
113+
114+
In order to use the water sensor to check the water availability in a tank, we have to fit the sensor inside it.
115+
116+
We can do a little hack to the sensor if we want to check the presence of water at a certain level or a minimum quantity of water.
117+
118+
We need two solid wires, of different length. For example, if we want to be sure to check the presence of at least 10 cm of water, the difference length will be exactly that.
119+
120+
![Length of wires](assets/wire-length.jpg)
121+
122+
Now just look at the water sensor: there is a sequence of tinned bar, alternatively connected together.
123+
124+
![Position on grove module](assets/groove-wires.jpg)
125+
126+
When a drop of water touch at least 2 adjacent bars, then the circuit is closed.
127+
128+
So we have to solder one ends of the solid wires to 2 tinned bar that are not connected together.
129+
130+
![Where to solder wires](assets/soldering.jpg)
131+
132+
Now it will be enough to fit the solid wires in the water, and let the sensor outside the tank, in order to measure the water availability.
133+
134+
## Sketch #2: Barometric Sensor
135+
136+
We have a barometric sensor based on the DPS310 chip, connected to the TWI port.
137+
138+
We can use it to read the pressure and the temperature.
139+
140+
If we try to search a library for this component, we'll see that there's no one available.
141+
142+
That's because not all libraries are directly available: sometimes we need to install a new one, by using the Library Manager.
143+
144+
![Library in the online editor](assets/sketch-2-editor-1.jpg)
145+
146+
Let's install the Infineon library, simply by starring it!
147+
148+
![Installing library](assets/sketch-2-editor-2.jpg)
149+
150+
Now that the library is available, for a basic test of the sensor, we can try the "I2C_command" example.
151+
152+
![Example in library](assets/sketch-2-editor-3.jpg)
153+
154+
From that example, we'll get the lines needed for the sensor to work!
155+
156+
We'll need to add to our code the include of the library and the creation of a new Dps310 object, in order to use it.
157+
158+
```arduino
159+
#include <Dps310.h>
160+
// Dps310 Object
161+
Dps310 Dps310PressureSensor = Dps310();
162+
//more oversamplig (7 is the highest usable value) means more precision!
163+
const int dps310_oversampling = 7;
164+
```
165+
166+
Then we need to initialize this object in the setup:
167+
168+
```arduino
169+
Dps310PressureSensor.begin(Wire);
170+
```
171+
172+
and then we need only to put these rows in the loop, to have a pressure and temperature values!
173+
174+
```arduino
175+
float temperature;
176+
float pressure;
177+
Dps310PressureSensor.measureTempOnce(temperature, dps310_oversampling);
178+
Dps310PressureSensor.measurePressureOnce(pressure, dps310_oversampling);
179+
```
180+
181+
We'll use these values later on!
182+
183+
## Sketch #3: Moisture Sensor and Relay
184+
185+
Let's introduce in the system another sensor: the Moisture Sensor.
186+
187+
Fitted in the ground, it's able to measure its humidity level. The output is an analog value (in the range 0-1023), so it's connected to the A0 pin.
188+
189+
The relay, connected to pin D1, will be used to activate a pump, or to open an electronic valve, that need far more than the 3v3 provided by the MKRZERO board in order to work!
190+
191+
Now, we need to find out the threshold for the moisture sensor, used to trig the watering.
192+
193+
First, fit the sensor in the plant ground. Then upload this simple sketch, and open the serial monitor.
194+
195+
```arduino
196+
const int moistureSensor = A0;
197+
void setup() {
198+
Serial.begin(9600);
199+
}
200+
void loop() {
201+
int moistureStatus = analogRead(moistureSensor);
202+
Serial.prinln(moistureStatus);
203+
delay(500);
204+
}
205+
```
206+
207+
Now look at the values scrolling in the serial monitor, first with the dried ground, and then after watering the plant. The value we are going to use as threshold, is between the lower and the higher seen in this test.
208+
209+
Now come back to the main sketch.
210+
211+
We need to update the header by:
212+
213+
- Defining the constant for the relay and moisture sensor pins;
214+
215+
- Define the threshold for the moisture sensor;
216+
217+
- Define a duration, used to control the quantity of water provided. Depending on the pump or the pipe diameter, we could need 10 seconds or up to minutes; we need to check on our specific setup to estimate the right value.
218+
219+
- Define an interval between watering, in order to let the water to be absorbed, before to check again the ground humidity. It depends on our specific setup (for example, on the dimension of the vase).
220+
221+
- Define a couple of variables to keep the count of when we started the last watering, and the actual watering status.
222+
223+
```arduino
224+
//Grove Relay -> D1
225+
const int relay = 1;
226+
//Grove Moisture Sensor -> A0
227+
const int moistureSensor = A0;
228+
//watering duration and threshold
229+
const int threshold = 256;
230+
const int watering_duration = 30 * 1000;
231+
const int interval_between_watering = 60*1000;
232+
unsigned long last_watering = 0;
233+
bool watering = false;
234+
```
235+
236+
Then move to the loop().
237+
238+
Add these line at the beginning:
239+
240+
```arduino
241+
unsigned long now = millis();
242+
unsigned long last_watering_ago = now - last_watering;
243+
```
244+
245+
`millis()` returns the milliseconds passed since the board began running the current program, and it's very useful if we need to track intervals or duration.
246+
247+
`last_watering_ago` is used to store the total time passed since the last watering.
248+
249+
The first check is if it's passed at least the `interval_between_watering`.
250+
251+
If so, we can evaluate the humidity measurement, and if it's lower than the threshold, than the relay will be turned on. At the same time, it will update the `last_watering` and the watering variables in order to keep track of what's happening (and when).
252+
253+
```arduino
254+
if (last_watering_ago > interval_between_watering) {
255+
//check the humidity level, and if under the threshold, start watering!
256+
if (moistureStatus < threshold) {
257+
last_watering = now;
258+
watering = true;
259+
digitalWrite(relay, HIGH);
260+
}
261+
}
262+
```
263+
264+
We have to add only another piece of code: the one that will turn off the relay after the watering_duration time. It will update the watering status as well.
265+
266+
```arduino
267+
if (now - last_watering > watering_duration) {
268+
watering = false;
269+
digitalWrite(relay, LOW);
270+
}
271+
```
272+
273+
## Sketch #4: OLED Display
274+
275+
The last component is the Oled Display!
276+
277+
It's quite small but the definition is high enough: it allows you to display graphics or up to 8 rows of text.
278+
279+
We'll use it to display all the sensors' measurements.
280+
281+
As already done for the pressure sensor., we have to use the Library Manager in order to install the right library. Just search for "oled" and star the Grove Oled Display 0.96 library
282+
283+
![Installing library](assets/sketch-4-library.jpg)
284+
285+
For a basic test of the display, we can start from the OLED_Hello_World example:
286+
287+
![Library example](assets/sketch-4-library-2.jpg)
288+
289+
To include the display in our main sketch, we have to include the required libraries:
290+
291+
```arduino
292+
#include <Wire.h>
293+
#include <SeeedOLED.h>
294+
```
295+
296+
and to initialize the display in the setup and clear it at least at the beginning:
297+
298+
```arduino
299+
Wire.begin();
300+
SeeedOled.init();
301+
SeeedOled.setNormalDisplay(); //Set display to normal mode
302+
SeeedOled.setPageMode(); //Set addressing mode to Page Mode
303+
SeeedOled.clearDisplay(); //Clear the display
304+
```
305+
306+
Now we can use it in our loop.
307+
308+
For every element we want to display, we have to specify the row and the column where we want it to appear using the `setTextXY` function.
309+
310+
Then for every data type, there's a different function to print it:
311+
312+
- String: `putString()`
313+
314+
- int: `putNumber()`
315+
316+
- float: `putFloat()`
317+
318+
Instead of using `clearDisplay` at every loop (it makes the display flickering!) we can "empty" the row used to display the measurements by putting a string of spaces, and then at the same position, write the new value!
319+
320+
The last row is used to display how many minutes ago the last watering was!
321+
322+
So at the end of the loop, just before the last curly bracket, we can put these rows:
323+
324+
```arduino
325+
//1^ & 2^ rows: the moisture value
326+
SeeedOled.setTextXY(0, 0);
327+
SeeedOled.putString("Moisture:");
328+
//empty the row
329+
SeeedOled.setTextXY(1, 2);
330+
SeeedOled.putString(" ");
331+
//...and then write the new value
332+
SeeedOled.setTextXY(1, 2);
333+
SeeedOled.putNumber(moistureStatus);
334+
//3^ & 4^ rows: the temperature value
335+
SeeedOled.setTextXY(2, 0);
336+
SeeedOled.putString("Temperature (C):");
337+
SeeedOled.setTextXY(3, 2);
338+
SeeedOled.putString(" ");
339+
SeeedOled.setTextXY(3, 2);
340+
SeeedOled.putFloat(temperature);
341+
//5^ & 6^ rows: the pressure value
342+
SeeedOled.setTextXY(4, 0);
343+
SeeedOled.putString("Pressure (hPa):");
344+
SeeedOled.setTextXY(5, 2);
345+
SeeedOled.putString(" ");
346+
SeeedOled.setTextXY(5, 2);
347+
SeeedOled.putFloat(pressure);
348+
//7^ & 8^ rows: Last watering
349+
SeeedOled.setTextXY(6, 0);
350+
SeeedOled.putString("Last (min. ago):");
351+
SeeedOled.setTextXY(7, 2);
352+
SeeedOled.putString(" ");
353+
SeeedOled.setTextXY(7, 2);
354+
//milliseconds / 1000 -> seconds / 60 -> minutes
355+
SeeedOled.putNumber(last_watering_ago / 1000 / 60);
356+
```
357+
358+
The result:
359+
360+
![The result](assets/the-result.jpg)
361+
362+
## Next Step
363+
364+
Now we have a fully automated system that will help us taking care of our plants at home. If we want to power the board and all the components, included the pump or valve, using a singular power supply, we have to switch to a 12V one. The MKR Connector Carrier is already ready to this voltage: there's screw block in which we can attach external power supply (VIN and GND).
365+
366+
In this simple schema you can find the power circuit and how to connect to it the relay and the pump.
367+
368+
![Next step](assets/next-step-image.jpg)
369+
370+
The next improvements are then up to you! You could try to estimate the weather forecast upon the pressure variation! Or avoid watering if the temperature it too high. Or again, you could add a solar panel and a battery in order to have an off-grid system! And why not use the I2S combined to an uSD card to let your plants talk?

0 commit comments

Comments
 (0)