Подключаем датчики к Raspberry Pi без проводов и с Arduino

в 22:59, , рубрики: arduino, nRF24L01+, Raspberry Pi, умный дом, Электроника для начинающих

Подключение датчиков к Raspberry Pi по радиоканалу.

В процессе создания умного дома, каждый рано или поздно сталкивается с размещением датчиков, показатели которых нужно выводить на экран, а то и обрабатывать для чего-то более умного.

Большинство датчиков легче всего подключаются к Arduino, за счет наличия библиотек, безгеморройных PWM, ADC и прочих вкусностей.
Но слишком умную логику на Arduino не построишь, и волей-неволей возникает необходимость использования чего-то более быстрого, универсального, и с простой индикациейуправлением. Например, почти ставший стандартом де-факто, Raspberry Pi.
У него есть HDMIAV выход. Есть флешка, сеть, память, USB и SSH. image Все что нам нужно.

Но напрямую датчики к Raspberry Pi подключить весьма непросто, в силу отсутствия большого количества библиотек, примеров, и просто потому что она не совсем к этому приспособлена. Да и держать эти датчики тогда придется рядом, а значит либо Малинке придется жить на балконе, либо датчику влажности воздуха у вас в шкафу.

Разумеется, тянуть два-три провода от датчиков к Малине — тоже не вариант, ибо тогда умный дом станет сложным домом.

Интересно?

Для этих целей была придумана радиосвязь.

В качестве самой дешевой, понятной и доступной радиосвязи, я выбрал радиомодуль-трансивер nrf24l01, и вот почему:
1) Дальность. В пределах дома — до ста метров. То что нам подходит.
2) Скорость передачи данных — до 2 Мбит. Хоть потоковое видео передавай.
3) Возможности подключения точка-точка, точки-хаб, хаб-хаб, хаб-точка.
4) Толерантны к 5В, хотя могут принимать и 3.3В.
5) Эти контроллеры имеют свою прошивку, которая позволяет им становиться независимым девайсом.
6) Автоматически шлет идентификатор сигнала, избавляя нас от необходимости заморачиваться с индивидуальной настройкой каналов для каждого трансивера.
7) Дуплекс.
8) Дешевизна. Кстати взял я их не дешево, решил не ждать три недели ради экономии 10 баксов.

Вот так выглядит этот девайс.

image

Топология связи очень проста, дешева и понятна.

1) Набор датчиков в какой-либо локации, подключается к Arduino. Таких локаций может быть несколько.
2) Она (Arduino) играет роль предварительного буфера, который собирает данные с датчиков, и комбинирует их для последующей отправки.
Ну и выполняет какую-то базовую логику, например включает на балконе свет по датчику движения (без участия центрального сервера). В общем согласно наши потребностям.
3) Raspberry Pi через такой же самый модуль, принимает радиосигнал.

В интернете очень много примеров связи Arduino-Raspberry Pi, используя эти трансиверы nrf24l01.
Однако почему-то все эти примеры рассматривают Arduino как центральный узел (хаб), а Raspberry Pi как придаток (клиент). И мало что из примеров работоспособно с первого раза.

Методом проб и ошибок, мне удалось сделать обратное — один Raspberry Pi-блок, и несколько узлов с Ардуинами, которые настраиваются абсолютно одинаково, не нуждаются в выборе каналов, частот и прочего. Поменяли циферку в строке — получили новое устройство.

Несколько фоток из центра событий.

Малиновый сервер. Не удобно подключаться по сети, WiFi рулит.
image

Первый подопечный. Arduino Nano с датчиком движения.
image

Второй подопечный. Arduino Mini и USB-TTL. Где-то там отстает проводок.
image

Все вместе.
image

Итак, не буду вдаваться в подробности установок IDE, библиотек, а выложу сразу работающий код для двух устройств.

Arduino-часть.
#include <SPI.h>
#include <RF24.h>
 
// CE,CSN пины
RF24 radio(9,10);
 
// init counter
 unsigned long count = 0;
int sensor1 = 2;

