Подключение датчика NPK почвы к Arduino
Выращивание крепких и здоровых растений — это не только солнечный свет и вода. Растениям тоже нужна пища! Как и нашему организму нужно сбалансированное питание для энергии и здоровья, так и растения зависят от трёх основных питательных веществ для роста, сохранения зелёного цвета и формирования цветов или плодов: азот (N), фосфор (P) и калий (K). Эти три элемента часто объединяют под аббревиатурой NPK, и они составляют основу здоровья растений.
Чтобы помочь растениям раскрыть свой потенциал, очень важно знать точное содержание каждого элемента в вашей почве. Так вы сможете вносить только то, что действительно нужно растениям, вместо того чтобы просто гадать и надеяться на лучшее. Именно здесь датчик NPK почвы становится невероятно полезным. Подключив датчик NPK почвы к Arduino, вы можете измерять уровни азота, фосфора и калия в почве в реальном времени и принимать обоснованные решения по уходу за садом или полем.
В этом руководстве вы узнаете, как работает датчик NPK почвы, научитесь подключать его к Arduino, поймёте основы протокола Modbus (через который датчик и Arduino обмениваются данными), узнаете, как отправлять и принимать команды Modbus для считывания данных датчика, и, наконец, отобразите значения в мониторе последовательного порта.
Давайте начнём!
Что такое NPK и почему это важно?
NPK — это аббревиатура трёх основных питательных веществ, необходимых всем растениям для роста и процветания: азот, фосфор и калий. Каждый из этих элементов играет определённую и важную роль в здоровье растений.
Азот поддерживает рост листвы и придаёт растениям здоровый зелёный цвет.
Фосфор отвечает за развитие крепкой корневой системы и способствует росту цветов, плодов и семян.
Калий помогает растениям регулировать потребление воды, укрепляет их общую структуру и повышает устойчивость к болезням и воздействию окружающей среды.
Когда растения не получают достаточно этих элементов, они начинают проявлять явные признаки проблем. Например, при нехватке азота листья желтеют, а рост замедляется. При недостатке фосфора корни остаются слабыми, и растение плохо цветёт. А при дефиците калия края листьев коричневеют или выглядят обожжёнными, а стебли становятся слабыми и вялыми.
Вы наверняка замечали цифры на упаковках удобрений в магазине — например, 10-10-10 или 5-10-5. Эти числа обозначают процентное содержание азота, фосфора и калия в удобрении. Удобрение 10-10-10 обеспечивает растениям равное количество всех трёх элементов, тогда как 5-10-5 содержит больше фосфора, что особенно полезно для растений, производящих цветы и плоды.
Датчик NPK почвы JXCT
Датчик NPK почвы JXCT — это доступное, быстрореагирующее, достаточно точное и портативное устройство, предназначенное для измерения уровней питательных веществ NPK в почве в реальном времени.
Проверяя содержание NPK непосредственно в почве, датчик облегчает понимание плодородности почвы и того, получают ли растения необходимые питательные вещества. Важно отметить, что этот датчик работает только с почвой, а не с водой или жидкими растворами.
Датчик работает от 5–30 вольт и потребляет очень мало энергии. Согласно его даташиту, он может измерять азот, фосфор и калий с разрешением до 1 мг на килограмм (мг/кг).
Датчик оснащён зондом из нержавеющей стали, который не ржавеет и устойчив к повреждениям от электролиза и солещелочных условий. Это означает, что его можно использовать в любом типе почвы: щелочной, кислой, субстратной, почве для рассады и даже в кокосовом субстрате.
Одна из лучших характеристик этого датчика — рейтинг IP68, который является стандартной мерой защиты. Этот рейтинг означает полную защиту от пыли и влаги, поэтому датчик может надёжно работать в течение очень долгого времени даже в суровых уличных условиях.
Для эффективного использования на больших расстояниях в сельскохозяйственных полях или крупных садах датчик использует интерфейс RS485 и поддерживает протокол Modbus-RTU.
Технические характеристики
Вот основные характеристики:
Питание |
5V-30V |
|---|---|
Диапазон измерения |
0-1999 mg/kg (ml/l) |
Рабочая температура |
5-45 °C |
Разрешение |
1mg/kg (ml/l) |
Точность |
±2% F.S. |
Выходной сигнал |
RS485 |
Класс защиты |
IP68 |
Распиновка датчика NPK почвы
Датчик поставляется с 2-метровым кабелем с лужёными медными проводами на конце. Распиновка показана на схеме ниже.
VCC — провод питания. Подключается к источнику напряжения от 5В до 30В.
A — один из дифференциальных сигнальных проводов. Подключается к контакту A на модуле RS485.
B — другой дифференциальный сигнальный провод. Подключается к контакту B на модуле RS485.
GND — провод земли.
Подключение датчика NPK почвы к Arduino
Датчик NPK нельзя подключить напрямую к Arduino, поскольку он использует стандарт связи RS-485, который Arduino по умолчанию не поддерживает. Для обеспечения связи между ними необходим специальный адаптер — модуль приёмопередатчика RS485. Этот модуль преобразует последовательные UART-сигналы Arduino в сигналы RS485, понятные датчику.
После приобретения модуля RS485 можно приступать к подключению.
Датчик NPK почвы имеет четыре цветных провода. Коричневый провод — провод питания, который должен быть подключён к источнику 5В–30В. Чёрный провод — провод земли, который должен быть подключён к общей земле схемы. Жёлтый провод подключается к контакту A модуля RS485, а синий — к контакту B.
Далее необходимо подключить модуль RS485 к Arduino. Поскольку этот модуль использует UART-связь, вы можете подумать о подключении к контактам UART (0 и 1) на Arduino Uno. Однако есть проблема: эти же контакты используются при связи Arduino с компьютером, например при загрузке кода или просмотре монитора последовательного порта.
Поскольку Arduino Uno имеет только один встроенный UART, нам нужно создать второй специально для модуля RS485. К счастью, есть простое решение — `библиотека SoftwareSerial `_, которая позволяет обычным цифровым контактам работать как дополнительные UART-контакты.
Для этого проекта мы используем цифровые контакты 2 и 3 на Arduino. Подключите контакт RO (Receiver Output) модуля RS485 к цифровому контакту 2, а контакт DI (Driver Input) — к цифровому контакту 3. Затем подключите контакт VCC модуля к выходу 5V Arduino, а контакт GND — к контакту GND Arduino. Подключите контакты DE (Driver Enable) и RE (Receiver Enable) модуля к цифровым контактам 7 и 8 Arduino; эти контакты управляют тем, отправляет модуль данные или принимает.
Наконец, убедитесь, что Arduino и вся схема имеют общую землю.
На этой схеме показано, как именно всё подключить:
Инструкции по использованию
Когда вы готовы использовать датчик в поле, выберите подходящее место для размещения датчика. Убедитесь, что в этом месте нет камней. Воткните датчик вертикально прямо в почву так, чтобы он был равномерно окружён землёй.
При желании датчик можно установить и горизонтально. Для этого выкопайте вертикальную яму шириной более 20 сантиметров, чтобы обеспечить достаточно места для датчика и окружающей почвы. Затем вставьте датчик горизонтально в боковую стенку ямы и плотно утрамбуйте почву вокруг него.
Что такое Modbus?
На случай, если вы не знакомы с Modbus, будет полезно разобраться в нём перед тем, как продолжить проект.
Modbus — это де-факто стандартный протокол связи для промышленного оборудования, во многом благодаря тому, что он является открытым и бесплатным. Он может передавать данные через различные интерфейсы, включая RS-485, RS-422 и RS-232, а также по сетям Ethernet TCP/IP.
Существует несколько различных реализаций Modbus. Вот наиболее популярные типы протоколов:
Modbus RTU (именно его мы настроим и будем использовать)
Modbus ASCII
Modbus TCP
Протокол Modbus RTU
Modbus RTU использует метод связи «ведущий-ведомый». В этой системе только ведущее устройство может инициировать обмен данными. Ведущий запрашивает информацию, а ведомые отвечают только по запросу. В нашем случае Arduino выступает в роли ведущего, а подключённые к нему датчики NPK — в роли ведомых. Одна сеть Modbus RTU может поддерживать до 247 ведомых устройств на одной линии связи, что означает возможность подключения и мониторинга множества датчиков одновременно.
Кадр данных Modbus RTU
Когда устройства Modbus обмениваются данными, они отправляют сообщения в виде кадров данных. Существуют два типа кадров: кадры запроса и кадры ответа. Кадр запроса отправляется ведущим для запроса информации у конкретного ведомого, а кадр ответа отправляется ведомым для предоставления этой информации.
Типичный кадр данных Modbus RTU содержит несколько частей. Он включает адрес ведомого устройства (Slave ID), код функции, указывающий ведомому, какой тип действия требуется, поле данных, зависящее от кода функции, и контрольную сумму CRC для проверки точности сообщения.
Вот пример кадра запроса Modbus RTU, когда Arduino (как ведущий) отправляет запрос ведомому #1 на возврат значения регистра, начинающегося с адреса 2.
Когда это сообщение отправляется в сеть, все ведомые устройства, кроме ведомого #1, полностью его игнорируют. Ведомый #1 затем отправляет обратно кадр ответа с запрошенной информацией.
Запросы Modbus RTU для чтения датчика NPK
Теперь, когда вы понимаете, как работает кадр данных Modbus RTU, пора научиться отправлять запросы Modbus RTU к датчику NPK для считывания значений азота, фосфора и калия, а также интерпретировать ответные сообщения для извлечения правильных показаний.
Для каждого элемента требуется немного отличающийся формат запроса Modbus, поэтому датчик должен получить правильный запрос для конкретного значения, которое вы хотите измерить.
Ниже приведены три примера запросов Modbus RTU, которые можно использовать для чтения значений NPK с датчика, а также типичные ответные сообщения, которые вы можете получить.
Для чтения азота
Запрос Modbus RTU для чтения уровня азота выглядит следующим образом:
В ответ вы получите сообщение, подобное этому:
Из ответа значение азота можно найти в поле данных. Например, если ответ содержит значение 0x0020 в поле данных, можно вычислить уровень азота, преобразовав его из шестнадцатеричной системы в десятичную:
Nitrogen = 0x0020HEX = 32DEC => 32 mg/kg
Для чтения фосфора
Процесс чтения фосфора очень похож. Запрос Modbus RTU для чтения уровня фосфора выглядит так:
Вы получите ответ, подобный этому:
Из этого ответа можно определить уровень фосфора. Например, если ответ содержит значение 0x0025 в поле данных, можно вычислить уровень фосфора следующим образом:
Phosphorous = 0x0025HEX = 37DEC => 37 mg/kg
Для чтения калия
Следуя тому же принципу, что и для предыдущих двух элементов, запрос Modbus RTU для чтения уровня калия выглядит так:
Вы получите ответ, подобный этому:
Из этого ответа можно узнать уровень калия. Например, если ответ содержит значение 0x0030 в поле данных, можно вычислить уровень калия следующим образом:
Potassium = 0x0030HEX = 48DEC => 48 mg/kg
Пример кода Arduino
Следующий скетч считывает значения азота, фосфора и калия с датчика и выводит их в монитор последовательного порта.
#include <SoftwareSerial.h>
#include <Wire.h>
// RE and DE Pins set the RS485 module
// to Receiver or Transmitter mode
#define RE 8
#define DE 7
// Modbus RTU requests for reading NPK values
const byte nitro[] = { 0x01, 0x03, 0x00, 0x1e, 0x00, 0x01, 0xe4, 0x0c };
const byte phos[] = { 0x01, 0x03, 0x00, 0x1f, 0x00, 0x01, 0xb5, 0xcc };
const byte pota[] = { 0x01, 0x03, 0x00, 0x20, 0x00, 0x01, 0x85, 0xc0 };
// A variable used to store NPK values
byte values[11];
// Sets up a new SoftwareSerial object
// Digital pins 10 and 11 should be used with a Mega or Mega 2560
SoftwareSerial mod(2, 3);
//SoftwareSerial mod(10, 11);
void setup() {
// Set the baud rate for the Serial port
Serial.begin(9600);
// Set the baud rate for the SerialSoftware object
mod.begin(9600);
// Define pin modes for RE and DE
pinMode(RE, OUTPUT);
pinMode(DE, OUTPUT);
delay(500);
}
void loop() {
// Read values
byte val1, val2, val3;
val1 = nitrogen();
delay(250);
val2 = phosphorous();
delay(250);
val3 = potassium();
delay(250);
// Print values to the serial monitor
Serial.print("Nitrogen: ");
Serial.print(val1);
Serial.println(" mg/kg");
Serial.print("Phosphorous: ");
Serial.print(val2);
Serial.println(" mg/kg");
Serial.print("Potassium: ");
Serial.print(val3);
Serial.println(" mg/kg");
delay(2000);
}
byte nitrogen() {
digitalWrite(DE, HIGH);
digitalWrite(RE, HIGH);
delay(10);
if (mod.write(nitro, sizeof(nitro)) == 8) {
digitalWrite(DE, LOW);
digitalWrite(RE, LOW);
for (byte i = 0; i < 7; i++) {
//Serial.print(mod.read(),HEX);
values[i] = mod.read();
Serial.print(values[i], HEX);
}
Serial.println();
}
return values[4];
}
byte phosphorous() {
digitalWrite(DE, HIGH);
digitalWrite(RE, HIGH);
delay(10);
if (mod.write(phos, sizeof(phos)) == 8) {
digitalWrite(DE, LOW);
digitalWrite(RE, LOW);
for (byte i = 0; i < 7; i++) {
//Serial.print(mod.read(),HEX);
values[i] = mod.read();
Serial.print(values[i], HEX);
}
Serial.println();
}
return values[4];
}
byte potassium() {
digitalWrite(DE, HIGH);
digitalWrite(RE, HIGH);
delay(10);
if (mod.write(pota, sizeof(pota)) == 8) {
digitalWrite(DE, LOW);
digitalWrite(RE, LOW);
for (byte i = 0; i < 7; i++) {
//Serial.print(mod.read(),HEX);
values[i] = mod.read();
Serial.print(values[i], HEX);
}
Serial.println();
}
return values[4];
}
После загрузки этого скетча в Arduino откройте монитор последовательного порта и убедитесь, что скорость установлена на 9600. Вы должны увидеть значения азота, фосфора и калия, выводимые на экран.
Датчик NPK почвы JXCT — это датчик электропроводности (EC). Это означает, что он не измеряет точное содержание NPK в почве напрямую. Вместо этого он оценивает уровни NPK путём измерения электропроводности почвы. Следует учитывать, что этот косвенный метод иногда может давать не совсем точные результаты.
Пояснение к коду
В начале скетча подключаются все необходимые библиотеки. Библиотека SoftwareSerial.h помогает создать виртуальный последовательный порт на обычных цифровых контактах. А библиотека Wire.h обеспечивает связь между устройствами.
#include <SoftwareSerial.h>
#include <Wire.h>
Далее определяются контакты, управляющие режимом модуля RS485. Контакт RE (Receiver Enable) назначен на пин 8, а DE (Driver Enable) — на пин 7. Эти контакты переключают модуль RS485 между режимом приёма (когда он ожидает ответы) и режимом передачи (когда он отправляет запросы).
#define RE 8
#define DE 7
После этого создаются три константных массива, содержащих точные запросы Modbus RTU для азота, фосфора и калия, а также массив values для временного хранения ответного сообщения от датчика.
// Modbus RTU requests for reading NPK values
const byte nitro[] = { 0x01, 0x03, 0x00, 0x1e, 0x00, 0x01, 0xe4, 0x0c };
const byte phos[] = { 0x01, 0x03, 0x00, 0x1f, 0x00, 0x01, 0xb5, 0xcc };
const byte pota[] = { 0x01, 0x03, 0x00, 0x20, 0x00, 0x01, 0x85, 0xc0 };
// A variable used to store NPK values
byte values[11];
Затем создаётся объект SoftwareSerial с именем mod. Он создаёт виртуальный последовательный порт на контактах 2 и 3. Если вы используете Arduino Mega или Mega 2560, следует раскомментировать вторую строку и использовать контакты 10 и 11, поскольку контакты 2 и 3 некорректно работают с SoftwareSerial на этих платах.
// Sets up a new SoftwareSerial object
SoftwareSerial mod(2, 3);
//SoftwareSerial mod(10, 11); // Digital pins 10 and 11 should be used with a Mega or Mega 2560
В функции setup мы сначала инициализируем монитор последовательного порта на скорости 9600. Затем запускаем порт SoftwareSerial на той же скорости для связи с датчиком. Также устанавливаем контакты RE и DE как выходы, потому что будем переключать их между HIGH и LOW для смены режимов приёма и передачи на модуле RS485. В конце добавляем небольшую задержку 500 мс перед началом измерений.
void setup() {
// Set the baud rate for the Serial port
Serial.begin(9600);
// Set the baud rate for the SerialSoftware object
mod.begin(9600);
// Define pin modes for RE and DE
pinMode(RE, OUTPUT);
pinMode(DE, OUTPUT);
delay(500);
}
В функции loop мы сначала вызываем функцию nitrogen(), затем phosphorous(), затем potassium() с небольшими задержками между ними. Потом выводим значения в удобном формате для чтения.
void loop() {
// Read values
byte val1, val2, val3;
val1 = nitrogen();
delay(250);
val2 = phosphorous();
delay(250);
val3 = potassium();
delay(250);
// Print values to the serial monitor
Serial.print("Nitrogen: ");
Serial.print(val1);
Serial.println(" mg/kg");
Serial.print("Phosphorous: ");
Serial.print(val2);
Serial.println(" mg/kg");
Serial.print("Potassium: ");
Serial.print(val3);
Serial.println(" mg/kg");
delay(2000);
}
Три функции — nitrogen(), phosphorous() и potassium() — работают практически одинаково. Рассмотрим работу функции nitrogen() в качестве примера. Сначала мы устанавливаем оба контакта DE и RE в HIGH, что переводит модуль RS485 в режим передачи для отправки запроса. Ждём 10 мс, чтобы убедиться в завершении переключения режима. Затем отправляем команду запроса азота через функцию mod.write(). Если все 8 байт отправлены успешно, мы немедленно переключаем модуль RS485 в режим приёма, устанавливая DE и RE в LOW. Теперь модуль готов принимать ответ датчика. Далее в цикле считываем 7 байт от датчика (полное ответное сообщение) и сохраняем их в массиве values[]. Собственно значение азота находится в 5-й позиции (values[4]) ответа, поэтому именно его мы возвращаем. Функции phosphorous() и potassium() работают точно так же, только с собственными командами запроса.
byte nitrogen() {
digitalWrite(DE, HIGH);
digitalWrite(RE, HIGH);
delay(10);
if (mod.write(nitro, sizeof(nitro)) == 8) {
digitalWrite(DE, LOW);
digitalWrite(RE, LOW);
for (byte i = 0; i < 7; i++) {
//Serial.print(mod.read(),HEX);
values[i] = mod.read();
Serial.print(values[i], HEX);
}
Serial.println();
}
return values[4];
}
byte phosphorous() {
digitalWrite(DE, HIGH);
digitalWrite(RE, HIGH);
delay(10);
if (mod.write(phos, sizeof(phos)) == 8) {
digitalWrite(DE, LOW);
digitalWrite(RE, LOW);
for (byte i = 0; i < 7; i++) {
//Serial.print(mod.read(),HEX);
values[i] = mod.read();
Serial.print(values[i], HEX);
}
Serial.println();
}
return values[4];
}
byte potassium() {
digitalWrite(DE, HIGH);
digitalWrite(RE, HIGH);
delay(10);
if (mod.write(pota, sizeof(pota)) == 8) {
digitalWrite(DE, LOW);
digitalWrite(RE, LOW);
for (byte i = 0; i < 7; i++) {
//Serial.print(mod.read(),HEX);
values[i] = mod.read();
Serial.print(values[i], HEX);
}
Serial.println();
}
return values[4];
}