Opensource контроллер умного дома на базе Arduino Mega 2560 с поддержкой MQTT, DMX-512, 1-Wire, Modbus и Openhab / Хабр

Opensource контроллер умного дома на базе Arduino Mega 2560 с поддержкой MQTT, DMX-512, 1-Wire, Modbus и Openhab / Хабр Вертолеты

Radiocopter.ru – система контроля и управления доступом

Модель системы контроля и управления доступом на предприятии на базе Arduino

С изобретением и широким распространением микроконтроллеров появились небывалого разнообразия возможности для развития пользовательской электроники. Одна из сфер применения программируемых чипов – различные СКУД. Такие системы разрабатываются и продаются, но цены на готовые комплексы представляются чрезмерно большими. Например, стоимость минимального комплекта программного обеспечения (ПО)SP09 от ведущего российского производителя систем безопасности – PERCoсоставляет 265 евро [1].

Необходимость расходов, которые несут потребители для того, чтобы возместить производителям постоянные затраты материальных, человеческих ресурсов (на производство преграждающих устройств, замков, печатных плат и т.д.) не вызывает сомнений. Однако, в смете имеет место и программное обеспечение. Проприетарное, не обновляемое,оно, единожды окупив продажей некоторого количества своих лицензий затраты на разработку, далее не может справедливо также высоко цениться. Тем временем по всему миру разворачиваются проекты категории freeandopen-sourcesoftware(FOSS), а исходный код различных уважаемых, известных платных решений становится общедоступным.Последнее нередко происходит в связи с давлением перспективы быть вытесненными с рынка за нерентабельностью использования в сравнении с применением свободных аналогов. В связи с этим мы считаем, что создание программно-аппаратного решения с открытыми исходным кодом и архитектурой поможет решить выше описанную проблему.

В ходе разработки нами были изучены:

  1. Touch memory –технология, Touch memory key,
  2. OneWire – технология, протокол взаимодействия,
  3. Промышленные аналоги СКУД,
  4. Проектировочная платформа Arduino.

Основой нашего программно-аппаратного комплекса стал контроллер ATMega328p, используемый на плате Arduino. Основной причиной его использования послужил низкий порог вхождения в процесс разработки: готовые IDE (англ. IntegratedDevelopmentEnvironment), набор открытых библиотек и примеров к ним, дешевизна оборудования для программирования контроллера.

1-Wire(OneWire) – технология, изобретённая для упрощения и удешевления подключения небольших, не требующих высокой мощности питания и пропускной способности канала устройств. Данная технология позволяет подключать по одному физическому каналу несколько устройств, управляющихся одноимённым протоколом[2].Эта возможность обеспечивается используемым принципом передачи данных. Биты синхронизируются временными слотами (TimeSlots) и определяются их продолжительностью. Для работы проекта потребуется библиотека OneWire[3].

Устройством для хранения UIDTouchmemoryилиiButton[4] – оригинальное семейство микросхем, разработанных и выпускаемых фирмой DallasSemiconductor, USA. Каждая такая микросхема заключена в стальной герметичный цилиндрический корпус, служащий для защиты. Нами были использованы ключи, относящиеся к семействуDS1990Aс восьмибайтовым ПЗУ [5, 6]. В младшем байте содержится код семейства, для DS1990A он всегда будет равен 01h.В шести последующих байтах содержится серийный номер ключа (уникальный 48-битный код). Последний байт называется cyclicredundancycheck (CRC) – это контроль четности, обеспечивающий подлинность переданных данных (рис. 1).

1332115484.png

Рис. 1. Структура ПЗУ ключа

Работа контроллера состоит из считывания идентификатора ключа, сигнализирования, отправки информации контролирующему СКУД устройству посредством интерфейса USB, получения от последнего команды (на открытие, игнорирование и ожидание нового ключа или просто на игнорирование) и реакции на команду. Со стороны ПО на персональном компьютере пользователям, в соответствии с уровнем их прав, предоставляются различные возможности взаимодействия со СКУД. При получении данных от контроллера производится сверка UID (англ. UserIdentifier – идентификатор пользователя) с хранимыми в базе данных и, в случае совпадения, на мониторе отображается информация. Был разработан простой протокол взаимодействия. Для определения, вход или выход совершается сотрудником, используется дополнительный байт. Чтобы ускорить процесс реализации, была создана визуализация протокола в виде блок-схемы (рис. 2).

1989824644.png

Рис. 2. Блок-схемы визуализации протокола

Выбранная в качестве базы для разработки системы платформа Arduino снабжена специализированным ПО [7].

Бесплатно распространяемая интегрированная среда разработки Arduino IDE 1.6.1предоставляет условия для удобных написания, компилирования и загрузки управляющего кода.

Ниже представлены схема сборки и внешний вид аппаратной части системы (рис. 3,4).

936478522.png

Рис. 3. Принципиальная схема

2247187242.png

Рис. 4. Внешний вид результата сборки

Пользователи ПО могут обладать одним из 3х типов привилегий: администратор, директор, охранник. Для каждого из них предусмотрен индивидуальный интерфейс, позволяющий охраннику сверять фотографию на мониторе с лицом проходящего через контрольно-пропускной пункт (КПП), директору – просматривать журнал посещения предприятия сотрудниками, администратору – обеспечивать работоспособность системы.

