CraftDuino v2.0
  • - это CraftDuino - наш вариант полностью Arduino-совместимой платы.
  • CraftDuino - настоящий конструктор, для очень быстрого прототипирования и реализации идей.
  • Любая возможность автоматизировать что-то с лёгкостью реализуется с CraftDuino!
Просто добавьте CraftDuino!

Программируемый логический контроллер (ПЛК) на базе Arduino + Ethernet shield + 74HC165 + 74HC595

Идея заключалась в том, чтобы сделать контроллер исполнительных устройств с некоторой степенью автоматизации и настраиваемый полностью через web интерфейс. Логика работы контроллера хранится в файле на SD карте, а не в коде, что позволяет очень просто модифицировать логику работы, без изменения кода и перепрошивки контроллера.
Поскольку формировать web странички в коде очень не хотелось, то пришлось порыться на просторах сети и откопать такой интересный проект — TinyWebServer. С помощью этой библиотеки логика работы контроллера теперь полностью отделена от отображения страниц. Arduino не формирует страницы полностью. Интерактивная часть формируется в браузере.
Все странички, скрипты и другая информация (в моем случае еще и все настройки контроллера) хранятся на SD карте.
Состав
1. Mega 2560
2. Ethernet+SD shield
3. Сдвиговые регистры 74HC595 (контроллер может поддерживать большое количество регистров, но есть ограничение по объему ОЗУ, так как имена и настройки загружаются в ОЗУ).
4. Для логической обработки возможно использовать в качестве входных сигналов:
a) свободные цифровые входы Arduino
b) аналоговые входы
c) цифровые входы, подключенные через сдвиговые регистры 74HC165
d) также можно добавить любые типы датчиков непосредственно в коде под свои нужды (далее я опишу как это можно сделать).

Что умеет получившийся контроллер.
1. Ручной режим управления выходами, реализованный через WEB интерфейс (Включить/Выключить/Подать импульс).
2. Задержку включения после подачи питания. Если установлена задержка включения, то логические правила для этого выхода не действуют и реле управляется только в ручном режиме.
3. Управление выходами с помощью логических правил, в которых можно использовать любые типы датчиков, логические операции NOT/AND/OR и скобки. В формулах используются ID датчиков, которые также настраиваются через WEB интерфейс. Например, можно написать такую формулу (0|1)&!2. Для приведения значения аналоговых датчиков к логическому значению используются два граничных значения для обеспечения гистерезиса. Если значение больше или равно верхнему граничному значению, то значению сигнала будет true, а если меньше или равно нижнему, то false. Для всех датчиков возможно использовать инверсию значения. Например, при подключении кнопки, если она не нажата, на входе будет логическая 1 (true), а при инвертировании сигнала true будет обрабатываться при нажатой кнопке, т.е. при логическом 0 на входе.
4. Посылка SMS через SMS провайдера при включении и при переключении реле. К сожалению работает не очень хорошо, так что лучше не использовать.
5. Возможна работа без Ethernet shild, только с SD. Для этого необходимо закомментировать объявление #define WEB_INTERFACE. Изменять все настройки и логику работы в этом случае можно редактированием файлов на SD карте.

