Печать

Проекты (Автор: dez)

Несколько лет назад мне казалось, что большинством моих проектов здесь будут прикольные эксперименты типа светомузыки. Теперь же складывается впечатление, что основным источником идей для моих постов является гараж. Собственно, в этот раз получилось примерно так же.

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

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

 

Не так быстро, ковбой!

Первое, с чем нужно было разобраться - изменение скорости вращения. Обычно в таких станках ставят асинхронные двигатели и частотные преобразователи, но в нашей задаче другие исходные данные и тип двигателя уже определен - как было сказано, это коллекторный двигатель постоянного тока. Таким двигателем можно управлять путем изменения напряжения питания. Что, в принципе, достаточно просто и сразу наводит на мысли про ШИМ и транзистор. Но здесь будет немного по-другому, потому что эта зверюга может жрать до 70 А при напряжении 27 В. Источника "ровного" напряжения под такие аппетиты не было, зато был сварочный трансформатор, мощные диоды и тиристоры размером почти с кулак. Как известно, с тиристорами есть нюанс - мы их можем только открывать, а вот закрываться они будут сами каждый раз, когда сетевое напряжение переходит через ноль. Поэтому нас ждет фазовое регулирование.

Фазовое регулирование на выпрямителе / Controlled rectifier

Долго разбираться с этим вопросом не пришлось - интернет подсказал готовую схему тиристорного регулятора (из журнала Электрик 2004/08), удачно подходившую под наши обстоятельства. В этой схеме между трансформатором и двигателем стоит управляемый выпрямитель - диодный мост, в котором два диода заменены на тиристоры. Сигналы для тиристоров формируются "мозгами" на основе 561ЛА7 (удобно, еще один винтаж из закромов). Для питания "мозгов" используется отдельные вторичная обмотка и мост.

Схема диммера / dimmer schematic

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

Практика показала, что двигатель вполне неплохо уживается с управляемым выпрямителем. Было только одно замечание по логике работы "мозгов" - они подают сигнал на тиристоры с задержкой, как и положено, но вот снимают сигнал всегда под самый конец полуволны. Поэтому, если поддать газку, ток через управляющие электроды тиристоров будет идти практически постоянно, а ток им нужен приличный - около 200 мА. Этот же ток проходит через резисторы номиналом 91 Ом, которые все это время будут зря нагреваться.

Нюансы фазового регулирования

Впрочем, недостатки "мозгов" на 561ЛА7 меня мало волновали - они были обречены на замену, ведь нам нужно нечто большее, чем ручной диммер. Главное, что сам принцип работает, и можно двигаться дальше.

 

Круиз-контроль

Теперь можно думать в сторону поддержания оборотов и индикации - сочетания, которое просто кричит: "Ставь микроконтроллер!".

Результат получился следующий. Рулит станком Atmega8 - классический выбор для классических задач. В мозгах у атмеги крутится алгоритм ПИД-регулятора (точнее, ПД в текущем варианте). Естественно, ПИД-регулятор подразумевает наличие обратной связи, поэтому к ноге ICP1 (модуль захвата) подключен оптический датчик. Еще нужно иметь в виду, что в качестве ключей у нас стоят тиристоры, и открывать их надо в определенные моменты времени - но об этом позже. Требуемая установка числа оборотов вводится посредством двух кнопок, также предусмотрен альтернативный вариант - потенциометр. И не забываем про тумблер для запуска двигателя :) Наконец, вывод измеренного и заданного числа оборотов идет на два 7-сегментных светодиодных дисплея, подключенных через регистры 74HC595.

Конструкцию в этом проекте решил делать модульную - разнес схему на несколько маленьких плат, выполняющих какие-то свои отдельные функции. Заодно смог повторно использовать кусок предыдущей схемы, поскольку "прототип" также был предусмотрительно разделен на две платы. Получилось примерно то, что на упрощенной схеме ниже.

Диммер на Atmega8

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

