Доработка овощесушилки под сушку пластика для 3D-печати

Представляю вниманию доработку простой дешёвой овощесушилки с целью приспособить её под сушку пластика для 3D-печати.
Испытав немалое разочарование от результатов доработки сушилки eSun eBOX, озадачился поисками более подходящего для этого агрегата, пусть и не такого удобного в плане хранения катушек.
Ещё до приобретения eBOX покупал дешёвую овощесушилку Olto HD-20. Выпилил промежуточные решётки и прикрутил к крышке удобную ручку. Девайс получился в целом неплохой, свою задачу выполнял вполне сносно.

Однако есть у него некоторые фатальные недостатки. Во-первых, чисто условная стабильность температуры. Настраивается она классическим биметаллическим терморегулятором (далее просто «терморегулятор»). Погрешность в два-три десятка градусов для такой конструкции — это вполне норма. Под сушку овощей сойдёт, но для пластика неприемлемо абсолютно. Если PETG при температуре 60℃ будет чувствовать себя прекрасно, то PLA запросто может «поплыть». Во-вторых, установка температуры ручкой тоже очень приблизительная, каждый раз приходится калибровать по внешнему термометру. В-третьих, нет никакого таймера и нужно как-то засекать время сушки.
Конечно же, можно было бы просто выкинуть эту сушилку и пойти купить другую, с цифровым управлением и таймером. Не настолько уж она дороже. Однако, у неё также есть существенный недостаток, уже в плане юзабилити. Существуют таблицы температуры/времени сушки пластика, наподобие такой. И каждый раз вспоминать её и вводить значения заново откровенно лениво.
В общем, как нельзя кстати вспомнился девиз «наши руки не для скуки!». Сушилка уже есть, нужно просто слегка доработать её напильником. Приступим!
Разбираем сушилку. Снимаем решётки, откручиваем крышку. И видим такое:

В середине находится труба с нагревательным элементом внутри. Рядом с ней установлен вентилятор с двигателем, какие когда-то ставились в проигрыватели пластинок. Спереди выключатель сети и терморегулятор с ручкой-крутилкой. Всё очень просто и скромно. Производитель пожлобился даже на стеклянный предохранитель. Хотя, справедливости ради, термопредохранитель всё-таки поставили прямо внутри трубы с нагревателем:

Принцип действия незамысловат. Установленная на вентиляторе крыльчатка через отверстия в днище сушилки затягивает воздух, пропускает через трубу нагревателя и выбрасывает наверх, к сеткам с овощами/фруктами. Ручка терморегулятора в зависимости от угла поворота сильнее или меньше поджимает биметаллическую пластинку, которая обмотана нихромовой проволокой. По мере прогрева проволоки пластинка изгибается и размыкает контакты. То есть, по сути, это регулирование не по температуре воздуха, а по времени нагрева пластинки. Которое сильно зависит от окружающей среды и подобрано примерно, «на глаз». Отсюда и такие поразительные «точность» и «стабильность».
По-хорошему, для максимального эффекта осушения воздух должен циркулировать по замкнутому контуру, а водяные пары из него должны удаляться абсорбентом. Здесь ничего этого нет, контур не замкнут, абсорбент отсутствует. Тем не менее и как ни странно, сушилка вполне неплохо справляется с пластиком.
Изучив конструкцию, приступаем к переделке.
Рисуем новую схему управления стабилизацией температуры:

К разъёму «LINE» подключается сеть 230 В, к разъёму «FAN» — вентилятор, к разъёму «HEATER» — нагреватель. Подключение датчика, дисплея и энкодера:

Выводить информацию будем на дешёвый, популярный и удобный в применении LCD-дисплей 1602 (две строки по 16 символов). Взята версия с дополнительным модулем I2C, что позволяет существенно сократить количество линий подключения.
Для управления используется энкодер. Очень мне нравится этот вид контроллеров, считаю его исключительно удобным и подходящим для множества вариантов использования. Можно было бы просто сделать пару кнопок, но добавить энкодер более перспективно, если вдруг захочется как-то расширить функциональность.
Отдельно стоит отметить, что подключен энкодер по достаточно интересной, на мой взгляд, схеме из делителей напряжения на резисторах R1~R4. Это позволяет считывать с него информацию, используя всего один вход контроллера. Однако, есть у такой схемы и существенный недостаток — в ней полностью отсутствует аппаратное подавление дребезга контактов. Его требуется реализовывать программно в прошивке. Это не слишком сложно, но не всегда приемлемо, поскольку требует добавления блокировок и задержек. В моём случае такое вполне допустимо, поскольку никакое управление сушилкой во время её работы не предусмотрено и не требуется.
В качестве термодатчика применим DS18B20. По началу хотел использовать AM2302, более известный как DHT22. Он весьма удобен тем, что предоставляет также данные о влажности воздуха, что для сушилки очень актуально. Однако, собрав и протестировав схему на макете, выяснилось, что данный датчик обладает просто колоссальной инертностью. Мало того, что показания с него можно считывать с частотой не более 0.5 Гц, так они ещё и изменяются крайне медленно в обе стороны (повышения/понижения). Превышение заданной температуры на прогреве достигало 35℃, давая фору даже неторопливому аналоговому терморегулятору. Поэтому в финальной версии схемы применяется именно DS18B20, который обладает куда большей чувствительностью и меньшей тепловой инерцией.
Для управления нагревателем применено твердотельное реле KSD205AC3 с номинальным током коммутации 5 А. Значение тока взято с большим запасом, нагреватель потребляет не более 1.2 А. Поэтому реле вообще не нагревается при работе. Можно было бы сделать ШИМ-регуляцию, но предварительные тесты на макете показали, что и реле вполне может обеспечить поддержание температуры с точностью ±2℃.
Питание обеспечивает MeanWell IRM-01-5 (5 В 200 мА). Вся электроника в целом потребляет 35~60 мА, так что хватает с большим запасом.
Так же в схему добавлена «пищалка» со встроенным генератором для уведомления о различных событиях (сушилка включилась, сушка закончена, произошла ошибка).
Разводим платы. Их две — управление и силовая часть с блоком питания:

