28 ноя 2017 (OFF) Zhumarin (P) : "Умный" фонарь




Или немного о том, как тупой фронтендер фонарь делал.

Ещё в начале сентября я закупился 100W светодиодом, кулером LGA775, повышающим DC-DC и аккумулятором на 12Ah. И только на позапрошлых выходных я собрал это в кучу. (время было только на выходных, в рабочие дни недели я этим не занимался, как некоторые коллеги могут подумать)

Забегая наперёд, что получилось:
1. Почти 130 Вт потребления при 100% яркости, ёмкость аккумулятора 12V * 12Ah в идеале 145 Вт. т.е около часа работы при максимальной яркости.
2. В идеале 8500 люмен, если верить китайцам. Хочу в будущем на более яркий заменить.
3. 101 уровень яркости, управление через энкодер. Сохраняется во внутреннюю flash.
4. Стробоскоп 15-1000 Гц. Сделал только потому что мог сделать. Поигрался минут 10 на вращающихся предметах и забить.
5. Брутальный кустарный внешний вид, при этом весит 5 кг.

В итоге схема пришла к такому виду:




Но перед этим я наступил на кучу граблей...

Идея

Идея простая - собрать достаточно яркий фонарь, с защитой от перегрева светодиода и плавным управлением яркостью. Наверное, это всё можно было заменить на самое просто термореле и NE555, но это не наши методы. Слишком просто!

Поэтому решено было делать это всё вокруг отладочной платы STM32.
С первого взгляда всё просто:
1. Переменный резистор к stm32
2. Полевой транзистор между DC-DC и светодиодом.
3. Крутим резистор - считываем через ADC напряжение - меняем скважность PWM
4. Прикручиваем ds18b20, чекаем температуру и занижаем яркость при перегреве (>50C).
5. При остывании - возвращаем яркость обратно.

Всё просто? Справится даже школьник с ардуиной? А вот хуй.

Проблема первая. Укрощение полевика.
Изначально я планировал подключить полевой транзистор прямо к ноге таймера STM32. Напрямую. Но тут меня ждал крупный фэйл. Да, полевик действительно может управляться от 2-4V на гейте.




Вот только работает он при этом в линейном режиме, а не как ключ. От чего его сопротивление не минимальное, заметно ограничивает ток и греется.
Что бы вывести MOSFET транзистор в ключевой режим - нужно около 10-12 вольт на гейт, но STM32 на ноге выдаёт не более 3.3V.

Логичное решение - сделать простейший усилитель, с эмиттерным повторителем на выходе.

Изначально в гуглении готовых решений управления мосфета от 3.3V я наткнулся на комплиментарный эмиттерный повторитель.




Я тогда ещё не знал его свойства - усиливает ток, а напряжение дублирует. А мне нужно было ещё и напряжение поднять.
Поэтому нужного мне результата не добился. А заодно спалил почти десяток STM32, т.к. не поставил токоограничительный резистор между ногой STM32 и входом эмиттерного повторителя. В итоге между эмиттером и базой протекал слишком большой ток и stm32 выгорала. К сожалению, слишком поздно это понял.

После этого, я изучил тонну теории и испробовал на практике кучу разных вариантов в онлайн симуляторе: http://www.falstad.com/circuit/circuitjs.html

И начал делать усилитель^W драйвер для MOSFET примерно по такой схеме:



Было ОЧЕНЬ много вариантов.

Я даже писал расчёт усилительных и ключевых каскадов на JS:
https://zhumarin.ru/ra/1/
https://zhumarin.ru/ra/2/
https://zhumarin.ru/ra/3/
https://zhumarin.ru/ra/

БЕСПОЛЕЗНО! Просто заваливались фронты и плыла заполненность PWM при высокой частоте (100-200 khz). Устанавливаешь 50% - а там 70% по факту.
У меня не было осцилографа, что бы заняться отладкой и пофиксить этот баг.

Со временем я устал от этих попыток запилить хэнджоб драйвер и я купил готовый - MC33151PG.

Проблема вторая. КРУТИСТОР ШУМИТ.
Ну не сам крутистор, конечно. Идея была такая:
1. Подключаю потенциометр как делитель напряжения. Крайние к 3.3V и GND, а средний в ADC. Типа так:


2. Читаю ADC, меняю заполненность PWM.

Всё просто, никаких проблем не должно быть. Но и тут я настрадался:
1. У меня оказались только обратно логарифмические потенциометры. А нужны были линейные. Пробовал программно переводить логарифм в линейный по таблице, но результат не понравился. Пришлось докупать линейные.
2. Внезапно, мои отладочные платы STM32 как-то шумят в опорное напряжение. Там нет отдельного опорного напряжения. И нормального фильтра для него.
В итоге значение ADC даже при КЗ с gnd скачет до 5 (из 4095), а в потенциометре - ещё больше, до десятка и выше. Зависит от позиции.
Что я только не делал. И экранированный провод, и конденстаторы подбирал и хитрые алгоритмы усреднения делал. В итоге всё равно получалась хрень, даже если удавалось задушить помехи, то образовывались две заметные мёртвые зоны у потенциометра. В самом начале и в самом конце. Мне это не понравилось.

Без осцилографа это сложно победить и я просто отказался от потенциометра в пользу очень крутой штуки - энкодера.

На этом этапе я даже пару раз психанул. Заменял STM32 на простой ШИМ регулятор на NE555. Только всё равно мне не понравилось. 100% заполненности при 100% яркости не добиться (т.е. просто 1 лог на выходе) без сложных костылей. Ещё и при регулировании яркости на минимальных значениях как-то дребезжало, моргало при прокрутке потенциометра. Ещё и частота плыла.

Проблема третья. Энкодер ШУМИТ.
В STM32 энкодер вешается на таймер. Энкодер генерирует импульсы и таймер по ним увеличивает/уменьшает свой счётчик и генерирует IRQ при переполнении. Обычно Энкодер настраивают на один щелчок (импульс), а далее в обработчике прерывания определяют направление и инкрементят/декрементят нужную переменную.

Я так же попробовал. В итоге, направление было часто совсем рандомное, а не то, в какую сторону я кручу.

НО ПРИ ЭТОМ. Если установить IRQ при 100 щелчках, то внутренний счётчик таймера правильно инкрементился и декрементился от 0 до 100, без лишних скачков, ровно в ту сторону, в которую я кручу. С высокой точностью. Но при этом я не нашёл способа генерировать прерывание, когда меняется внутренний счётчик таймера. Он умеет генерировать его только при переполнении.

Поэтому я не нашёл ничего лучше, как заюзать второй таймер и с определённым интервалом читать текущее значение у первого таймера. И если оно изменилось более, чем на 90%, то считать это переполнением.

Получился простой код:

volatile void TIM2_IRQHandler() {
++sched_counter;

int cnt = TIM_GetCounter(TIM3);
if (last_counter != cnt) {
// Фиксим переполнение счётчика энкодера (вправо ENCODER_MAX->0 и влево 0->ENCODER_MAX)
if (cnt - last_counter > ENCODER_OVERFLOW_MAX) {
counter_fixer -= ENCODER_MAX;
} else if (cnt - last_counter < -ENCODER_OVERFLOW_MAX) {
counter_fixer += ENCODER_MAX;
}
last_counter = cnt;
encoder_value = cnt + counter_fixer;
recalc_pwm_value();
}

TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
Который крутит encoder_value на любое кол-во в минус и в плюс.

Проблема четвёртая. ЛОГАРИФМЫ.
Даже после замены регулятора на энкодер - яркость всё равно не регулировалась плавно. Вначале плавно, около 30%, потом резко слишком ярко. И вот тут я понял, что человек воспринимает уровень яркости не линейно, а почти по логарифмической кривой!
В итоге написал простой генератор:

<?php
$n = 101; // Количество уровней яркости
$max_pwm = 1000; // Максимальный уровень PWM
$pwm_lightness_table = array();
for ($x = 1; $x <= $n; ++$x) {
$y = (1 - log($x, $n));
$pwm = round($max_pwm * $y);

$pwm_lightness_table[] = $pwm;

echo "$x: ".round($y * 100, 2)."% ".$pwm."\n";
}
echo "\n{".implode(", ", array_reverse($pwm_lightness_table))."}\n";
Который генерирует 101 уровень яркости (примерно полный оборот энкодера на 360 градусов)
И всё стало круто и плавно.

Немного о конструкции
Есть один интересный чел на YouTube, AlexGyver, я как-то наткнулся на один его видос про аналогичный фонарь:
11:22



Но он имеет фатальные недостатки:
1. DC-DC без стабилизации тока! Т.е. никак не может являться драйвером светодиода.
2. Регулировка яркости через регулятор напряжения повышайки?)
Ни о какой плавности не может идти речь, а в куче с п1 может превысить максимально допустимый ток.
3. Ёмкость аккумулятора всего 11.1V * 3.3Ah = 36 Вт
При этом автор заявляет про 1 час на максимальной яркости.
Тут два вариант - он приукрасил/неправильно посчитал или же светодиод работает не на полную мощность, DC-DC не выдаёт нужный ток.