void setup(void)
{
    // Инициализируем канал связи и не только.
    radio.begin();
    radio.setPALevel(RF24_PA_MAX);
    radio.setChannel(0x4c);
    radio.openWritingPipe(0xF0F0F0F0E1LL);
    radio.enableDynamicPayloads();
    radio.powerUp();
    pinMode(sensor1, INPUT);
    pinMode(3, OUTPUT);
}
 
void loop(void)
{
char outBuffer[32]= "";
int pin1 = digitalRead(sensor1); 
// Следующая строка изменяется по нашему желанию. Я шлю на сервер три значения: ID блока (ардуины), ID пина, и его значение. Больше ничего изменять не нужно.
String out = "dev1:p1:"+pin1;

    out.toCharArray(outBuffer, 32);
    radio.write(outBuffer, 32);
    delay(50);
// Не знаю почему, но периодически трансивер зависает. Помогает повторная инициализация.
    radio.begin();
    radio.setPALevel(RF24_PA_MAX);
    radio.setChannel(0x4c);
    radio.openWritingPipe(0xF0F0F0F0E1LL);
    radio.enableDynamicPayloads();
    radio.powerUp();
    delay(50);

// Следующий костыль включает свет по датчику движения на 10 секунд, не замораживая при этом основной цикл loop.

 if (pin1=HIGH)
 {
 digitalWrite(3, HIGH);  
 count=0;   
 }
count++;
if (count>100)
{
 digitalWrite(3, LOW); 
 count=0;
}
 
}

На Малине нам понадобится библиотека, установить которую можно так:

git clone https://github.com/stanleyseow/RF24.git
cd RF24
cd librf24-rpi/librf24
make
sudo make install
C++ код для Raspberry Pi. В инклуде нужно указать путь к файлу хидера.
#include <cstdlib>
#include <iostream>
#include "../RF24.h"
#include <fstream> 
using namespace std;
 
// spi device, spi speed, ce gpio pin
RF24 radio("/dev/spidev0.0",8000000,25);
 
void setup(void)
{
    // init radio for reading
    radio.begin();
    radio.enableDynamicPayloads();
    radio.setAutoAck(1);
    radio.setRetries(15,15);
    radio.setDataRate(RF24_1MBPS);
    radio.setPALevel(RF24_PA_MAX);
    radio.setChannel(76);
    radio.setCRCLength(RF24_CRC_16);
    radio.openReadingPipe(1,0xF0F0F0F0E1LL);
    radio.startListening();
}
 
void loop(void)
{
char receivePayload[64];
    while (radio.available())
    {
uint8_t len = radio.getDynamicPayloadSize();
radio.read(receivePayload, len);

// Костыль для создания промежуточного файла.
ofstream out("/dev/nrf24");
out << receivePayload << "n";
out.close ();
delay(200);
    }
}
 
int main(int argc, char** argv) 
{
cout << "Driver initialized, please check values of /dev/nrf24" << endl;
    setup();
    while(1)
        loop();
 
    return 0;
}

Скомпилировать на Малинке мы его можем командой

g++ -Wall -Ofast -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s -L../librf24/  -lrf24 receiver.cpp -o rpi

Не забываем, где мы положили librf24.
И запустить

./rpi &

Запустив это поделие в фоне, мы получим файл /dev/nrf24, который будет содержать строку, пришедшую к нам по радиоканалу.
Его мы можем читать и парсить как нам заблагорассудится. Хоть read, хоть cat, хоть tail.
Внимание: костыль с этим файлом был введен ТОЛЬКО для «удобства» совместной работы приложений на разных языках: bash, PHP. По феншую все делать только на С++.

На закуску, видео работы двух Arduino с одной Raspberry Pi.

Ради интереса попробовал сформировать строку в JSON, это видно на видео. Неэффективно, если датчиков много. Лимит на 32 символа, а разбираться глубже не было времени. Просто поменять циферку 32 на 64 — не помогает.

Все элементы использую только для наглядности примера. Реальная реализация выглядит по-другому.

Автор: ntfs1984

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js