1302048919.png

Рис. 5. Интерфейс формы охранника

Для примера возьмем комплект ПО и оборудования PERCo-KT02.3 с активированным PERCo-SP13,его стоимость составит 1135 евро [8].Стоимость же компонентов для нашей СКУД составит:

Таблица 1

Итоговая стоимость компонентов

Обозначение

Кол-во

Тип

Свойства

Стоимость

LED1

1

RGB LED

4х контактный RGBсветодиод

0,93 € / 1 шт.

R3,R4,R5,R6

4

220Ωрезистор

допуск ± 5% сопротивление 220Ω

1,74 € / 200 шт.

SG1

1

Buzzer 12mm

Зуммер 12мм

0,79€ / 1 шт.

S2

1

Button

Контактная кнопка 12мм

0,29€/ 1 шт.

R7,R8

2

4,7kΩрезистор

допуск ± 5% сопротивление 4,7kΩ

1,79€/ 200 шт.

VCC 12V

1

VCC

Блок питания 12В 1А

2,14€/ 1шт.

 

1

МК

ArduinoNano(Rev. 3)

3,19€/ 1 шт.

 

1

Реле

songle srd-05vdc-sl-s

1,07 € / 1 шт.

 

1

Lock

Магнитный замок

16,72€/ 1 шт.

Итого: ~ 25,19 €

На данном этапе цель работы продолжает казаться достижимой: цена на комплектующие, уже использующиеся в нашем аппаратном комплексе, составляет менее 5% от цены, установленной за комплект оборудования, поставляемого известными производителями. Кроме заметной разницы в стоимостях аппаратных систем, следует ещё раз подчеркнуть отсутствие затрат, связанных с проприетарностью нашей СКУД, благодаря абсолютной открытости её исходного кода и архитектуры. Любой желающий имеет ничем не ограниченную возможность обратиться к серверам GitHubс целью полного или частичного копирования для себя наших наработок и пользоваться ими на условиях открытой лицензии GPLтретьей или более поздней версии[9],также вы можете ознакомиться с видео презентацией по ссылке в описание проекта.

Ожидается увеличение (не более, чем в два раза) издержек за счёт добавления таких периферийных компонентов, как удлинённые кабели (USBи провода к интерфейсам считывания и к магнитному замку) и корпус из оргстекла или подобного материала.

ПО требует доработки не в меньшей степени. Набор библиотек для графического интерфейса, который мы использовали для его создания —WindowsForms. Это так, потому что только с ним мы были достаточно знакомы на момент начала разработки. Теперь, когда нам начали преподавать теорию распределённых вычислительных систем (РВС), мы понимаем, что программа для ПК должна быть полностью переработана — переписана с использованием Web-технологий: необходимо вынести логическую часть из приложения клиента в приложение сервера, оставив первому только возможность получения интерфейса в Web-браузере.

Проблема выбора платформы для реализации этих планов пока остаётся для нас открытой: поверхностное ознакомление с возможностями и особенностями каждой из них ещё только начинается.

Видео

2892387257.JPG324464088.JPG

Литература и примечания:

[1] Комплекты ПО S-20 https://www.perco.ru/products/sistemy-kontrolya-dostupa/sistema-kontrolya-dostupa-s-20/komplekty-programmnogo-obespecheniya/

Смотрите про коптеры:  Steam Community :: Guide :: Учимся побеждать у вражеских Империй (2.6.0 - 3.4.x)

[2] OneWirehttp://en.wikipedia.org/wiki/1-Wire

[3]Latest version of the libraryhttp://playground.arduino.cc/Learning/OneWire

[4] iButtonhttp://www.ibutton.ru/about/info/

[5] DS1990A datasheethttp://datasheets.maximintegrated.com/en/ds/DS1990A.pdf

[6] Копирование ключей iButtonDS1990Ahttp://electromost.com/news/kopirovanie_kljuchej_ibutton_ds1990a/2022-05-04-26

[7] Arduino code tutorials and exampleshttp://arduino.cc/en/Tutorial/HomePage

[8] Прайс-лист электронные проходные с ПО https://www.perco.ru/download/price/price_PERCo.pdf

[9] Страница проекта на GitHubhttps://github.com/veter069/OneWireArdiuno2022

Автор: Bruce

Устройство бортового компьютера

Компоненты устройства:1. Платформа Arduino2. Модуль гироскопа акселерометра высотомера3. Модуль записи на SD-карте SD-карта4. Батарея питания5. Тумблер отключения питания6. Кнопка для сброса высоты7. Светодиоды-индикаторы взвода и зажигания8. Реле для замыкания внешней цепи при зажигании9. Несколько резисторов, указанных на схеме

Принципы работы устройства:1. Устройство непрерывно замеряет текущую высоту с помощью датчика высоты, и вычисляет среднее значение за последние 16 измерений — скользящее среднее (это нужно для сглаживания колебаний измерения, так как они довольно сильно «скачут»).2.

