Electronic
Вертушка с моторчиком
В этом проекте Arduino будет управлять вращающейся с помощью моторчика вертушки.
Управлять моторами с помощью Arduino намного сложнее чем управлять светодиодами. Во-первых, моторы требуют больше тока чем может дать Arduino. Во-вторых, моторы могут сами генерировать электрический ток за счет являния, называемого индукцией, и этот ток может повредить элементы схемы. Однако, моторы приводят в движение разные вещи, и от этого проекты становяться интереснее. В общем оно того стоит.
Для того, чтобы что-то двигать, требуется много энергии. Кроме того, что моторы требуют больше тока, чем дает Arduino (только 40мА на цифровом выходе), некоторым так же нужно более высокое напряжение. В момент начала движения или при высоких нагрузках, потребление тока также может значительно возрастать.
С помощью транзисторов, подсоединенных к Arduino можно решить эту проблему. Транзисторы позволяют управлять большим током и источниками питания с высоким напряжением с помощью небольшого управляющего тока, который уже может идти от Arduino. Существует можество разновидностей транзисторов, но принцип действия у всех одинаковый. В нашем примере транзистор лучше представить как цифровой выключатель. Есть подать напряжение на один из выходов транзистора (затвор), то он замыкает два других выхода (сток и исток). Таким образом можно включать и выключать высоковольтные и высокоамперные моторы при помощи Arduino.
Электромотор — это индуктивное устройство. Индукция — это являние возникновения изменяющегося магнитного поля вокруг провода, по которому протекает изменяющийся электрический ток. Внутри электромотора есть катушка с плотно намотанным на нее медным проводом. Когда на мотор подается электрический ток, внутри этой катушки возникает магнитное поле. Это магнитное поле заставляет вал двигателя вращаться.
В обратную сторону индукция тоже работает: мотор может вырабатывать электричество, если вращать его вал. Если подключить к выходам мотора светодиод и начать вращать вал двигателя, то диод будет светиться. Так можно превратить мотор в маленький электрогенератор.
Если прекратить подавать электричество, то он по инерции продолжает какое-то время вращаться. Пока он вращается, он вырабатывает электрический ток, противоположный по направлению тому, который его вращал. Этот ток называют «обратным током», он может вывести из строя транзистор. Чтобы избежать этого, параллельно с мотором надо подключить диод и обратный ток будет проходить через диод.
С учетом всего вышесказанного схема для управления мотором получается такая:
Поскольку для мотора требуется много энергии, он питается от дополнительного источника — 9-ти вольтовой батерейки. И так получается, что управление транзистором производится с помощью Arduino, а сам мотор запитан от дополнительного мощного источника электроэнергии. Обязательное правило, которое следует соблюдать если в схеме используется несколько источников энергии — минусы всех источников должны быть соединены вместе.
Теперь, когда макет готов, осталось написать программу:
int motor=9; //пин управления мотором int switchButn=2; //кнопка включения мотора int switchButnVal=0;//значение считанное с кнопки включения мотора void setup(){ Serial.begin(9600); pinMode (switchButn,INPUT); pinMode(motor,OUTPUT); } void loop(){ switchButnVal=digitalRead(switchButn);//считываем состояние кнопки Serial.println(switchButnVal); if(switchButnVal==HIGH){ digitalWrite(motor,HIGH);//если кнопка нажата включаем мотор } else{ digitalWrite(motor,LOW);//если не нажата — выключаем } }
Работает вот так:
Чтобы за вращением наблюдать было интереснее, мы сделали деревянный диск, наклеили на него разноцветный рисунок, и подсоединили к мотору.
Если скорость вращения мотора уменьшить, то на диске с рисунком, который крутиться, можно увидеть интересный оптический эффект. Для управления скоростью вращения в схему добавили потенциометр, и на затвор транзистора подаем напряжение от 0 до 5В, в зависимости от положения потенциометра. Программа чуть-чуть увеличилась.
int motor=9; //пин управления мотором int switchButn=2; //кнопка включения мотора int switchButnVal=0;//значение считанное с кнопки включения мотора int pot=A0; // пин с потенциометром int potVal=0;//значение считанное с потенциометра int Val=0;//значение выдаваемое на пин управления мотором void setup(){ Serial.begin(9600); pinMode (switchButn,INPUT); pinMode(motor,OUTPUT); } void loop(){ potVal=analogRead(pot);//читаем значение с потенциометра Val=map(potVal,0,1023,0,254); // в значение для вывода switchButnVal=digitalRead(switchButn);//считываем состояние кнопки Serial.println(switchButnVal); if(switchButnVal==HIGH){ analogWrite(motor,Val);//если кнопка нажата включаем мотор } else{ digitalWrite(motor,LOW);//если не нажата — выключаем } }
Паяем LOL shield
Человек, умеющий что-то делать своими руками, обычно вызывает симпатию и уважение у родных и близких. Можно бесконечно долго собирать проекты на макетных платах. Можно даже собирать очень сложные схемы. Например такие:
Но для того, чтобы сделать законченное устройство, скорее всего, придется паять. Не обязательно «травить» плату.
Можно использовать монтажную плату типа такой:
Вобщем пришло время обзавестись паяльником и овладевать навыками. Мы приобрели небольшой набор для паяния со всем необходимым:
А также небольшой конструктор типа DIY, чтобы было на чем тренироваться. Состоит он из небольшой печатной платы, на которую надо припаять светодиод, кнопочку и батарейку. В собранном виде выглядит вот так:
Но самое интересное было дальше. После того, как несколько таких штук было успешно спаяны и раздарены бабушке с дедушкой мы решились на нечто грандиозное. Есть такой интересный проект LOL Shield для Arduino. На одной плате 126 светодиодов. Плата подключается с Arduino использует все его выходы, кроме двух. Получается такая свето-диодная матрица. Можно на ней бегущую строку делать, можно мультики рисовать или игрушки делать. Вобщем со всех сторон полезная вещь. Распространяется она в виде набора деталей, которые надо самостоятельно спаять.
Вот все детали, которые предстоит соединить вместе с помощью паяльника и припоя:
Поначалу объем работ пугает: припаять на плату 126 диодов, это 252 контакта. Но глаза боятся...
Вставляем первый ряд:
Переворачиваем плату и понеслась:
Пять часов прошли незаметно, шаг за шагом, светодиодная панель готова:
Пока мы с Арсением паяли, Фёдор успел поспать, а рядом пристоился котик:
К LOL Shield есть несколько бибилиотек для вывода текста, бегущей строки, картинок. Есть даже тетрис. Мы немного допилили программу для тетриса, так что стало можно с помощью потенциометров управлять фигурками. На некоторое время это стало любимой игрой Федора:
А вот небольшой ролик, который демонстрирует некоторые возможности этой игрушки:
В этом ролике еще нет потенциометров для управления, немного позже мы приделали вместо потенциометров нормальный джойстик. Но это уже в следующих сериях.
Электронные клавиши.
C помощью нескольких резисторов и нескольких кнопок мы собираемся сделать небольшой электро-клавишный инструмент.
В принципе, можно подключить несколько выключателей к цифровым входам и использовать их для воспроизвдения различных нот. Но в этом проекте мы будем конструировать что-то вроде резисторной матрицы.
С помощью этого приёма можно считывать нажатия нескольких клавиш, используя только один аналоговый вход. Это очень полезно, когда обнаруживается недостаток в цифровых входах. Несколько выключателей соединяются параллельно с аналоговым входом Arduino и плюсом, на минус они подключаются через общий резитор. На плюс большая часть выключателей подсоединяется через свой резитор. С таким подключением при нажатии различных кнопок на пине будет разное наряжение. Если нажать несколько кнопок одновременно, на входе получится другое значение, в зависимости от того какие резиторы оказались соединёнными параллельно.
Схема подключения этого всего к Arduino выглядит так:
Первый выключатель подсоединяется к плюсу напрямую без резистора, второй — через резистор на 220 Ом, третий — через резистор на 10кОм, четвёртый — через резистор на 1МОм. Вторые выходы выключателей соединяются с аналоговым входом Arduino и через общий резистор в 10кОм идут на 0. В общем получается схема делителя напряжения, которую мы уже использовали.
Собранный макет:
Программа, с помощью которой вся эта шарманка будет играть:
int notes[]={ 262,294,330,349};//ноты до-фа (массив) int keys=A0;//клавиши int speak=8;//пьезоэлемент void setup(){ pinMode(speak, OUTPUT); Serial.begin(9600); } void loop(){ int keysVal=0;//переменная для хранения значения клавиши keysVal=analogRead(keys); Serial.println(keysVal); if (keysVal==1023){ tone(speak,notes[0]); } else if ( (keysVal>=990)&&(keysVal<=1010)){ tone(speak,notes[1]); } else if ( (keysVal>=505 )&&(keysVal<=515)){ tone(speak,notes[2]); } else if( (keysVal>=5)&&(keysVal<=10)){ tone(speak,notes[3]); } else{ noTone(speak);//если ничего не нажато, замолчать } }
Для того, чтобы программа могла воспроизвести ноты, она должна где-то хранить список частот, для каждой ноты. Мы будем играть ноты до, ре, ми, фа (262Гц, 294Гц, 330Гц и 349Гц). Для этого в программе мы используем массив.
Массивы используют для хранения списков однотипных элементов, например, частоты нот, используя одно имя переменной. Это достаточно удобный инструмент для быстрого и эффективного доступа к информации. Массив объявляется так же как и обычная переменная, но после её имени следует пара квадратных скобок []. Если нужно присвоить значения сразу всем элементам массива, то после знака равенства эти значения перечисляются через запятую и обрамляются фигурными скобками {}.
Для того, чтобы прочитать значения из массива, к массиву обращаются по имени и в квадратных скобках указать индекс (номер) конкретного элемента. Номера элементов в массиве начинаются с нуля. Первый элемент имеет индек 0, второй — 1 и т. д.
Теперь небольшое описание программы:
Сначала мы создаем массив с частотами звуков, которые будем воспроизводить. В функции setup() указываем режим работы выхода, к которому подключен пьезоэлемент и включаем консоль (она нам нужна, чтобы определить какие значения за аналоговом входе будут выдавать нажатия различных кнопок).
В основной программе, сначала мы считываем значение с аналогового входа, затем выводим его на консоль. Этими двумя строчками мы ограничились в первом варианте программы и запустили её, записали значения, кототорые получали на входе при нажатии разных кнопок. Поскольку для каждой кнопки значения немного отличались для разных нажатий, то мы решили использовать не конкретные предпределённые значения, а интервалы. В зависимости от интервала, в котором находится считанное со входа значение, мы выдаем тот или иной тон, частоты берем из нашего массива. Если ни одна из кнопок не нажата, то даем команду «замолчать».
Небольшое видео:
Использование сервопривода.
Сервопривод — это такие типы двигателей, которые не крутятся все время по кругу, а поворачиваются на определённый угол и останавливаются до тех пор, пока им не поступит другая команда повернуться. Сервопривод обычно поворачиваются только на 180 градусов (половина круга). Если присоединить к такому мотору вырезанную из картона шкалу, можно использовать его в качестве указателя чего-нибудь, например, настроения.
Аналогично тому, как мы использовали ШИМ для управления светодиодами в опыте с «лампой-хамелеоном», сервопривод ожидает поступления определенного количества импульсов, чтобы понять, на какой угол ему надо повернуться. С аналогового выхода Arduino импульсы всегда поступают через один и тот же временной интервал, но продолжительность их меняется от 1000 до 2000 микросекунд. Программу, которая генерирует такие импульсы написать не очень сложно самим, но среда разработки Arduino уже включает в себя специальную библиотеку для управления моторами. Поскольку сообщество разработчиков для Arduino достаточно велико, существует великое множество дополнительных программ и библиотек для разных сенсоров, актуаторов и прочих устройств, которые могут взаимодействовать с Arduino. И мы этим тоже будем пользоваться.
Схема, которую мы будем собирать выглядит так:
Один контакт потенциометр подсоединяем на плюс, второй — на минус, подвижный контакт — к аналоговому входу Arduino. При вращении ручки потенциометр, напряжение между подвижным контактом (входом Arduino) и минусом будет изменяться, это изменение мы будем «читать» и управлять вращением сервопривод.
Сервопривод тоже имеет три контакта: два — питание (плюс и минус), третий для управления, его подсоединяем с выходу Arduino.
Когда сервопривод начинает движение, ток, проходящий через него, значительно больше, чем во время самого движения, из-за этого происходить сильное падение напряжения во всей схеме. Если подключить два конденсатора параллельно сервопривод и потенциометр, можно это сгладить. Такие конденсаторы называют «развязывающие» или разделяющие, так как они отделяют изменения, произведенные какими-либо компонентами, от остальной схемы.
Итак, макет готов:
Теперь пишем программу:
#include<Servo.h> //используем библиотеку для управления сервоприводом Servo motor; //наш мотор int potens=A0; //пин потенциометра int motorpin=9; //пин мотора int potensVal=0; //значение потенциометра int angle; //угол поворота сервопривода void setup(){ motor.attach(motorpin); //подключаем мотор Serial.begin(9600); } void loop(){ potensVal=analogRead(potens);//читаем положение потенциометра Serial.print(«potensVal: „); Serial.print(potensVal); angle=map(potensVal,0,1023,0,179);//преобразуем в градусы Serial.print(“, angle: „); Serial.println(angle); motor.write(angle);//поворачиваем мотор delay(15); }
Небольшой комментарий по преобразованию значения, считанного с потенциометр, в градусы. С аналогового входа Arduino можно считать значение от 0 до 1023, в зависимости от напряжения на нем. В случае с потенциометром мы задействует все эти значения. На аналоговый выход Arduino мы может подать значение от 0 до 254, а в случае с сервоприводом, в команду движения мы вообще можем передавать значения только до 179. То есть нам надо пропорционально преобразовать значения из интервала [0;1023] в интервал [0;179]. У Arduino для этого есть специальная функция map(), в качестве первого параметра мы передаем значение, которое надо преобразовать, в качестве второго и третьего — границы первого интервала, четвертое и пятое — границы второго интервала. В результате функция возвращает преобразованное значение, которое уже можно использовать. После команды поворота добавлена небольшая пауза, чтобы сервопривод успел повернуться. Фу… вроде все.
На консоль мы выводим значение, прочитанное с потециометра и уже преобразованное значение (угол поворота сервопривод).
Теперь мы решили вместо потенциометр поставить в схему термосенсор, и поворачивать сервопривод в зависимости от внешней температуры. Немного изменили программу:
void loop(){ tempVal=analogRead(tempPin); float v=(tempVal/1024.0)*5.0; float t=(v-0.5)*100; Serial.print(» temperature: «); Serial.print(t); angle=map( t, 15, 35,0,179); Serial.print(«, angle: „); Serial.println(angle); motor.write(angle); delay(1000); }
Преобразовываем значение, считанное с термосенсор, в градусы, как мы это уже делали. В функции map() мы указали интервал от 15 до 35, потому что именно в этих пределах будет меняться температура в нашем опыте, и сервопривод будет поворачиваться на все 180 градусов при изменении температуры.
angle
Blinking LED, dimming LED.
Ещё две схемы Арсений собрал и запрограммировал самостоятельно.
Первая: управление частотой моргания диода при помощи потенциометра.
К аналоговому входу Arduino подключается потенциометр, с его помощью мы будем менять напряжение на на входе и регулировать частоту моргания диода, который подключим к цифровому входу.
int led1=3; int onoff=A0;//потенциометр int onoffVal=0; void setup(){ pinMode(led1,OUTPUT); } void loop(){ onoffVal= analogRead(onoff);//считываем данные с потециометра delay(onoffVal);//делаем паузу длинной в зависимости от потециометра digitalWrite(led1,HIGH);//включаем диод delay(onoffVal);//делаем паузу в зависимости от потециометра digitalWrite(led1,LOW);//выключаем диод }
Слово Арсению:
Вторая схема — модифицированный вариант первой, добавили еще один светодиод и при помощи ШИМ (использованной в предыдущем опыте) регулируем его яркость. В схему добавилось еще два элемента:
В прогамму две строки: в функцию инициализации:
pinMode(led2,OUTPUT);
И в конец основной программы:
analogWrite(led2,onoffVal/4);
Поскольку с аналогового входа (от потенциометра) мы получаем значение в диапазоне от 0 до 1023, а на выход можем подавать значение от 0 до 255, мы отправляем на выход значение в четыре раза меньшее чем на входе.
И снова Арсений:
Лампа хамелеон (color mixing lamp)
В этом проекте, мы будем использовать трехцветный светодиод и три фоторезистора, чтобы сделать лампу, которая плавно меняет свой цвет, в зависимости от внешних условий освещения.
Arduino не может менять напряжение на выходах, оно может быть либо 0, либо 5 вольт. Однако для плавного изменения яркости светодиода можно использовать технику под названием широтно-импульсная модуляция (ШИМ). ШИМ с высокой частотой включает и выключает напряжение на выходе. Это происходит так быстро, что при подключении к такому выходу светодиода человеческих глаз не может это различить. Когда вы бысто меняете на выходе HIGH и LOW, это как если бы вы меняли напряжение. Часть времени, когда на выходе HIGH, называется рабочим циклом. Чем больше рабочий цикл, тем ярче светится светодиод.
Для проекта мы использовали фоторезисторы (сенсоры, которые меняют свое сопротивление в зависимости от количества света, которое на них попадает). Если эти фоторезисторы подсоединить к Arduino, то можно измерять изменение сопротивления, измеряя напряжение на входе Arduino, к которому подключен сенсор.
Вот схема, которую мы будем собирать:
На каждый из трех фоторезисторов мы наденем цветную пленку (красную, синюю и зеленую). Благодаря этому на каждый из сенсоров будет попадать только свет опраделенной длины волны (цвета) и можно будет определить примерный уровень освещенности.
Трехцветный светодиод состоит из трех раздельных элементов (красный, зеленый и синий), которые имеют общий катод (минус). Подавая напряжение на контакты светодиода, которые подсоединены к аналоговым (ШИМ) выходам Arduino (обозначены на плате ~), мы будем плавно изменять его цвет. Для включения режима ШИМ на выходах Arduino используется команда analogWrite().
Макет готов:
После долгих трудов мы с Арсений получили вот такую программу:
int redSens=A0;//красный фоторезистор pin int greenSens=A1;//зелёный фоторезистор pin int blueSens=A2;//синий фоторезистор pin int redLed=11;//красный диод int blueLed=10;//синий диод int greenLed=9;//зелёный диод int redVal=0;//выводим накрасный диод int greenVal=0;//выводим на зелёный диод int blueVal=0;//выводим на синий диод int redSensVal=0;//показания красного фоторизистора int blueSensVal=0;//показания синего фоторизистора int greenSensVal=0;//показания зелёного фоторизистора void setup(){ pinMode(redLed,OUTPUT); pinMode(blueLed,OUTPUT); pinMode(greenLed,OUTPUT); Serial.begin(9600); } void loop(){ //считываем показания фоторизисторов redSensVal=analogRead(redSens); delay(5); greenSensVal=analogRead(greenSens); delay(5); blueSensVal=analogRead(blueSens); redVal=redSensVal/4; greenVal=greenSensVal/4; blueVal=blueSensVal/4; //выводим значения на экран компьютера Serial.print(«sensor Values \t Red: „); Serial.print(redSensVal); Serial.print(“ „); Serial.print(redVal); Serial.print(“\t Green: „); Serial.print(greenSensVal); Serial.print(“ „); Serial.print(greenVal); Serial.print(“\t Blue: „); Serial.print(blueSensVal); Serial.print(“ „); Serial.println(blueVal); analogWrite(redLed,redVal); analogWrite(greenLed,greenVal); analogWrite(blueLed,blueVal); }
Здесь надо прокомментировать, что с аналоговых сенсоров мы получаем значения в диапозоне от 0 до 1023, а выводить на аналоговые выходы может значения от 0 до 254, по этому предварительно значения из одного диапазона надо «привести» к значениям из другого диапазона, в данном случае мы просто делим на 4.
Для большей зрелищности на светодиод мы надели шарик для пинпонга и получили такой небольшой светильник:
Heat-o-Meter (измерение температуры).
Arduino можно использовать для измерения температуры.
Переключатели и кнопки — замечательно, но реальный мир вокруг не всегда можно описать двумя состояниями (вкл. и выкл.)
Немного теории:
Несмотря на то, что Arduino — это цифровое устройство, оно может получать информацию с аналоговых сенсоров для измерения температуры или освещенности. Для этих целей необходимо использовать встроенный в Arduino аналого-цифровой перобразователь (АЦП). Аналоговые входы A0-A5 выдают значение от 0 до 1023, что соответствует напряжению от 0 до 5-ти вольт.
Для измерения температуры мы использовали температурный сенсор (TMP 36).
Этот компонент изменяет напряжение на выходе в зависимости от температуры окружающей среды. Датчик имеет три контакта: один подсоединяется на «ground», второй — на «power», а третий, который выдает изменяющееся напряжение, подсоединяется к Arduino. В программе для этого проекта мы будем считывать значения, которые выдает сенсор, и использовать их для включения и выключения светодиодов для индикации температуры.
Теперь к практике. Как обычно, сначала рисуем «схему»:
В собранном виде на макетной плате, она выглядит так:
В среде разработки (IDE) Arduino есть терминал, который позволяет получать и просматривать информацию с микроконтроллера. С использованием этого терминала, можно отображать на экране компьютера информацию, считываемую с сенсоров, а потом придумать, как ее обработать и дописать программу.
Вот такая получилась программа, для считывания и вывода информации с сенсора:
int spin = A0; //датчик температуры void setup(){ Serial.begin (9600);//для вывода на экран компьютера } void loop(){ int sVal = analogRead(spin);//Считываем информацию с сенсора Serial.print(«Sensor Value: „);//выводим значение на экран компьютера Serial.print(sVal); //конвертируем значение в вольты float v=(sVal/1024.0)*5.0; Serial.print(“, Volts: „); Serial.print(v); Serial.print(“, degrees C: „); //переводим вольты в градусы float t=(v-0.5)*100; Serial.println(t); }
В этой программе использована команда Serial.begin(9600), с помощью неё открывается соединение между Arduino и компьютером. Функция analogRead() считывает значение с аналогового входа и возвращается значение от 0 до 1024, в зависимости от напряжения. Функция Serial.print() отправляет информацию с Arduino на компьютер, затем эта информация отображается в терминале.
Как расчитывается температура? Сначала необходимо понять сколько вольт получается на выходе термосенсора. Поскольку всего может быть 1024 значения (от 0 до 1023), а напряжение от 0В до 5В, используется формула [значение на аналоговом входе]* 5В/1024. Затем по документации на этот термосенсор переводим выдаваемое им напряжение в градусы по шкале Цельсия t=(v-0.5)*100.
Вот как выглядят результаты работы программы:
Теперь программируем работу светодиодов. Базовой температурой будем считать 23 градуса (такая температура была у нас в комнате). Если термосенсор нагревается на 2 градуса — загорается первый диод, еще на 2 (всего на 4) — второй диод, затем еще на 4 градуса (всего на 8) — третий диод.
Параллельно а работой над программой мы решили, что будет интереснее сделать светодиоды разноцветными:
Вот наша программа:
int spin = A0; //датчик температуры float basetemp= 23.0; //комнатная температура int led1 = 2;//красный int led2 = 3;//жёлтый int led3 = 4;//зелёный void setup(){ Serial.begin (9600);//для вывода на экран компьютера pinMode(led1,OUTPUT); pinMode(led2,OUTPUT); pinMode(led3,OUTPUT); digitalWrite(led1,LOW); digitalWrite(led2,LOW); digitalWrite(led3,LOW); } void loop(){ int sVal = analogRead(spin); Serial.print(«Sensor Value: „);//выводим информацию на экран компьютера Serial.print(sVal); //конвертируем значение в вольты float v=(sVal/1024.0)*5.0; Serial.print(“, Volts: „); Serial.print(v); Serial.print(“, degrees C: „); //переводим вольты в градусы float t=(v-0.5)*100; Serial.println(t); if(t<basetemp){//температура поднимается на 2 градуса — ничего не горит digitalWrite(led2,LOW); digitalWrite(led3,LOW); digitalWrite(led1,LOW); } else if( (t>=basetemp+2)&&(t<basetemp+4) ){//температура подниамется от 2 до 4 градусов горит только зеленый digitalWrite(led2,LOW); digitalWrite(led3,HIGH); digitalWrite(led1,LOW); } else if( (t>=basetemp+4)&&(t<basetemp+8) ){ digitalWrite(led2,HIGH); digitalWrite(led3,LOW); digitalWrite(led1,LOW); } else if (t>=basetemp+8){ digitalWrite(led2,LOW); digitalWrite(led3,LOW); digitalWrite(led1,HIGH); } }
Результаты работы программы: