J'ai acheté une Matrix LED (64x64) chez Shigezone à Akihabara, mais j'ai décidé de l'exécuter sur ROS. Dans cet article, nous allons créer un "nœud ROS qui s'abonne à la rubrique Image et affiche l'image sur la LED Matrix".
Cette fois, nous utiliserons Raspberry Pi 3 avec Ubuntu installé pour gérer ROS. Flashez l'image de ici sur la carte SD et installez ROS. J'ai installé Ubuntu 18.04.3. De arm64. ROS a installé ros-melodic-desktop en se référant à ce site.
Afin d'utiliser ce logiciel comme pilote pour MatrixLED, nous avons préparé une carte pilote correspondante. La carte a été [obtenue] de electrodragon (https://www.electrodragon.com/product/rgb-matrix-panel-drive-board-raspberry-pi/), mais vous pouvez la préparer vous-même. La carte que vous avez achetée dispose d'un convertisseur de niveau intégré de 3,3 V à 5 V, vous pouvez donc vous attendre à un fonctionnement stable. Puisque la LED Matrix utilisée est de 64x64 et a des lignes d'adresse A à E, il est nécessaire de souder le côté de la carte de commande en un seul endroit pour connecter «E». Pour le panneau LED Matrix que j'ai acheté cette fois, j'ai défini un cavalier pour connecter la broche 8 à E. Il est nécessaire d'alimenter 5V (je pense que c'est au moins 3A) séparément au corps du panneau LED.
Pour voir si le matériel fonctionne correctement, clonez à partir du référentiel, puis compilez l'exemple de programme.
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
Les cubes colorés devraient tourner. En fonction du type de panneau LED Matrix, le FM6126A peut être monté sous forme de puce, auquel cas il est nécessaire de spécifier une option car le signal requis pour l'initialisation est différent.
Si cela fonctionne, installez la bibliothèque pour Python selon les Procédures du même référentiel. Je vais.
$ 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
À ce stade, vous serez en mesure de faire "à partir de rgbmatrix importer RGBMatrix, RGBMatrixOptions".
Le logiciel du pilote Matrix LED utilisé cette fois doit être exécuté par sudo. Avec la combinaison Ubuntu18.04 + Raspberry pi3, je ne pouvais pas accéder aux ressources matérielles (GPIO, etc.) requises par les utilisateurs généraux, j'ai donc décidé de lancer le côté ROS avec sudo. (Je pense qu'il devrait être configuré pour que les utilisateurs généraux puissent accéder aux ressources matérielles nécessaires.)
Généralement, ROS ne fonctionne pas bien car les variables d'environnement sont effacées lorsque sudo est exécuté. J'ai donc décidé d'ajouter les paramètres au fichier sudoers.
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"
En ajoutant cette ligne avec la commande "sudo visudo", les variables d'environnement requises pour ROS sont héritées lorsque sudo est exécuté. Cependant, LD_LIBRARY_PATH n'est pas hérité par les spécifications.
Par conséquent, j'ai décidé de lier les chemins nécessaires dans "/etc/ld.so.conf.d/ros.conf". Dans le cas du mérodique ROS, cela ressemble à ceci.
/home/user/catkin_ws/devel/lib
/opt/ros/melodic/lib
Après avoir terminé les réglages, exécutez "sudo ld config".
En outre, définissez des autorisations pour que les utilisateurs du démon puissent accéder à /home/user/.ros/log. Sans cela, il s'arrêtera avec une erreur d'autorisation lors de l'exécution d'un nœud ROS. (Lors de l'exécution d'un nœud ROS avec sudo, le fichier journal semble être généré en tant qu'utilisateur du démon.) À ce stade, je pense que vous pouvez accéder aux ressources ROS même avec sudo.
Commencez par créer un package ROS.
~/catkin_ws/src$ catkin_create_pkg matrix_led_ros roscpp rospy std_msgs
~/catkin_ws$ catkin_make
À partir de là, nous allons implémenter le script sous le package matrix_led_ros créé.
Afin de tester le programme à créer ensuite, j'ai implémenté un nœud qui lit GIF et le publie en tant que sujet Image.
#!/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)
Utilisez-le comme "python gif-publisher.py -f test.gif -r 10". Cet exemple publie test.gif à 10 ips avec le nom / imagetopic. Si rien n'est spécifié, l'image sera publiée à une vitesse explosive, donc je règle la fréquence d'images avec "r = rospy.Rate (hz)" et "r.sleep ()". Dans le cas du Raspberry pi, cela fonctionnait jusqu'à moins de 30 images par seconde.
C'est finalement le sujet principal. Un script qui s'abonne à / imagetopic et l'affiche sur le panneau LED Matrix.
#!/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)
Démarrez-le comme "sudo python image-viewer-ros.py". Ce script ne fonctionnera pas correctement à moins que vous n'ayez les privilèges root, mais vous pouvez l'exécuter avec ROS dans sudo par le contenu défini dans "Pour utiliser ROS avec sudo" plus tôt. Ça ressemble à ça quand ça bouge. J'ai emprunté cette animation GIF.
Dans la partie "self.matrix = RGBMatrix (options = self.options)", vous pouvez spécifier les options à passer à la LED de la matrice. Pour les images plus grandes que 64x64, les côtés longs ont été réduits à 64 pixels et les marges ont été remplies de noir.
Qu'as-tu pensé. Dans cette implémentation, il y a une partie où le scintillement est un peu inquiétant, il semble donc y avoir place à l'amélioration. Si j'ai une chance, je listerai également celui implémenté en C ++. De plus, la carte pilote utilisée cette fois-ci peut utiliser 3 canaux en même temps, et en tant que LED Matrix, elle peut être étendue en connectant des perles, donc si vous pouvez obtenir plusieurs panneaux LED, j'aimerais essayer une résolution plus élevée.
Recommended Posts