Утро, лето, жара. Я просыпаюсь в 6:00 весь в поту. В квартире 27, на улице 21. Но по дороге на работу солнце возьмет свое, а наш офис находится на солнечной стороне. Каждое утро я вхожу в душное помещение, открываю окна, в надежде хоть немного его проветрить, включаю кондиционер. Как вы понимаете, всем дует в спину и включить кондиционер на полную не получится. Температура немного стабилизируется к обеду. С 14:00 до 17:00 можно жить и работать, а дальше все повторяется сначала.
Удаленное управление кондиционером – дело не новое, есть Smart технологии и мобильные приложения. Но случается, что кондиционер старенький, не smart, а заранее его запустить и прийти утром в прохладное помещение желание есть. Потому и было принято решение – автоматизировать функцию включения при помощи сервопривода и механического нажатия на кнопку.
Идею я позаимствовал у коллеги. Был срочный заказ на печать в типографии, ставить человека в ночную смену накладно. Требовалось нажимать три разные кнопки, что было не по силу компьютеру. Та история закончилась удаленным управлением сервоприводами через Arduino.
Я же с Arduino не работал, потому искал что-нибудь без внутрисхемного программирования. Купил у местных умельцев плату RoboIntellect controller 001 на которой распаяна микросхема PCA9685 и CH341T. Значит, связка USB компьютера с ШИМ контроллером уже есть. В дополнение нам понадобятся двусторонний скотч, малярный скотч, магнитик для упора, стёрка и нитка.
Схема выглядит приблизительно так. Через удаленный рабочий стол заходим на компьютер, к которому подключена наша плата. На первом канале ШИМ висит сервопривод. Через «умную» систему рычагов нажимаем на кнопку пульта. Управляет всем небольшой скрипт на Python.
![](https://habrastorage.org/getpro/habr/upload_files/77a/f76/51e/77af7651e4094d7bd4b2ed02e2910250.jpg)
Насколько я понял, плату RoboIntellect применяют в конструкторе, для которого написана библиотека RISDK. Её и будем использовать. После инициализации и создания компонентов нужна только одна функция RI_SDK_exec_ServoDrive_TurnByDutyCycle для вращения оси сервопривода. Вызываем функцию два раза: нажатие кнопки и возврат в начальное положение.
import sys
from ctypes import *
# Подключаем внешнюю библиотеку для работы с SDK
lib = cdll.LoadLibrary("./librisdk.dll")
# Указываем типы аргументов для функций библиотеки RI_SDK
lib.RI_SDK_InitSDK.argtypes = [c_int, c_char_p]
lib.RI_SDK_CreateModelComponent.argtypes = [c_char_p, c_char_p, c_char_p, POINTER(c_int), c_char_p]
lib.RI_SDK_LinkPWMToController.argtypes = [c_int, c_int, c_uint8, c_char_p]
lib.RI_SDK_LinkServodriveToController.argtypes = [c_int, c_int, c_int, c_char_p]
lib.RI_SDK_DestroySDK.argtypes = [c_bool, c_char_p]
lib.RI_SDK_exec_ServoDrive_Turn.argtypes = [c_int, c_int, c_int, c_bool, c_char_p]
def main():
errTextC = create_string_buffer(1000) # Текст ошибки. C type: char*
i2c = c_int()
pwm = c_int()
servo = c_int()
# Инициализация библиотеки RI SDK с уровнем логирования 3
errCode = lib.RI_SDK_InitSDK(3, errTextC)
if errCode != 0:
print(errCode, errTextC.raw.decode())
sys.exit(2)
# Создание компонента i2c адаптера модели ch341
errCode = lib.RI_SDK_CreateModelComponent("connector".encode(), "i2c_adapter".encode(), "ch341".encode(), i2c,
errTextC)
if errCode != 0:
print(errCode, errTextC.raw.decode())
sys.exit(2)
print("i2c: ", i2c.value)
# Создание компонента ШИМ модели pca9685
errCode = lib.RI_SDK_CreateModelComponent("connector".encode(), "pwm".encode(), "pca9685".encode(), pwm, errTextC)
if errCode != 0:
print(errCode, errTextC.raw.decode())
sys.exit(2)
print("pwm: ", pwm.value)
# Создание компонента сервопривода модели mg90s
errCode = lib.RI_SDK_CreateModelComponent("executor".encode(), "servodrive".encode(), "mg90s".encode(), servo,
errTextC)
if errCode != 0:
print(errCode, errTextC.raw.decode())
sys.exit(2)
print("servo: ", servo.value)
# Связывание i2c с ШИМ
errCode = lib.RI_SDK_LinkPWMToController(pwm, i2c, 0x40, errTextC)
if errCode != 0:
print(errCode, errTextC.raw.decode())
sys.exit(2)
# Связывание ШИМ с сервоприводом
errCode = lib.RI_SDK_LinkServodriveToController(servo, pwm, 0, errTextC)
if errCode != 0:
print(errCode, errTextC.raw.decode())
sys.exit(2)
# Моментальный поворот сервопривода к значению угла, соответствующему 500 шагам
# Диапазон углов 554 - 75
# Нажатие кнопки
errCode = lib.RI_SDK_exec_ServoDrive_TurnByDutyCycle(servo, 180, errTextC)
if errCode != 0:
print(errCode, errTextC.raw.decode())
sys.exit(2)
# Возврат в начальную позицию
errCode = lib.RI_SDK_exec_ServoDrive_TurnByDutyCycle(servo, 80, errTextC)
if errCode != 0:
print(errCode, errTextC.raw.decode())
sys.exit(2)
# Удаление библиотеки со всеми компонентами
errCode = lib.RI_SDK_DestroySDK(True, errTextC)
if errCode != 0:
print(errCode, errTextC.raw.decode())
sys.exit(2)
print("Success")
main()
Сперва все казалось легко и просто. При помощи скотча крепим сервопривод, запускаем скрипт и проблема решена. Но на деле даже в таком развлечении нашлись подводные камни. Движение пальца поступательное, а оси сервопривода - вращательное. Если просто толкать кнопку рычагом, то точка прилагаемого усилия меняется и пульт съезжает набок. Беспрерывная чреда экспериментов с учетом мнения бесконечного числа технических специалистов офиса позволили найти рабочее решение.
![](https://habrastorage.org/getpro/habr/upload_files/fe0/7c7/893/fe07c78931dfc1bb8dc30d3a7069ed77.jpg)
Размещаем пульт на столе кнопкой (упором вниз), крепим один конец двусторонним скотчем. С другого конца тянем пульт при помощи нитки. Происходит нажатие.
Таким вот образом, можно заниматься автоматизацией, не отходя от рабочего места. Главное не терять позитивного настроя и чувства юмора. Допускаю, что наш метод не производит сильного впечатления с технической точки зрения, но одну задачу он точно решил. Директор пообещал купить новый кондиционер.