Начнем с датчика скорости. Это единственный элемент электроники, который крепится непосредственно на станке, поэтому его выбор вызвал много споров по части конструкции. Изначально речь шла об индукционном датчике - предполагалось, что мы спрячем его внутрь корпуса двигателя и он там будет считать зубья шестеренки на валу. Однако задумка со встраиванием оказалась слишком сложной, а сам датчик - довольно медленным. Второй идеей был оптический датчик аналогичный тому, что использовался когда-то в БСЗ. Принцип проверенный, работающий, и все с ним было бы идеально, если бы не одно но - проходящими через щель метками должны стать гайки винтов на наружной стороне шкива. Мне не нравилось то, что такому датчику придется выйти за габариты станка и его можно будет случайно зацепить, поэтому я какое-то время колебался и пытался придумать еще варианты. Например, нарисовать на шкиве метку и считывать ее по отражению света, но были сомнения - например, не сотрется ли она? В рамках мозгового штурма даже проскочила мысль прислонить к главному шкиву энкодер с колесиком от мышки, но идея моментально была признана бредовой, потому что при таком огромном соотношении диаметров шкива и колеса датчик просто рассыпется от скорости.

В конечном итоге, идеи лучше не нашлось и мы остановились на щелевом оптическом датчике, срабатывающем от гаек. Первый вариант был собран на базе компаратора LM393. Какое-то время он проработал нормально, но потом начал периодически играть в молчанку с симптомами, похожими на микротрещину. И прежде чем микротрещина была найдена, на датчике возникла еще и макротрещина. Станок тогда стоял посреди мастерской, к нему был подход сбоку, и в какой-то момент датчик просто задели. Да так задели, что он переломился пополам, в полном соответствии с моими первоначальными опасениями.

Второй вариант датчика был сделан без моего участия из того, что было - из россыпи КТ315 и выводных резисторов. Текущая схема приведена ниже. Почему там составной транзистор? Когда с первой платы снимали фототранзистор, его приняли за фотодиод и перестаховались. Ладно, работать датчику это не помешало в итоге. Также на этот раз плату датчика сделали чуток пошире, для прочности и чтоб вибрации не доканали. Сейчас станок поселился в отдельном углу, так что ходить датчик не мешает и прохожие ему больше не угрожают :)

Схема датчика скорости / Speed sensor schematic

Крепление датчика / Sensor mounting

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

Самым логичным местом для этого транзистора оказалась плата источника питания. Основная ее задача - сделать 5 В для питания микроконтроллера, дисплеев и датчика. На вход эта плата как раз получает пульсирующее напряжение размахом около 20 В, которое берется с выпрямителя на плате драйвера тиристоров. Ну а раз уж оно здесь, то тут же можно и детектор нуля развернуть. Главное - не забыть про конденсатор на входе стабилизатора напряжения. Чтобы он не вмешивался в работу детектора, его нужно "изолировать" при помощи диода.

Источник питания и детектор нуля / Power supply and zero detector

Замечание: Как видите, я поставил линейный стабилизатор 7805, и на нем падает 15 В. Хотя потребление по цепи 5 В не превышает 150 мА, с таким падением даже этого тока хватает, чтоб пекло. Поэтому стаб установлен на радиатор - просторный корпус с отверстиями позволяет так шикануть. Получилось адекватно - не обжигает, но теплый. Но, конечно, импульсник был бы лучшим решением.

От детектора нуля ожидались короткие (<1мс) импульсы каждые 10 мс, так как после выпрямителя частота становится 100 Гц. Однако, уже при первых включениях на столе оказалось, что детектор пропускает каждый второй полупериод, потому что напряжение после моста через раз немного не доходит до нуля.

Осциллограмма / oscillogram

Проблема временно ушла, когда я слегка нагрузил мост, прицепив к клеммнику резистор 6.8 кОм. Но потом она все равно вылезла на станке. Причина осталась для меня загадкой - может, это связано с намагничиванием сердечника трансформатора, а может, с чем-то другим... В любом случае, это возможно обойти программным способом. Частоту напряжения в сети мы знаем - она равна 50 Гц и достаточно стабильна, поэтому микроконтроллеру несложно предсказать момент следующего перехода.