Если нажата кнопка сброса высоты, текущее скользящее среднее высоты берётся в качестве начала отсчёта, и, в дальнейшем измеряется так называемая «высота от точки старта» — это высота за вычетом данного начала отсчёта. Соответственно, в месте, где кнопка была нажата, будет 0 этой высоты.3.

В ходе вычислений замеряется максимальная «высота от точки старта», после достижения которой 10 метров (например), устройство переходит в состояние «взвод», максимальная высота продолжает замеряться (любая измеренная высота больше максимальной — объявляется новой максимальной), при этом зажигается светодиод взвода4.

Если, находясь в состоянии «взвод» замерянная высота окажется меньше максимальной на 1 метр (например), устройство переходит в состояние «запуск», замыкая реле, и зажигая светодиод запуска. Светодиод взвода при этом гасится. Реле может выполнить любую работу, например, подать напряжение на сервопривод, выпускающий парашют.5.

Общая схема подключения компонентов:

Модули, необходимые для приложения:

Для работы программы я собрал несколько библиотек, либо не входящих в репозиторий Arduino, либо других версий, которые удалось заставить работать.

Библиотека BMP085:BMP085.cppBMP085.h

Библиотека HMC5883LHMC5883L.cppHMC5883L.h

Библиотека I2CI2Cdev.cpp I2Cdev.h

Библиотека MPU6050MPU6050.cpp MPU6050.h

Все эти модули можно найти вместе с основным файлом программы в репозитории.

Код приложения:

#include <Wire.h>#include "BMP085.h"#include "I2Cdev.h"#include "MPU6050.h"#include "HMC5883L.h"#include <SPI.h>#include <Wire.h>#include "BMP085.h"#include "I2Cdev.h"#include "MPU6050.h"#include "HMC5883L.h"#include <SPI.h>#include <SD.h>
 
#define TRUE 1#define FALSE 0
 
File myFile;
 
HMC5883L compass;
BMP085 pressure_m;
MPU6050 accelgyro;
 
//Контакт, куда подключено рэле#define EXEC_PIN 3//Контакт, куда подключена кнопка "сброс высоты"#define RESET_ALT_PIN 6//Контакт, куда подключен светодиод "взвод" (красный)#define ARMED_PIN 9//Время в течении которого надо держать рэле замкнутым, в миллисекундах#define FIRE_TIME 6000//Количество итераций для вычисления скользящего среднего высоты (лучше, чтобы было степенью двойки)#define RUN_ALT_NUM 16
 
//Контакт, куда подключена кнопка "положение X"#define POS_X_PIN 7//Контакт, куда подключена кнопка "положение Y"#define POS_Y_PIN 8//Контакт, куда подключена кнопка "положение Z"#define POS_Z_PIN 10
 
 
int16_t ax, ay, az;int16_t gx, gy, gz;
bool blinkState =false;double dt =;long counter =;double t0 =-1;double millis_t =;double io_t =;double io_dt =40;double fired_millis_t =;
 
float base_altitude =;
 
float run_alt[RUN_ALT_NUM];int run_alt_index =;int last_run_alt_index =;int run_alt_count =;float run_alt_summ =;
 
bool is_prepared = FALSE;
bool is_armed = FALSE;
bool is_fired = FALSE;
bool is_led_armed = FALSE;
bool is_led_fired = FALSE;
bool is_done = FALSE;
 
float arming_altitude =10;float fire_minus_altitude =1;float max_altitude =;
 
char filename[]="GY88_000.TXT";
 
void reset_running_alt();void reset_alt(float current_alt);
 
/**
 * Сгенерировать имя файла
 */void generateFileName(){for(int i =; i<1000; i  ){
    filename[5]= i/100 '0';
    filename[6]=(i%100)/10 '0';
    filename[7]=(i%10) '0';if(SD.exists(filename))continue;
    Serial.print("File: ");
    Serial.println(filename);break;}}
 
/**
 * Отладочная функция, вычисляет сумму скользящего среднего "по-настоящему"
 */float debug_get_alt_summ(){float summ =;for(int i=; i< run_alt_count; i  ){
    summ  = run_alt[i];}return summ;}
 
void setup(){//Настраиваем режимы работы для цифровых контактов
    pinMode(EXEC_PIN, OUTPUT);
    pinMode(RESET_ALT_PIN, INPUT);
    pinMode(ARMED_PIN, OUTPUT);//Сбрасываем значения для скользящего среднего по высоте
    reset_running_alt();
 
    //Включаем последовательный порт на максимальную скорость
    Serial.begin(230400);//while (!Serial) {;// wait for serial port to connect. Needed for native USB port only//}    
 
    Serial.print("Initializing SD card...");
 
    if(!SD.begin(4)){
      Serial.println("initialization failed!");return;}
    Serial.println("initialization done.");
 
    //Сгенерируем имя файла
    generateFileName();
    myFile = SD.open(filename, O_WRITE | O_CREAT);
 
    //Включаем протокол Wire
    Wire.begin();
    TWBR =24;
    Serial.println("Initializing I2C devices...");//инициализируем акселерометр с гироскопом
    accelgyro.initialize();
    accelgyro.setMasterClockSpeed(13);
    accelgyro.setI2CMasterModeEnabled(true);//инициализируем компас
    compass = HMC5883L();
    setupHMC5883L(); 
 
    //проверяем содеинение
    Serial.println("Testing device connections...");
    Serial.println(accelgyro.testConnection()?"MPU6050 connection successful":"MPU6050 connection failed");
 
    //калибруем датчик давления
    pressure_m.bmp085Calibration();}
 
