Один из ярких воспоминаний детства — просмотр семьёй диафильмов. Выключался свет, и на самодельном экране из простыни мы смотрели сказки. Детское воображение дорисовывало детали, и картинки оживали.

Сейчас в эпоху интернета, мультимедиа и ИИ вроде бы как такой необходимости нет, но слишком сильное чувство ностальгии. Поэтому решил получить ностальгические воспоминания с использованием современных технологий, а заодно и попрактиковаться в использовании энкодеров, разработке программ на Си и настройке Linux на Raspberry Pi.

Фильмоскопа у меня уже давно нет, поэтому я решил его эмулировать при помощи Raspberry Pi Zero 2 W и дешёвого энкодера для макетной платы. Выход HDMI можно подключить к современному проектору или, что менее аутентично, к телевизору и попробовать освежить детские воспоминания.

Что получилось у меня в итоге

У меня получилось устройство, фотографию которого вы видели в заголовке. Приведу ещё несколько фотографий:

А также видео работы фильмоскопа в действии:

Из чего состоит устройство

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

Мой эмулятор фильмоскопа состоит из:

  • Raspberry Pi Zero 2W с распаянной PLS-вилкой (with headers),

  • модуля энкодера,

  • шлейфа из 5-ти проводов с Dupont-коннекторами,

  • корпуса и ручки энкодера, распечатанных на 3D-принтере.

Raspberry Pi Zero 2W с распаянной PLS-вилкой
Raspberry Pi Zero 2W с распаянной PLS-вилкой

Если у вас нет 3D-принтера, то корпус можно попробовать сделать из подручных материалов, например, картона. Но придётся повозиться.

Для себя я понял, что 3D-принтер — сейчас обязательное устройство для DIY-проектов, позволяющее создавать завершённые устройства, дающее дополнительные возможности для реализации своих идей и экономящее время.

Постановка задачи

Задача создания фильмоскопа состоит из следующих шагов:

  • подключить к Raspberry энкодер,

  • написать небольшую программу, которая будет обрабатывать события от энкодера и выполнять прокрутку серии отсканированных кадров диафильма,

  • поставить программу для просмотра в автозагрузку,

  • поместить это несложное устройство в корпус.

Последние два пункта придают завершённости устройству, но даже без них всплывают детские воспоминания.

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

Подключение энкодера

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

Часто в статьях приводятся принципы работы энкодера и как обрабатывать его сигналы с GPIO-пинов или как использовать библиотеки для работы с энкодером.

Модуль энкодера подключается к GPIO-пинам Raspberry Pi Zero W 2. У меня следующая схема подключения.

схема подключения модуля энкодера
схема подключения модуля энкодера

В Linux не нужно погружаться в основы принципов работы энкодера, а просто использовать готовый драйвер, интегрируемый в систему ввода Linux.

Чтобы Linux распознал энкодер и мог с ним работать на встраиваемом устройстве, необходимо написать корректное Device Tree. В Raspbian можно сделать проще с использованием оверлея.

Для этого необходимо отредактировать файл /boot/firmware/config.txt. В конец файла добавить строку

dtoverlay=rotary-encoder, pin_a=2, pin_b=4,relative_axis=8

где:

  • dtoverlay=rotary-encoder — включение оверлея для драйвера роторного энкодера,

  • pin_a=2 — GPIO 2 используется как канал A энкодера,

  • pin_b=4 — GPIO 4 используется как канал B,

  • relative_axis=8 — указывается, какое событие Linux генерировать. Значение 8 — это числовой код Linux input subsystem — REL_WHEEL (прокрутка колеса мыши).

Драйвер сравнивает фазу A и B, чтобы понимать направление вращения: по часовой — одно направление, против часовой — другое.

Для того чтобы Linux узнал о наличии кнопки у энкодера, нужно подключить ещё один оверлей. В файл config.txt добавить

dtoverlay=gpio-key,gpio=3,keycode=28,label=encoder_button 

где:

  • dtoverlay=gpio-key — включает оверлей драйвера кнопок GPIO,

  • gpio=3 — кнопка подключена к GPIO 3,

  • keycode=28 — задаёт код клавиши Linux input subsystem — KEY_ENTER (клавиша Enter),

  • label=encoder_button — имя (метка) кнопки.

Нажатие на кнопку энкодера будет равнозначно нажатию Enter на клавиатуре.

Модуль энкодера лучше покупать тот, где есть фиксирующие гайки, такой проще закрепить на корпусе.

Реализация программы просмотра диафильмов

Для работы с графикой удобно использовать OpenGL, а ещё удобнее и быстрее библиотеку SDL, которая представляет собой абстракции для построения графических приложений и игр.

Так как разработанный эмулятор фильмоскопа является прототипом, который можно повторить самому за несколько часов, у него минимальный функционал: можно только переключать диафильмы при помощи кнопки энкодера и прокручивать диафильмы вперёд-назад.

В FAT-раздел SD-карты в директорию diafilms помещаются директории с отсканированными диафильмами.

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

Интересный факт я обнаружил при разработке программы: события от кнопки энкодера будут приходить в SDL-приложение, а вот для поворотов энкодера нужно использовать библиотеку libevdev.

Привожу код главной функции приложения, остальное вы можете посмотреть в моём репозитории на GitHub.