Обе платы односторонние. Единственная дорожка по второй стороне (синего цвета) — это «паразитная» дорожка самой Arduino, которая использована чтобы не делать свою собственную перемычку. Весь процесс изготовления плат не показываю, всё стандартно и по классике: лазерный принтер, глянцевая бумага, ламинатор, травление в перекиси с лимонной кислотой. Собранные платы:

Разумеется, не обошлось без проблем и ошибок. Отверстия в плате управления расставлены таким образом, чтобы она вставала «вторым этажом» на плату дисплея. Однако по невыясненным причинам размеры в EasyEDA и в реальном мире разошлись на несколько миллиметров. И выяснилось это, по закону подлости, только при попытке собрать всё это вместе. Пришлось поработать напильником…
Также изготавливаем комплект кабелей:

На термодатчик и питание запущен монтажный провод МГТФЭ 0.2 мм. Не столько для защиты от помех, просто обычные мои монтажные провода AWG 24 невозможно обжать в контактах разъёмов из-за их (проводов) слишком толстой силиконовой изоляции.
Прошивка получилась достаточно длинной, но простой и линейной. Постарался прокомментировать все наиболее неочевидные места. Если будут какие-то вопросы и/или предложения — прошу в комментарии.
Общий алгоритм следующий. После включения сушилки предлагаем выбрать пластик из заранее подготовленного списка. Вращением энкодера находим нужный и подтверждаем выбор нажатием на кнопку энкодера. Включается предварительный прогрев до заданной температуры. Когда температура достигнута, стартует обратный отсчёт времени и начинается её поддержание периодическим включением нагрева. Когда время выйдет, включается звуковой сигнал и сушилка ожидает нажатия на кнопку энкодера. После этого управление возвращается снова к выбору пластика.
Для крепления и размещения плат, дисплея и энкодера замоделил и напечатал несколько деталей. В первую очередь перенёс на заднюю сторону сушилки выключатель и добавил разъём, чтобы кабель подключения к сети был съёмным:

Собираем корпус для плат дисплея, управления и энкодера:



Между передней панелью и дисплеем вклеиваем кусочек толстой плёнки для защиты экранов планшетов чтобы дисплей не сильно пылился.
Далее собираем силовую часть. Плату крепим к днищу на уголки. Добавляем стеклянный предохранитель на 2 А в разъёмном корпусе:

Термодатчик крепим максимально близко к трубе нагревателя, чтобы он обязательно находился в потоке выходящего воздуха. Это необходимо для максимально быстрой реакции на изменение температуры и наиболее точных показаний. Пробовал разместить датчик на периферии, поближе к краю, однако это сильно увеличивает время реакции и погрешность поддержания заданной температуры. К тому же, как показали измерения и эксперименты, за счёт высокой скорости потока воздуха и достаточной мощности нагревателя, разница в температуре непосредственно у выхода из трубы и на периферии у края не превышает 3℃. Датчик крепим за кабель кусочком листовой латуни:

Собираем всё вместе. В итоге получаем вот такой аппарат:

Сразу же отвечая на резонный вопрос — а не поплавятся ли печатные детали, особенно внутри сушилки? Нет, не поплавятся. Всё напечатано из PLA. В «подвале» сушилки температура едва превышает комнатную, поскольку именно снизу крыльчатка вентилятора забирает воздух. Тестовый прогон в течение суток при максимальной температуре 70℃ с последующей разборкой и исследованием деталей никаких деформаций не выявил. Для полной уверенности можно напечатать их из ABS. Тогда они точно выдержат, поскольку корпус самой сушилки отлит из именно этого пластика, и делать детали более термостойкими нет никакого смысла.
Полагая, что лучше один раз увидеть и услышать, чем десять раз прочитать, записал видео с демо-прогоном сушки. В целях сокращения его длительности частично разобрал корпус и прошил код, в котором время сушки нейлона уменьшено до 15 секунд:
Предыдущую попытку доработать сушилку eSun eBOX нельзя назвать совсем уже полным провалом, кое-что улучшить мне всё-таки удалось. Однако и разогнать температуру выше 48℃ не получилось даже после нескольких часов непрерывной сушки.
В данном случае ситуация совсем иная. Благодаря более мощному нагревателю и более быстрому потоку воздуха доработанная овощесушилка легко и непринуждённо набирает температуру 70℃ меньше чем за минуту. Вдобавок, за счёт адаптированного под себя управления ею намного удобнее пользоваться — достаточно просто выбрать нужный пластик, всё остальное (температура и время) уже настроено заранее. При необходимости всегда можно добавить другие пластики и новую функциональность.
Так что этой переделкой я остался крайне доволен. Да, к сожалению эту сушилку не выйдет поставить рядом с принтером и печатать прямо из неё, как позволяет eBOX. Зато свою основную задачу она теперь выполняет отлично.
Стоит ли повторять мою доработку — решать исключительно вам. С точки зрения стоимости деталей и материалов, а также затрат времени и труда она невыгодна. Намного быстрее, проще и дешевле купить любую овощесушилку, подходящую по размерам, функциональности и характеристикам. А таблицу с температурой и временем сушки просто напечатать на бумаге и приклеить прямо на корпус.
Однако, если у вас есть время и желание сделать что-то своими руками, то результат этих трудов вполне окупится и порадует.
На этом всё, благодарю за внимание! Вопросы и конструктивная критика — приветствуются.
Схема и платы в EasyEDA.
Модели печатных деталей.
Предисловие
Испытав немалое разочарование от результатов доработки сушилки eSun eBOX, озадачился поисками более подходящего для этого агрегата, пусть и не такого удобного в плане хранения катушек.
Ещё до приобретения eBOX покупал дешёвую овощесушилку Olto HD-20. Выпилил промежуточные решётки и прикрутил к крышке удобную ручку. Девайс получился в целом неплохой, свою задачу выполнял вполне сносно.