void loop(){
  millis_t = millis();//Считаем температуру (её знает датчик давления)float temperature = pressure_m.bmp085GetTemperature();//MUST be called first//Считаем давлениеfloat pressure = pressure_m.bmp085GetPressure();//Вычислим высоту над уровнем моряfloat altitude = pressure_m.calcAltitude(pressure);float altitude_b = altitude - base_altitude;
 
  //Проведём вычисления для скользящего среднего по высоте
  run_alt[run_alt_index]= altitude_b;//run_alt_summ  = altitude_b;if(run_alt_count == RUN_ALT_NUM){
    last_run_alt_index =(run_alt_index ==)? RUN_ALT_NUM -1: run_alt_index -1;//run_alt_summ -= run_alt[last_run_alt_index];}else{
    run_alt_count  =1;}
  run_alt_index =(run_alt_index  1== RUN_ALT_NUM)?: run_alt_index  1;
 
  //Временно вычисляем медленным методом
  run_alt_summ = debug_get_alt_summ();
 
  float run_altitude = run_alt_summ /(float) run_alt_count;
 
  //Вычислим dt (интервал между замерами в миллисекундах)if(t0 <){
    t0 = millis_t;}else{
    dt = millis_t - t0;
    t0 = millis_t;}
 
  if(run_altitude > max_altitude){
    max_altitude = run_altitude;}
 
 
  if(millis_t - io_t > io_dt){
    io_t = millis_t;if(digitalRead(RESET_ALT_PIN)== HIGH){
      reset_alt(altitude);}
 
 
 
    if(!is_done){if(!is_fired){if(is_prepared){if(!is_armed){if(max_altitude > arming_altitude){
              is_armed = TRUE;}}else{if(max_altitude - run_altitude > fire_minus_altitude){
              is_armed = FALSE;
              is_fired = TRUE;
              fired_millis_t = millis_t;}}}}else{if(millis_t - fired_millis_t > FIRE_TIME){
          is_fired = FALSE;
          is_done = TRUE;
          is_prepared = FALSE;}}}
 
    if(is_armed != is_led_armed){
      is_led_armed = is_armed;
      digitalWrite(ARMED_PIN, is_armed ? HIGH : LOW);}
 
    if(is_fired != is_led_fired){
      is_led_fired = is_fired;
      digitalWrite(EXEC_PIN, is_fired ? HIGH : LOW);}
 
  }
 
  //Интервал между замерами
  Serial.print("dt:"); Serial.print(dt /1000,3);
  myFile.print("dt:"); myFile.print(dt /1000,3);//Сколько времени прошло с запуска?
  Serial.print(" tm:"); Serial.print(millis_t);
  myFile.print(" tm:"); myFile.print(millis_t);//Температура, в градусах цельсия
  Serial.print(" t:"); Serial.print(temperature,2); 
  myFile.print(" t:"); myFile.print(temperature,2);//Давление, в паскалях
  Serial.print(" p:"); Serial.print(pressure,); 
  myFile.print(" p:"); myFile.print(pressure,);//Высота над уровнем моря, в метрах
  Serial.print(" alt:"); Serial.print(altitude,2); 
  myFile.print(" alt:"); myFile.print(altitude,2);//Высота над базовым уровнем, в метрах
  Serial.print(" altb:"); Serial.print(altitude_b,2); 
  myFile.print(" altb:"); myFile.print(altitude_b,2);//Высота над базовым уровнем, в метрах, скользящее среднее
  Serial.print(" altr:"); Serial.print(run_altitude,2); 
  myFile.print(" altr:"); myFile.print(run_altitude,2);//Высота над базовым уровнем, в метрах, максимальная
  Serial.print(" Malt:"); Serial.print(max_altitude,2); 
  myFile.print(" Malt:"); myFile.print(max_altitude,2);
 
  //Статусы:
  Serial.print(" P"); Serial.print(is_prepared ?"1":"0"); 
  myFile.print(" P"); myFile.print(is_prepared ?"1":"0");
  Serial.print(" A"); Serial.print(is_armed ?"1":"0"); 
  myFile.print(" A"); myFile.print(is_armed ?"1":"0");
  Serial.print(" F"); Serial.print(is_fired ?"1":"0"); 
  myFile.print(" F"); myFile.print(is_fired ?"1":"0");
  Serial.print(" D"); Serial.print(is_done ?"1":"0"); 
  myFile.print(" D"); myFile.print(is_done ?"1":"0");
 
  //Считаем значения с магнитометра
  MagnetometerScaled scaled = compass.ReadScaledAxis();//Считаем значения с акселерометра и гироскопа
  accelgyro.getMotion6(&ax,&ay,&az,&gx,&gy,&gz);
 
  //Данные акселерометра:
  Serial.print(" ax:"); Serial.print(ax);
  Serial.print(" ay:"); Serial.print(ay);
  Serial.print(" az:"); Serial.print(az);
  myFile.print(" ax:"); myFile.print(ax);
  myFile.print(" ay:"); myFile.print(ay);
  myFile.print(" az:"); myFile.print(az);//Данные гироскопа
  Serial.print(" wx:"); Serial.print(gx);
  Serial.print(" wy:"); Serial.print(gy);
  Serial.print(" wz:"); Serial.print(gz);
  myFile.print(" wx:"); myFile.print(gx);
  myFile.print(" wy:"); myFile.print(gy);
  myFile.print(" wz:"); myFile.print(gz);//Данные магнитометра    
  Serial.print(" cx:"); Serial.print(scaled.XAxis,3);
  Serial.print(" cy:"); Serial.print(scaled.YAxis,3);
  Serial.print(" cz:"); Serial.print(scaled.ZAxis,3);
  Serial.println();
  myFile.print(" cx:"); myFile.print(scaled.XAxis,3);
  myFile.print(" cy:"); myFile.print(scaled.YAxis,3);
  myFile.print(" cz:"); myFile.print(scaled.ZAxis,3);
  myFile.println();
 
  myFile.flush();}
 