int main(int argc, char *argv[]) {

  init_encoder();

  if (SDL_Init(SDL_INIT_VIDEO) != 0) {
    printf("SDL_Init failed: %s\n", SDL_GetError());
    return 1;
  }

  IMG_Init(IMG_INIT_PNG);

  SDL_DisplayMode mode;
  SDL_GetDesktopDisplayMode(0, &mode);
  SDL_ShowCursor(SDL_DISABLE);
  render_width = mode.w;
  render_height = mode.h;

  win = SDL_CreateWindow("Filmoscope", SDL_WINDOWPOS_CENTERED,
                         SDL_WINDOWPOS_CENTERED, render_width, render_height,
                         SDL_WINDOW_FULLSCREEN);
  renderer = SDL_CreateRenderer(
      win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

  const char *dir = "resources";

  if (argc > 1) {
    dir = argv[1];
  }

  load_diafilm_list(dir);

  if (diafilm_count == 0) {
    printf("No diafilms found\n");
    return 1;
  }

  load_diafilm(&d, diafilm_dirs[current_diafilm]);

  load_initial_slides();

  int running = 1;
  SDL_Event e;

  while (running) {
    if (encoder) {
      int rc = libevdev_next_event(encoder, LIBEVDEV_READ_FLAG_NORMAL, &ev);
      if (rc == 0) {
        if (ev.type == 2) {
          scroll(ev.value * render_height / 12);
        }
      }
    }
    while (SDL_PollEvent(&e)) {
      if (e.type == SDL_QUIT)
        running = 0;
      else if (e.type == SDL_KEYDOWN) {
        if (e.key.keysym.sym == SDLK_ESCAPE)
          running = 0;
        else if (e.key.keysym.sym == SDLK_DOWN)
          scroll(render_height / 12);
        else if (e.key.keysym.sym == SDLK_UP)
          scroll(-render_height / 12);
        else if (e.key.keysym.sym == SDLK_RETURN)
          switch_diafilm();
      }
    }
    render();
    SDL_Delay(16);
  }
  cleanup_graphics();
  return 0;
}

Добавить функции и улучшить код можно всегда.

Сборка и запуск приложения

Вы можете установить приложение из исходных кодов, которые находятся на GitHub-репозитории.

  1. Берём чистую microSD-карту и устанавливаем образ Raspbian Lite.

  2. Вставляем microSD-карту в Raspberry Pi Zero 2 W и выполняем загрузку Raspbian.

  3. Добавляем недостающие пакеты:

    sudo apt install libsdl2-dev libevdev-dev
    
  4. Клонируем репозиторий:

    git clone 
    
  5. Собираем приложение:

    make
    
  6. Помещаем в директорию diafilms в FAT-разделе папки с отсканированными диафильмами. Если вы используете microSD-карту в Windows, то директория diafilms должна находиться в корне файловой системы, в Raspbian Lite — в директории /firmware.

  7. Запускаем приложение:

    ./filmoscope
    

Добавление приложения в автозагрузку

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

Автозагрузку приложения в Linux можно сделать несколькими способами. Так же это зависит от того, какой используется дистрибутив — с графическим интерфейсом или без, какой установлен Desktop Environment.

Простой способ добавить приложение в автозагрузку в Raspbian Lite — добавить следующие строки в конец файла .profile в домашней директории:

cd ~/pi-zero-filmoscope
./filmoscope

Эти строчки будут выполняться при логине пользователя. Подразумевается, что приложение у вас находится в директории /home/pi/pi-zero-filmoscope. Чтобы не нужно было вводить пользователя и пароль при логине, необходимо настроить autologin.

В Raspbian это удобно сделать при помощи команды ‘raspi-config’.

Разработка корпуса

Я разрабатывал корпус «по мотивам» советских фильмоскопов, чтобы он был похож на них, и им было более или менее удобно пользоваться.

Для начала я загрузил с сайта grabcad.com 3D модели Raspberry Pi Zero 2 W и модуля KY-040, чтобы легче было определять габариты и расположение компонентов.

Проектирование корпуса, как я уже говорил в прошлых статьях, — процесс увлекательный и творческий.

В этот раз у меня корпус получился с первого раза, если не считать испорченную деталь по причине отключения электричества на 1 секунду. Урок на будущее — печатать только с использованием бесперебойника.

Корпус проектировался для сборки без шурупов, так как он проще в изготовлении, да просто хотелось попробовать изготовить такой корпус и проверить, как он будет себя вести в эксплуатации.

3D-модель фильмоскопа в сборе
3D-модель фильмоскопа в сборе

Недостатки в корпусе есть, но это оставим пытливому читателю.

Часть деталей делал в контексте сборки, как и прорези для mini-HDMI, micro-USB и microSD-карты.

3D-модели деталей корпуса в виде STEP-файлов, а также модели для Bambu Lab находятся в GitHub-репозитории.

Верх корпуса
Верх корпуса
Низ корпуса
Низ корпуса
Объектив
Объектив
Ручка для прокрутки
Ручка для прокрутки

Что можно улучшить

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

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

Также можно добавить ножки для корпуса.

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

В просмотрщик можно добавить межкадровые промежутки, чтобы ещё больше походило на прокрутку диафильма.

Интересная доработка, которая требует проверки, — попробовать использовать беспроводной вывод вместо HDMI.

Заключение

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

Но самое интересное в нём — не Raspberry Pi, не энкодер и непрограммная часть. Когда крутишь ручку и кадры сменяются один за другим, появляются какие-то знакомые ощущения из детства.

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

© 2026 ООО «МТ ФИНАНС»