[PYTHON] Steuern Sie das Matrix-LED-Panel von ROS aus

Einführung

Ich habe eine Matrix-LED (64 x 64) von Shigezone in Akihabara gekauft, aber ich habe beschlossen, sie auf ROS zu betreiben. In diesem Artikel erstellen wir einen "ROS-Knoten, der das Bildthema abonniert und das Bild auf der Matrix-LED anzeigt".

Umweltvorbereitung

Raspberry Pi vorbereiten

Dieses Mal werden wir Raspberry Pi 3 mit Ubuntu verwenden, um ROS zu handhaben. Flashen Sie das Image von hier auf die SD-Karte und installieren Sie ROS. Ich habe Ubuntu 18.04.3. Von arm64 installiert. ROS installierte ros-melodic-desktop unter Bezugnahme auf diese Site.

Vorbereitung der Matrix-LED-Panel-Verbindungsplatine

Um diese Software als Treiber für MatrixLED zu verwenden, haben wir eine entsprechende Treiberplatine vorbereitet. Das Board wurde von Electrodragon (https://www.electrodragon.com/product/rgb-matrix-panel-drive-board-raspberry-pi/) bezogen, aber Sie können es selbst vorbereiten. Die von Ihnen gekaufte Karte verfügt über einen eingebauten Pegelwandler von 3,3 V auf 5 V, sodass Sie einen stabilen Betrieb erwarten können. Da die verwendete Matrix-LED 64 x 64 groß ist und Adressleitungen von A nach E hat, muss die Treiberplattenseite an einer Stelle verlötet werden, um "E" anzuschließen. Für das Matrix-LED-Panel, das ich dieses Mal gekauft habe, habe ich einen Jumper gesetzt, um Pin8 mit E zu verbinden. Es ist notwendig, 5 V (ich denke, es sind mindestens 3 A) separat an das LED-Panel-Gehäuse zu liefern.

Vorbereitung des LED-Panel-Treibers

Um festzustellen, ob die Hardware ordnungsgemäß funktioniert, klonen Sie aus dem Repository und kompilieren Sie das Beispielprogramm.

rpi-rgb-led-matrix$ make -C examples-api-use
rpi-rgb-led-matrix$ sudo examples-api-use/demo -D0 --led-rows=64 --led-cols=64 --led-panel-type=FM6126A

Die bunten Würfel sollten sich drehen. Abhängig vom Typ des Matrix-LED-Panels kann FM6126A als Chip montiert werden. In diesem Fall muss eine Option angegeben werden, da das für die Initialisierung erforderliche Signal unterschiedlich ist.

Wenn dies funktioniert, installieren Sie die Bibliothek für Python gemäß den Prozeduren desselben Repositorys. Ich werde.

$ sudo apt-get update && sudo apt-get install python2.7-dev python-pillow -y
rpi-rgb-led-matrix/bindings/python$ make build-python
rpi-rgb-led-matrix/bindings/python$ sudo make install-python

An diesem Punkt können Sie "aus rgbmatrix RGBMatrix, RGBMatrixOptions importieren".

ROS mit sudo verwenden

Die diesmal verwendete Matrix LED-Treibersoftware muss von sudo ausgeführt werden. Mit der Kombination von Ubuntu18.04 + Raspberry pi3 konnte ich nicht auf die Hardwareressourcen (GPIO usw.) zugreifen, die von allgemeinen Benutzern benötigt werden, und entschied mich daher, die ROS-Seite mit sudo auszuführen. (Ich denke, es sollte so eingestellt werden, dass allgemeine Benutzer auf die erforderlichen Hardwareressourcen zugreifen können.)

Im Allgemeinen funktioniert ROS nicht gut, da Umgebungsvariablen gelöscht werden, wenn sudo ausgeführt wird. Also habe ich beschlossen, die Einstellungen zur sudoers-Datei hinzuzufügen.

Defaults        env_keep += "PATH PKG_CONFIG_PATH PYTHONPATH ROS_ROOT ROS_ETC_DIR ROS_MASTER_URI ROS_VERSION ROS_PYTHON_VERSION ROS_PACKAGE_PATH ROS_DISTRO CMAKE_PREFIX_PATH LD_LIBRARY_PATH"

Durch Hinzufügen dieser einen Zeile mit dem Befehl "sudo visudo" werden die für ROS erforderlichen Umgebungsvariablen bei der Ausführung von sudo vererbt. LD_LIBRARY_PATH wird jedoch nicht von den Spezifikationen geerbt.

Daher habe ich beschlossen, die erforderlichen Pfade in "/etc/ld.so.conf.d/ros.conf" zu verknüpfen. Im Fall von ROS Merodic sieht es so aus.

/home/user/catkin_ws/devel/lib
/opt/ros/melodic/lib

Führen Sie nach Abschluss der Einstellungen "sudo ld config" aus.

Legen Sie außerdem Berechtigungen fest, damit Daemon-Benutzer auf /home/user/.ros/log zugreifen können. Ohne dies wird es mit einem Berechtigungsfehler beendet, wenn ein ROS-Knoten ausgeführt wird. (Wenn Sie einen ROS-Knoten mit sudo ausführen, scheint die Protokolldatei als Daemon-Benutzer generiert zu werden.) An diesem Punkt können Sie meiner Meinung nach auch mit sudo auf ROS-Ressourcen zugreifen.

Implementierung des ROS-Knotens

Erstellen Sie zunächst ein ROS-Paket.

~/catkin_ws/src$ catkin_create_pkg matrix_led_ros roscpp rospy std_msgs
~/catkin_ws$ catkin_make

Von hier aus implementieren wir das Skript unter dem erstellten Paket matrix_led_ros.

Erstellen Sie einen Knoten zum Veröffentlichen von Bildthemen aus GIF

Um das als nächstes zu erstellende Programm zu testen, habe ich einen Knoten implementiert, der GIF liest und als Image-Thema veröffentlicht.

#!/usr/bin/env python
from __future__ import print_function

import roslib
import sys
import rospy
import cv2
from std_msgs.msg import String
from sensor_msgs.msg import Image
from cv_bridge import CvBridge, CvBridgeError
import argparse

FILE_NAME = "test.gif"
REFRESH_RATE = 1
parser = argparse.ArgumentParser(
            prog='gif-publisher.py',
            usage='python gif-publisher --filename inputfilename',
            description='publish Image message from gif file',
            epilog='end',
            add_help=True,
            )
parser.add_argument('-f', '--filename', help='input file name',
                    required=True)
parser.add_argument('-r', '--rate', help='refresh rate',type=int)
args = parser.parse_args()

if args.filename:
  FILE_NAME = args.filename
if args.rate:
  REFRESH_RATE = args.rate
  
class image_publisher:
  def __init__(self):
    self.image_pub = rospy.Publisher("/imagetopic",Image)
    self.bridge = CvBridge()

  def readGif(self, filename, hz=1):
    gif = cv2.VideoCapture(filename)
    r = rospy.Rate(hz)
    while not rospy.is_shutdown():
        try:
            stat, frame = gif.read()
            if not stat:
                gif = cv2.VideoCapture(filename)
            else:
              try:
                self.image_pub.publish(self.bridge.cv2_to_imgmsg(frame, "bgr8"))
                r.sleep()
              except CvBridgeError as e:
                  print(e)
        except KeyboardInterrupt:
            break

def main(args):
  ip = image_publisher()
  rospy.init_node('gif_image_publisher', anonymous=True)
  ip.readGif(FILE_NAME, REFRESH_RATE)
  try:
    rospy.spin()
  except KeyboardInterrupt:
    print("Shutting down")

if __name__ == '__main__':
    main(sys.argv)

Verwenden Sie es wie "python gif-publisher.py -f test.gif -r 10". In diesem Beispiel wird test.gif mit 10 fps mit dem Namen / imagetopic veröffentlicht. Wenn nichts angegeben ist, wird der Frame mit explosiver Geschwindigkeit veröffentlicht, daher setze ich die Framerate mit "r = rospy.Rate (hz)" und "r.sleep ()". Im Fall von Raspberry Pi funktionierte es bis zu weniger als 30 fps.

Erstellen Sie einen ROS-Knoten, der das Image-Thema empfängt

Es ist endlich das Hauptthema. Ein Skript, das / imagetopic abonniert und auf dem Matrix-LED-Bedienfeld anzeigt.

#!/usr/bin/env python
from __future__ import print_function

import roslib
import sys, time
import rospy
import cv2
from std_msgs.msg import String
from sensor_msgs.msg import Image
from cv_bridge import CvBridge, CvBridgeError
from rgbmatrix import RGBMatrix, RGBMatrixOptions
from PIL import Image as pilI

BRIGHTNESS = 0.5

class image_viewer:
  def __init__(self):
    self.bridge = CvBridge()
    self.image_sub = rospy.Subscriber("imagetopic",Image,self.callback)

    # Configuration for the matrix
    self.options = RGBMatrixOptions()
    self.options.rows = 64
    self.options.cols = 64
    self.options.chain_length = 1
    self.options.parallel = 1
    self.options.hardware_mapping = 'regular'
    self.matrix = RGBMatrix(options = self.options)
    self.max_brightness = self.matrix.brightness
    self.matrix.brightness = self.max_brightness * BRIGHTNESS
    self.double_buffer = self.matrix.CreateFrameCanvas()

  def toSquare(self, img):
    w, h =img.size
    if w == h:
        return img
    elif w > h:
        result = pilI.new(img.mode, (w, w), (0,0,0))
        result.paste(img, (0, (w - h) // 2))
        return result
    else:
        result = pilI.new(img.mode, (h, h), (0,0,0))
        result.paste(img, ((h - w) // 2, 0))
        return result
      
  def callback(self,data):
    try:
      cv_image = self.bridge.imgmsg_to_cv2(data, "bgr8")
    except CvBridgeError as e:
      print(e)
    pilImage = cv2.cvtColor(cv_image, cv2.COLOR_BGR2RGB)
    pilImage = pilI.fromarray(pilImage)
    pilImage.thumbnail((self.matrix.width, self.matrix.height), pilI.ANTIALIAS)
    offset = (int)(self.matrix.height - pilImage.height)/2
    
    self.double_buffer.SetImage(self.toSquare(pilImage), 0)
    self.double_buffer = self.matrix.SwapOnVSync(self.double_buffer)
    
    
def main(args):
  iv = image_viewer()
  rospy.init_node('image_viewer')
  try:
    rospy.spin()
  except KeyboardInterrupt:
    print("Shutting down")

if __name__ == '__main__':
    main(sys.argv)

Starten Sie es wie "sudo python image-viewer-ros.py". Dieses Skript funktioniert nur dann gut, wenn Sie über Root-Rechte verfügen. Sie können es jedoch mit ROS in sudo verwenden, indem Sie den Inhalt unter "So verwenden Sie ROS mit sudo" verwenden. Es sieht so aus, wenn es sich bewegt. Ich habe [diese GIF-Animation] ausgeliehen (https://gifmagazine.net/post_images/3976039). P_20191109_160055 (2) .gif

Im Teil "self.matrix = RGBMatrix (options = self.options)" können Sie die Optionen angeben, die an die Matrix-LED übergeben werden sollen. Bei Bildern größer als 64 x 64 wurden die langen Seiten auf 64 Pixel reduziert und die Ränder mit Schwarz gefüllt.

Am Ende

Was haben Sie gedacht. In dieser Implementierung gibt es einen Teil, in dem das Flimmern etwas besorgniserregend ist, sodass Raum für Verbesserungen zu bestehen scheint. Wenn ich eine Chance habe, werde ich auch die in C ++ implementierte auflisten. Darüber hinaus kann die diesmal verwendete Treiberplatine 3 Kanäle gleichzeitig verwenden. Als Matrix-LED kann sie durch Verbinden von Perlen erweitert werden. Wenn Sie also mehrere LED-Panels erhalten, möchte ich eine höhere Auflösung ausprobieren.

Recommended Posts

Steuern Sie das Matrix-LED-Panel von ROS aus
Bildreduktion (LED-Matrix-Panel 16 x 32)
Pymel Bedienfeld
Steuern Sie LED-Lampen von einem Mikrocomputer (Intel Edison) (1)
Steuern Sie LED-Lampen von einem Mikrocomputer (Intel Edison) (2)
Fernbedienung der Klimaanlage von außen (per MQTT)
Generierung von PPM-Dateien auf dem LED-Matrix-Panel (japanisch RGB-kompatibel)
Rufen Sie Ihr eigenes Python-Modul aus dem ROS-Paket auf
Steuern Sie Linux-Trackpads
Home Control von Cortana.
Über die Verwirrungsmatrix
Steuern Sie Smart Light "Yeelight" von Python aus, ohne die Cloud zu verwenden
Spielen Sie Musik von einem USB-Lautsprecher mit dem ROS-Paket (gx_sound_player) ab.