//Настройка модуля HMC5883L (компаса)void setupHMC5883L(){//Setup the HMC5883L, and check for errorsint error;  
  error = compass.SetScale(1.3);//Set the scale of the compass.if(error !=) Serial.println(compass.GetErrorText(error));//check if there is an error, and print if so
 
  error = compass.SetMeasurementMode(Measurement_Continuous);// Set the measurement mode to Continuousif(error !=) Serial.println(compass.GetErrorText(error));//check if there is an error, and print if so}
 
/**
 * Сброс высоты и перевод в состояние готовности - выполняется по нажатию кнопки
 */void reset_alt(float current_alt){
  base_altitude = current_alt;
  is_prepared = TRUE;
  is_armed = FALSE;
  max_altitude =;  
  reset_running_alt();}
 
/**
 * Сброс скользящего среднего для высоты
 */void reset_running_alt(){
  run_alt_index =;
  run_alt_count =;
  run_alt_summ =;
  last_run_alt_index =;for(int i =; i<RUN_ALT_NUM; i  ){
      run_alt[i]=;}}

#include <Wire.h>
#include “BMP085.h”
#include “I2Cdev.h”
#include “MPU6050.h”
#include “HMC5883L.h”
#include <SPI.h>
#include <Wire.h>
#include “BMP085.h”
#include “I2Cdev.h”
#include “MPU6050.h”
#include “HMC5883L.h”
#include <SPI.h>
#include <SD.h>

Смотрите про коптеры:  👓Лучшие шлемы и FPV-очки для квадрокоптеров на 2022 год

#define TRUE 1
#define FALSE 0

File myFile;

HMC5883L compass;
BMP085 pressure_m;
MPU6050 accelgyro;

//Контакт, куда подключено рэле
#define EXEC_PIN 3
//Контакт, куда подключена кнопка “сброс высоты”
#define RESET_ALT_PIN 6
//Контакт, куда подключен светодиод “взвод” (красный)
#define ARMED_PIN 9
//Время в течении которого надо держать рэле замкнутым, в миллисекундах
#define FIRE_TIME 6000
//Количество итераций для вычисления скользящего среднего высоты (лучше, чтобы было степенью двойки)
#define RUN_ALT_NUM 16

//Контакт, куда подключена кнопка “положение X”
#define POS_X_PIN 7
//Контакт, куда подключена кнопка “положение Y”
#define POS_Y_PIN 8
//Контакт, куда подключена кнопка “положение Z”
#define POS_Z_PIN 10

int16_t ax, ay, az;
int16_t gx, gy, gz;
bool blinkState = false;
double dt = 0;
long counter = 0;
double t0 = -1;
double millis_t = 0;
double io_t = 0;
double io_dt = 40;
double fired_millis_t = 0;

float base_altitude = 0;

float run_alt[RUN_ALT_NUM];
int run_alt_index = 0;
int last_run_alt_index = 0;
int run_alt_count = 0;
float run_alt_summ = 0;

bool is_prepared = FALSE;
bool is_armed = FALSE;
bool is_fired = FALSE;
bool is_led_armed = FALSE;
bool is_led_fired = FALSE;
bool is_done = FALSE;

float arming_altitude = 10;
float fire_minus_altitude = 1;
float max_altitude = 0;

char filename[] = “GY88_000.TXT”;

void reset_running_alt();
void reset_alt(float current_alt);

/**
* Сгенерировать имя файла
*/
void generateFileName()
{
for (int i = 0; i< 1000; i )
{
filename[5] = i/100 ‘0’;
filename[6] = (i0)/10 ‘0’;
filename[7] = (i) ‘0’;
if (SD.exists(filename)) continue;
Serial.print(“File: “);
Serial.println(filename);
break;
}
}

