Озвучка самокатов, часть 1: зачем нам пьезокерамика и как ее готовить

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

В Софт, хард и два колеса: как мы строили IT-инфраструктуру в Whoosh упоминалось, что первые версии IoT мы ставили под непрозрачную крышку, замещая стандартный модуль управления от самоката Xiaomi M365. То есть, после установки и проклеивания крышки, связь с модулем была только через облако. В идеальном мире этого было бы достаточно, но реальность диктовала условия, в которых нужна индикация процессов — как в режиме обслуживания, так и в городе, у пользователей. Прием управляющих команд, отправка телеметрии, подключение к сети и выход устройств в онлайн — разные этапы нужно было различать сервисной команде для быстрой диагностики, а пользователя — предупреждать об изменениях в базовых сценариях использования — командах, ошибках, ограничениях и т.д. Отдельная тема для рефлексии — методы озвучки тихого электротранспорта для повышения пассивной безопасности в условиях шумной городской среды.

Ок, нужны звуки — решили ставить buzzer (или зуммер). Это такая электромеханическая штуковина, которая под воздействием внешнего переменного напряжения умеет деформироваться и издавать звуки.

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

Немного теории

Зуммеры обычно бывают двух типов - электромагнитные и пьезокерамические. Первые работают на более низких напряжениях и более высоких токах (~ 1.5V - 12V, >20mA), а вторые — наоборот (~ 12V - 200V, <20mA). В электромагнитных зуммерах ток пропускается через катушку, которая создает магнитное поле; гибкий ферромагнитный диск притягивается к катушке при наличии тока и возвращается в положение покоя, когда ток через катушку не протекает — такими колебаниями и создается звук. Это устройство, управляемое током; ток, проходящий через катушку, определяется приложенным напряжением и собственным импедансом.

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

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

У Murata есть неплохой документ Piezoelectric Ceramic Sensors — там нет именно зуммеров, но есть много интересного про пьезоэлектрическую керамику, используемую в сенсорах (вообще, зуммеры тоже можно заставить генерировать ЭДС, воздействуя на них механически). А у TDK есть каталог Piezoelectronic buzzers, откуда отдельно хотелось бы извлечь следующие утверждения (к ним вернемся чуть позже, в описании схемы управления):

  • Do not apply DC bias to the piezoelectric buzzer; otherwise insulation resistance may become low and affect the performance

  • Do not supply any voltage higher than applicable to the piezoelectric buzzer

Ключевые характеристики зуммеров:

  • Frequency Response — насколько эффективно зуммер воспроизводит звук на заданной частоте

  • Sound Pressure Level (dB Pa) – уровень звукового давления, представляет собой отклонение от атмосферного давления, вызванное звуковой волной, выраженное в децибел-паскалях. Обычно он пропорционален входному напряжению и затухает на 6dB при удвоении расстояния от зуммера

  • Resonant Frequency (Hz) — все вещи имеют определенную частоту, на которой они склонны вибрировать, эта частота называется резонансной. Для зуммеров резонансная частота — та, при которой они звучат наиболее громко

  • Impedance (Ohm) — электрический импеданс представляет собой отношение приложенного напряжения к току и зависит от частоты

  • Mounting — зуммеры доступны в различных установочных конфигурациях в зависимости от необходимости применения: монтаж на панель, винтовые клеммы, пружинный контакт, монтаж на поверхность, сквозное отверстие, проволочные выводы и многое другое

Установка в IoT модуль

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

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

Внутри них нет никакой дополнительной электроники — лишь пластина керамики (на последнем фото, кстати, не пьезокерамический излучатель, а магнитный) с выводами для DIP монтажа в печатную плату. Существуют излучатели, на которые достаточно подать напряжение питания — и они звучат на одной единственной частоте, что создает готовое решение — подключай, подавай питание и звучи. Это удобно, когда не нужно перегружать схему модуляцией управляющего сигнала, но у нас все равно стоял микроконтроллер с кучей аппаратных таймеров, да и хотелось оставить возможность играть сложные звуки и мелодии.

Теперь несколько слов про то, как этим управлять.

Основы управления

Для раскачки требуется внешний возбуждающий сигнал — обычно используют транзистор, усиливающий воздействие. Для магнитного зуммера дополнительно ставят диод отсечки обратного напряжения, возникающего при быстром закрытии ключа. В схеме управления пьезозуммером диод уже не нужен, поскольку индуктивность его мала, но требуется параллельный резистор сброса напряжения при разомкнутом ключе. Вот пример типичной схемы управления из гайда от TDK c одним транзистором:

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