Но при этом у него очень крутая идея в плане корпуса - использовать канализационные фитинги и кулер от LGA775, который идеально входит в 110-ю трубу.

Поэтому блок со светодиодом был реализовано в точности, как на видео. (только очень криво)






Сам корпус дальше хоть и использует канализационные трубы, но уже сильно отличается. За основу взята муфта и редуктор 150 -> 110




Блок электроники.
Вся электроника аккуратно смонтирована внутри редуктора. Всё, кроме платы контроля, привинчено на болты. Только она на приклеенных канцелярских кнопках зафиксирована. Дополнительно завернул в пакет от STM32, что бы если отвалится - не было КЗ.




Сама плата контроля выглядит так:

Содержит в себе DC-DC 12V -> 5V, STM32 и ключи управления индикатором статуса.




Крепёж аккуумулятора.
Изначально я планировал использовать 110-ю трубу, но аккумулятор туда не влез. Я просчитался немного. Поэтому пришлось использовать муфту 150-ку и редуктор 150 в 110.

После этого аккумулятор стал слишком маленьким для муфты

Но я нашёл выход - обклеил пенопластом корпус изнутри (на термосопли)
И покрыл его антистатик пакетами от использованных STM32.




Правда в итоге пришлось отказаться от некоторых пенопластовых блоков, ради циркуляции воздуха. Воздух проходит через весь корпус к радиатору светодиода.




Задняя крышка
Задняя крышка внутри не особо интересна. Изнутри обклеена сеткой от комаров, что бы внутрь не всасывались крупные предметы. Дополнительно наклеил кусок пенопласта, что бы жёстко фиксировать аккумулятор.




Внешний вид
В итоге фонарь выглядит так:













Задняя часть выглядит не очень, а всё потому, что:
1. Изначально планировался встроенный Power Bank, но lm7805 слишком греется при 1A и я пока отказался от этой идеи. А дырка осталась - заменил её на включатель зарядки и вольтметра.
2. Тактовых кнопок не было, поэтому стробоскоп включается тумблером. В будущем заменю на кнопку, можно будет сделать много режимов, кроме стробоскопа.

Планирую в будущем заменить и сделать как изначально хотел, есть запасная заглушка.

Сама софтовая часть доступна тут: https://github.com/Azq2/stm32_fonarik
223 0 7 0
Комментарии (6)
Шыдееевр!!!!!
Огонь!

А зачем два светодиода параллельно? Там, где написано status led.

Почему не помогают хитрые алгоритмы усреднения? Лаг до 300мс будет комфортен, до 100мс вообще незаметным.
Мёртвые зоны по краям ведь можно убрав просто растянув значения. Можно растянуть нелинейно.
Один вопрос, зачем тебе фонарь с таким количеством уровня яркости?
А с этим фонарём видно кол-во задач, в которых тебя очень ждут?
100 Вт всё-таки.
чтобы траву выращивать
А я в тумблер их вставил. Там красный прозрачный пластмасс.
Да может и можно было. Но я тогда не знал про логарифм и "не линейность" яркости была решающим фактором. Думал, что это от резистора, т.к. и на ne555 такой "баг" был.
А после всех плюсов энкодера возвращаться на резистор уже не захотелось.
Показать комментарий
Скрыть комментарий
Для добавления комментариев необходимо авторизоваться
Драконы
Погрузитесь в мир чудесных драконов, раскинувшем...
Версия: Mobile | Lite | Touch