Как это все работает.
Работа с выходными сдвиговыми регистрами 74HC595 организована через мою библиотеку SPI595. Управление регистрами осуществляется по шине SPI с выбором устройства на пине 7 (#define SPI595_CS 7).
Работа с входными сдвиговыми регистрами 74HC165 организована через мою библиотеку SPI165. Управление регистрами осуществляется по шине SPI с выбором устройства на пине 6 (#define SPI165_CS 6).
Ethernet shield W5100 работает со стандартной библиотекой (#define ETHER_CS 10).
SD карта работает с библиотекой SdFat (#define SD_CS 4).
При включении контроллера считывается информация из файла sett.txt. На основании этих данных инициализируются Ethernet shield, сдвиговые регистры и глобальные переменные. Если SD карта не инициализировалась при старте, то LED 13 будет быстро моргать.
Затем считываются файлы настроек реле и датчиков. При загрузки правил они автоматом переводятся в обратную польскую нотацию, для быстрого вычисления void prepareRPN(byte idx, char* formula)
Вычисление значения логического выражения после этого становится очень простым. Ниже приведена функция вычисления формулы, представленной в виде обратной польской нотации.
bool evaluateRPN(byte relayIdx){
bool res[20];
byte i = 0;
byte idx = 0;

while(relayArr[relayIdx].rule[i] != OPERATIONS_END){
switch(relayArr[relayIdx].rule[i]){
			case OPERATIONS_NOT:{
				res[idx-1] = ! res[idx-1];
break;
}
case OPERATIONS_AND:{
res[idx-2] = res[idx-2] && res[idx-1];
idx--;
break;
}
case OPERATIONS_OR:{
res[idx-2] = res[idx-2] || res[idx-1];
idx--;
break;
}
default:{
res[idx] = getSensor(relayArr[relayIdx].rule[i]);
idx++;
break;
}
}
		i++;
	}
	return(res[0]);
}

Добавление своего типа датчика
Определить его тип и признак в константах:
#define SENSOR_DS18S20 4                            код типа
#define SENSOR_SETT_DS18S20 ‘T’               символ для настройки
Реализовать его код в функции
bool getSensor(byte index).
    switch(sensorArr[index].type){
        …
        case SENSOR_DS18S20:{
            return(GETDS18S20(sensorArr[index].number));
        }
        …
    }
    return(false);
}

Произвести загрузку его свойств и проинициализировать в функции void loadSettings(bool all)
Подправить sensett.js для правильного отображения в браузере.
WEB интерфейс
Собственно, за основу с самого начала я взял пример из TinyWebServer.

Скриншоты




Периодичность опроса контроллера 0,4 секунды.
После изменения настроек реле или сенсоров и нажатии кнопки Save изменения вступают в силу сразу же. Общие настройки применяются только при инициализации контроллера.

На будущее
1. Поскольку я с web программированием практически никак, то делал как можно проще, без изысков. Каждый может для себя поправить файлы. В самом коде скетча ничего править не нужно. Собственно ради этого все это и затевалось.
2. При загрузке данных браузер постоянно запрашивает все данные. А поскольку используется jquery.js, а она достаточно большая, то хотелось бы заставить браузер закэшировать ее (а еще лучше все htm и js файлы) на все время сессии. Тогда arduino передавал бы только файлы настроек и состояние реле и датчиков. Но пока, увы, не получилось. Если кто-нибудь подскажет как это сделать — буду признателен.
3. В разборе правил проверок нет, так что, если формула будет некорректной, то последствия непредсказуемы. Возможно когда-то появится проверка правил.
4. Сделать командное управление через com-порт. В принципе класс для этого у меня есть, но пока я его в этот проект не подключал. Что то типа:
relay 1 on
OK
get relay state
relay 1 ON
relay 99 OFF
5. Добавить переменные для сохранения логических выражений, для того чтобы в логических правилах можно было бы использовать не только идентификаторы датчиков, но и переменные, например, (0|A)&!2, где A это переменная, значение которой присваивается другой формулой.
Сейчас конечно можно выйти из положения подключив выход 74HC595 к цифровому входу Arduino или в входному регистру 74HC165.
6. Сделать входы счетчики…
7. Сделать несколько типов выходов. Не только через сдвиговый регистр, но и напрямую управлять цифровыми портами Arduino (в Mega2560 их достаточно).
8. Сделать не только Init state для выходов, но и init pulse.
9. Возможно реализовать MODBUS, но это в последнюю очередь.
10. Реализовать вход как логическую функция от часов реального времени, и как функцию таймера.

Баги
При включении выходные регистры включаются хаотически. А поскольку контроллер инициализируется некоторое время, то выходные реле могут быть включены. Пока схема сброса регистров не реализована.
После заливке скетча иногда почему-то не инициализируется SdFat. Приходится сбрасывать контроллер кнопкой reset.

Один важный момент.
Всё подключено через аппаратный SPI.
Собственно подключение Ethenet shield, SD shield и 74HC595 никаких трудностей не представляет.
Проблемой было подключить 74HC165. Выход у этого регистра не может переходить в Z-состояние (кто-то сэкономил на паре транзисторов :) ), и при подключении его напрямую к MISO делает невозможным работу с другими устройствами. Для решения этой проблемы был использован буфер 74HC125. Управляется он выходом, определенным константой SPI165_CS.

Схема подключения регистра


Итого
В принципе уже сейчас на базе этого контроллера можно реализовать некоторую достаточно сложную автоматизацию. А при возможность править web интерфейс не вмешиваясь в код, можно реализовать удобное взаимодействие с пользователем. Единственная проблема — при работе с web клиентом контроллер полностью занят и не может реагировать на изменения состояний датчиков (для этого я и хотел заставить браузер кешировать данные на все время сессии), поэтому иногда появляются задержки. Вынос обработки логики в таймер пока не планирую, все таки это не real time device.

Ссылки

Проект
https://drive.google.com/folderview?id=0B7NuO_z3PX3NUTNncGw0VzQwRTQ&usp=sharing
В каталоге LIB лежат библиотеки, которые позволяют упростить работу с регистрами.
В HTML лежит web интерфейс.

TinyWebSerwer
https://github.com/ovidiucp/TinyWebServer

SDFat
https://code.google.com/p/sdfatlib/

Комментарии (21)

RSS свернуть / развернуть
+
0
Очень, ОЧЕНЬ полезная работа. Но для подавляющего большинства начинающих пользователей всетаки не нужно считывать показания 100 датчиков и переключать 100 реле, а нужно быстро и с минимальными затратами (как денег так и усилий) запустить то же самое, но ограничившись 16-тью реле в виде стандартного блока реле ардуино, без сдвиговых регистров, просто плата и изернет щит :)
avatar

Nikolaevsk

  • 23 июня 2014, 08:43
+
0
Просто без использования аппаратного SPI мне этот проект был не особо интересен.
В ближайшее время думаю сделать условную компиляцию для отключения 74HC165, 74HC595.
И сделаю прямые выходы.
avatar

GraninDm

  • 23 июня 2014, 13:29
+
0
А можно посмотреть, как Ваш проект реализован аппаратно? Фотографии, может быть разводка печатной платы? Может быть, всё не так страшно как звучит, если посмотреть глазами на готовый девайс? И кстати, не вырастет ли общая стабильность системы если отказаться от использования регистров?
avatar

Nikolaevsk

  • 23 июня 2014, 13:35
+
0
Вот тут добавил фотографию :))))
avatar

