Добавил:
МТУСИ Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Практическая работа - индивидуальное задание / ПР_Индивидуальное_задание_Мягков_БАП2201

.docx
Скачиваний:
1
Добавлен:
21.04.2026
Размер:
1.75 Mб
Скачать

МИНИСТЕРСТВО ЦИФРОВОГО РАЗВИТИЯ, СВЯЗИ И МАССОВЫХ

КОММУНИКАЦИЙ РОССИЙСКОЙ ФЕДЕРАЦИИ

Ордена Трудового Красного Знамени федеральное государственное бюджетное образовательное учреждение высшего образования

«Московский технический университет связи и информатики»

(МТУСИ)

Кафедра «Интеллектуальные системы в управлении и автоматизации»

(ИСУиА)

ИНДИВИДУАЛЬНОЕ ЗАДАНИЕ

По дисциплине

Технологии промышленного интернета вещей

Выполнили:

Студенты 4-го курса

Группы БАП2201

Ли Самен

Мягков А.К.

Проверил:

к.т.н., доцент

Воронов В.И.

Москва 2026

СОДЕРЖАНИЕ

ВЫПОЛНЕНИЕ 3

ВЫВОДЫ 9

Модуль 2-х осевого джойстика KY-023 представлен на рисунке 1.

Характеристики:

– Рабочее напряжение: 3,3 – 5 В;

– Потребляемый ток: до 0,25 мА;

– Размер: 34х26х32 мм;

– Вес: 11 гр.

Рисунок 1 – Внешний вид и габаритные размеры модуля аналогового

двухосевого джойстика с пятью контактами для подключения

Модуль KY-023 состоит из двух потенциометров на 10 кОм (расположенных перпендикулярно), для определения осей X и Y (рисунок 2) необходимо изменить положение джойстика. Средняя нога каждого потенциометра выведена на разъем J1 (контакты VRX и VRY), а вторая и третья нога подключена к питанию и массе. Дополнительно установлена тактовая кнопка, показания снимаются с разъема J1 (контакт SW), так-же предусмотрено посадочное место для подтягивающего резистора (R1).

Рисунок 2 – Устройство модуля двухосевого джойстика с тактовой кнопкой для нажатия и двумя потенциометрами для отслеживания осей X и Y

Для считывания данных с выводов VRX (ось X) и VRY (ось Y) необходимо использовать аналоговые порт ESP32. (значение от 0 до 5В или от 0 до 1023, как на рисунке 3), а для считывания данных с вывода RW используем цифровой порт (значение 0 В и 5 В или 0 и 1). Так-как один вывод тактовой кнопки подключен к земле и при нажатии на джойстик вниз, происходит замыкание цепи, но возможно ложные срабатывания (наводки). Для получения стабильных показаний, вывод RW необходимо подтянуть к питанию +5В, через подтягивающий резистор R1 или использовать встроенный подтягивающий резистор.

Рисунок 3 – Cхема распределения значений координат X и Y (от 0 до 1023) при перемещении рычага джойстика в крайние положения

ВЫПОЛНЕНИЕ

В отличие от теоретического 10-битного АЦП (0–1023), плата ESP32 обладает 12-битным аналогово-цифровым преобразователем, что расширяет диапазон считываемых значений до 0 – 4095. Логика работы программы (Листинг 1) включает следующие этапы:

1) Непрерывное чтение для сбора данных последовательного порта (COM7, 115200 бод) и парсинг строки, содержащей шесть значений: координаты X, Y и состояние кнопки для каждого из двух модулей KY-023;

2) При запуске программы автоматически вычисляется положение центра стиков путём усреднения выборки показаний за 2 секунды, что компенсирует механическое смещение потенциометров;

3) Нелинейная нормализация – применение мертвой зоны (DEADZONE = 300) для фильтрации шумов и люфта в центральном положении. Значения за пределами мертвой зоны нормализуются в диапазон от -1,0 до 1,0;

4) Использовали экспоненциальное сглаживание как фильтр (коэффициент α = 0,35) для исключения дребезга показаний и обеспечения плавности движения курсора;

5) Преобразование нормализованных значений в 16-битный формат осей Xbox-контроллера (от -32767 до 32767) с последующей инверсией оси Y. Состояния тактовых кнопок (SW) маппируются на виртуальные кнопки «A» и «B».

Листинг 1 – Программа управления двумя стиками с помощью ESP32 на языке python

import sys

import time

import serial

import vgamepad as vg

PORT = "COM7" # Наш рабочий порт

BAUDRATE = 115200

# Последние считанные значения

last_values = [2048, 2048, 1, 2048, 2048, 1]

# Центры стиков, будут откалиброваны при запуске

center1_x = 2048

center1_y = 2048

center2_x = 2048

center2_y = 2048

# Настройки

DEADZONE = 300

SMOOTHING = 0.35 # 0..1, чем больше, тем резче реакция

PRINT_DEBUG = True

def clamp(value, low, high):

return max(low, min(high, value))

def read_serial_line(ser):

global last_values

try:

line = ser.readline().decode("utf-8", errors="ignore").strip()

if not line:

return last_values

parts = line.split(",")

if len(parts) != 6:

return last_values

values = [int(p) for p in parts]

last_values = values

return values

except Exception:

return last_values

def calibrate_center(ser, seconds=2.0):

print("Калибровка центра. Не трогай джойстики...")

samples = []

start = time.time()