Murata в документации приводит следующие схемы раскачки, собранные на RC цепочках, транзисторах или логических элементах:

Можно избавиться от резистора сброса, используя комплементарную пару транзисторов, работающих в режиме полумоста. А можно пойти дальше и поставить два полумоста, работающих в противофазе: то есть, собрать полный мост, состоящий из четырех ключей. Преимущество ее состоит в том, что повышается доступное напряжение питания, дважды (чем мы и воспользуемся чуть позже) и как следствие — повышается громкость звука на ~6dB.

В первой версии IoT мы использовали N-канальный MOSFET, затвор которого раскачивается таймером микроконтроллера в режиме capture/compare — это аппаратный PWM с возможностью установки частоты и скважности импульсов. Приблизительный код управления можно найти в статье STM32: FreeRTOS и пьезокерамический излучатель.

В итоге, звуковой семпл описывается структурой BuzzerSample_t, мелодия - массивом структур; разные потоки RTOS накидывают семплов в очередь, а поток-драйвер динамика разбирает ее и проигрывает мелодию:

typedef struct
{
	NOTE_t Note;
	u32 Amplitude;
	u32 Duration;
	u32 Pause;
} BuzzerSample_t;

Вот как выглядит вступление Start Wars - The Imperial March:

#define BUZZER_STAR_WARS_DURATION_DEF	130
#define BUZZER_STAR_WARS_PAUSE_DEF		25