GraninDm

  • 23 июня 2014, 13:59
+
0
Странно. Ссылка пропала.
В папке проекта в папке Doc
https://drive.google.com/folderview?id=0B7NuO_z3PX3NcUJIdGFvZlJNY00&usp=sharing&tid=0B7NuO_z3PX3NUTNncGw0VzQwRTQ
avatar

GraninDm

  • 23 июня 2014, 14:01
+
0
Ох, чтото мне страшно стало от вида этого клубка проводов :)возможно, что описанный Вами баг(что при включении состояния реле могут быть произвольными) исчезнет, если развести аккуратную печатную плату на двустороннем текстолите, и убрать этот клубок проводов… нет, я пожалуй предпочту сперва испытать без регистровый вариант, с бутербродом из главной платы и изернет щита :)
avatar

Nikolaevsk

  • 23 июня 2014, 14:06
+
0
Нет. Не исчезнет. Дело в самих регистрах. Я это могу побороть. Но мне лень.
В вашем случае при управлении реле через выходы ардуино напрямую такого не будет.
avatar

GraninDm

  • 23 июня 2014, 14:09
+
0
По кэшированию. Надо правильные http-заголовки отдавать, при чём с правильным временем. Сам в своё время намучился, когда писал свой МакроСервер (ныне заброшенный).

Тот самый заголовок выглядит так:

Last-Modified: Sat, 19 Sep 2015 18:00:00 GMT