Однако есть у него некоторые фатальные недостатки. Во-первых, чисто условная стабильность температуры. Настраивается она классическим биметаллическим терморегулятором (далее просто «терморегулятор»). Погрешность в два-три десятка градусов для такой конструкции — это вполне норма. Под сушку овощей сойдёт, но для пластика неприемлемо абсолютно. Если PETG при температуре 60℃ будет чувствовать себя прекрасно, то PLA запросто может «поплыть». Во-вторых, установка температуры ручкой тоже очень приблизительная, каждый раз приходится калибровать по внешнему термометру. В-третьих, нет никакого таймера и нужно как-то засекать время сушки.
Конечно же, можно было бы просто выкинуть эту сушилку и пойти купить другую, с цифровым управлением и таймером. Не настолько уж она дороже. Однако, у неё также есть существенный недостаток, уже в плане юзабилити. Существуют таблицы температуры/времени сушки пластика, наподобие такой. И каждый раз вспоминать её и вводить значения заново откровенно лениво.
В общем, как нельзя кстати вспомнился девиз «наши руки не для скуки!». Сушилка уже есть, нужно просто слегка доработать её напильником. Приступим!
Изучение
Разбираем сушилку. Снимаем решётки, откручиваем крышку. И видим такое:

В середине находится труба с нагревательным элементом внутри. Рядом с ней установлен вентилятор с двигателем, какие когда-то ставились в проигрыватели пластинок. Спереди выключатель сети и терморегулятор с ручкой-крутилкой. Всё очень просто и скромно. Производитель пожлобился даже на стеклянный предохранитель. Хотя, справедливости ради, термопредохранитель всё-таки поставили прямо внутри трубы с нагревателем:

Принцип действия незамысловат. Установленная на вентиляторе крыльчатка через отверстия в днище сушилки затягивает воздух, пропускает через трубу нагревателя и выбрасывает наверх, к сеткам с овощами/фруктами. Ручка терморегулятора в зависимости от угла поворота сильнее или меньше поджимает биметаллическую пластинку, которая обмотана нихромовой проволокой. По мере прогрева проволоки пластинка изгибается и размыкает контакты. То есть, по сути, это регулирование не по температуре воздуха, а по времени нагрева пластинки. Которое сильно зависит от окружающей среды и подобрано примерно, «на глаз». Отсюда и такие поразительные «точность» и «стабильность».
По-хорошему, для максимального эффекта осушения воздух должен циркулировать по замкнутому контуру, а водяные пары из него должны удаляться абсорбентом. Здесь ничего этого нет, контур не замкнут, абсорбент отсутствует. Тем не менее и как ни странно, сушилка вполне неплохо справляется с пластиком.
Изучив конструкцию, приступаем к переделке.
Схема
Рисуем новую схему управления стабилизацией температуры:

К разъёму «LINE» подключается сеть 230 В, к разъёму «FAN» — вентилятор, к разъёму «HEATER» — нагреватель. Подключение датчика, дисплея и энкодера:

Выводить информацию будем на дешёвый, популярный и удобный в применении LCD-дисплей 1602 (две строки по 16 символов). Взята версия с дополнительным модулем I2C, что позволяет существенно сократить количество линий подключения.
Для управления используется энкодер. Очень мне нравится этот вид контроллеров, считаю его исключительно удобным и подходящим для множества вариантов использования. Можно было бы просто сделать пару кнопок, но добавить энкодер более перспективно, если вдруг захочется как-то расширить функциональность.
Отдельно стоит отметить, что подключен энкодер по достаточно интересной, на мой взгляд, схеме из делителей напряжения на резисторах R1~R4. Это позволяет считывать с него информацию, используя всего один вход контроллера. Однако, есть у такой схемы и существенный недостаток — в ней полностью отсутствует аппаратное подавление дребезга контактов. Его требуется реализовывать программно в прошивке. Это не слишком сложно, но не всегда приемлемо, поскольку требует добавления блокировок и задержек. В моём случае такое вполне допустимо, поскольку никакое управление сушилкой во время её работы не предусмотрено и не требуется.
В качестве термодатчика применим DS18B20. По началу хотел использовать AM2302, более известный как DHT22. Он весьма удобен тем, что предоставляет также данные о влажности воздуха, что для сушилки очень актуально. Однако, собрав и протестировав схему на макете, выяснилось, что данный датчик обладает просто колоссальной инертностью. Мало того, что показания с него можно считывать с частотой не более 0.5 Гц, так они ещё и изменяются крайне медленно в обе стороны (повышения/понижения). Превышение заданной температуры на прогреве достигало 35℃, давая фору даже неторопливому аналоговому терморегулятору. Поэтому в финальной версии схемы применяется именно DS18B20, который обладает куда большей чувствительностью и меньшей тепловой инерцией.
Для управления нагревателем применено твердотельное реле KSD205AC3 с номинальным током коммутации 5 А. Значение тока взято с большим запасом, нагреватель потребляет не более 1.2 А. Поэтому реле вообще не нагревается при работе. Можно было бы сделать ШИМ-регуляцию, но предварительные тесты на макете показали, что и реле вполне может обеспечить поддержание температуры с точностью ±2℃.
Питание обеспечивает MeanWell IRM-01-5 (5 В 200 мА). Вся электроника в целом потребляет 35~60 мА, так что хватает с большим запасом.
Так же в схему добавлена «пищалка» со встроенным генератором для уведомления о различных событиях (сушилка включилась, сушка закончена, произошла ошибка).
Платы
Разводим платы. Их две — управление и силовая часть с блоком питания:

Обе платы односторонние. Единственная дорожка по второй стороне (синего цвета) — это «паразитная» дорожка самой Arduino, которая использована чтобы не делать свою собственную перемычку. Весь процесс изготовления плат не показываю, всё стандартно и по классике: лазерный принтер, глянцевая бумага, ламинатор, травление в перекиси с лимонной кислотой. Собранные платы:

Разумеется, не обошлось без проблем и ошибок. Отверстия в плате управления расставлены таким образом, чтобы она вставала «вторым этажом» на плату дисплея. Однако по невыясненным причинам размеры в EasyEDA и в реальном мире разошлись на несколько миллиметров. И выяснилось это, по закону подлости, только при попытке собрать всё это вместе. Пришлось поработать напильником…
Также изготавливаем комплект кабелей:

На термодатчик и питание запущен монтажный провод МГТФЭ 0.2 мм. Не столько для защиты от помех, просто обычные мои монтажные провода AWG 24 невозможно обжать в контактах разъёмов из-за их (проводов) слишком толстой силиконовой изоляции.
Прошивка
Прошивка получилась достаточно длинной, но простой и линейной. Постарался прокомментировать все наиболее неочевидные места. Если будут какие-то вопросы и/или предложения — прошу в комментарии.
Развернуть очень длинный листинг на 552 строки
#include <OneWire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal_I2C.h>
// Примерное время дребезга контактов энкодера, мс.
#define ENCODER_JITTER (5)
// Таймаут на ожидание следующего события от энкодера, мс.
#define ENCODER_TIMEOUT (350)
// Параметры длительности сигналов азбуки Морзе, мс. >:3
#define DOT_LEN (500)
#define DASH_LEN (3 * DOT_LEN)
#define SIGN_DELAY (DOT_LEN)
#define LETTER_DELAY (3 * DOT_LEN)
#define REPEAT_DELAY (7 * DOT_LEN)
// Макрос для удобства записи часов.
#define HOURS(value) (value * 3600UL)
// Пин термодатчика.
#define SENSOR_PIN (2)
// Пин "пищалки".
#define BEEPER_PIN (11)
// Пин твердотельного реле управления нагревателем.
#define HEATER_PIN (12)
// Пин сигналов от энкодера.
#define ENCODER_PIN (A0)
// Действие, произведённое энкодером.
enum EncoderAction
{
NoAction, // Бездействие.
ActionNext, // Вращение в одну сторону.
ActionPrev, // Вращение в другую сторону.
ActionConfirm, // Нажатие кнопки.
};
// Стадия (состояние) сушки.
enum HeatingStage
{
Idle, // Выключено (бездействие).
PreHeating, // Прогрев.
Working, // Стабилизация температуры.
};
// Описание настроек пластика.
typedef struct
{
const char *const name; // Название.
const uint8_t temp; // Температура сушки.
const unsigned long time_sec; // Время сушки, с.
} Filament;
// Таблица с настройками для разных видов пластика.
const Filament filaments[] = {
{
.name = "PLA",
.temp = 45,
.time_sec = HOURS(6),
},
{
.name = "ABS",
.temp = 60,
.time_sec = HOURS(4),
},
{
.name = "PETG",
.temp = 65,
.time_sec = HOURS(4),
},
{
.name = "TPU",
.temp = 50,
.time_sec = HOURS(8),
},
{
.name = "Nylon",
.temp = 70,
.time_sec = HOURS(12),
},
};
// Минимальный индекс таблицы с настройками пластиков.
#define MIN_IDX (0)
// Максимальный индекс таблицы с настройками пластиков.
#define MAX_IDX ((sizeof(filaments) / sizeof(filaments[0])) - 1)
// Настройка шины 1-wire и термодатчика DS18B20.
OneWire ow_bus(SENSOR_PIN);
DallasTemperature sensor(&ow_bus);
// Настройка LCD-дисплея 1602.
LiquidCrystal_I2C screen(0x27, 16, 2);
// Выбранный пластик.
volatile const Filament *filament = NULL;
// Флаг, показывающий что пора обновить значения на дисплее.
volatile bool refresh_screen = false;
// Счётчик секунд, прошедших с момента запуска текущей стадии.
volatile unsigned long seconds = 0;
// Флаг, показывающий включен сейчас нагрев или выключен.
// На дисплее отображается буквой 'H'.
volatile bool heater_is_on = false;
// Флаг, показывающий что есть событие от энкодера.
volatile bool event_on_encoder = false;
// Текущая стадия сушки.
volatile HeatingStage heating_stage = Idle;
// Обработчик прерывания от таймера. Срабатывает 1 раз в секунду.
ISR(TIMER1_COMPA_vect)
{
seconds++;
refresh_screen = true;
}
// Обработчик прерывания с пина энкодера.
// Срабатывает по изменению напряжения
// в любую сторону (уменьшение/увеличение).
ISR(PCINT1_vect)
{
event_on_encoder = true;
}
// Сброс таймера.
void reset_timer(void)
{
// На время сброса запрещаем прерывания
// чтобы значение счётчика не изменилось.
noInterrupts();
seconds = 0;
refresh_screen = false;
interrupts();
}
// Включение нагрева.
void turn_on(void)
{
digitalWrite(HEATER_PIN, HIGH);
heater_is_on = true;
}
// Выключение нагрева.
void turn_off(void)
{
digitalWrite(HEATER_PIN, LOW);
heater_is_on = false;
}
// Пищание "пищалкой".
void beep(uint16_t duration)
{
digitalWrite(BEEPER_PIN, HIGH);
delay(duration);
digitalWrite(BEEPER_PIN, LOW);
}
// Полностью очистить дисплей.
void clear_screen(void)
{
screen.clear();
screen.home();
}
// Обработчик ошибок.
// Аргументом получает сообщение об ошибке.
// Играет "пищалкой" сигнал 'S.O.S' азбукой Морзе.
void panic(const char *const reason)
{
turn_off();
clear_screen();
screen.setCursor(0, 0);
screen.print("PANIC! Reason:");
screen.setCursor(0, 1);
screen.print(reason);
for (;;) {
// 'S': ...
beep(DOT_LEN);
delay(SIGN_DELAY);
beep(DOT_LEN);
delay(SIGN_DELAY);
beep(DOT_LEN);
delay(LETTER_DELAY);
// 'O': ---
beep(DASH_LEN);
delay(SIGN_DELAY);
beep(DASH_LEN);
delay(SIGN_DELAY);
beep(DASH_LEN);
delay(LETTER_DELAY);
// 'S': ...
beep(DOT_LEN);
delay(SIGN_DELAY);
beep(DOT_LEN);
delay(SIGN_DELAY);
beep(DOT_LEN);
delay(LETTER_DELAY);
delay(REPEAT_DELAY);
}
}
// Получение текущей температуры с термодатчика.
uint8_t query_sensor(void)
{
sensor.requestTemperatures();
const float value = sensor.getTempCByIndex(0);
if (value == DEVICE_DISCONNECTED_C)
panic("Temp NaN.");
const uint8_t temp = ((unsigned int) value) & 0xFF;
if (temp <= 1)
panic("Frozen.");
if (temp >= 120)
panic("Burned.");
return temp;
}
// Показывает на дисплее температуру и время сушки
// выбранного пластика.
void present_filament(void)
{
screen.setCursor(0, 0);
screen.print(filament->name);
screen.print(" ? ");
screen.setCursor(0, 1);
screen.print(filament->time_sec / 3600);
screen.print(" hours at ");
screen.print(filament->temp);
screen.print("* ");
}
// Чтение действия энкодера.
// Выполняется до тех пор, пока не определит действие,
// игнорируя случайные срабатывания.
// Значения настраиваются эмпирическим путём.
// Текущие значения указаны для номиналов резисторов согласно схеме,
// при точности резисторов 1%.
EncoderAction read_action(void)
{
int value = 0;
for (;;) {
value = analogRead(ENCODER_PIN);
if (value == 0)
return NoAction;
if (value > 840 && value < 850)
return ActionPrev;
if (value > 690 && value < 705)
return ActionNext;
if (value > 560 && value < 610)
return ActionConfirm;
}
}
// Дожидается любого действия от энкодера и возвращает его.
EncoderAction wait_for_action(void)
{
// Ждём пока на энкодере произойдёт какое-либо действие.
while (!event_on_encoder)
delay(1);
const EncoderAction action = read_action();
// Если энкодер бездействует, то сразу же выходим.
if (action == NoAction)
return NoAction;
unsigned long time_diff = 0;
unsigned long time_begin = millis();
/*
Алгоритм обработки вращения энкодера и подавления дребезга контактов.
Основан на механике работы энкодера. При вращении в любую сторону сначала
замыкается один контакт, затем пока он замкнут замыкается другой контакт.
За счёт того, что в схеме реализован делитель напряжения на резисторах,
два этих замыкания контактов дают разное значение напряжения. И мы здесь
получаем два события: сначала о том, что замкнулся один контакт, затем
что замкнулся второй.
При вращении в одну сторону (action == ActionPrev) ожидаем прихода
следующего действие (ActionNext). Однако здесь есть гонка! Если из-за
дребезга контактов или тормозов в АЦП раньше фронта сигнала со второго
контакта напряжение упало до нуля, то придёт действие NoAction. Поэтому
ограничиваем ожидание таймаутом.
При вращении в другую сторону всё точно также, только порядок замыкания
контактов меняется местами.
*/
if (action == ActionPrev) {
for (;;) {
if (read_action() == ActionNext)
break;
delay(1);
if (millis() - time_begin > ENCODER_TIMEOUT)
break;
}
}
if (action == ActionNext) {
for (;;) {
if (read_action() == ActionPrev)
break;
delay(1);
if (millis() - time_begin > ENCODER_TIMEOUT)
break;
}
}
/*
Когда при вращении оба контакта отработали, напряжение возвращается
в ноль (действие NoAction). Дожидаемся этого. Если нажимали кнопку,
то ждём пока её отпустят.
*/
while (read_action() != NoAction)
delay(1);
/*
Если нажимали кнопку, тогда спим в пределах погрешности энкодера
(приблизительного времени, в течение которого контакты дребезжат).
Если энкодер крутили, тогда спим в два раза большее время, чем заняла
длительность импульса, начавшегося с замыкания одного контакта и
закончившаяся с размыканием любого из контактов. Это с достаточно
высокой вероятностью гарантирует, что контакты отработали и даёт
защиту от ложных срабатываний при слишком быстром вращении энкодера.
*/
if (action == ActionConfirm)
time_diff = 0;
else
time_diff = millis() - time_begin;
delay(time_diff * 2 + ENCODER_JITTER);
// Сбрасываем флаг, показывающий что от энкодера приходили события.
// Это нужно для подавления дребезга контактов, событий могло прийти
// множество, но одно мы уже обработали. Остальные будут обработаны
// позже.
noInterrupts();
event_on_encoder = false;
interrupts();
return action;
}
// Цикл отображения меню выбора пластика.
void choose_filament(void)
{
clear_screen();
size_t cur_idx = MIN_IDX;
filament = &(filaments[cur_idx]);
present_filament();
for (;;) {
EncoderAction action = wait_for_action();
if (action == ActionConfirm)
return;
if (action == ActionNext) {
// Если добрались до конца таблицы, переходим в её начало.
if (cur_idx == MAX_IDX)
cur_idx = 0;
else
cur_idx++;
}
if (action == ActionPrev) {
// Если добрались до начала таблицы, переходим в её начало.
if (cur_idx == MIN_IDX)
cur_idx = MAX_IDX;
else
cur_idx--;
}
filament = &(filaments[cur_idx]);
present_filament();
}
}
// Включаем/выключаем нагреватель и переключаем стадию сушки.
void set_heater_state(const uint8_t temp)
{
if (filament == NULL)
panic("Heater state.");
if (temp > filament->temp) {
turn_off();
// Если сушилка была в состоянии прогрева, значит с первого выключения
// нагревателя включается основной рабочий режим просушки. Сбрасываем
// счётчик времени, чтобы начать обратный отсчёт.
// Если сушилка была в состоянии бездействия, но температура уже выше
// нужной, значит плаcтик начали сушить не дождавшись пока она остынет.
// Тоже переключаемся в основной режим.
if (heating_stage == Idle || heating_stage == PreHeating) {
heating_stage = Working;
reset_timer();
}
} else {
turn_on();
if (heating_stage == Idle) {
// Если сушилка бездействовала, значит с первого включения нагревателя
// начинаем прогрев. Сбрасываем счётчик времени, чтобы показать, сколько
// уже идёт прогрев.
heating_stage = PreHeating;
reset_timer();
}
}
}
// Обновление данных на дисплее.
void update_screen(const uint8_t temp)
{
screen.setCursor(0, 0);
screen.print(filament->name);
screen.print(" ");
screen.print(filament->temp);
screen.print(" / ");
screen.print(temp);
screen.print("* ");
// Если нагреватель включен, рисуем в конце первой строки букву 'H'.
if (heater_is_on)
screen.print("H");
// Добавляем в конец несколько пробелов чтобы гарантированно корректно
// отрисовать всю строку и в ней не осталось "призраков" от предыдущих
// символов, если прежняя строка была короче по длине.
screen.print(" ");
screen.setCursor(0, 1);
unsigned long time_val = 0;
// Если сушилка находится в стадии сушки, отображаем
// сколько времени осталось до окончания.
if (heating_stage == Working) {
screen.print("ETA ");
time_val = filament->time_sec - seconds;
const uint8_t hours = (time_val / 3600) & 0xFF;
if (hours < 10)
screen.print("0");
screen.print(hours);
screen.print(":");
} else {
// Если сушилка находится в состоянии прогрева, тогда
// показываем, сколько времени прошло с момента его
// начала.
screen.print("Preheating ");
time_val = seconds;
// Если в течение часа так и не удалось прогреть сушилку
// до заданной температуры, значит что-то точно идёт не так.
if (time_val >= 3600)
panic("Preheating.");
}
const uint8_t mins = ((time_val % 3600) / 60) & 0xFF;
if (mins < 10)
screen.print("0");
screen.print(mins);
screen.print(":");
const uint8_t secs = (time_val % 60) & 0xFF;
if (secs < 10)
screen.print("0");
screen.print(secs);
screen.print(" ");
}
void setup()
{
// Настраиваем пины на выход.
pinMode(BEEPER_PIN, OUTPUT);
pinMode(HEATER_PIN, OUTPUT);
// Сразу же выключаем нагреватель.
turn_off();
// Настраиваем экран, выводим приветствие и пищим.
screen.init();
screen.backlight();
clear_screen();
screen.print("Hello world!");
beep(250);
// Настраиваем термодатчик.
sensor.begin();
// Настраиваем обработчик прерывания от таймера.
// Подробнее см.: https://habr.com/ru/post/453276/
noInterrupts();
TCCR1A = 0;
TCCR1B = 0;
OCR1A = 15624;
TCCR1B |= (1 << WGM12);
TCCR1B |= (1 << CS10);
TCCR1B |= (1 << CS12);
TIMSK1 |= (1 << OCIE1A);
interrupts();
// Настраиваем прерывания от пина, куда подключен энкодер.
// Подробнее см.:
// https://tsibrov.blogspot.com/2019/06/arduino-interrupts-part2.html
PCICR |= (1 << PCIE1);
PCMSK1 |= (1 << PC0);
}
void loop()
{
uint8_t temp = 0;
// Если пластик ещё не выбран, показываем меню выбора.
// Затем запускаем прогрев.
if (filament == NULL) {
turn_off();
choose_filament();
clear_screen();
reset_timer();
heating_stage = Idle;
refresh_screen = true;
}
// Если идёт сушка и время подошло к концу, показываем сообщение,
// пищим, ожидаем нажатия на кнопку энкодера и снова показываем
// меню выбора пластика.
if (heating_stage == Working && seconds > filament->time_sec) {
turn_off();
clear_screen();
screen.setCursor(0, 0);
screen.print("Finished!");
beep(2000);
delay(1000);
beep(2000);
delay(1000);
beep(2000);
screen.setCursor(0, 1);
screen.print("Press any key...");
while (wait_for_action() != ActionConfirm)
;
filament = NULL;
return;
}
temp = query_sensor();
set_heater_state(temp);
if (refresh_screen) {
refresh_screen = false;
update_screen(temp);
}
}
Общий алгоритм следующий. После включения сушилки предлагаем выбрать пластик из заранее подготовленного списка. Вращением энкодера находим нужный и подтверждаем выбор нажатием на кнопку энкодера. Включается предварительный прогрев до заданной температуры. Когда температура достигнута, стартует обратный отсчёт времени и начинается её поддержание периодическим включением нагрева. Когда время выйдет, включается звуковой сигнал и сушилка ожидает нажатия на кнопку энкодера. После этого управление возвращается снова к выбору пластика.
Дополнительные детали
Для крепления и размещения плат, дисплея и энкодера замоделил и напечатал несколько деталей. В первую очередь перенёс на заднюю сторону сушилки выключатель и добавил разъём, чтобы кабель подключения к сети был съёмным:

Собираем корпус для плат дисплея, управления и энкодера:



Между передней панелью и дисплеем вклеиваем кусочек толстой плёнки для защиты экранов планшетов чтобы дисплей не сильно пылился.
Далее собираем силовую часть. Плату крепим к днищу на уголки. Добавляем стеклянный предохранитель на 2 А в разъёмном корпусе:

Термодатчик крепим максимально близко к трубе нагревателя, чтобы он обязательно находился в потоке выходящего воздуха. Это необходимо для максимально быстрой реакции на изменение температуры и наиболее точных показаний. Пробовал разместить датчик на периферии, поближе к краю, однако это сильно увеличивает время реакции и погрешность поддержания заданной температуры. К тому же, как показали измерения и эксперименты, за счёт высокой скорости потока воздуха и достаточной мощности нагревателя, разница в температуре непосредственно у выхода из трубы и на периферии у края не превышает 3℃. Датчик крепим за кабель кусочком листовой латуни:

Собираем всё вместе. В итоге получаем вот такой аппарат:

Сразу же отвечая на резонный вопрос — а не поплавятся ли печатные детали, особенно внутри сушилки? Нет, не поплавятся. Всё напечатано из PLA. В «подвале» сушилки температура едва превышает комнатную, поскольку именно снизу крыльчатка вентилятора забирает воздух. Тестовый прогон в течение суток при максимальной температуре 70℃ с последующей разборкой и исследованием деталей никаких деформаций не выявил. Для полной уверенности можно напечатать их из ABS. Тогда они точно выдержат, поскольку корпус самой сушилки отлит из именно этого пластика, и делать детали более термостойкими нет никакого смысла.
Испытания
Полагая, что лучше один раз увидеть и услышать, чем десять раз прочитать, записал видео с демо-прогоном сушки. В целях сокращения его длительности частично разобрал корпус и прошил код, в котором время сушки нейлона уменьшено до 15 секунд:
Заключение
Предыдущую попытку доработать сушилку eSun eBOX нельзя назвать совсем уже полным провалом, кое-что улучшить мне всё-таки удалось. Однако и разогнать температуру выше 48℃ не получилось даже после нескольких часов непрерывной сушки.
В данном случае ситуация совсем иная. Благодаря более мощному нагревателю и более быстрому потоку воздуха доработанная овощесушилка легко и непринуждённо набирает температуру 70℃ меньше чем за минуту. Вдобавок, за счёт адаптированного под себя управления ею намного удобнее пользоваться — достаточно просто выбрать нужный пластик, всё остальное (температура и время) уже настроено заранее. При необходимости всегда можно добавить другие пластики и новую функциональность.
Так что этой переделкой я остался крайне доволен. Да, к сожалению эту сушилку не выйдет поставить рядом с принтером и печатать прямо из неё, как позволяет eBOX. Зато свою основную задачу она теперь выполняет отлично.
Стоит ли повторять мою доработку — решать исключительно вам. С точки зрения стоимости деталей и материалов, а также затрат времени и труда она невыгодна. Намного быстрее, проще и дешевле купить любую овощесушилку, подходящую по размерам, функциональности и характеристикам. А таблицу с температурой и временем сушки просто напечатать на бумаге и приклеить прямо на корпус.
Однако, если у вас есть время и желание сделать что-то своими руками, то результат этих трудов вполне окупится и порадует.
На этом всё, благодарю за внимание! Вопросы и конструктивная критика — приветствуются.
Ссылки
Схема и платы в EasyEDA.
Модели печатных деталей.
Самые обсуждаемые обзоры
+44 |
1922
67
|
+141 |
3075
68
|
+77 |
2104
90
|
можно еще поставить на датчики весов и сообщать сколько влаги было удалено :)
К 5 кг датчику подвесил 2.5 кг и оставил на выходные — в понедельник получил 2.4 кг и «0» уплыл на те-же 0.1 кг.
Есть хоть какие-то замеры? Или так, «к слову пришлось»?
Кстати, вместо AM2302 лучше поставить BME280, там как раз тоже i2C
Если что, в машинах летом даже белый PLA плывёт )
Или одновременно нельзя использовать по каким-то другим причинам?
Ещё можно сделать фильтры на дырках, чтобы пыль отсеивать и провести тефлоновую трубку напрямик к экструдеру.
А вот это уже интересная идея, спасибо! Надо будет подумать…
Вообще, держатель катушки можно закрепить как угодно, можно даже за стенки сушилки — было бы желание, пластик и небольшое умение чертить 3д модели.
Както так, нюансы уже по месту))
зы. конструкцию лучше делать съемной — тогда сушилку и для фруктов можно использовать пока не печатаете…
Аналогично, когда после океанских купаний с гопро и не полной просушкой увидел испарину внутри стекла. Стеклянный лоток для обедов с пластиковой крышкой с резиновым уплотнителем и пакетик туда с камерой с открытым батарейным отсеком и вся влага высосана и без подогрева и циркуляции…
Кстати, одноюнитовые вентилляторы от серверов по даташиту выдерживают +70, и их везде как грязи…
Ключевой момент здесь в том, что в случае с силикагелем греть всё до 90 не нужно, а значит подойдёт любой практически вентилятор на подшипниках, коими серверные и являются, и не нужно колхоза с выносом мотора вне зоны нагрева. В вашей же таблице написано, что силикагель сушат при 65 :) вот и дайте +70, что вписывается в паспортную температуру вентиллятора.
Можно и без движения. Греть немного ускоряет процесс, но когда уйма времени, то можно и не греть
Сушите повторно силикагель в сушке при 65, храните в стеклянной банке с крышкой. Да бросайте в коробку с филаментом, и найдите способ контроля влажности в коробке: 5% — аларм — меняем силикагель.
Я просто не знаю, насколько достоверно работают датчики влажности при околонулевом её значении.
Ну аналогия не совсем уместна. Памперсы и кошачие лотки впитывают органику, которая даже после сушки не уйдёт из материала. Например азотосодержащие соединения.
А в случае с силикагелем это чистый водяной пар. Что делает его идеальным для повторного использования. Испарил пар и вперёд.
Привёл их в пример потому, что силикагель добываю в формате наполнителя для лотка, и что после его использования по назначению никто ни про какие RRR не вспоминает — просто берут и вываливают в общий мешок с мусором.
С сухим силикагелем — не розовеет.
Я его добываю из упаковок многокилобаксовых свичей в пакетиках, не россыпью… Ну и из посылок от digikey. Остановился добывать когда набрал пару кило :)
Вентилятор – как вариант разносить двигатель и крыльчатку по разным местам.
Но ломать решётки не очень хочется.
Пусть остаются целые для грибов и яблок.
Поэтому если буду делать то скорее всего просто подниму верхнюю крышку дистансером.
Прикидывал его высоту — нужно миллиметров 50-60.
Если принтер был бы побольше то можно его напечатать.
Или отрезать полосу тонкого пластика и, соединив концы, свернуть её в трубу нужного диаметра.
Но чисто из рук и головы из правильного места респект и уважуха, за проделанную работу.
Или еще добавлю напоминает как народ тратит время на моделирование и печать несколько часов того, что легко и быстро делается из деревяшек, уголков, алюм профилей и сопоставимой иди даже меньшей цене )) Если че — сам 3Д печатник )
3D-принтер откатает её легко и играючи. Даже без поддержек, они тут не требуются. Вообще, проникнувшись миром 3D печати, быстро понимаешь, что одна из главных проблем — понимание того, когда печать уместна и когда — нет.
Плюс еще учиться моделировать тоже интереснее на чем-нибудь простом, но нужном, что потом будет печататься и в идеальном случае использоваться.
Да, и то что можно сделать быстро из деревяшек и уголков, моделить вообще минуты. Дольше печататься будет, но и за деревяшками нужно ехать покупать.
Я бы ещё добавил пункт «кастом», где можно накрутить самому температуру и время. Так, чисто для обратной совместимости с сушкой фруктов :)
А потом этот режим, я так думаю, и стал бы самым основным и удобным
Эту сушилку никакие дополнительные пункты не уже спасут. После выпиливания промежуточных решёток склеил их на первый попавшийся в руки клей для пластика, никак не заботясь о его санитарной пригодности. Потому как кроме пластика сушить мне больше всё равно нечего. Но в целом идея о возможности что-то перенастроить — годная. Именно это я и подразумевал в заключении: "при необходимости всегда можно добавить другие пластики и новую функциональность".
Иногда используется предварительное охлаждение воздуха с целью вымораживания влаги, но и здесь свое веское слово говорит экономика: энергия на вымораживание 1г влаги — одна и та же, а влагосодержание забортного воздуха в большинстве случаев ниже, чем выбрасываемого после сушки. Так зачем тратить лишнюю энергию там, где можно не тратить? :)
Извините, не вижу термопары в оригинальной конструкции. По логике повествования сюда просится «регулятор температуры».
Стрелка указывает на саму биметаллическую пластину. С этого ракурса её действительно плохо видно.
Добавить туда аналогичное управление, но скорее даже удаленное, через Blynk.
Там как раз воздух по кругу гоняется. Заодно очень заинтересовала новомодная фишка типа «закалки» деталей в мелкой соли, в кухонной духовке не охота пластики «жарить».
В начале сушки, когда испаряется много влаги нужно подмешивать много сухого воздуха. В конце, когда последние капли влаги испаряются можно делать рециркуляцию почти без подмеса.
Можно датчик влажности прилепить. Но это актуально если электроэнергия дорогая.
На глазок можно 95% воздуха отправлять на рециркуляцию, а 5% подмешивать, постепенно вся влага выйдет. А в сушилках полностью воздух выбрасывается, что приводит к затратам электроэнергии на подогрев…
А можно ссылку на модель задней накладки? (ту, где выключатель и гнездо питания).Все, разобрался.
cad.onshape.com/documents/48613eff7021a5a121f711d3/w/77d1ae8fef780ecb373c445f/e/9dde7ee88f23dc3bf9cb27f3