Остается загнать сигнал с детектора в контроллер и написать код. Подать эти импульсы можно на любую ногу с прерываниями, например INT0/1. Я же решил использовать встроенный компаратор и подключил выход детектора к ноге AIN1. На ноге AIN0 сделал 2.5 В делителем из резисторов, хотя в принципе ничего не мешает использовать внутренний источник 1.2 В.

void AnaComp_Init(void){
    ACSR = (1<<ACI) | (1<<ACIS1); //cброс флага, прерывание по FALLING
    DDRD |= (1<<PD5); //OUT (упр. тиристорами)
    PORTD &= ~(1<<PD5);
    ACSR |= (1<<ACIE); //разрешить прерывания
}

В коде магия управления тиристорами происходит в двух функциях - прерывание компаратора и прерывание по совпадению таймера 2. Интервал открытия тиристора задается через глобальную переменную dimLevel. Она может принимать значения от 0 до 255, где 0 - ключи закрыты, а 255 - "рев мотора, полный газ до упора". В прерывании компаратора это значение "инвертируется", загрубляется до 32 градаций и сохраняется в локальную переменную dLev. Загрубляется для упрощения работы с таймером и потому что этой точности достаточно, а "инвертируется" потому, что мы будем работать с задержкой открытия тиристоров - чем больше число, тем позже они откроются и тем меньше двигателю достанется тока.

Дальше на основании значения dLev принимается решение: открыть тиристоры сразу, отложить этот торжественный момент на потом или вообще ничего не делать. Если открыть тиристоры нужно с задержкой, то взводится таймер 2 - в прерывании по совпадению будет выдан сигнал на тиристор. Если требуется вжарить по полной (dLev=0), то тиристоры открываются тут же, в прерывании компаратора (оно ж как раз в начале полупериода). При этом опять-таки взводится таймер 2, но уже затем, чтобы он потом снял управляющий сигнал. Получается, что одно прерывание таймера может делать два разных дела, поэтому двум разным обработчикам прерываний нужно договариваться между собой, чем сейчас заниматься. И делают они это через переменную dimState.

Что касается пропусков в синхронизации, то этот вопрос решается парой строк в функции прерывания таймера. В тот момент, когда она снимает управляющий сигнал, нужно повторить поведение прерывания компаратора - установить флаг ожидания в dimState и поставить будильник. В самом простом случае - на длительность полупериода. Тогда если прерывание компаратора не сработает, благодаря будильнику следующий полупериод повторит предыдущий. Правда, если при потере синхроимпульса dimLevel изменится между двумя такими прерываниями таймера, то новое значение не будет принято в расчет. С этим можно мириться, если импульсы теряются через раз (наш случай), но если импульсы теряются чаще или могут пропасть полностью - есть риск полностью потерять управление. Поэтому крайне желательно потерю слишком большого числа сихроимпульсов воспринимать как аварию. Для отлова таких ситуаций можно, например, завести переменную dimErrorCount, которая увеличивается в прерывании таймера, а при получении синхроимпульса обнуляется.

#define D_STATE_WAIT 0
#define D_STATE_ON 1

 

#define D_ERR_LIMIT 5

 

