В начале 2021 года я начал свой проект роботов. Одним из его подпроектов было знакомство с Arduino и C-программированием. Arduino не имеет себе равных с точки зрения библиотек датчиков и исполнительных механизмов и не имеет себе равных по принципу «подключи и работай». Однако в середине года я принял решение перейти на использование Raspberry Pico и MicroPython для реализации моего робота. Этот выбор мотивирован использованием одного и только одного языка программирования для промежуточного программного обеспечения Robotics, SBD и микроконтроллера, а также использования мощных библиотек Python для распознавания изображений, которые предлагает камера RealSense D435.
Для начала мне нужно заново изучить основы последовательных подключений между Raspberry Pico с MicroPython и Raspberry Pi с Python. В этой статье объясняются основы успешного подключения.
Чтобы подключиться от Pi к Pico, есть три варианта:
Поскольку Raspberry Pico еще относительно молод, техническая зрелость стека MicroPython влияет на то, какие из этих подключений можно использовать.
Когда вы используете вариант A или C, вы можете сразу перейти к примерам. Если вы хотите использовать вариант B, вам необходимо включить контакты Tx / Rx, выполнив действия, описанные в следующем разделе.
После этой замечательной статьи вам необходимо сделать следующее:
$> sudo raspi-config
=> 3. Interface Option
=> P6. Serial Port
=> Would you like a login shell to be accessible over serial?
Answer with 'No'
=> Would you like the serial port hardware to be enabled?
Answer with 'Yes'
/dev/ttyS0
$> sudo systemctl stop serial-getty@ttyS0.service
$> sudo systemctl disable serial-getty@ttyS0.service
$> sudo nano /boot/cmdline.txt
=> Remove or comment out a line that says 'console=serial0,115200'
Интересно, что Pi по-прежнему будет отправлять системные сообщения через контакты Tx / Rx - это может быть конкретный вариант использования, который вы искали. Вот пример вывода, когда я выключаю Pi.
>> [ OK ] Stopped LSB: automatic crash report generation.
>> [ OK ] Stopped User Manager for UID 1000.
>> [ OK ] Stopped Login Service.
>> RPI 4 Model B (0xc03111)
Отправка данных с Raspberry Pi на Pico - это один и тот же код во всех примерах с небольшими изменениями: порт, к которому подключен Pico.
Используйте этот шаблонный код:
# sender.py
import time
import serial
ser = serial.Serial(
port='/dev/ttyS0', # Change this according to connection methods, e.g. /dev/ttyUSB0
baudrate = 115200,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1
)
msg = ""
i = 0
while True:
i+=1
print("Counter {} - Hello from Raspberry Pi".format(i))
ser.write('hello'.encode('utf-8'))
time.sleep(2)
Объяснение:
serial
, которая обеспечивает последовательное соединение.port
должн быть настроен в соответствии с методами подключения - см ниже подробного описаниеencode
строковые данные, а затем отправить их с помощью write
в последовательный объект.Теперь рассмотрим приемную сторону.
На момент написания этой статьи самой последней версией MicroPython, работающей на Pico, была MicroPython v1.16 on 2021-06-18
. В этой версии нет встроенной библиотеки для последовательной связи через USB.
Однако в этом потоке Pico Forum пользователь предоставляет чистую реализацию MicroPython, которая порождает поток на втором ядре процессора Pico, который активно прослушивает входящие байты через USB. Я пробовал этот код в своем раннем прототипе робота и мог использовать его для получения сообщений через USB на Pico, которые приказывали моему роботу двигаться.
Вот мой рабочий пример:
# receiver.py / USB => USB
import sys
sys.path.append('/radu')
import os
from bot import Bot
from rusb import USB
from _thread import start_new_thread
from time import sleep_ms
radu = Bot('Radu MK1')
usb = USB()
input_msg = None
bufferSTDINthread = start_new_thread(usb.bufferSTDIN, ())
while True:
input_msg = usb.getLineBuffer()
if input_msg and 'ros_msg' in input_msg:
obj = eval(input_msg)
radu.notify(obj)
sleep_ms(10)
Прямое соединение между выводами Tx / Rx означает:
Как объяснялось выше, вам также необходимо настроить Raspberry Pi для включения этих контактов. По завершении используйте следующий код:
# receiver.py / Tx/Rx => Tx/Rx
import os
import machine
from time import sleep
uart = machine.UART(0, 115200)
print(uart)
b = None
msg = ""
while True:
sleep(1)
if uart.any():
b = uart.readline()
print(type(b))
print(b)
try:
msg = b.decode('utf-8')
print(type(msg))
print(">> " + msg)
except:
pass
В этой программе:
uart
, обратившись к внутреннему экземпляру Pico machine.UART
. Он определяется с теми же значениями, с которыми настроен код отправителя. Обратите внимание, что документация MicroPython также позволяет вам создать инстанс UART с другой конфигурацией, например, с более медленной скоростью передачи.uart.any()
возвращает положительное целое число, если в соединении UART доступен хотя бы один символ.read(i)
, где i
- количество символов, или readline()
чтобы прочитать все символы, пока не будет достигнута новая строка. Работа с отдельными символами эффективнее и быстрее, работа с полными строками более надежна, если вам нужно обмениваться сложной информацией.try - except
начинается блок, в котором ...Во-первых, вам нужно приобрести адаптер USB-TTL, который поставляется как минимум с двумя разными чипсетами: FT232RL и CH340g.
Вставьте адаптер в USB-порты Picos, а затем используйте его dmesg
, чтобы увидеть, как настроено это устройство.
[326612.390873] usb 1-2: new full-speed USB device number 54 using xhci_hcd
[326612.543888] usb 1-2: New USB device found, idVendor=1a86, idProduct=7523, bcdDevice= 2.64
[326612.543893] usb 1-2: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[326612.543895] usb 1-2: Product: USB Serial
[326612.546221] ch341 1-2:1.0: ch341-uart converter detected
[326612.549000] usb 1-2: ch341-uart converter now attached to ttyUSB0
В последней строке говорится ttyUSB0
, что код отправителя необходимо изменить следующим образом:
# sender.py / USB-TTL => Tx/Rx
# ...
ser = serial.Serial(
port='/dev/USB0'
# ...
)
Код для приема данных остается таким же, как и при прямом соединении Tx / Rx.
Теперь давайте посмотрим на наш код в действии.
Выполнение sender.py
на Raspberry Pi выводит эту информацию:
>>>
Counter 1 - Hello from Pi4
Counter 2 - Hello from Pi4
Counter 3 - Hello from Pi4
Counter 4 - Hello from Pi4
И запуск receinver.py
на Raspberry Pico покажет это:
%Run -c $EDITOR_CONTENT
(sysname='rp2', nodename='rp2', release='1.16.0', version='v1.16 on 2021-06-18 (GNU 10.2.0 MinSizeRel)', machine='Raspberry Pi Pico with RP2040')
UART(0, baudrate=115200, bits=8, parity=None, stop=1, tx=0, rx=1, txbuf=256, rxbuf=256, timeout=0, timeout_char=1, invert=None)
<class 'bytes'>
b'hello\n'
<class 'str'>
>> hello