static BuzzerSample_t StarWarsBuff[] =
{
	{.Note = NOTE_G4, .Amplitude = BUZZER_AMPL_MAX, .Duration = 4 * BUZZER_STAR_WARS_DURATION_DEF, .Pause = BUZZER_STAR_WARS_PAUSE_DEF},
	{.Note = NOTE_G4, .Amplitude = BUZZER_AMPL_MAX, .Duration = 4 * BUZZER_STAR_WARS_DURATION_DEF, .Pause = BUZZER_STAR_WARS_PAUSE_DEF},
	{.Note = NOTE_G4, .Amplitude = BUZZER_AMPL_MAX, .Duration = 4 * BUZZER_STAR_WARS_DURATION_DEF, .Pause = BUZZER_STAR_WARS_PAUSE_DEF},
	{.Note = NOTE_Ds4, .Amplitude = BUZZER_AMPL_MAX, .Duration = 3 * BUZZER_STAR_WARS_DURATION_DEF, .Pause = BUZZER_STAR_WARS_PAUSE_DEF},
	{.Note = NOTE_As4, .Amplitude = BUZZER_AMPL_MAX, .Duration = 1 * BUZZER_STAR_WARS_DURATION_DEF, .Pause = BUZZER_STAR_WARS_PAUSE_DEF},
	{.Note = NOTE_G4, .Amplitude = BUZZER_AMPL_MAX, .Duration = 4 * BUZZER_STAR_WARS_DURATION_DEF, .Pause = BUZZER_STAR_WARS_PAUSE_DEF},
	{.Note = NOTE_Ds4, .Amplitude = BUZZER_AMPL_MAX, .Duration = 3 * BUZZER_STAR_WARS_DURATION_DEF, .Pause = BUZZER_STAR_WARS_PAUSE_DEF},
	{.Note = NOTE_As4, .Amplitude = BUZZER_AMPL_MAX, .Duration = 1 * BUZZER_STAR_WARS_DURATION_DEF, .Pause = BUZZER_STAR_WARS_PAUSE_DEF},
	{.Note = NOTE_G4, .Amplitude = BUZZER_AMPL_MAX, .Duration = 8 * BUZZER_STAR_WARS_DURATION_DEF, .Pause = BUZZER_STAR_WARS_PAUSE_DEF},

	{.Note = NOTE_D5, .Amplitude = BUZZER_AMPL_MAX, .Duration = 4 * BUZZER_STAR_WARS_DURATION_DEF, .Pause = BUZZER_STAR_WARS_PAUSE_DEF},
	{.Note = NOTE_D5, .Amplitude = BUZZER_AMPL_MAX, .Duration = 4 * BUZZER_STAR_WARS_DURATION_DEF, .Pause = BUZZER_STAR_WARS_PAUSE_DEF},
	{.Note = NOTE_D5, .Amplitude = BUZZER_AMPL_MAX, .Duration = 4 * BUZZER_STAR_WARS_DURATION_DEF, .Pause = BUZZER_STAR_WARS_PAUSE_DEF},
	{.Note = NOTE_Ds5, .Amplitude = BUZZER_AMPL_MAX, .Duration = 3 * BUZZER_STAR_WARS_DURATION_DEF, .Pause = BUZZER_STAR_WARS_PAUSE_DEF},
	{.Note = NOTE_As4, .Amplitude = BUZZER_AMPL_MAX, .Duration = 1 * BUZZER_STAR_WARS_DURATION_DEF, .Pause = BUZZER_STAR_WARS_PAUSE_DEF},
	{.Note = NOTE_Fs4, .Amplitude = BUZZER_AMPL_MAX, .Duration = 4 * BUZZER_STAR_WARS_DURATION_DEF, .Pause = BUZZER_STAR_WARS_PAUSE_DEF},
	{.Note = NOTE_Ds4, .Amplitude = BUZZER_AMPL_MAX, .Duration = 3 * BUZZER_STAR_WARS_DURATION_DEF, .Pause = BUZZER_STAR_WARS_PAUSE_DEF},
	{.Note = NOTE_As4, .Amplitude = BUZZER_AMPL_MAX, .Duration = 1 * BUZZER_STAR_WARS_DURATION_DEF, .Pause = BUZZER_STAR_WARS_PAUSE_DEF},
	{.Note = NOTE_G4, .Amplitude = BUZZER_AMPL_MAX, .Duration = 8 * BUZZER_STAR_WARS_DURATION_DEF, .Pause = BUZZER_STAR_WARS_PAUSE_DEF},

И вот, как оно проигрывается на керамическом и на магнитном излучателях:

Если с частотой все понятно, то с амплитудой уже чуть сложнее. Технически, тут она вообще не применима — излучатель раскачивается постоянным напряжением в ключевом режиме. Однако, на практике максимальная звуковая амплитуда достигается при симметричном сигнале (скважность импульсов 50%) и смещение в любую сторону от середины ослабляет звук, подмешивая соседние гармоники, которые иногда проявляются даже сильнее, чем основная частота:

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

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

Обновленный hardware дизайн

В новой версии IoT мы выбрали PKM22EPPH4012 (или его аналог от L-KLS3-PT-22*08). Это был самый большой излучатель, чьи размеры идеально подходили для установки на печатную плату и в корпус, не превышая допустимых габаритов расположения в рулевой стойке.

АЧХ все еще плохая — но я и не видел керамических излучателей, где бы она была ровной формы — ну не предназначены они для воспроизведения музыки.

Для раскачки взяли микросхему DRV88703.6-A Brushed DC Motor Driver. Да, она позиционируется, как микросхема управления щеточным мотором, но по сути является мостовым драйвером, а значит умеет не просто переключать выход от нуля до питающего, а инвертирует напряжение, попеременно подавая его то на одну обкладку, то на другую, увеличивая амплитуду колебаний излучателя в два раза.

Тут стоит отметить, что мы нарушили правило из гайда от TDK и запитали мостовой драйвер напряжением 25V, что дает напряжение 50Vp-p на излучателе. Хотя, не совсем так, но до этого еще доберемся.

Согласно таблице управления драйвером, для смены направления приложенного напряжения, на входы IN1/IN2 нужно подавать взаимно инверсные сигналы; в остальных случаях драйвер засыпает, переводя выходы в Hi-Z или же вешает их на землю.

Лучшим решением было бы использовать таймер, который умеет выдавать комплементарный PWM, но насколько сейчас могу вспомнить, эти выводы были заняты, а complementary output PWM доступен на сильно ограниченном числе таймеров. Инвертор на входе нужен как раз для того, что бы переключаться от одной ножки микроконтроллера, но с его использованием связан неприятный нюанс — ведь как было сказано выше, на излучатель не рекомендуется прикладывать постоянную составляющую напряжения. А подать нужную для отключения комбинацию на IN1/IN2 невозможно - не позволит инвертор. В нашем случае решение пришло из разряда “не баг, а фича” — мы просто запитали мостовой драйвер от DC-DC конвертора, который в выключенном состоянии на выходе имеет напряжение со входа — 5V. А это ниже минимально допустимого напряжения питания драйвера и он просто отключается. Повезло то, что нужно!

Но ведь мы стремились повысить громкость за счет увеличения напряжения, а не только силами мостового драйвера, разве нет?

Да. Вот так:

DC-DC можно включать и отключать, используя вход ENABLE. Но этого мало — нужно еще уметь корректировать выходное напряжение. Оригинальная формула расчета выхода выглядит так:

Vout = \dfrac{\dfrac{R1}{R2}+1}{Vref}

Но есть классный способ добавить внешнее управление, используя DAC + дополнительный резистор R3 в цепи ОС — в такой схеме выход DC-DC поддается линейной регулировке внешним сигналом. Формула выходного напряжение принимает следующую форму:

Vout = Vref * (1 + \dfrac{R1}{R2}) + (Vref-Vdac) * \dfrac{R1}{R2}

Cигнал +25V_DAC ∈ [0, 3.3]V — в нашем случае, это выход RC low-pass фильтра на ножке таймера, настроенного на частоту фильтра. DAC в MCU можно использовать тоже, но лучше таймер — небольшие колебания и ослабление фильтра не критичны, а закладывать в схему DAC, которого может не быть в чипе, не хотелось. В итоге имеем следующие выходные граничные напряжения:

>>> 1.23 * (1 + 169/10) - (169/27.4) * (0.0 - 1.23)
29.603496350364964
>>> 1.23 * (1 + 169/10) - (169/27.4) * (3.3 - 1.23)
9.249481751824817

Отлично, тюнить дальше уже можно программно, подстраивая параметры PWM сигнала. Более подробно технику Digital Adjustment of DC-DC Converter Output Voltage можно найти в статьях:

  • https://www.analog.com/en/technical-articles/digital-adjustment-of-dcdc-converter-output-voltage-in-portable-applications.html

  • https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/196/1373.slyt777_5F00_Methods-of-output_2D00_voltage-adjustment-for-dcdc-converters.pdf

  • или по запросу dc dc feedback adjustment.

Хоть технически на пьезопластине и не бывает 50V сигнала, но попеременная инверсия 25V раскачивает ее в обе стороны на удвоенную амплитуду, что слегка выходит за допуски, заложенные производителем. В любом случае, теперь есть возможность контролировать приложенную амплитуду программно.

Раз у нас есть функционал настройки амплитуды, можно совсем убрать управление скважностью частотозадающего сигнала, а всю настройку DC-DC конвертора обернуть в одну функцию, где параметр ampl задает диапазон выходного напряжения:

#define TIM_DACPWM_MIN_PWM		0
#define TIM_DACPWM_MAX_PWM		100

void Pl_Buzzer_SetAmpl(float ampl)
{
	ASSERT_NORM_FLOAT(ampl);
	CUT_NORM_FLOAT(ampl);

	u8 amplTIM_PWM = ampl * TIM_DACPWM_MAX_PWM;
	u8 amplMinTIM_PWM = TIM_DACPWM_MIN_PWM;

#if TIM_DACPWM_SIGNAL_INVERTED
	amplTIM_PWM = TIM_DACPWM_MAX_PWM - amplTIM_PWM;
	amplMinTIM_PWM = TIM_DACPWM_MAX_PWM;
#endif /* TIM_DACPWM_SIGNAL_INVERTED */

	if(amplTIM_PWM == amplMinTIM_PWM)
	{
		TIM_DACPWM_SetAmpl(amplTIM_PWM);
		GPIO_BuzzerEnableDCDC_SetState(GPIO_RST);
		return;
	}

#if !SOUND_DISABLE
	GPIO_BuzzerEnableDCDC_SetState(GPIO_SET);
	TIM_DACPWM_SetAmpl(amplTIM_PWM);
#endif /* !SOUND_DISABLE */
}

Что дальше

Отлично, железка работает, громкость приемлема. Базовые ручки управления присутствуют, рекомендуемые ограничения соблюдены. Ну, почти соблюдены — однако за время эксплуатации мы не увидели какой-то явной деградации зуммеров.

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

P.S. Кстати, узнать много всего про зуммеры, в доступной форме и с красивыми картинками, можно на этом сайте: https://www.cuidevices.com/blog/audio

картинка: Magneticmag.com

Источник: https://habr.com/ru/companies/whoosh/articles/734332/


Интересные статьи

Интересные статьи

Хай Хабр! Это серия статей по написанию моей ОС с нуля. Я лютый фанат ретропрограммирования, поэтому я мгновенно забуду про существование EDК. Просьба не писать комменты по типу "BIOS давно устарела ...
Бывают ситуации, когда у заказчиков есть свои экосистемы и несколько приложений, и они решают упаковать их в SDK и встроить в другие, расширив таким образом функционал. SDK — не единичный Fragment/Act...
Этот заключительный пост посвящен анализу дисперсии. Анализ дисперсии, который в специальной литературе также обозначается как ANOVA от англ. ANalysis Of VAriance, — это ...
Здравствуйте, товарищи! Прошло чуть больше полугода после выхода предыдущей статьи о Windows 10 Sophia Script — скрипте, который за прошедшие годы стал самым крупным (а и...
Javascript на данный момент является самым популярным языком программирования по версиям многих площадок (например Github). Является ли при этом он самым продвинутым или самым любимым...