diff --git a/Makefile b/Makefile index 0449489..9e2f38f 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,2 @@ run: - chmod +x robot_pi_service/robot_pi_service.py python3 robot_pi_service/robot_pi_service.py \ No newline at end of file diff --git a/README.md b/README.md index 0d3606f..f9c6913 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,11 @@ **Robot-pi-service** - сервис для управления роботом на orange pi, работающий на linux Armbian. +**Для работы с GPIO:** + +1. `chmod +x gpio_setup.sh` +2. `./gpio_setup.sh` + **Запуск сервиса (как проекта python3)** - `make run`
diff --git a/gpio_setup.sh b/gpio_setup.sh new file mode 100644 index 0000000..2c1fadb --- /dev/null +++ b/gpio_setup.sh @@ -0,0 +1,7 @@ +#!/bin/bash +chmod -R +x robot_pi_service/ +sudo groupadd gpio +sudo usermod -aG gpio $USER +echo 'SUBSYSTEM=="gpio", KERNEL=="gpiochip[0-9]*", GROUP="gpio", MODE="0660"' | sudo tee /etc/udev/rules.d/99-gpio.rules +sudo udevadm control --reload-rules +sudo udevadm trigger \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 8de613a..7906869 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ websockets==15.0.1 -pydantic-settings==2.9.1 \ No newline at end of file +pydantic-settings==2.9.1 +gpiod==2.3.0 \ No newline at end of file diff --git a/robot_pi_service/gpio_control.py b/robot_pi_service/gpio_control.py new file mode 100644 index 0000000..85a5328 --- /dev/null +++ b/robot_pi_service/gpio_control.py @@ -0,0 +1,34 @@ +from gpiod import request_lines, LineSettings +from gpiod.line import Direction, Value + + +class LedLineGpio: + """Класс для управления динией gpio для LED""" + + def __init__(self, line: int) -> None: + self.line = line + self._request = request_lines( + '/dev/gpiochip0', + consumer='led-blinker', + config={ + line: LineSettings( + direction=Direction.OUTPUT, + output_value=Value.INACTIVE + ) + } + ) + + def on(self) -> None: + """Метод для включения LED""" + + self._request.set_value(self.line, Value.ACTIVE) + + def off(self) -> None: + """Метод для выключения LED""" + + self._request.set_value(self.line, Value.INACTIVE) + + def close(self) -> None: + """Метод для освобождения ресурса""" + + self._request.release() diff --git a/robot_pi_service/robot_pi_service.py b/robot_pi_service/robot_pi_service.py index a00f7fb..387ff13 100755 --- a/robot_pi_service/robot_pi_service.py +++ b/robot_pi_service/robot_pi_service.py @@ -1,8 +1,10 @@ import asyncio from websockets import serve, exceptions from websockets.legacy.server import WebSocketServerProtocol +from json import loads, JSONDecodeError from settings import settings +from gpio_control import LedLineGpio async def robot_control_gpio(websocket: WebSocketServerProtocol): @@ -11,16 +13,28 @@ async def robot_control_gpio(websocket: WebSocketServerProtocol): """ try: + led_line_gpio = LedLineGpio(line=6) + action = None + while True: try: command = await asyncio.wait_for(websocket.recv(), timeout=30.0) + data = loads(command) except asyncio.TimeoutError as err: print('Таймаут ожидания команды от клиента') continue # продолжение цикла, чтобы не закрывать соединение + except JSONDecodeError: + print("Ошибка при декодировании JSON") + continue - match command: + match next(iter(data), None): case settings.commands_robot.forward: - action = 'Робот едет вперёд' + if data.get(settings.commands_robot.forward): + action = 'Робот едет вперёд' + led_line_gpio.on() + else: + action = 'Команда вперёд стоп' + led_line_gpio.off() print(action) await websocket.send(message=action) case settings.commands_robot.backward: @@ -45,11 +59,15 @@ async def robot_control_gpio(websocket: WebSocketServerProtocol): message_err = f'{err.__class__.__name__}: {err}' print(message_err) await websocket.send(message=message_err) + finally: + led_line_gpio.close() async def start(): """Асинхронная функция запуска вебсокета и бесконечного цикла""" + print('Старт сервиса робота для приёма команд.') + async with serve(handler=robot_control_gpio, host=settings.websocket_host, port=settings.websocket_port): # бесконечный цикл await asyncio.Future() @@ -61,7 +79,7 @@ def run_app(): try: asyncio.run(start()) except KeyboardInterrupt: - pass + print('Выключение сервиса робота для приёма команд.') if __name__ == '__main__':