while time.time() - start < seconds:

vals = read_serial_line(ser)

samples.append(vals)

time.sleep(0.01)

if not samples:

return 2048, 2048, 2048, 2048

avg_x1 = sum(v[0] for v in samples) // len(samples)

avg_y1 = sum(v[1] for v in samples) // len(samples)

avg_x2 = sum(v[3] for v in samples) // len(samples)

avg_y2 = sum(v[4] for v in samples) // len(samples)

print(f"Центр 1: X={avg_x1}, Y={avg_y1}")

print(f"Центр 2: X={avg_x2}, Y={avg_y2}")

return avg_x1, avg_y1, avg_x2, avg_y2

def normalize_axis(raw, center, deadzone):

delta = raw - center

if abs(delta) <= deadzone:

return 0.0

if delta > 0:

denom = 4095 - center - deadzone

if denom <= 0:

return 0.0

value = (delta - deadzone) / denom

return min(value, 1.0)

else:

denom = center - deadzone

if denom <= 0:

return 0.0

value = (delta + deadzone) / denom

return max(value, -1.0)

def to_xbox_axis(norm_value):

return int(clamp(norm_value, -1.0, 1.0) * 32767)

def smooth(prev_value, new_value, alpha):

return prev_value * (1.0 - alpha) + new_value * alpha

def main():

global center1_x, center1_y, center2_x, center2_y

try:

ser = serial.Serial(PORT, BAUDRATE, timeout=0.05)

except Exception as e:

print(f"Не удалось открыть порт {PORT}: {e}")

sys.exit(1)

gamepad = vg.VX360Gamepad()

time.sleep(2.0) # дать порту стабилизироваться

center1_x, center1_y, center2_x, center2_y = calibrate_center(ser, seconds=2.0)

print("Геймпад запущен.")

print("SW первого джойстика -> A")

print("SW второго джойстика -> B")

print("Ctrl+C для выхода")

filtered_lx = 0.0

filtered_ly = 0.0

filtered_rx = 0.0

filtered_ry = 0.0

last_debug_time = 0

try:

while True:

x1, y1, s1, x2, y2, s2 = read_serial_line(ser)

raw_lx = normalize_axis(x1, center1_x, DEADZONE)

raw_ly = normalize_axis(y1, center1_y, DEADZONE)

raw_rx = normalize_axis(x2, center2_x, DEADZONE)

raw_ry = normalize_axis(y2, center2_y, DEADZONE)

# Сглаживание

filtered_lx = smooth(filtered_lx, raw_lx, SMOOTHING)

filtered_ly = smooth(filtered_ly, raw_ly, SMOOTHING)

filtered_rx = smooth(filtered_rx, raw_rx, SMOOTHING)

filtered_ry = smooth(filtered_ry, raw_ry, SMOOTHING)

# Отправка в виртуальный Xbox-геймпад

gamepad.left_joystick(

x_value=to_xbox_axis(filtered_lx),

y_value=to_xbox_axis(-filtered_ly) # инверсия Y

)

gamepad.right_joystick(

x_value=to_xbox_axis(filtered_rx),

y_value=to_xbox_axis(-filtered_ry) # инверсия Y

)

# Кнопки

if s1 == 0:

gamepad.press_button(button=vg.XUSB_BUTTON.XUSB_GAMEPAD_A)

else:

gamepad.release_button(button=vg.XUSB_BUTTON.XUSB_GAMEPAD_A)

if s2 == 0:

gamepad.press_button(button=vg.XUSB_BUTTON.XUSB_GAMEPAD_B)

else:

gamepad.release_button(button=vg.XUSB_BUTTON.XUSB_GAMEPAD_B)

gamepad.update()

# Отладка раз в 0.2 сек

now = time.time()

if PRINT_DEBUG and (now - last_debug_time > 0.2):

last_debug_time = now

print(

f"J1 raw=({x1:4d},{y1:4d}) norm=({filtered_lx:+.2f},{filtered_ly:+.2f}) | "

f"J2 raw=({x2:4d},{y2:4d}) norm=({filtered_rx:+.2f},{filtered_ry:+.2f})"

)

time.sleep(0.01)

except KeyboardInterrupt:

print("Остановлено.")

finally:

ser.close()

if __name__ == "__main__":

main()

На рисунке 4 представлено присоединение двух стиков к плате ESP32.

Рисунок 4 – Присоединение триггеров к ESP32

Для верификации работоспособности системы была проведена проверка с использованием веб-сервиса mitinogame.ru/gamepad-tester. В ходе тестирования инициилизируется виртуальное устройство (xbox 360) в операционной системе. Отклонение модулей KY-023 отображалось перемещением соответствующих осей на экране, а нажатие на стики вызывало фиксацию кнопок «A» и «B».

Рисунок 5 – Фиксация отклонения осей и нажатия виртуальных кнопок

эмулируемого геймпада на веб-сервисе онлайн-тестирования

ВЫВОДЫ

В ходе выполнения работы была разработана программа на языке Python, преобразующая аналоговые сигналы двух модулей KY-023 в данные виртуального Xbox-геймпада. Для обеспечения стабильного управления в коде реализованы процедуры автоматической калибровки центра, программной фильтрации дребезга и настройки мертвой зоны осей. Функциональность созданного устройства успешно подтверждена путем тестирования на специализированном веб-сервисе с фиксацией отклонения стиков и нажатия кнопок.