/**
* Отладочная функция, вычисляет сумму скользящего среднего “по-настоящему”
*/
float debug_get_alt_summ()
{
float summ = 0;
for (int i=0; i< run_alt_count; i )
{
summ = run_alt[i];
}
return summ;
}

void setup(){
//Настраиваем режимы работы для цифровых контактов
pinMode(EXEC_PIN, OUTPUT);
pinMode(RESET_ALT_PIN, INPUT);
pinMode(ARMED_PIN, OUTPUT);
//Сбрасываем значения для скользящего среднего по высоте
reset_running_alt();

//Включаем последовательный порт на максимальную скорость
Serial.begin(230400);
//while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
//}

Serial.print(“Initializing SD card…”);

if (!SD.begin(4)) {
Serial.println(“initialization failed!”);
return;
}
Serial.println(“initialization done.”);

//Сгенерируем имя файла
generateFileName();
myFile = SD.open(filename, O_WRITE | O_CREAT);

//Включаем протокол Wire
Wire.begin();
TWBR = 24;
Serial.println(“Initializing I2C devices…”);
//инициализируем акселерометр с гироскопом
accelgyro.initialize();
accelgyro.setMasterClockSpeed(13);
accelgyro.setI2CMasterModeEnabled(true);
//инициализируем компас
compass = HMC5883L();
setupHMC5883L();

//проверяем содеинение
Serial.println(“Testing device connections…”);
Serial.println(accelgyro.testConnection() ? “MPU6050 connection successful” : “MPU6050 connection failed”);

//калибруем датчик давления
pressure_m.bmp085Calibration();
}

void loop()
{
millis_t = millis();
//Считаем температуру (её знает датчик давления)
float temperature = pressure_m.bmp085GetTemperature(); //MUST be called first
//Считаем давление
float pressure = pressure_m.bmp085GetPressure();
//Вычислим высоту над уровнем моря
float altitude = pressure_m.calcAltitude(pressure);
float altitude_b = altitude – base_altitude;

//Проведём вычисления для скользящего среднего по высоте
run_alt[run_alt_index] = altitude_b;
//run_alt_summ = altitude_b;
if (run_alt_count == RUN_ALT_NUM)
{
last_run_alt_index = (run_alt_index == 0) ? RUN_ALT_NUM – 1 : run_alt_index – 1;
//run_alt_summ -= run_alt[last_run_alt_index];
}
else
{
run_alt_count =1;
}
run_alt_index = (run_alt_index 1 == RUN_ALT_NUM) ? 0 : run_alt_index 1;

//Временно вычисляем медленным методом
run_alt_summ = debug_get_alt_summ();

float run_altitude = run_alt_summ / (float) run_alt_count;

//Вычислим dt (интервал между замерами в миллисекундах)
if (t0 < 0)
{
t0 = millis_t;
}
else
{
dt = millis_t – t0;
t0 = millis_t;
}

if (run_altitude > max_altitude)
{
max_altitude = run_altitude;
}

if (millis_t – io_t > io_dt)
{
io_t = millis_t;
if (digitalRead(RESET_ALT_PIN) == HIGH)
{
reset_alt(altitude);
}

if (!is_done)
{
if (!is_fired)
{
if (is_prepared)
{
if (!is_armed)
{
if (max_altitude > arming_altitude)
{
is_armed = TRUE;
}
}
else
{
if (max_altitude – run_altitude > fire_minus_altitude)
{
is_armed = FALSE;
is_fired = TRUE;
fired_millis_t = millis_t;
}
}
}
}
else
{
if (millis_t – fired_millis_t > FIRE_TIME)
{
is_fired = FALSE;
is_done = TRUE;
is_prepared = FALSE;
}
}
}

if (is_armed != is_led_armed)
{
is_led_armed = is_armed;
digitalWrite(ARMED_PIN, is_armed ? HIGH : LOW);
}

if (is_fired != is_led_fired)
{
is_led_fired = is_fired;
digitalWrite(EXEC_PIN, is_fired ? HIGH : LOW);
}

Смотрите про коптеры:  TOP-13 дронов с большим радиусом действия и камерой

}

//Интервал между замерами
Serial.print(“dt:”); Serial.print(dt / 1000, 3);
myFile.print(“dt:”); myFile.print(dt / 1000, 3);
//Сколько времени прошло с запуска?
Serial.print(” tm:”); Serial.print(millis_t);
myFile.print(” tm:”); myFile.print(millis_t);
//Температура, в градусах цельсия
Serial.print(” t:”); Serial.print(temperature, 2);
myFile.print(” t:”); myFile.print(temperature, 2);
//Давление, в паскалях
Serial.print(” p:”); Serial.print(pressure, 0);
myFile.print(” p:”); myFile.print(pressure, 0);
//Высота над уровнем моря, в метрах
Serial.print(” alt:”); Serial.print(altitude, 2);
myFile.print(” alt:”); myFile.print(altitude, 2);
//Высота над базовым уровнем, в метрах
Serial.print(” altb:”); Serial.print(altitude_b, 2);
myFile.print(” altb:”); myFile.print(altitude_b, 2);
//Высота над базовым уровнем, в метрах, скользящее среднее
Serial.print(” altr:”); Serial.print(run_altitude, 2);
myFile.print(” altr:”); myFile.print(run_altitude, 2);
//Высота над базовым уровнем, в метрах, максимальная
Serial.print(” Malt:”); Serial.print(max_altitude, 2);
myFile.print(” Malt:”); myFile.print(max_altitude, 2);

//Статусы:
Serial.print(” P”); Serial.print(is_prepared ? “1” : “0”);
myFile.print(” P”); myFile.print(is_prepared ? “1” : “0”);
Serial.print(” A”); Serial.print(is_armed ? “1” : “0”);
myFile.print(” A”); myFile.print(is_armed ? “1” : “0”);
Serial.print(” F”); Serial.print(is_fired ? “1” : “0”);
myFile.print(” F”); myFile.print(is_fired ? “1” : “0”);
Serial.print(” D”); Serial.print(is_done ? “1” : “0”);
myFile.print(” D”); myFile.print(is_done ? “1” : “0”);

//Считаем значения с магнитометра
MagnetometerScaled scaled = compass.ReadScaledAxis();
//Считаем значения с акселерометра и гироскопа
accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

//Данные акселерометра:
Serial.print(” ax:”); Serial.print(ax);
Serial.print(” ay:”); Serial.print(ay);
Serial.print(” az:”); Serial.print(az);
myFile.print(” ax:”); myFile.print(ax);
myFile.print(” ay:”); myFile.print(ay);
myFile.print(” az:”); myFile.print(az);
//Данные гироскопа
Serial.print(” wx:”); Serial.print(gx);
Serial.print(” wy:”); Serial.print(gy);
Serial.print(” wz:”); Serial.print(gz);
myFile.print(” wx:”); myFile.print(gx);
myFile.print(” wy:”); myFile.print(gy);
myFile.print(” wz:”); myFile.print(gz);
//Данные магнитометра
Serial.print(” cx:”); Serial.print(scaled.XAxis, 3);
Serial.print(” cy:”); Serial.print(scaled.YAxis, 3);
Serial.print(” cz:”); Serial.print(scaled.ZAxis, 3);
Serial.println();
myFile.print(” cx:”); myFile.print(scaled.XAxis, 3);
myFile.print(” cy:”); myFile.print(scaled.YAxis, 3);
myFile.print(” cz:”); myFile.print(scaled.ZAxis, 3);
myFile.println();

myFile.flush();
}