volatile uint8_t dimLevel = 0; //интервал открытия тиристора (0-255)
volatile uint8_t dimState = D_STATE_WAIT; //слежение за управл.
volatile uint8_t dimErrorCount = 0; //пропуски синхронизации
ISR(ANA_COMP_vect){
    uint8_t dLev = 31 - (dimLevel>>3); //пока 32 градации
    dimErrorCount = 0;
    if(dLev>=0x1F) {
        PORTD &= ~(1<<PD5);
        TIMSK &= ~(1<<OCIE2); //выкл таймер
    } //--!выкл
    else if(dLev==0){ //на полную (открыть без задержки!)
        dimState = D_STATE_ON;
        PORTD |= (1<<PD5);
        TCNT2 = 0; //сброс таймера
        OCR2 = 6; //удерживать затвор ~800 us
        TCCR2 = (1<<CS22) | (1<<CS21) | (1<<CS20); //div 1024, 1 тик = 128 us
                //полупериод примерно 80 тиков
        TIFR |= (1<<OCF2); //сброс флага
        TIMSK |= (1<<OCIE2); //разрешить прерывания таймер 2
    } //--!на полную
    else{
        dimState = D_STATE_WAIT;
        TCNT2 = 0; //сброс таймера
        OCR2 = 3 + (dLev<<1); // max = 3 + (31*2) = 65
        TCCR2 = (1<<CS22) | (1<<CS21) | (1<<CS20); //div 1024, 1 тик = 128 us
        TIFR |= (1<<OCF2); //сброс флага
        TIMSK |= (1<<OCIE2); //разрешить прерывания таймер 2
    }
}//--!прерывание компаратора

 

ISR(TIMER2_COMP_vect){
    TCNT2 = 0;
    if(dimErrorCount>D_ERR_LIMIT){ //авария - синхронизация потеряна
        PORTD &= ~(1<<PD5); //не открывать тиристоры
        TIMSK &= ~(1<<OCIE2); //выкл таймер
    } //--!авария
    else if(dimState == D_STATE_WAIT){
        ACSR &= ~(1<<ACIE); //запрет прерыв компаратора
                    //(защита от помех, да и зачем он?)
        OCR2 = 6; //удерживать затвор ~800 us
        PORTD |= (1<<PD5);
        dimState = D_STATE_ON;
    }
    else if(dimState == D_STATE_ON){
        dimErrorCount++; //один сигнал обработан, ждем обнуления в ANA_COMP
        PORTD &= ~(1<<PD5);
        ACSR |= (1<<ACIE); //снова разрешить прерыв компаратора
        dimState = D_STATE_WAIT;
        OCR2 = 74; // 80-6 вкл еще раз через полупериод
   }
}

В принципе, вот и весь код, отвечающий за управление тиристорами. Остается только в main() менять значение dimLevel и получать результат. Конечно, в идеале он напрашивается на то, чтобы его переработали, допилили и спрятали в отдельный модуль, но для одного хобби-проекта и для демонстрации принципа в рамках этого поста вполне сойдет.

Замечание: Для дополнительной отзывчивости в случае пропусков в сихронизации можно было бы пересчитать задержку, а не ставить будильник жестко на длительность полупериода. Но для данного устройства нет большого смысла с этим заморачиваться, потому что частота изменения dimLevel даже близко не подойдет к 100 Гц.

И еще один нюанс - задержка на подачу управляющего сигнала в этом примере рассчитывается по простой линейной формуле. Но напряжение регулируется синусоидальное, и при одинаковых шагах задержки напряжение меняется резче в середине полупериода, чем по краям. Более продуманный код фазового регулирования, возможно, включал бы в себя коррекцию с помощью таблицы или формулу посложнее. С другой стороны, лучшее - враг хорошего, не чини то, что не ломалось :) ПИД-регулятор нормально отрабатывает, цели достигнуты, и это главное.

 

Happy End

На этом все, что я хотел сказать про получившийся блок управления двигателем. Остальные работы над прошивкой состояли уже из привычных вещей - кнопки, дисплей, получение оборотов, потенциометр на АЦП и все такое. Особого внимания заслуживает разве что алгоритм ПИД-регулирования, но это большая отдельная тема и вряд ли я расскажу лучше, чем статья Тима Уэскотта, с помощью которой ПИД, собственно, и делал. Добавлю только, что при выборе частоты выполнения цикла управления остановился на значении 12.5 Гц, а обороты регулируются в диапазоне от 300 до 3000 об/мин.

Если не считать одного поломаного датчика, наладка станка прошла без сюрпризов и заключалась по сути в подборе коэффициентов ПИД-регулятора. Сейчас блок управления более-менее отлажен, обзавелся корпусом и активно используется. Значит, не зря старался.

Статья опубликована 2021-05-04 18:32:32, её прочитали 3592 раз(а).