Firmata — это базовый протокол, который предоставляет возможность для коммуникации между микроконтроллером и ПО, работающим на компьютере.
Любое программное обеспечение на любом компьютере, которое совместимо с Serial-соединением может обмениваться данными с микроконтроллером, используя Firmata.
Firmata дает полный доступ к Arduino прямо из ПО и исключает процессы модификации и загрузки скетчей Arduino.
Используя протокол Firmata, разработчик может загрузить скетч, который поддерживает протокол с клиентом Arduino. После этого, появляется возможность писать собственное ПО на управляющем компьютере и выполнять сложные задачи. Это ПО передает команды через последовательный порт в плату Arduino, по протоколу Firmata, что позволяет изменять логику работы программы на управляющем компьютере, не сбрасывая Arduino.
Установка Firmata на Arduino
Давайте загрузим библиотеку Firmata на вашу плату Arduino.
Сначала убедитесь, что на вашем компьютере установлена Arduino IDE. Вы можете загрузить Arduino IDE с официальной страницы загрузки Arduino .
Выберите систему (Windows, Mac, Linux), которую вы сейчас используете, загрузите и запустите установщик. Если на вашем компьютере уже установлена Arduino IDE, убедитесь, что у нее последняя версия (при необходимости обновите).
Если нет библиотеки. Необходимо установить её.
Открываем раделы Скетч- Подключить библиотеку.
Откроем Менеджер библиотек. В теме, в поисковой строке забьём “Firmata”. Найдём библиотеку и загрузим последнюю версию библиотеки.
Подключим плату к компьютеру.
Теперь откройте Arduino IDE и подключите плату Arduino к компьютеру.
Выберите подходящую плату в разделе «Инструменты» > «Платы» (здесь Arduino Uno)
и порт, к которому подключена плата. Номер порта можно узнать в Диспетчере устройств компьютера
или так.
Номер может варьироваться в зависимости от вашей системы и того, что еще подключено к вашему компьютеру.
Теперь, когда ваша плата Arduino правильно обнаружена Arduino IDE, вы можете открыть эскиз Firmata из доступных примеров.
Ссылка на информацию по документации
Реализация Firmata в Python
Существует множество способов для коммуникации платы Arduino с управляющим компьютером, используя протокол Firmata. Например, можно написать собственную программу на Python, используя библиотеку, поддерживающую этот протокол.
Например, pyfirmata — это известная библиотека Python, позволяющая использовать Firmata в качестве клиента. Существуют библиотеки, доступные на многих языках ( список здесь ), но в этом руководстве мы сосредоточимся только на написании клиента Python.
При помощи команды
pip install pyFirmata
в командной строке установим библиотеку.
Для демонстрации возможности подобного управления мы будем мигать светодиодом в плате Arduino при помощи команд на языке Python.
Для лучшего понимания работы этого проекта желательно прочитать документацию на программное обеспечение pyFirmata, которое можно найти по этой ссылке.
Пример 1
Импортируйте библиотеку pyFirmata.
import pyfirmata
Определим контакт Arduino к которому будет подключен светодиод.
led_pin = 13
Теперь мы должны записать имя последовательного порта, к которому будет подключена плата Arduino с использованием функции pyfirmata.Arduino() и инициализируем этот порт на конкретную переменную. COM12, вот именно так и записываем номер нашего порта в кавычках.
board = pyfirmata.Arduino(“COM12”)
print “Code is running”
В цикле while мы будем поочередно устанавливать на контакте, к которому подключен светодиод, напряжение высокого (HIGH) и низкого (low) уровня с использованием функции board.digital[].write() и использованием задержки с помощью функции board.pass_time().
while True:
board.digital[led_pin].write(0)
board.pass_time(1)
board.digital[led_pin].write(1)
board.pass_time(1)
board.digital
– это список, элементы которого представляют цифровые контакты Arduino.
Эти элементы имеют методы read()
и write()
, которые будут читать и записывать состояние выводов.
Как и большинство встроенных программ для устройств, эта программа в основном состоит из бесконечного цикла:
Наш код готов, выполните код в IDE Python
import pyfirmata
led_pin = 13
board = pyfirmata.Arduino(“COM12”)
while True:
board.digital[led_pin].write(0)
board.pass_time(1)
board.digital[led_pin].write(1)
board.pass_time(1)
Убедитесь в том, что плата Arduino соединена с компьютером с помощью USB кабеля.
Пример 2
Код на Python для постепенного угасания яркости свечения светодиода
Примечание: Здесь реализовано управление на 9 пине, так как он поддерживает ШИМ.
import time
import pyfirmata
delay = 0.3
brightness = 0
board = pyfirmata.Arduino("COM12")
led = board.get_pin('d:9:p')
while True:
for i in range(0, 10):
brightness = brightness + 0.1
print("Установка яркости на %s" % brightness)
led.write(brightness)
board.pass_time(delay)
for i in range(0, 10):
print("Установка яркости на %s" % brightness)
led.write(brightness)
brightness = brightness - 0.1
board.pass_time(delay)
Пример 3
Подключаем библиотеки
from pyfirmata import Arduino
from time import sleep
Подключение к порту платы
board = Arduino(‘COM12’)
Инициализация светодиодов
led1 = board.get_pin(‘d:13:o’)
led2 = board.get_pin(‘d:12:o’)
led3 = board.get_pin(‘d:11:o’)
led4 = board.get_pin(‘d:10:o’)
Подождите 1 секунду при каждом значении счета
wait = 1
Инициализируйте все значением False (выкл.)
val_1 = val_2 = val_3 = val_4 = False
led4 – это наименее значимый бит, а led1 – наиболее значимый бит
Это бесконечный цикл, который не закончится до тех пор, пока терминал не будет отключен
while True:
for ____ in range(2):
for ___ in range(2):
for __ in range(2):
for _ in range(2):
sleep(wait)
Обновление значений и их печать
led1.write(val_1)
led2.write(val_2)
led3.write(val_3)
led4.write(val_4)
print(int(val_1), int(val_2), int(val_3), int(val_4))
val_4 = not val_4
val_3 = not val_3
val_2 = not val_2
val_1 = not val_1
print(“\n\n”)
Код полностью.
from pyfirmata import Arduino
from time import sleep
board = Arduino('COM12')
led1 = board.get_pin('d:13:o')
led2 = board.get_pin('d:12:o')
led3 = board.get_pin('d:11:o')
led4 = board.get_pin('d:10:o')
wait = 1
val_1 = val_2 = val_3 = val_4 = False
while True:
for ____ in range(2):
for ___ in range(2):
for __ in range(2):
for _ in range(2):
sleep(wait)
led1.write(val_1)
led2.write(val_2)
led3.write(val_3)
led4.write(val_4)
print(int(val_1), int(val_2), int(val_3), int(val_4))
val_4 = not val_4
val_3 = not val_3
val_2 = not val_2
val_1 = not val_1
print("\n\n")
Пример 4
Включение и выключение светодиода с помощью кнопок, созданных в Tkinter.
В коде (‘d:13:o’)
led = arduino.get_pin(‘d:13:o’)
d= значит Digital
Номер пина = 13
o значит = OUTPUT
Полный код
from pyfirmata import Arduino
from tkinter import *
PORT = “COM12”
arduino = Arduino(PORT)
led = arduino.get_pin(‘d:13:o’)
def acender():
led.write(1)
def apagar():
led.write(2)
janela = Tk()
janela.title(“Включение и выключение светодиода с помощью кнопки”)
janela.geometry(“350×60”)
frame = Frame(master=janela)
frame.pack()
btacende = Button(master=frame, text=”Включить”, command=acender)
btacende.grid(row=0, column=0)
btapaga = Button(master=frame, text=”Выключить”, command=apagar)
btapaga.grid(row=0, column=1)
janela.mainloop()
Пример 5
Интенсивность свечение светодиода (на 10 пине) с помощью бегунка, созданного в Tkinter.
from pyfirmata import Arduino, PWM
from tkinter import *
PORT = ‘COM12’
arduino = Arduino(PORT)
arduino.digital[10].mode = PWM
def controle (intensidade):
arduino.digital[10].write(int(intensidade)/100)
if intensidade == 100:
print(intensidade, ‘\n’)
janela = Tk()
janela.title(“Контроль интенсивности LED”)
janela.geometry(“400×50”)
frame = Frame(master=janela)
frame.pack()
slider = Scale(master=frame, length=300, from_=0, to=100, orient=HORIZONTAL, command=controle)
slider.grid(row=0, column=0)
janela.mainloop()
Пример 6
Пример управления шаговыми двигателями , созданного в Tkinter. (Скачивать нужно все файлы в одно место).
Изучим код поэтапно:
Подключаем библиотеки
from tkinter import *
from pyfirmata import ArduinoMega, util from time
import sleep
Через строку ввода должны ввести номер порта, на котором подключена плата Ардуино (например, вводим как COM12).
Введённые данные передаём в переменную com
com = input(“Введите номер COM-порта для Arduino (напр: COM4): “)
Если заккоментировать код сверху и создать переменную сразу с нужным портом,
com = “COM12”
то программа сразу откроется.
В Python исключения обрабатываются с помощью блоков try/except
. Для этого операция, которая может вызвать исключение, помещается внутрь блока try
. А код, который должен быть выполнен при возникновении ошибки, находится внутри except
. В переменную b вносим значение ком порта, через класс ArduinoMega загруженной библиотекиpyfirmata (from pyfirmata import ArduinoMega).
b = ArduinoMega(com)
Если значение верно и произошло соединение код работает далее. Если произошла ошибка (исключение) то подключается оператор Exception.
Оператор « Exception as e » используется с операторами try-Exception для захвата любого исключения, возникшего в блоке try , и сохранения его в объекте с именем e .
except Exception as e:
Далее открывым файл с названием error (он нахдится там же где файл с кодом. Значение файла передаем в переменную logf.
logf = open(“error.log”, “w”)
Через функцию write, записываем текст “Не удалось подключиться к порту” и значение не правильного ком порта в виде строки.
logf.write(“Не удалось подключиться к порту {0}: {1}\n”.format(com, str(e)))
Закрываем файл
logf.close()
Функция exit()
модуля sys
– это быстрый способ выйти из программы при возникновении ошибки.
sys.exit()
except Exception as e:
logf = open(“error.log”, “w”)
logf.write(“Не удалось подключиться к порту {0}: {1}\n”.format(com, str(e)))
logf.close()
sys.exit()
Создаём итерацию для переменной b (итерация обязательна). Перебираем и обновляем состояние пинов.
it = util.Iterator(b)
it.start()
И назначаем значения цифровых пинов переменным при помощи итерации (перебора).
stp_1 = b.digital[22]
dir_1 = b.digital[23]
MS1_1 = b.digital[24]
MS2_1 = b.digital[25]
MS3_1 = b.digital[26]
EN_1 = b.digital[27]
stp_2 = b.digital[30]
dir_2 = b.digital[31]
MS1_2 = b.digital[32]
MS2_2 = b.digital[33]
MS3_2 = b.digital[34]
EN_2 = b.digital[35]
stp_3 = b.digital[38]
dir_3 = b.digital[39]
MS1_3 = b.digital[40]
MS2_3 = b.digital[41]
MS3_3 = b.digital[42]
EN_3 = b.digital[43]
stp_4 = b.digital[46]
dir_4 = b.digital[47]
MS1_4 = b.digital[48]
MS2_4 = b.digital[49]
MS3_4 = b.digital[50]
EN_4 = b.digital[51]
Создаём переменную thing и не передаём значение None.
Обычно None используется, когда вы хотите создать переменную (поскольку Python не отличает создание от присвоения: создание переменной – это просто присвоение ей значения), но пока не хотите присваивать ей какое-либо конкретное значение.
Хотя как мы уже говорили, None – это тоже значение.
Его не следует интерпретировать как значение NULL в языках типа C и C++, которое применяется только к указателям. None может быть присвоено любому объекту.
thing = None
Создаём объект (окно) в библиотеки Tkinter. С надписью заголовка “Motor Control”.
root = Tk() root.title(“Motor Control”)
Создаём размеры окна Tkinter.
root.geometry(“800×500”)
Показываем позицию начального расположения окна Tkinter при создании.
root.resizable(0, 0)
Здесь создаём переменные со своими значениями.
vert_pos = 5000
hor_pos = 5000
foc_pos = 5000
stage_pos = 5000
rate = 100
limit = 10000
Создаём функцию. Функция main записывает (передаёт) значения в соответствующие переменные (которые были созданны ранее). И создаёт новую переменную resetPins с назначенным значением (5). А также назначаем статус подключения цифровых пинов MS3_1.write(0)
def main():
resetPins(5)
stp_1.write(0)
dir_1.write(0)
MS1_1.write(0)
MS2_1.write(0)
MS3_1.write(0)
EN_1.write(1)
sleep(2)
Функция start_motorfwd работает по событию (event).
Эта функция при вызове перезаписывает (расчитывает) значения переменных и создаёт текст в соответствии с назначением функции. В переменную move Записывается текстовая строка с видом команды (например “forward”).
def start_motorfwd(event):
global rate
dir_1.write(0) # Pull direction pin low to move “forward”
EN_1.write(0)
rate = 101 – speed.get() #rate = 1001 – speed.get()
sleep(0.1)
direction = “forward”
print(“Запуск мотора %s…” % direction)
move(direction)
Все остальные функции также выполняют похожие действия.
Функция move получает аргументы значения переменной direction.
def move(direction):
Эта функция принимает значение переменных, которые назначены Глобальными.
global thing, vert_pos, hor_pos, stage_pos, foc_pos, rate, limit
Оператор if-else (если-иначе) исполняет одну порцию инструкций, если условие истинно и другое — если нет. Таким образом этот оператор предлагает два направления действий.
Здесь, сравнивается значение переменной direction с текстом “forward”, и с другими значениями direction. При выполнении условия совпадения (или не совпадения) выполняется перезапись данных в соответствующие переменные. Функция print выводит соответствующий текст.
if direction == "forward":
if hor_pos >= limit:
print("Horizontal edge reached at %d...Stopping." % hor_pos)
safe_stop()
else:
stp_1.write(1)
sleep(0.001) #sleep(rate/100000)
stp_1.write(0)
print("forward %d" % hor_pos)
hor_pos += 1
elif direction == "reverse":
if hor_pos <= 0:
print("Horizontal edge reached at %d...Stopping." % hor_pos)
safe_stop()
else:
stp_1.write(1)
sleep(rate/100000)
stp_1.write(0)
print("reverse %d" % hor_pos)
hor_pos -= 1
В конце если нет совпадений, выполняется ветвление Ошибка. И выполнятся функция after().
Tkinter предоставляет множество встроенных функций для разработки интерактивного и функционального графического интерфейса пользователя (графического интерфейса пользователя).
Функция after() также является универсальной функцией, которую можно использовать непосредственно в корне, а также с другими виджетами.
after(родитель, мс, функция = нет, *args)
Метод after()
требует двух основных аргументов:
- Задержка в миллисекундах (1000 миллисекунд = 1 секунда).
- Функция или метод, который будет выполнен после задержки (move, direction).
else:
print(“error”)
safe_stop()
#int(rate)
thing = root.after(1, move, direction)
Функция safe_stop использует значение Глобальной переменной thing. При ошибки “Неверное направление… вызов безопасной остановки”.
def safe_stop():
global thing
root.after_cancel(thing)
print(“Неверное направление… вызов безопасной остановки.”)
Функция resetPins принимает аргумент (num):
Эта функция сравнивает значение num в диапазоне (от 1 до 5), через ветвление if
if num == 1 or num == 5:
Если выполнение выполняется в переменные передаются значения.
def resetPins(num):
if num == 1 or num == 5:
stp_1.write(0)
dir_1.write(0)
MS1_1.write(0)
MS2_1.write(0)
MS3_1.write(0)
EN_1.write(1)
if num == 2 or num == 5:
stp_2.write(0)
dir_2.write(0)
MS1_2.write(0)
MS2_2.write(0)
MS3_2.write(0)
EN_2.write(1)
if num == 3 or num == 5:
stp_3.write(0)
dir_3.write(0)
MS1_3.write(0)
MS2_3.write(0)
MS3_3.write(0)
EN_3.write(1)
if num == 4 or num == 5:
stp_4.write(0)
dir_4.write(0)
MS1_4.write(0)
MS2_4.write(0)
MS3_4.write(0)
EN_4.write(1)
Функция return_home возвращает в начальную (домашнюю) точку двигателя.
def return_home(event):
Эта часть кода создаёт кнопки, даёт надпись на кнопках, расположение, размеры и цвет.
button1 = Button(root, text=”Вперед”, height=5, width=20, bg=”white”, fg=”blue”)
button1.grid(row=6, column=2)
В следующем коде реализуется вызов функций при помощи созданных кнопок.
Здесь в коде “<ButtonPress-1>” ButtonPress
– название события – нажатие кнопки мыши, а “1” указывает на конкретную кнопку – левую кнопку мыши.
<ButtonRelease-1> – кнопка была отпущена. Это, вероятно, лучший выбор в большинстве случаев, чем событие Button(), потому что если пользователь случайно нажимает кнопку, они могут отодвинуть мышь от виджета, чтобы избежать отключения события.
button1.bind(‘<ButtonPress-1>’, start_motorfwd)
button1.bind(‘<ButtonRelease-1>’, stop_motorfwd)
Конструкци if __name__ == ‘__main__’: main () в Python определяет какая функция будет исполняться в качестве основной. Обычно это main (). В Python есть понятие namespace. main — основной namespace, с ним происходит работа из оболочки, каждый импортируемый модуль относится к другому namespace, имя которого совпадает с именем модуля. Если пишется простой CGI скрипт на питоне можно не указывать «if name main».
if name == ‘main‘:
main()
Это цикл из библиотеки ткинтер (пайтон) оно превращает всё в цикл который будет работать вечно. его можно писать несколькими вариациями:window.mainloop() , mainloop() и т.д. Его нужно ставить в конец
root.mainloop()
Функция exit() позволяет выйти из программы в любой момент выполнения и возвращает код возврата. Код возврата — это число, которое указывает на результат выполнения программы.
Если код возврата равен 0, это означает успешное завершение программы, в то время как любое другое значение указывает на ошибку или некорректное завершение программы.
b.exit()
Код полностью.
from tkinter import *
from pyfirmata import ArduinoMega, util
from time import sleep
com = input("Введите номер COM-порта для Arduino (напр: COM4): ")
try:
b = ArduinoMega(com)
except Exception as e:
logf = open("error.log", "w")
logf.write("Не удалось подключиться к порту {0}: {1}\n".format(com, str(e)))
logf.close()
sys.exit()
it = util.Iterator(b)
it.start()
stp_1 = b.digital[22]
dir_1 = b.digital[23]
MS1_1 = b.digital[24]
MS2_1 = b.digital[25]
MS3_1 = b.digital[26]
EN_1 = b.digital[27]
stp_2 = b.digital[30]
dir_2 = b.digital[31]
MS1_2 = b.digital[32]
MS2_2 = b.digital[33]
MS3_2 = b.digital[34]
EN_2 = b.digital[35]
stp_3 = b.digital[38]
dir_3 = b.digital[39]
MS1_3 = b.digital[40]
MS2_3 = b.digital[41]
MS3_3 = b.digital[42]
EN_3 = b.digital[43]
stp_4 = b.digital[46]
dir_4 = b.digital[47]
MS1_4 = b.digital[48]
MS2_4 = b.digital[49]
MS3_4 = b.digital[50]
EN_4 = b.digital[51]
thing = None
root = Tk()
root.title("Motor Control")
root.geometry("800x500")
root.resizable(0, 0)
vert_pos = 5000
hor_pos = 5000
foc_pos = 5000
stage_pos = 5000
rate = 100
limit = 10000
def main():
resetPins(5)
stp_1.write(0)
dir_1.write(0)
MS1_1.write(0)
MS2_1.write(0)
MS3_1.write(0)
EN_1.write(1)
sleep(2)
def start_motorfwd(event):
global rate
dir_1.write(0) # Pull direction pin low to move "forward"
EN_1.write(0)
rate = 101 - speed.get() #rate = 1001 - speed.get()
sleep(0.1)
direction = "forward"
print("Запуск мотора %s..." % direction)
move(direction)
def stop_motorfwd(event):
resetPins(1)
direction = "forward"
global thing
root.after_cancel(thing)
print("Остановка мотора %s..." % direction)
def start_motorrev(event):
global rate
dir_1.write(1) # Pull direction pin low to move "forward"
EN_1.write(0)
rate = 101 - speed.get() #rate = 1001 - speed.get()
sleep(0.1)
direction = "reverse"
print("Запуск мотора %s..." % direction)
move(direction)
def stop_motorrev(event):
resetPins(1)
direction = "reverse"
global thing
root.after_cancel(thing)
print("Остановка мотора %s..." % direction)
def start_motorup(event):
global rate
dir_2.write(0) # Pull direction pin low to move "forward"
EN_2.write(0)
rate = 101 - speed.get() #rate = 1001 - speed.get()
sleep(0.1)
direction = "up"
print("starting motor %s..." % direction)
move(direction)
def stop_motorup(event):
resetPins(2)
direction = "up"
global thing
root.after_cancel(thing)
print("Остановка мотора %s..." % direction)
def start_motordown(event):
global rate
dir_2.write(1) # Pull direction pin low to move "forward"
EN_2.write(0)
rate = 101 - speed.get() #rate = 1001 - speed.get()
sleep(0.1)
direction = "down"
print("Запуск мотора %s..." % direction)
move(direction)
def stop_motordown(event):
resetPins(2)
direction = "down"
global thing
root.after_cancel(thing)
print("Остановка мотора %s..." % direction)
def start_stage_motorup(event):
global rate
dir_3.write(0) # Pull direction pin low to move "forward"
EN_3.write(0)
rate = 101 - speed.get() #rate = 1001 - speed.get()
sleep(0.1)
direction = "stage up"
print("Запуск мотора %s..." % direction)
move(direction)
def stop_stage_motorup(event):
resetPins(3)
direction = "stage up"
global thing
root.after_cancel(thing)
print("Остановка мотора %s..." % direction)
def start_stage_motordown(event):
global rate
dir_3.write(1) # Pull direction pin low to move "forward"
EN_3.write(0)
rate = 101 - speed.get() #rate = 1001 - speed.get()
sleep(0.1)
direction = "stage down"
print("Запуск мотора %s..." % direction)
move(direction)
def stop_stage_motordown(event):
resetPins(3)
direction = "stage down"
global thing
root.after_cancel(thing)
print("Остановка мотора %s..." % direction)
def start_focus_motorup(event):
global rate
dir_4.write(0) # Pull direction pin low to move "forward"
EN_4.write(0)
rate = 101 - speed.get() #rate = 1001 - speed.get()
sleep(0.1)
direction = "focus up"
print("Запуск мотора %s..." % direction)
move(direction)
def stop_focus_motorup(event):
resetPins(4)
direction = "focus up"
global thing
root.after_cancel(thing)
print("Остановка мотора %s..." % direction)
def start_focus_motordown(event):
global rate
dir_4.write(1) # Pull direction pin low to move "forward"
EN_4.write(0)
rate = 101 - speed.get() #rate = 1001 - speed.get()
sleep(0.1)
direction = "focus down"
print("Запуск мотора %s..." % direction)
move(direction)
def stop_focus_motordown(event):
resetPins(4)
direction = "focus down"
global thing
root.after_cancel(thing)
print("Остановка мотора %s..." % direction)
def move(direction):
global thing, vert_pos, hor_pos, stage_pos, foc_pos, rate, limit
if direction == "forward":
if hor_pos >= limit:
print("Horizontal edge reached at %d...Stopping." % hor_pos)
safe_stop()
else:
stp_1.write(1)
sleep(0.001) #sleep(rate/100000)
stp_1.write(0)
print("forward %d" % hor_pos)
hor_pos += 1
elif direction == "reverse":
if hor_pos <= 0:
print("Horizontal edge reached at %d...Stopping." % hor_pos)
safe_stop()
else:
stp_1.write(1)
sleep(rate/100000)
stp_1.write(0)
print("reverse %d" % hor_pos)
hor_pos -= 1
elif direction == "up":
if vert_pos >= limit:
print("Horizontal edge reached at %d...Stopping." % vert_pos)
safe_stop()
else:
stp_2.write(1)
sleep(rate/100000)
stp_2.write(0)
print("up")
vert_pos += 1
elif direction == "down":
if vert_pos <= 0:
print("Horizontal edge reached at %d...Stopping." % vert_pos)
safe_stop()
else:
stp_2.write(1)
sleep(rate/100000)
stp_2.write(0)
print("down")
vert_pos -= 1
elif direction == "stage up":
if stage_pos >= limit:
print("Horizontal edge reached at %d...Stopping." % stage_pos)
safe_stop()
else:
stp_3.write(1)
sleep(rate/100000)
stp_3.write(0)
print("stage up")
stage_pos += 1
elif direction == "stage down":
if stage_pos <= 0:
print("Horizontal edge reached at %d...Stopping." % stage_pos)
safe_stop()
else:
stp_3.write(1)
sleep(rate/100000)
stp_3.write(0)
print("stage down")
stage_pos -= 1
elif direction == "focus up":
if foc_pos >= limit:
print("Horizontal edge reached at %d...Stopping." % foc_pos)
safe_stop()
else:
stp_4.write(1)
sleep(rate/100000)
stp_4.write(0)
print("focus up")
foc_pos += 1
elif direction == "focus down":
if foc_pos <= 0:
print("Horizontal edge reached at %d...Stopping." % foc_pos)
safe_stop()
else:
stp_4.write(1)
sleep(rate/100000)
stp_4.write(0)
print("focus down")
foc_pos -= 1
else:
print("error")
safe_stop()
#int(rate)
thing = root.after(1, move, direction)
def safe_stop():
global thing
root.after_cancel(thing)
print("Неверное направление... вызов безопасной остановки.")
def resetPins(num):
if num == 1 or num == 5:
stp_1.write(0)
dir_1.write(0)
MS1_1.write(0)
MS2_1.write(0)
MS3_1.write(0)
EN_1.write(1)
if num == 2 or num == 5:
stp_2.write(0)
dir_2.write(0)
MS1_2.write(0)
MS2_2.write(0)
MS3_2.write(0)
EN_2.write(1)
if num == 3 or num == 5:
stp_3.write(0)
dir_3.write(0)
MS1_3.write(0)
MS2_3.write(0)
MS3_3.write(0)
EN_3.write(1)
if num == 4 or num == 5:
stp_4.write(0)
dir_4.write(0)
MS1_4.write(0)
MS2_4.write(0)
MS3_4.write(0)
EN_4.write(1)
def return_home(event):
global hor_pos, vert_pos, stage_pos, foc_pos
if hor_pos - 5000 != 0:
dist = abs(hor_pos - 5000)
if hor_pos > 5000:
dir_1.write(1)
else:
dir_1.write(0)
EN_1.write(0)
sleep(0.1)
while dist > 0:
stp_1.write(1)
sleep(0.0001)
stp_1.write(0)
sleep(0.001)
dist -= 1
print(dist)
resetPins(1)
hor_pos = 5000
if vert_pos - 5000 != 0:
dist = abs(vert_pos - 5000)
if vert_pos > 5000:
dir_2.write(1)
else:
dir_2.write(0)
EN_2.write(0)
sleep(0.1)
while dist > 0:
stp_2.write(1)
sleep(0.0001)
stp_2.write(0)
sleep(0.00001)
dist -= 1
print(dist)
resetPins(2)
vert_pos = 5000
if stage_pos - 5000 != 0:
dist = abs(stage_pos - 5000)
if stage_pos > 5000:
dir_3.write(1)
else:
dir_3.write(0)
EN_3.write(0)
sleep(0.1)
while dist > 0:
stp_3.write(1)
sleep(0.0001)
stp_3.write(0)
sleep(0.00001)
dist -= 1
print(dist)
resetPins(3)
stage_pos = 5000
if foc_pos - 5000 != 0:
dist = abs(foc_pos - 5000)
if foc_pos > 5000:
dir_4.write(1)
else:
dir_4.write(0)
EN_4.write(0)
sleep(0.1)
while dist > 0:
stp_4.write(1)
sleep(0.0001)
stp_4.write(0)
sleep(0.00001)
dist -= 1
print(dist)
resetPins(1)
foc_pos = 5000
button1 = Button(root, text="Вперед", height=5, width=20, bg="white", fg="blue")
button1.grid(row=6, column=2)
button1.bind('<ButtonPress-1>', start_motorfwd)
button1.bind('<ButtonRelease-1>', stop_motorfwd)
button2 = Button(root, text="Обратно", height=5, width=20, bg="white", fg="red")
button2.grid(row=6, column=0)
button2.bind('<ButtonPress-1>', start_motorrev)
button2.bind('<ButtonRelease-1>', stop_motorrev)
button3 = Button(root, text="Вверх", height=5, width=20, bg="white", fg="blue")
button3.grid(row=0, column=1)
button3.bind('<ButtonPress-1>', start_motorup)
button3.bind('<ButtonRelease-1>', stop_motorup)
button4 = Button(root, text="Вниз", height=5, width=20, bg="white", fg="red")
button4.grid(row=10, column=1)
button4.bind('<ButtonPress-1>', start_motordown)
button4.bind('<ButtonRelease-1>', stop_motordown)
button5 = Button(root, text="Ступень вверх", height=5, width=20, bg="white", fg="blue")
button5.grid(row=12, column=0)
button5.bind('<ButtonPress-1>', start_stage_motorup)
button5.bind('<ButtonRelease-1>', stop_stage_motorup)
button6 = Button(root, text="Ступень вниз", height=5, width=20, bg="white", fg="red")
button6.grid(row=13, column=0)
button6.bind('<ButtonPress-1>', start_stage_motordown)
button6.bind('<ButtonRelease-1>', stop_stage_motordown)
button7 = Button(root, text="Фокус вверх", height=5, width=20, bg="white", fg="blue")
button7.grid(row=12, column=2)
button7.bind('<ButtonPress-1>', start_focus_motorup)
button7.bind('<ButtonRelease-1>', stop_focus_motorup)
button8 = Button(root, text="Фокус вниз", height=5, width=20, bg="white", fg="red")
button8.grid(row=13, column=2)
button8.bind('<ButtonPress-1>', start_focus_motordown)
button8.bind('<ButtonRelease-1>', stop_focus_motordown)
button9 = Button(root, text="Возврат домой", height=5, width=20, bg="white", fg="red")
button9.grid(row=6, column=1)
button9.bind('<ButtonPress-1>', return_home)
speed = Scale(root, from_=1, to=100, orient=HORIZONTAL, label="Скорость", length=435, width=30, bg="white")
speed.grid(row=24, column=1)
if __name__ == '__main__':
main()
root.mainloop()
b.exit()
Тест Программа
Простая тестовая программа Firmata для Arduino Uno через Python Tkinter и инфраструктуру pyFirmata.
from tkinter import *
from tkinter.simpledialog import askinteger
from pyfirmata import Arduino, PWM
from serial.tools.list_ports import comports
root = Tk()
# меню радиокнопки для отображения списка и выбора последовательного порта
class PortsMenu(Menu):
def __init__(self, parent=None, ports=[]):
Menu.__init__(self, parent)
self.ports = ports
self.port = StringVar()
self.add_menu()
def add_menu(self):
for port in self.ports:
self.add_radiobutton(
label=port,
variable=self.port, value=port,
command=self.choose_port)
def choose_port(self):
global board
try:
board = Arduino(self.port.get())
print("подключен к последовательному порту: %s" % self.port.get())
except:
print("пожалуйста, убедитесь, что вы выбрали правильный последовательный порт")
# новый класс Frame содержит метку для отображения его функции
# кнопка с быстрым меню для выбора pin-кода и отображения текущего пина в коде,
# и кнопка для изменения и отображения статуса пина в коде.
class Block(Frame):
def __init__(self, parent=None, text="", pins=[]):
Frame.__init__(self, parent)
self.pins = {}
self.init_pin(pins)
self.current_pin = IntVar()
self.current_pin.set(pins[0])
self.add_label(text)
self.menu_button = self.add_options(pins)
self.button = CustomButton(self, text="LOW", command=self.click_button)
self.pack()
def init_pin(self, pins):
for pin in pins:
self.pins[pin] = 0
def get_pin(self):
return self.current_pin.get()
def add_label(self, text):
label = Label(self, text=text)
label.config(width='15', height='3', font=('courier', 16, 'bold'))
label.pack(side=LEFT)
def add_options(self, pins):
menu_button = CustomButton(self, text="Pin " + str(pins[0]))
menu_button.bind(
'<Button-1>', (lambda event: menu.post(event.x_root, event.y_root)))
menu = Menu(tearoff=False)
for pin in self.pins.keys():
menu.add_radiobutton(
label="Pin " + str(pin),
command=self.update_status,
variable=self.current_pin, value=pin)
return menu_button
def update_status(self):
current_pin = self.get_pin()
self.menu_button.config(text="Pin " + str(current_pin))
if self.pins[current_pin]:
self.button.config(text='HIGH', fg='red')
else:
self.button.config(text='LOW', fg='black')
def click_button(self):
current_pin = self.get_pin()
self.pins[current_pin] = 1 - self.pins[current_pin]
try:
board.digital[current_pin].write(self.pins[current_pin])
if self.pins[current_pin]:
self.button.config(text="HIGH", fg="red")
print("Pin %s sets to HIGH" % current_pin)
else:
self.button.config(text="LOW", fg="black")
print("Pin %s sets to LOW" % current_pin)
except:
print("пожалуйста, убедитесь, что вы выбрали правильный последовательный порт")
# пользовательский класс кнопок для создания кнопок с некоторыми общими свойствами
class CustomButton(Button):
def __init__(self, parent=None, **config):
Button.__init__(self, parent, **config)
self.config(width='10', height='2', font=(
'courier', 18, 'bold'), bd=1, relief=RAISED)
self.pack(side=LEFT, padx=20, pady=20)
# новый класс фреймов содержит метку, кнопку с быстрым меню для выбора закрепления
# и шкала для изменения и отображения значения pwm_output
class PwmBlock(Block):
def __init__(self, parent=None, text="", pins=[]):
Block.__init__(self, parent, text, pins)
self.scale_var = IntVar()
self.scale_var.set(0)
self.add_scale()
self.button.config(text="0")
def update_status(self):
current_pin = self.get_pin()
self.menu_button.config(text="Pin " + str(current_pin))
self.button.config(text=self.pins[current_pin])
self.scale_var.set(self.pins[current_pin])
def click_button(self):
input_value = askinteger(
"PWM value", "Please input a number between 0-1023",
minvalue=0, maxvalue=1023, initialvalue=0)
if input_value is not None:
self.onMove(input_value)
self.scale_var.set(input_value)
def add_scale(self):
Scale(self, label="Перетащите, чтобы выбрать выходное значение",
command=self.onMove,
variable=self.scale_var,
from_=0, to_=1023, length=300,
orient='horizontal').pack(side=LEFT)
def onMove(self, value):
current_pin = self.get_pin()
self.pins[current_pin] = int(value)
self.button.config(text=value)
value = int(value) / 1024
try:
board.digital[current_pin].mode = PWM
board.digital[current_pin].write(value)
print("Pin %s sets PWM output: %d" %
(current_pin, self.pins[current_pin]))
except:
print("пожалуйста, убедитесь, что вы выбрали правильный последовательный порт")
# в меню портов панели меню выберите последовательный порт arduino
serial_ports = [port[0] for port in comports()]
menu = Menu(root)
root.config(menu=menu)
ports_menu = PortsMenu(menu, serial_ports)
menu.add_cascade(label="Ports", menu=ports_menu)
# цифровой выход с контакта 2 до контакта 13
digital_pins = [x + 2 for x in range(12)]
digital_pins_block = Block(root, "Digital Write", digital_pins)
pwm_pins = [3, 5, 6, 9, 10, 11]
pwm_pins_block = PwmBlock(root, "PWM Write", pwm_pins)
pwm_pins_block.pack(side=BOTTOM)
if __name__ == '__main__':
root.mainloop()
Подведём итоги
- Для начала, надо установить библиотеку в IDE Arduino.
- Подключить плату Ардуино и выбрать в меню IDE Arduino, раздел “Примеры”, далее Firmata – StandartFirmata, загрузить файл (не забыть выбрать тип платы и номер порта).
- Для работы с протоколом Firmata в Python вам понадобится пакет pyFirmata, который вы можете установить с помощью pip: pip install pyfirmata
- При создании проекта необходимо добавить в код библиотеку, например from pyfirmata *
- При подключении библиотеки pyfirmata, можно выборочно подключить определённые функции из этой библиотеки. Например по типу использоваемой платы: from pyfirmata import Arduino или from pyfirmata import ArduinoMega. Файл с описанием плат здесь.
- Вариант подключения через передачу через значения в переменную board. Здесь Arduino это функция библитеки pyfirmata. Например, если подключена плата Ардуино Мега, то будет ArduinoMega. Пример: board = Arduino(‘COM4’) # Пишем наш порт или b = ArduinoMega(com)
- Передача цифрового значения на пин.
board.digital
– это список, элементы которого представляют цифровые контакты Arduino. Эти элементы имеют методыread()
иwrite()
, которые будут читать и записывать состояние выводов. Пример: board.digital[13].write(1). Здесь назначаем цифровой пин 13 и записываем состояниепина 1 (включено). Как и большинство встроенных программ для устройств, эта программа в основном должна состоять из бесконечного цикла: Пример:
from pyfirmata import Arduino, util
from time import sleep
board = Arduino(‘COM4’) # Change to your port
print(“Start blinking D13”)
while True:
board.digital[13].write(1)
sleep(1)
board.digital[13].write(0)
sleep(1)
8. Приём цифрового значения пина. Устанавливаем вывод 10 как цифровой вход с pyfirmata.INPUT. Это необходимо, поскольку в конфигурации по умолчанию используются цифровые контакты в качестве выходов: board.digital[10].mode = pyfirmata.INPUT. Считываем значение с цифрового пина 10. board.digital[10].read().
9. Назначает итератор, который будет использоваться для считывания состояния входов схемы. it = pyfirmata.util.Iterator(board). Запускает итератор, который поддерживает цикл, работающий параллельно с вашим основным кодом it.start().
it = pyfirmata.util.Iterator(board)
it.start()
10. Компактный синтаксис. pyfirmata также предлагает более компактный синтаксис для работы с входными и выходными выводами. Это может быть хорошим вариантом, когда вы работаете с несколькими выводами. Вы можете переписать предыдущую программу, чтобы иметь более компактный синтаксис:
import pyfirmata import time board = pyfirmata.Arduino('/dev/ttyACM0')
it = pyfirmata.util.Iterator(board)
it.start()
digital_input = board.get_pin('d:10:i')
led = board.get_pin('d:13:o')
while True:
sw = digital_input.read()
if sw is True:
led.write(1)
else:
led.write(0)
time.sleep(0.1)
В этой версии вы используете board.get_pin() для создания двух объектов. digital_input представляет состояние цифрового входа, а led представляет состояние светодиода. Когда вы запускаете этот метод, вы должны передать строковый аргумент, состоящий из трех элементов, разделенных двоеточиями:
Поскольку digital_input – это цифровой вход, использующий вывод 10, вы передаете аргумент ‘d:10:i’.
digital_input = board.get_pin(‘d:10:i’)
Состояние светодиода устанавливается на цифровой выход с помощью контакта 13, поэтому аргумент светодиода ‘d:13:o’.
- Тип контакта (a для аналогового или d для цифрового);
- Номер контакта 13;
- Режим вывода (i для ввода или o для вывода).
Когда вы используете board.get_pin() нет необходимости явно устанавливать вывод 10 в качестве входа, как вы делали раньше с pyfirmata.INPUT. После того, как контакты установлены, вы можете получить доступ к статусу цифрового входного контакта, используя read(), и установить статус цифрового выходного контакта с помощью write().
11. Аналоговые входы. В отличие от цифровых входов, которые могут быть только включены или выключены, аналоговые входы используются для считывания значений в некотором диапазоне.
На Arduino Uno напряжение на аналоговом входе находится в диапазоне от 0 до 5 В. Соответствующие датчики используются для измерения физических величин, таких, например, как расстояния. Эти датчики отвечают за кодирование этих физических величин в надлежащем диапазоне напряжения, чтобы они могли считываться Arduino.
Для считывания аналогового напряжения Arduino использует аналого-цифровой преобразователь (АЦП), который преобразует входное напряжение в цифровое число с фиксированным числом битов. Это определяет разрешение преобразования. Arduino Uno использует 10-разрядный АЦП и может определять 1024 различных уровня напряжения.
Диапазон напряжения для аналогового входа кодируется числами от 0 до 1023. Когда подается напряжение 0 В, Arduino кодирует его в число 0. Когда подается напряжение 5 В, кодированное число равно 1023. Все значения промежуточного напряжения кодируются пропорционально.
import pyfirmata
import time
board = pyfirmata.Arduino("COM12")
it = pyfirmata.util.Iterator(board)
it.start()
analog_input = board.get_pin('a:0:i')
while True:
analog_value = analog_input.read()
print(analog_value)
time.sleep(0.1)
Вы устанавливаете analog_input в качестве аналогового входного вывода A0 с аргументом ‘a:0:i’.
analog_input = board.get_pin(‘a:0:i’)
Внутри бесконечного цикла while вы читаете это значение, сохраняете его в analog_value
analog_value = analog_input.read()
и выводите вывод на консоль с помощью print().
print(analog_value)
Полученные значения изменяются в диапазоне от 0, когда потенциометр находится в одном положении, до 1, когда он находится в противоположном состоянии. Обратите внимание, что все значения выводятся с плавающей запятой, что может потребовать преобразования в зависимости от приложения.
Чтобы изменить частоту мигания светодиода, вы можете использовать analog_value для контроля того, как долго светодиод будет гореть или выключаться:
import pyfirmata
import time
board = pyfirmata.Arduino('/dev/ttyACM0')
it = pyfirmata.util.Iterator(board)
it.start()
analog_input = board.get_pin('a:0:i')
led = board.get_pin('d:13:o')
while True:
analog_value = analog_input.read()
if analog_value is not None:
delay = analog_value + 0.01
led.write(1)
time.sleep(delay)
led.write(0)
time.sleep(delay)
else:
time.sleep(0.1)
Здесь вы вычисляете задержку как analog_value + 0.01, чтобы избежать задержки равной нулю.
В противном случае, в течение первых нескольких итераций обычно получается analog_value как none. Чтобы избежать появления ошибки при запуске программы, вы используете условное выражение в строке 13, чтобы проверить, является ли analog_value значением none. Затем вы контролируете период мигания светодиода.
Попробуйте запустить программу и изменить положение потенциометра. Вы заметите смену частоты мигающего светодиода:
12. Аналоговые выходы. Arduino не имеет реального аналогового выхода, в котором напряжение может быть установлено на любое значение в определенном диапазоне. Тем не менее, Arduino имеет несколько выходов с широтно-импульсной модуляцией (ШИМ).
ШИМ – это метод модуляции, при котором цифровой выход используется для генерации сигнала с переменной мощностью. Для этого используется цифровой сигнал постоянной частоты, в котором коэффициент заполнения изменяется в соответствии с желаемой мощностью. Рабочий цикл представляет собой долю периода, в течение которого сигнал установлен на высокий уровень.
Не все цифровые выводы Arduino могут использоваться в качестве выходов ШИМ. Те, которые могут быть обозначены тильдой (~):
Несколько устройств предназначены для управления сигналами ШИМ, включая некоторые двигатели. Можно даже получить реальный аналоговый сигнал из сигнала ШИМ, если вы используете аналоговые фильтры.
В предыдущем уроке вы использовали цифровой выход для включения или выключения светодиодной подсветки. В этом уроке вы будете использовать ШИМ для управления яркостью светодиода в соответствии со значением аналогового входа, заданного потенциометром.
Когда на светодиод подается сигнал ШИМ его яркость изменяется в соответствии с рабочим циклом сигнала ШИМ
Эта схема идентична той, которая использовалась в предыдущем уроке для проверки аналогового входа, за исключением одного отличия. Поскольку невозможно использовать ШИМ с выводом 13, вывод цифрового выхода, используемый для светодиода, – это вывод 11.
Собрав схему, вы можете управлять светодиодом с помощью ШИМ с помощью следующей программы:
import pyfirmata
import time
board = pyfirmata.Arduino('/dev/ttyACM0')
it = pyfirmata.util.Iterator(board)
it.start()
analog_input = board.get_pin('a:0:i')
led = board.get_pin('d:11:p')
while True:
analog_value = analog_input.read()
if analog_value is not None:
led.write(analog_value)
time.sleep(0.1)
Есть несколько отличий от программ, которые вы использовали ранее:
- В строке 10 вы устанавливаете светодиод в режим ШИМ, передавая аргумент ‘d:11:p’.
- В строке 15 вы вызываете led.write() с analog_value в качестве аргумента. Это значение от 0 до 1, считанное с аналогового входа.
Чтобы показать изменения в рабочем цикле, осциллограф подключается к контакту 11. Когда потенциометр находится в нулевом положении, вы можете видеть, что светодиод выключен, так как на выходе 11 у нас 0 В.
Когда вы поворачиваете потенциометр, светодиод становится ярче по мере увеличения рабочего цикла ШИМ. Когда вы полностью поворачиваете потенциометр, рабочий цикл достигает 100%. Светодиод горит постоянно на максимальной яркости.
Ещё пример с работой ШИМа
import pyfirmata
import time
board = pyfirmata.Arduino('/dev/ttyACM0')
it = pyfirmata.util.Iterator(board)
it.start()
analog_input = board.get_pin('a:0:i')
led = board.get_pin('d:11:p')
while True:
analog_value = analog_input.read()
from pyfirmata import Arduino, util
from time import sleep
board = Arduino('COM4') # Change to your port
lenPin = board.get_pin('d:6:p') # PWM Pin
print("Starting to output PWM signal")
while True:
for i in range(0, 101, 4):
lenPin.write(i/100)
sleep(0.05)
sleep(1)
for i in range(100, -1, -4):
lenPin.write(i/100)
sleep(0.05)
sleep(1)
13. Использование датчика для запуска уведомления.
Firmata – это хороший способ начать работу с Arduino и Python, но необходимость в ПК или другом устройстве для запуска приложения может быть не оправдано, и в некоторых случаях такой подход может оказаться нецелесообразным.
Однако, когда необходимо собрать данные и отправить их на ПК с помощью внешних датчиков, Arduino и Firmata создают хорошую комбинацию.
В этом уроке мы будем использовать кнопку, подключенную к вашему Arduino, чтобы имитировать цифровой датчик и запускать уведомления на вашем компьютере. Для более практического применения вы можете думать о кнопке как, например, о датчике двери, который вызовет “тревожное” уведомление.
Для отображения уведомления на ПК мы будем использовать Tkinter, стандартный набор инструментов Python GUI. Этот инструмент нам поможет показать окно сообщения при нажатии кнопки.
После сборки схемы используйте следующую программу для запуска уведомлений:
import pyfirmata
import time import
tkinter from tkinter
import messagebox
root = tkinter.Tk()
root.withdraw()
board = pyfirmata.Arduino('/dev/ttyACM0')
it = pyfirmata.util.Iterator(board)
it.start()
digital_input = board.get_pin('d:10:i')
led = board.get_pin('d:13:o')
while True:
sw = digital_input.read()
if sw is True:
led.write(1)
messagebox.showinfo("Notification", "Button was pressed")
root.update()
led.write(0)
time.sleep(0.1)
Эта программа похожа на ту, которая используется в уроке с цифровым входом, с некоторыми изменениями:
- Строки 3 и 4 импортируют библиотеки, необходимые для настройки Tkinter.
- Строка 6 создает главное окно Tkinter. root = tkinter.Tk()
- Строка 7 говорит Tkinter не показывать главное окно на экране. root.withdraw() . Для этого примера вам нужно только увидеть окно сообщения.
- Строка 17 запускает цикл while:
1. Когда вы нажимаете кнопку, включается светодиод, и messagebox.showinfo() отображает окно сообщения.
2. Цикл приостанавливается до тех пор, пока пользователь не нажмет OK. Таким образом, светодиод остается включенным, пока сообщение находится на экране.
3. После того, как пользователь нажмет OK, root.update() очищает окно сообщения с экрана, и индикатор выключается.
Чтобы расширить пример уведомления, вы можете даже использовать кнопку для отправки электронного письма при нажатии:
import pyfirmata
import time
import smtplib
import ssl
def send_email():
port = 465 # For SSL
smtp_server = "smtp.gmail.com"
sender_email = ""
receiver_email = ""
password = ""
message = """Subject: Arduino Notification\n The switch was turned on."""
context = ssl.create_default_context()
with smtplib.SMTP_SSL(smtp_server, port, context=context) as server:
print("Sending email")
server.login(sender_email, password)
server.sendmail(sender_email, receiver_email, message)
board = pyfirmata.Arduino('COM11')
it = pyfirmata.util.Iterator(board)
it.start()
digital_input = board.get_pin('d:10:i')
while True:
sw = digital_input.read()
if sw is True:
send_email()
time.sleep(0.1)
Здесь вы настраиваете функцию с учетными данными почтового сервера, которые будут использоваться для отправки электронной почты. Про работу send_email() и отправку писем с помощью Python мы поговорим в отдельном материале или курсе совсем скоро.
Примечание. Если вы используете учетную запись Gmail для отправки электронных писем, вам необходимо включить параметр “Разрешить менее безопасные приложения” (Allow less secure apps).
14. Обработка исключений в Python (try except)
Обработка исключений — это процесс написания кода для перехвата и обработки ошибок или исключений, которые могут возникать при выполнении программы. Это позволяет разработчикам создавать надёжные программы, которые продолжают работать даже при возникновении неожиданных событий или ошибок. Без системы обработки исключений подобное обычно приводит к фатальным сбоям.
При правильном выборе подключенного ком.порта, программа продолжает работу:
b = ArduinoMega(com)
При ошибки подключения:
except Exception as e:
происходит создание, открытие и запись ошибки в файл:
logf = open(“error.log”, “w”)
Происходит запись в файл текста “Не удалось подключиться к порту” сом и запись ошибки в строковом формате (е):
logf.write(“Не удалось подключиться к порту {0}: {1}\n”.format(com, str(e)))
Далее происходит закрытие файла:
logf.close()
И выход из программы:
sys.exit()
try:
b = ArduinoMega(com)
except Exception as e:
logf = open("error.log", "w")
logf.write("Не удалось подключиться к порту {0}: {1}\n".format(com, str(e)))
logf.close()
sys.exit()
Python-скрипт для Arduino IDE
Простейший интерфейс Python для управления выводами Arduino с использованием протокола Firmata
Исследования библиотеки pyFirmata для использования в платах ESP32 через StandardFirmata для ESP32
Скрипт Python для управления цифровым усилителем TAS5518 через I2C с использованием Firmata и Arduino
Считайте температуру с датчика DS1620, подключенного к Arduino, с помощью Firmata
4-осевой микроманипуляторный столик
Добро пожаловать в программу чтения кода Морзе для Arduino