//Настройка модуля HMC5883L (компаса)
void setupHMC5883L(){
//Setup the HMC5883L, and check for errors
int error;
error = compass.SetScale(1.3); //Set the scale of the compass.
if(error != 0) Serial.println(compass.GetErrorText(error)); //check if there is an error, and print if so

error = compass.SetMeasurementMode(Measurement_Continuous); // Set the measurement mode to Continuous
if(error != 0) Serial.println(compass.GetErrorText(error)); //check if there is an error, and print if so
}

/**
* Сброс высоты и перевод в состояние готовности – выполняется по нажатию кнопки
*/
void reset_alt(float current_alt)
{
base_altitude = current_alt;
is_prepared = TRUE;
is_armed = FALSE;
max_altitude = 0;
reset_running_alt();
}

/**
* Сброс скользящего среднего для высоты
*/
void reset_running_alt()
{
run_alt_index = 0;
run_alt_count = 0;
run_alt_summ = 0;
last_run_alt_index = 0;
for (int i =0; i<RUN_ALT_NUM; i )
{
run_alt[i]=0;
}
}

Данные, выдаваемые программой, должны быть примерно такими:

dt:0.048 tm:5760.00 t:26.80 p:100898 alt:35.61 altb:35.61 altr:35.60 Malt:35.60 P0 A0 F0 D0 ax:-1084 ay:16 az:-15708 wx:-282 wy:66 wz:-68 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.047 tm:5807.00 t:26.80 p:100898 alt:35.61 altb:35.61 altr:35.61 Malt:35.61 P0 A0 F0 D0 ax:-1132 ay:100 az:-16276 wx:-282 wy:213 wz:-81 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.048 tm:5855.00 t:26.80 p:100898 alt:35.61 altb:35.61 altr:35.63 Malt:35.63 P0 A0 F0 D0 ax:-1016 ay:16 az:-15740 wx:-279 wy:149 wz:-78 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.047 tm:5902.00 t:26.80 p:100895 alt:35.86 altb:35.86 altr:35.66 Malt:35.66 P0 A0 F0 D0 ax:-1152 ay:-48 az:-15596 wx:-247 wy:60 wz:-60 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.047 tm:5949.00 t:26.80 p:100904 alt:35.11 altb:35.11 altr:35.64 Malt:35.66 P0 A0 F0 D0 ax:-1080 ay:-52 az:-15704 wx:-276 wy:54 wz:-61 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.047 tm:5996.00 t:26.80 p:100902 alt:35.27 altb:35.27 altr:35.62 Malt:35.66 P0 A0 F0 D0 ax:-1152 ay:-44 az:-15652 wx:-290 wy:69 wz:-79 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.047 tm:6043.00 t:26.80 p:100900 alt:35.44 altb:35.44 altr:35.60 Malt:35.66 P0 A0 F0 D0 ax:-1128 ay:-8 az:-15496 wx:-281 wy:37 wz:-70 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.047 tm:6090.00 t:26.80 p:100897 alt:35.69 altb:35.69 altr:35.60 Malt:35.66 P0 A0 F0 D0 ax:-1048 ay:24 az:-15620 wx:-280 wy:59 wz:-75 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.047 tm:6137.00 t:26.80 p:100902 alt:35.27 altb:35.27 altr:35.55 Malt:35.66 P0 A0 F0 D0 ax:-1164 ay:0 az:-15736 wx:-292 wy:73 wz:-69 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.047 tm:6184.00 t:26.80 p:100899 alt:35.52 altb:35.52 altr:35.56 Malt:35.66 P0 A0 F0 D0 ax:-1088 ay:204 az:-15404 wx:-296 wy:-9 wz:-38 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.048 tm:6232.00 t:26.80 p:100897 alt:35.69 altb:35.69 altr:35.57 Malt:35.66 P0 A0 F0 D0 ax:-1220 ay:-340 az:-15976 wx:-261 wy:32 wz:-106 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.048 tm:6280.00 t:26.80 p:100902 alt:35.27 altb:35.27 altr:35.59 Malt:35.66 P0 A0 F0 D0 ax:-880 ay:144 az:-15828 wx:-289 wy:120 wz:-76 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.047 tm:6327.00 t:26.80 p:100906 alt:34.94 altb:34.94 altr:35.53 Malt:35.66 P0 A0 F0 D0 ax:-1300 ay:52 az:-15292 wx:-274 wy:97 wz:-71 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.047 tm:6374.00 t:26.80 p:100903 alt:35.19 altb:35.19 altr:35.50 Malt:35.66 P0 A0 F0 D0 ax:-1072 ay:-76 az:-15452 wx:-264 wy:55 wz:-74 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.047 tm:6421.00 t:26.80 p:100905 alt:35.02 altb:35.02 altr:35.44 Malt:35.66 P0 A0 F0 D0 ax:-1040 ay:-4 az:-15844 wx:-297 wy:70 wz:-80 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.047 tm:6468.00 t:26.80 p:100901 alt:35.36 altb:35.36 altr:35.40 Malt:35.66 P0 A0 F0 D0 ax:-1108 ay:64 az:-15644 wx:-294 wy:88 wz:-65 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.047 tm:6515.00 t:26.80 p:100901 alt:35.36 altb:35.36 altr:35.39 Malt:35.66 P0 A0 F0 D0 ax:-1136 ay:80 az:-15628 wx:-287 wy:75 wz:-62 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.047 tm:6562.00 t:26.80 p:100903 alt:35.19 altb:35.19 altr:35.36 Malt:35.66 P0 A0 F0 D0 ax:-1120 ay:-136 az:-15608 wx:-256 wy:37 wz:-76 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.047 tm:6609.00 t:26.80 p:100895 alt:35.86 altb:35.86 altr:35.38 Malt:35.66 P0 A0 F0 D0 ax:-1032 ay:-8 az:-15600 wx:-283 wy:81 wz:-68 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.048 tm:6657.00 t:26.80 p:100900 alt:35.44 altb:35.44 altr:35.35 Malt:35.66 P0 A0 F0 D0 ax:-1112 ay:-16 az:-15612 wx:-283 wy:59 wz:-77 cx:24508.800 cy:7121.720 cz:3551.200
dt:0.048 tm:6705.00 t:26.80 p:100901 alt:35.36 altb:35.36 altr:35.37 Malt:35.66 P0 A0 F0 D0 ax:-1084 ay:64 az:-15624 wx:-282 wy:73 wz:-66 cx:24508.800 cy:7121.720 cz:3551.200

Что означают данные:dt — интервал времени в миллисекундах с прошлого замераtm — количество миллисекунд, прошедшее с включения устройстваt — температура воздухаp — давление воздухаalt — высота по данным датчика-высотомераaltb — высота за вычетом «базовой» высоты, полученной при нажатии кнопкиaltr — скользящее среднее по последним 16 замерам высота altbЗначения-флаги (могут принимать значение 0 или 1, что означает НЕТ и ДА)

P — Была ли нажата кнопка установки базовой высоты, т.е. подготовлено ли устройство? (Prepared)A — Взведено ли устройство? Т.е. пройдена ли точка минимальной необходимой для взвода высоты (10 метров) (Armed)F — Активировано ли реле? т.е. выполнено ли условие снижения не 1 метр относительно максимальной набранной высоты?

(Fired)D — Закончена ли работа устройства? Этот флаг включается, когда выключается флаг F. После этого устройство больше никаких функций выполнять не будет, и для работы с ним его потребуется либо перезагрузить либо выключить и включить снова.

При этом те же самые данные программа будет писать на SD-карту, вставленную в кардридер. При каждом запуске устройства будет создаваться новый файл со следующим порядковым номером.

Оцените статью
Радиокоптер.ру
Добавить комментарий

Adblock
detector