Кроме того, сервер должен реагировать на заголовок If-Modified-Since в реквесте. Если он там есть, то надо проверять дату-время страницы, и если текущая дата изменения страницы меньше или равна дате из запроса, тогда сервер должен выдать ответ 304 Not Modified.

Например, при втором заходе на ту же страницу браузер может прислать в числе прочего:
If-Modified-Since: Sat, 19 Sep 2015 18:00:00 GMT

Тут указываются дата-время, которые были получены в прошлый раз в Last-Modified.

В ответ (если данные не изменились) надо вместо 200 Ok выдать 304 Not Modified, заголовок Last-Modified передаётся и в этом случае:

Last-Modified: Sat, 19 Sep 2015 18:00:00 GMT

Время, как видно, везде в GMT.

Ещё крайне рекомендую обеспечить «Connection: keep-alive», чтобы все запросы шли пачкой, и ответы лились один за другим без разрывов и установки соединений.

Можно ещё Cache-Control/Expires использовать, но для моих целей (в частности, при отладке сайта) это было неудобно, при изменении на сервере «статического» файла в браузере приходилось нажимать Ctrl-F5, в общем, я не пользовался.

Например:

Cache-Control: private, max-age=3600

Должно кэшировать на один час. Но при отладке сайта из-за каждого мельчайшего изменения каждый раз придётся принудительно перезагружать вообще всё.

Возможно, в самом сервере есть какие-то опции, которые всё это включают. Если же нет, вроде несложно добавить.
avatar

janych

  • 19 сентября 2015, 23:47
+
0
Спасибо. Как будет время попробую.
avatar

GraninDm

  • 21 сентября 2015, 07:39
+
0
Добрый день.

Пытаюсь все запустить и тут ошибка. Не могу импортировать библиотеки. Может версия Ардуины не та? Не подскажите где копать.
avatar

abnizami

  • 18 августа 2016, 12:47
+
0
Добрый день!
Вы какую версию пробуете?
Лучше пробуйте из папки V 2.0
И какая ошибка?
avatar

GraninDm

  • 18 августа 2016, 12:56
+
0
После открытия файла ардуино он не может найти SPI595.h, SPI165.h, TimerOne.h, Flash.h, TinyWebServer.h

Думаю может из-за того что версия ардуины не та?
avatar

abnizami

  • 18 августа 2016, 13:13
+
0
А вы библиотеки скачали из папки libs с google disk и установили?
avatar

GraninDm

  • 18 августа 2016, 13:15
+
0
Да скачал распокавал. Забросил в папку libraries.
avatar

abnizami

  • 18 августа 2016, 13:22
+
0
Скопируйте сюда текст ошибки
avatar

GraninDm

  • 18 августа 2016, 13:25
+
0
Скопируйте библиотеки в эту папку
arduino\hardware\arduino\avr\libraries
avatar

GraninDm

  • 18 августа 2016, 13:27
+
0
И сюда скопировал все равно не видет.

А можите вы создать архив самого ардуино с библиотеками и выложить.
Если нет может тогда версию ардуино скажите.
avatar

abnizami

  • 19 августа 2016, 07:00
+
0
У меня все дома. Вечером подготовлю.
avatar

GraninDm

  • 19 августа 2016, 07:21
+
0
Если не трудно. Буду очень благодарен.
avatar

abnizami

  • 19 августа 2016, 08:46
+
0
В папке V2.0 архивы
ArduinoIDE_and_LanPLC.zip — IDE с библиотеками
LanPLC.zip — скетч со всеми вспомогательными файлами
Файл HTML\server.cmd запускает маленький веб сервер для отладки HTML
Только нужно пути подправить.

В скетче отключены SPI регистры
//#define SPI595_ENABLE // comment for disabling SP595
//#define SPI165_ENABLE // comment for disabling SP165
С этим #define SPI165_ENABLE компилироваться не будет.
Я переделывал скетч и что-то накосячил. Надо разбираться…
С #define SPI595_ENABLE работать вроде будет, но не уверен, так как последний раз с регистрами не отлаживал.
avatar

GraninDm

  • 19 августа 2016, 20:44

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.