communication serie PI <=> ARDUINO

voyons ici quelques bases pour la communication serie bidirectionnele entre un Raspberry PI et un arduino UNO .

ce sujet est abordé brièvement ici mais uniquement sur l’aspect communication unidirectionnelle de l’arduino vers le raspberry Pi pour la réception de données et l’enregistrement sur le raspberry PI . nous allons essayer, ici, de le compléter avec quelques exemples centrés sur la communication bidirectionnelle dans le but d’instaurer des échanges type action/réaction entre les deux , cela a un interet par exemple pour les dialogue RPI <=> station meteo Arduino, pour les interaction electromecaniques ( arduino pilote des actionneurs et RPI envoi les commandes et sert d’interface homme machine pour gerer les menus et interactions ecran/claviers/souris/etc..)

EXEMPLE 1:

le premier exemple sera très simple, le RPI envoie un message a l’Arduino qui lui réponds, pour cela installer les 2 programmes ci dessous respectivement sur votre ARDUINO et votre Raspberry PI :

void setup() {
    Serial.begin(9600);
}

void loop() {
  if (Serial.available()>0) {
    String data=Serial.readStringUntil('\n');
    Serial.print("message reçu: ");
    Serial.println(data);
  }
}
import serial
import time
ser=serial.Serial(port='/dev/ttyACM0',baudrate=9600, timeout=0.2)

while True:
    ser.write(b"Coucou du RPI4\n")
    line=ser.readline().decode('utf-8').rstrip()
    print(line)
    time.sleep(1)

le programme C++ arduino , “ecoute” les données qui arrive sur le port série et renvoi sur celui ci le message “message reçu:” avec derriere le message reçu du RPI.

le programme Python du RPI , envoi sur le port USB le message “Coucou du RPI4” avec un retour chariot (\n) puis met dans la variable “line” ce qu’il lit en retour de l’arduino puis l’imprime (print(line) et attends 1 seconde avant de recommencer. voici ci dessous petite copie d’ecran des 2 programmes ouverts sur le RPI4 avec le résultat du lancement du pgme python qui s’affiche dans la fenêtre shell de thonny python.

EXEMPLE 2:

a partir du meme programme arduino que plus haut , a titre didactique, nous allons reprendre les bases du deuxième exemple de la rubrique “evenement CLAVIER SOURIS” pour batir un programme qui envoi a l’arduino des valeurs de mouvements x et Y sous forme de chaine de caractères et lit en retour le message renvoyé par l’arduino (à savoir la commande envoyée qui est retournée par l’arduino)

import tkinter as tk
root=tk.Tk()
root.geometry("500x500+450+100")
canvas1=tk.Canvas(root, width=500, heigh=500)
canvas1.pack()
command='M00'
def keypressed(k):
    x=0
    y=0
    global command
    if k.keysym=='Up':
        y=-1
    if k.keysym=='Down':
        y=1
    if k.keysym=='Left':
        x=-1
    if k.keysym=='Right':
        x=1
    command='M'+str(x)+str(y) 
    ser.write(command.encode('utf-8'))
    line=ser.readline().decode('utf-8').rstrip()
    print(line)
root.bind('<KeyPress>', keypressed)
root.mainloop()

la commande envoyée est de la forme Mxy avec x et y des valeurs de déplacements valant +1 ou -1 sous forme de caractères . il est asses facile ensuite de demander au programme Arduino de décoder ces 2 valeurs et les transformer par exemple en valeur Step pour commander un moteur pas a pas branché sur l’Arduino. même principe pour commander la rotation d’un moteur . on pourrait également demander a l’Arduino de retourner une valeur de fin de course ou de capteur sous forme de chaine type Cab (C pour capteur et a/b pour les valeurs a prendre en compte). avec ce type de principe il est donc facile de mettre en place un protocole de communication aller/retour et traiter chaque information de chaque coté en fonction du code de commande associé a la première lettre …

évènements CLAVIER et SOURIS avec TK inter

dans un programme python sur raspberry pi pour des appli astro il peut être intéressant d’utiliser clavier et souris pour des commandes spécifiques autre que de la saisie de données. par exemple, utiliser les touches fleches du clavier pour commander des mouvements de moteurs pas a pas sur une monture équatoriale motorisée.

nous allons voir ici les bases de la gestion des événements clavier et souris avec Tkinter.

EXEMPLE BASIQUE:

les quelques lignes de python ci dessous permettent d’exploiter de façon tres basique la gestion des evenements clavier et souris avec Tkinter. a noter que cela fonctionne egalement avec les clavier avec track pad reconnus comme une souris par Tkinter.

import tkinter as tk

def keypressed(k):
    print(k.keysym, k.keycode)
def mouse(m):
    print(m)
def button(b):
    print(b)
      
root=tk.Tk()
root.geometry("500x500+400+100")
root.bind('<KeyPress>', keypressed)
root.bind('<Motion>', mouse)
root.bind('<Button>',button)

root.mainloop()

dans le programme , on defini une fenetre “root=tk.Tk()” avec TKinter, ainsi que sa géometrie (largeur/hauteur :500×500 et position x/Y: 400+100) via la ligne :

root.geometrie(“500×500+400+100”)

la partie “stratégique” de ce bout de python est constituée des 3 lignes “root.bind()“. avec les 3 fonction bind permettant chacune d’associer des événements a des fonctions définies en début de programme. les 3 fonctions définies , impriment les paramètres des événements concernés; symbole et code de la touche clavier préssée, coordonnées X et Y de la souris dans le cadre root et bouton de souris enfoncé. voici ci dessous copie d’écran du résultat sous thonny Python avec un raspberry; le résultat des actions s’affiche dans la fenetre du shell en bas a gauche:

concernant l’architecture de la commande bind , elle est asses simple:

root.bind(‘<evenement>’, appel fonction)

ci dessous les principaux événements reconnus par Tkinter:

événements clavier:

événements souris:

a partir de ces éléments fondamentaux , il est possible ensuite d’implémenter des fonctions et actions évoluées a partir des événements souris ou clavier . par exemple, faire tourner un moteur pas a pas branché sur le GPIO du raspberry PI dans un sens ou dans l’autre avec les flèches gauche et droite du clavier (voir ici pour la commande d’un NEMA17), actionner un moteur CC d’ouverture de toiture , commander l’orientation d’une monture equatoriale, etc …

à titre d’exemple un peu plus complet , ci dessous petit programme qui bouge le caracter X , en partant du centre, dans la zone de fenetre Tkinter via les touches fleches droite -gauche-haut-bas . pour faire tourner 2 NEMA17 , il suffit d’utiliser les variables X et Y comme valeur STEP et envoyer ça sur 2 drivers Pololu A4988 via le GPIO . pas plus compliqué que ça ….

import tkinter as tk
root=tk.Tk()
root.geometry("500x500+450+100")
canvas1=tk.Canvas(root, width=500, heigh=500)
canvas1.pack()
x=250
y=250

def keypressed(k):
    global x
    global y
    if k.keysym=='Up':
        y+=-1
    if k.keysym=='Down':
        y+=1
    if k.keysym=='Left':
        x+=-1
    if k.keysym=='Right':
        x+=1
    text=tk.Label(root, text= 'X', fg='yellow', bg='blue')
    canvas1.create_window(x,y, window=text)

root.bind('<KeyPress>', keypressed)
root.mainloop()

et le resultat apres quelques appuis variés:

voila , ce sera tout pour cette rubrique sur la fonction bind() , quelques liens complémentaires utiles ci dessous :

http://tkinter.fdex.eu/doc/event.html

understanding TKinter event

Fichier NGC avec Python

en astronomie , les objets du ciel profond sont souvent désignés au travers de leur code du catalogue NGC . nous allons voir ici quelques manipulations avec Python sur le fichier NGC.

pour les exemples de programmes python , ci dessous le fichier NGC au format csv a télécharger et installer par exemple dans votre répertoire home/pi/Documents :

le format CSV , alias Comma-Separated Values , est un format texte ouvert, représentant des données tabulaires sous forme de valeurs séparées par des virgules. il est reconnu par excel , OpenOffice et LibreOffice.

les objets NGC sont enregistrés sous la forme ci dessous ( NGC0224=Andromède):

NGC0224;00:42:44.35;+41:16:08.6

chaque ligne du fichier fait 31 caractères avec un retour chariot a la fin de la ligne( non visible). on trouve dans les 7 premiers caractères la référence NGC , ensuite un point virgule derrière lequel on trouve l’ascension droite en heures:minutes:secondes (2 chiffres après la virgule), puis un nouveau point virgule puis la déclinaison en degrés, minutes, secondes (un seul chiffre après la virgule).

EXEMPLE 1: ouverture du fichier et lecture puis impression des lignes du fichier

import time
f = open("home/pi/Documents/NGC.csv", "rt")
for x in f:
	print(x)
	time.sleep(0.5)

comme souvent en python, rien de très compliqué , le fichier est stocké dans une variable f ( le fichier est considéré comme un array) via la commande open() , dans laquelle on précise le chemin d’accès et le nom, puis le type d’ouverture . la librairie time est ouverte et une ligne time.sleep() est rajoutée pour ralentir un peu le programme . ici “rt” qui veut dire Read Text soit une ouverture du fichier en mode lecture et au format text . pour écrire/enregistrer un fichier au format texte ce serait open(“nomfichier.csv”, “wt”) pour write Text . ci dessous le lien vers la page Python pour les fichiers:

lien doc python

EXEMPLE 2: petite variation du programme précédent, ouverture du fichier et recherche d’une référence NGC puis impression de la ligne correspondante . ici comme on affiche une seule ligne trouvée dans le fichier , pas besoin de la librairie time ni de la ligne time.sleep()

f = open("home/pi/Documents/NGC.csv")
for x in f:
	if "NGC3200" in x:
		print(x)

encore une fois rien de compliqué , avec 4 lignes de python , on ouvre le fichier , on trouve l’enregistrement et on imprime son contenu.

EXEMPLE 3: amélioration du programme précédent , on emballe tout ça dans une petite interface graphique sous tkinter, avec fenêtre de saisie de la ref NGC et bouton de recherche a cliquer pour lancer la recherche :

import tkinter as tk
root=tk.Tk()
canvas1=tk.Canvas(root, width=400, heigh=300)
canvas1.pack()
entry1=tk.Entry(root)
canvas1.create_window(200, 140, window=entry1)

def NGCsearch():
    x1 = entry1.get()
    f = open("/home/pi/Documents/FICHIERS NGC/NGC.csv", "rt")
    for x in f:
        if x1 in x:
            label1=tk.Label(root, text= x)
            canvas1.create_window(200,230, window=label1)
button1= tk.Button(text='recherche', command=NGCsearch)
canvas1.create_window(200, 180, window=button1)

root.mainloop()

ci dessous copie d’écran du résultat après recherche de NGC0224

pour finir voici a titre d’exemple , le resultat d’un petit programme de recherche , affichage et calcul pour un module GOTO en python . on entre les references NGC de l’objet de reference ( pointé avec un viseur laser) , puis la reference NGC de l’objet cible a rechercher , le programme ouvre le fichier NGC.CSV , trouve les datas des 2 objets NGC, les affiche puis calcule les delta angulaire AD et DEC pour envoyer a la monture DIY qui fait tourner les moteurs pas a pas du nombre de pas correspondant aux valeurs d’ecarts.

PAUSES LONGUES avec une PI cam HQ

la dernière née des PI camera , outre une meilleure définition (4056 x 3040) offre la possibilité de faire des pauses longues jusqu’à 200 secondes pour l’astrophotographie du ciel profond . nous allons voir comment exploiter ces capacités .

tout d’abord petit rappel des caractéristiques des différentes PIcam dans le tableau comparatif ci dessous:

pour exploiter les capacités des Picam , il existe 2 possibilités:

  • les commandes en ligne Raspistill pour la photo et Raspivid pour la video .
  • un programme Python avec 2 options: passer des commandes raspistill ou utiliser la librairie Picam .

Pauses longues avec Raspistill

on ouvre l’éditeur de commande et on tape une instruction du genre:

raspistill -n -md 3 -awb off -ex off -ISO 800 -ss 100000000 -o PLtest01.jpg

tout ce qui est derriere “raspistill” consiste aux differentes option , ici :

  • -n inhibe la previsualisationa l’issue de la prise de vue
  • -md 3 met la Picam HQ en mode 3 (permet les pauses longues jusqu’a 200″)
  • -awb off , annule la balance des blanc
  • -ex off , annule le mode d’exposition
  • -ISO 800 : fixe la sensibilité ISO a 800 , les valeurs possibles sont 100-200-400-800. il faut avoir enlever l’exposition et la balance des blancs pour controler les ISO.
  • -ss 100000000 : fixe le Shutter Speed a 100 secondes (100000000 microsecondes)
  • -o PLtest01.jpg enregistre la photo dans le fichier “PLtest01.jpg”

pour plus d’information sur les options raspistill et raspivid , voir le fichier PDF ci dessous

attention, raspistill ne met pas a jour les donnes EXIF du fichier ….

Pauses longues avec PYTHON

methode 1 : envoyer une commande raspistill avec Python

pour envoyer une commande shell avec Python, c’est tres simple, il faut appeller la fonction subprocess .call(), en reprenant la commande plus haut cela donne:

import subprocess
cmd="raspistill -n -md 3 -awb off -ex off -ISO 800 -ss 100000000 -o PLtest01.jpg"
subprocess.call(cmd, shell=True)

bien sur avec ce principe, il est possible de parametrer des variables pour la durée de pause et rajouter une boucle while avec compteur et implementation du nom de fichier pour une sequence time laps pause longue (voir ci dessous)

methode 2 : utiliser la librairie PICAM

voyons un premier exemple basique

import picamera
from time import sleep
from fractions import Fraction
camera = picamera.PiCamera()
# camera en resolution max
camera.resolution=(4056, 3040)
# capteur en mode Pause longue (mode 3) 
camera.sensor_mode=3
# exposure mode off pour pouvoir utiliser les ISO
camera.exposure_mode = 'off'
# autowhite balance mode off pour utiliser les ISO
camera.awb_mode = 'off'
# framerate a 50s
camera.framerate =Fraction(1,50)
# vitesse d'obturation a 50 secondes
camera.shutter_speed = 50000000
#sensibilite ISO a 800 pour un gain maximum en condition nocturnes
camera.iso = 800
#prise de vue et sauvegarde sous le nom 'pauselongue.jpg'
camera.capture('pauselongue.jpg')
camera.close()

ce petit bout de python, permet de voir qu’avec quelques simples lignes de commandes python on peut déclencher une prise de vue pause longue de 50 secondes a 800 ISO et sauvegarder le fichier résultant.

outre le fait que l’on peut paramétrer tout un tas de valeurs de reglage ( gain, AWB, ISO, résolution, shuter speed, etc …) . il est important de noter qu’avec la librairie PICAMERA la vitesse d’obturation (shutter speed ) est en fait dépendante directement du framerate. il est donc indispensable de ne jamais dissocier les deux => donc on défini systématiquement le framerate avec la fonction Fraction , et ensuite le shutter speed a l’identique avec la même valeur x 1000000.

ATTENTION: si au lancement du programme vous avez un message d’erreur Python du genre “out of ressources error” c’est en général que la memoire graphique GPU allouée est insuffisante . en standard elle est souvent fixée a 128, mais pour du traitement d’image pause longue a la def max du capteur de la PI cam HQ il faut au minimum passer a 256 . pour cela , via le shell aller dans le fichier “boot/config.txt” et avec l’éditeur nano de debian modifier la valeur memoire de 128 a 256 . cela devrait régler le problème. il est egalement possible de modifier l’allocation GPU dans le menu de configuration de la version debian avec bureau et ecran type windows.

NOTE: je n’ai personnellement pas reussi a faire des pauses de plus de 50 secondes avec la librairie PICAMERA , cela semble etre du a une limitation a 60 secondes du parametre time_out dans les fichiers de config et d’erreur de la librairie.

la PI camera HQ est fournie en standard avec un cadre fileté au pas de monture photo Type C . pour l’utiliser sur un telescope ou une lunette , il faut lui adjoindre un adaptateur d’oculaire au pas de la monture type C ( 11€ sur Amazone tarif mai 2021):

sur la base du premier programme , il est facile de programmer une sequence de prise de vues pause longue en automatique en ajoutant une boucle while avec increment et de numeroter automatiquement le nom du fichier a l’enregistrement :


import picamera
from time import sleep
from fractions import Fraction
camera = picamera.PiCamera()
camera.resolution=(4056, 3040)
camera.sensor_mode=3
camera.exposure_mode = 'off'
camera.awb_mode = 'off'
camera.framerate =Fraction(1,50)
camera.shutter_speed = 50000000
camera.iso = 800

i=1
while i=< 5:
	camera.capture('pauselongue' + str(i) +'.jpg')
	sleep(10)
	i=i+1

ce deuxième programme fait donc une série de 5 photos en pause de 50 secondes chacune avec un temps d’attente de 10 secondes entre chaque photo.

sur ces bases et en utilisant Tkinter ( voir rubrique ICI et ICI ) il est possible de faire des menu et d’intégrer des boutons et sliders pour paramétrer le nombre de photos, le temps de pause , le temps interpose , la sensibilité ISO et tous les autres paramètres potentiels utilisables.

exemple d’une appli perso qui transforme la PI cam HQ en capteur multimode combinant Video / timelapse Photo / timelaps pauses longues, l’ensemble très pratique en mode nomade avec un ecran TFT HDMI touschscreen qui permet d’activer les sliders et boutons sans clavier ni souris …

a vos clavier pour développer vos appli perso ….

pour aller plus loin , voici le lien vers la documentation picamera:

https://picamera.readthedocs.io/en/release-1.13/index.html

PIcam et Webcam en même temps

afficher l’image simultanée d’une PIcam et d’une webcam USB avec un bout de Python c’est possible , le programme est extrêmement simple:

copier le petit morceau de python ci dessous dans votre éditeur python et lancez le (votre PICAM doit etre raccordée a son slot et une webcam raccordée au RPI en USB), vous devriez voir 2 fenêtres s’ouvrir dans votre écran avec chacune la vidéo de la camera concernée a l’intérieur.

ce programme nécessite d’avoir installé au préalable la librairie python “OpenCV”.

import cv2

cap0=cv2.VideoCapture(0) #sortie 0 Picam
cap1=cv2.VideoCapture(1) #sortie 1 Webcam USB

while True:
    ret, frame0 = cap0.read()
    ret, frame1 = cap1.read()
    cv2.imshow("PIcam", frame0)
    cv2.imshow("USBcam", frame1)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

NOTA1: les numéros de sorties a utiliser (ici sortie 0 et sortie 1 ) sont fonctionnels dans la majorité des cas. mais si vous rencontrez des problèmes , utiliser la commande shell “lsusb” pour déterminer quelles sorties du RPI sont utilisées.

NOTA2:il est possible d’ajouter d’autres webcam , pour cela il suffit d’implémenter autant de lignes dédié ( capx , ret, et cv2.imshow) que de flux video souhaité.

ce type d’utilisation en astro , permet par exemple d’utiliser une Webcam USB en autoguidage et la PIcam HQ en prise de vue pause longue ou en vidéo planetaire . une autre utilisation potentielle avec plusieurs Wab cam serait pour la video surveillance exterieure et interieure d’un observatoire en combinaison avec de la detection de mouvement et un envoi automatique de photo par mail …

AMELIORATION: voyons comment redimensionner et positionner les 2 fenêtres d’affichage

import cv2

cap0=cv2.VideoCapture(0) #sortie 0 Picam
Picamwin="PIcam"    # nom de la fenetre PIcam
cv2.namedWindow(PIcamwin, cv2.WINDOW_NORMAL)
cv2.resizeWindow(PIcamwin, 600, 450)
cv2.moveWindow(PIcamwin, 420, 110)

cap1=cv2.VideoCapture(1) #sortie 1 Webcam USB
USBcamwin="USBcam"  # nom de la fenetre Webcam
cv2.namedWindow(USBcamwin,cv2.WINDOW_NORMAL)
cv2.resizeWindow(USBcamwin, 400, 300)
cv2.moveWindow(USBcamwin, 10, 260)

while True:
    ret, frame0 = cap0.read()
    ret, frame1 = cap1.read()
    cv2.imshow(PIcamwin", frame0)
    cv2.imshow(USBcamwin, frame1)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

voici un exemple du resultat du pgme ci dessus avec une PIcam sur son slot et une Webcam USB sur port USB, l’ensemble affiché sur un petit ecran HDMI touschscreen 7″ 1024×600 pixels .chacune des video est affichée en taille de fenetre differente et positionnées en bas et dans la largeur de l’ecran , permettant l’acces au menu du bureau du RPI . l’affichage avec des fenetres Opencv permet en outre d’avoir la vue video via VNC en acces distant . ce qui n’est pas possible avec les fenetres live view de la librairie Picam.

POLARSCOPE en Python

tout le monde connait le prix d’un pole master, voyons ici comment faire le sien avec une webcam et un bout de python pour exploiter ça sur un raspberry PI.

Un polemaster est tout simplement une camera CCD commandée par un software qui affiche une mire d’alignement polaire comme par exemple la mire Skywatcher.

le principe est donc simple, il faut superposer une mire “graphique” sur la video d’une camera.

vous trouverez ci dessous un petit bout de programme Python qui affichera en temps réel la mire d’entête par dessus la vidéo d’une webcam.

pour la mise au point finale, il faudra faire des essai en fonction de la camera choisie , et de la focale de l’objectif monté dessus et ajuster les diametres et coordonnées des figures graphiques en fonction de vos besoins. l’idéal étant de se calibrer avec un viseur polaire optique type skywatcher . le principe fonctionne egalement avec une PIcam sur son slot , il suffit de changer le numéro de sortie ( en général 0 pour la PIcam) .

il faudra en préliminaire installer la librairie python computer Vision “OpenCV“. bien entendu , libre a vous de concevoir votre propre mire en utilisant les option d’openCV draw .

import cv2

cv2.namedWindow("POLARALIGN")
vc = cv2.VideoCapture(1)

if vc.isOpened(): # try to get the first frame
    rval, frame = vc.read()
else:
    rval = False
    
while rval:
    cv2.imshow("POLARALIGN", frame)
    rval, frame = vc.read()
    key = cv2.waitKey(20)
    if key == 27: # exit on ESC
        break
    else:
        cv2.circle(img=frame, center=(320, 210), radius=110, color=(0, 0, 255), thickness=3, lineType=8, shift=0)
        cv2.circle(img=frame, center=(320, 210), radius=120, color=(0, 0, 255), thickness=3, lineType=8, shift=0)
        cv2.line(img=frame, pt1=(320, 60), pt2=(320, 360), color=(255, 0, 0), thickness=2, lineType=8, shift=0)
        cv2.line(img=frame, pt1=(180, 210), pt2=(460, 210), color=(255, 0, 0), thickness=2, lineType=8, shift=0)
        cv2.line(img=frame, pt1=(220, 100), pt2=(420, 320), color=(0, 255, 255), thickness=2, lineType=8, shift=0)
        cv2.line(img=frame, pt1=(220, 320), pt2=(420, 100), color=(0, 255, 255), thickness=2, lineType=8, shift=0)        

vc.release()
cv2.destroyWindow("POLARALIGN")

Commande d’un APN reflex avec GPHOTO2

il est possible de commander et configurer un APN reflex moderne en remote via USB avec un Raspberry PI en utilisant la librairie GPHOTO2.cette option est très intéressante pour l’astro-photo, en particulier pour des time-laps en pauses longues. nous allons voir ici comment procéder.

le site internet dédié a Gphoto2 est accessible via ce lien: http://www.gphoto.org/

avant de poursuivre plus loin, il est important de verifier que votre APN reflexe est compatible avec la librairie, pour cela voir la liste ici:

liste des APN compatibles: http://www.gphoto.org/proj/libgphoto2/support.php

INSTRUCTION D’INSTALLATION

avant de pouvoir utiliser Gphoto2 il va falloir faire l’installation des prérequis et de la librairie elle même . ci dessous les instructions qui sont disponible dans le fichier joint en PDF pour pour pouvoir faire des copier coller des lignes de commandes.

PREREQUIS: installation des dependances:

sudo apt-get install git make autoconf libltdl-dev libusb-dev libexif-dev libpopt-dev libxml2-dev libjpeg-dev libgd-dev gettext autopoint

INSTALLATION DE libghoto2:

télécharger le code pour libgphoto2 ici: https://github.com/gphoto/libgphoto2.git

executer les commandes ci dessous pour installer libgphoto2

cd ~/libgphoto2
autoreconf --install --symlink
./configure
make
sudo make install

INSTALLATION DE ghoto2

télécharger le code pour gphoto2 ici: https://github.com/gphoto/gphoto2.git

executer les commandes ci dessous pour installer gphoto2

cd ~/gphoto2
autoreconf --install --symlink
./configure
make
sudo make install

MISE A JOUR DE LA CONFIGURATION RPI

ajouter la lignes ci dessous dans le fichierde configuration : /etc/ld.so.conf.d/libc.conf

/usr/local/lib

rafraichir le cache avant de continuer:

sudo ldconfig

créer les regles udev pour l’APN

/usr/local/lib/libgphoto2/print-camera-list udev-rules version 201 group plugdev mode 0660 | sudo tee /etc/udev/rules.d/90-libgphoto2.rules

créer la base de données pour udev

/usr/local/lib/libgphoto2/print-camera-list hwdb | sudo tee /etc/udev/hwdb.d/20-gphoto.hwdb

UTILISATION DE GPHOTO2

gphoto2 est un “catalogue” de fonctions permettant d’envoyer des commandes a votre APN reflex via le port USB et avec des commandes shell sous linux . voici la liste des commandes:

http://www.gphoto.org/doc/manual/ref-gphoto2-cli.html

nous allons en tester 2 pour cela connecter votre APN reflex a votre RPI via son cordon USB et executer la commande shell ci dessous pour verifier que votre Gphoto2 detecte bien votre APN:

gphoto2 –auto-detect

si le nom de votre Appareil photo apparait après l’exécution de la commande c’est que tout est OK et vous pouvez aller plus loin et exécuter le premier test en prenant une photo. pour cela exécuter la commande shell ci dessous:

gphoto2 –capture-image

UTILISATION DE GPHOTO2 AVEC PYTHON

le travail en mode de commande shell n’est pas des plus convivial particulierement la nuit en nomade . nous allons voir ici comment utiliser Gphoto2 via un programme python. pour cela, il faut d’abord installer le module python permettant d’encapsuler Gphoto2 . exécuter la commande:

sudo pip install -v gphoto2

nous allons maintenant écrire un petit programme Python qui permet de prendre une photo et de l’enregistrer sur le raspberry

import logging
import os
import subprocess
import sys

import gphoto2 as gp

logging.basicConfig(
        format='%(levelname)s: %(name)s: %(message)s', level=logging.WARNING)
callback_obj = gp.check_result(gp.use_python_logging())

def get_camera():
    camera = gp.Camera()
    camera.init()
    return camera

def capture_image_from_dslr():
    camera = get_camera()
    capture_image(camera)
    camera.exit()
    return 0

def capture_image(camera):
    print('Capturing image')
    file_path = camera.capture(gp.GP_CAPTURE_IMAGE)
    print('Camera file path: {0}/{1}'.format(file_path.folder, file_path.name))
    target = os.path.join('/tmp', file_path.name)
    print('Copying image to', target)
    camera_file = camera.file_get(
        file_path.folder, file_path.name, gp.GP_FILE_TYPE_NORMAL)
    camera_file.save(target)
    return 0
  
  if __name__ == "__main__":
    sys.exit(capture_image_from_dslr())

INTERFACE GRAPIQUE AVEC TKINTER : TIME LAPS PAUSE LONGUE

nous allons voir ici comment créer une interface graphique ergonomique avec Tkinter pour lancer des commandes au travers de menus . le programme ci dessous permet de faire une serie de photo en pause longue , il fonctionne avec un ecran tactile et affiche un cadre avec menu dans lequel on peut faire varier un certain nombre de paramètres de prise de vue.

NOTA: il a ete optimisé pour un CANON EOS M50.

les paramètres sont :

  • durée de pause pour chaque photo => reglage par slider de 0 a 180 secondes
  • intervalle entre chaque photo=> reglage par slider de 0 a 100 secondes
  • nombre de photo=> reglage par slider de 0 a 100 photos
  • en haut a droite sensibliité ISO=> reglage par choix dans liste de valeur
  • un bouton bleu en bas a gauche de lancement de séquence de prise de vue , une fois le cycle lancé , un message affiche le statu d’avancement en bas de l’ecran entre les 2 boutons
  • un bouton rouge en bas a gauche pour quitter le programme

programme en fichier txt

a copier coller dans votre editeur python ou a enregistrer directement avec l’extension “.py”

import tkinter as tk
import signal
import os
import subprocess
import time

win = tk.Tk()
win.title(" AStrophoto Pauses Longues")

### WIDGETS ###
canvas1 = tk.Canvas(win, width = 550, height = 320, relief = 'raised')
canvas1.pack()
slider1 = tk.Scale(win, from_=0, to=180, orient='horizontal', resolution=5, tickinterval=60, length=300, label='pause (s)')
canvas1.create_window(170,50, window=slider1)
slider2 = tk.Scale(win, from_=0, to=100, orient='horizontal', resolution=1, tickinterval=25, length=300, label='intervale (s)')
canvas1.create_window(170,130, window=slider2)
slider3 = tk.Scale(win, from_=0, to=100, orient='horizontal', resolution=1, tickinterval=25, length=300, label='nombre')
canvas1.create_window(170,210, window=slider3)
label1 = tk.Label(win, text='ISO')
label1.config(font=('helvetica', 15))
canvas1.create_window(450,24, window=label1)
spinbox1 = tk.Spinbox(win, values=["250","320","400","500","640","800","1000","1250","1600","2000","2500","3200","4000","5000","6400" ],width=4)
spinbox1.config(font=('helvetica', 30))
canvas1.create_window(450,60, window=spinbox1)

### Event Functions ###
def killgphoto2Process():
    p = subprocess.Popen(['ps', '-A'], stdout=subprocess.PIPE)
    out, err = p.communicate()
    for line in out.splitlines():
        if b'gvfsd-gphoto2' in line:
            pid = int(line.split(None,1)[0])
            os.kill(pid, signal.SIGKILL)
def takepicture():    
    tmpPause = int(slider1.get())
    isovalue = int(spinbox1.get())
    interPause = int(slider2.get())
    nbrPhoto = int(slider3.get())
    tempphoto = (tmpPause + interPause)
    print("def BULB et def ISO")
    subprocess.run(["gphoto2","--set-config","shutterspeed=bulb"])
    time.sleep(2)
    print("Bulb OK")
    subprocess.run(["gphoto2","--set-config","iso="+str(isovalue)])
    time.sleep(2)
    print("ISO OK")
    i=1
    while i <= nbrPhoto :
        label2=tk.Label(win,text='photo '+str(i)+'/'+str(nbrPhoto)+' reste '+ str((nbrPhoto - i)*tempphoto)+ ' secondes', fg='blue',font=('helvetica',14, 'bold'),width=25)
        canvas1.create_window(275,300, window=label2)
        win.update_idletasks()
        print("i=",(i))
        subprocess.run(["gphoto2","--set-config","eosremoterelease=2"])
        time.sleep(tmpPause)
        subprocess.run(["gphoto2","--set-config","eosremoterelease=4"])
        time.sleep(2)
        print("photo",(i))
        time.sleep(interPause)
        i=i+1
def close():
    win.destroy()    # ferme le pgme

takePic = tk.Button (text='LANCER', command=takepicture, bg='blue', fg='white', font=('helvetica',10, 'bold'))
canvas1.create_window(50,300, window=takePic)
exitButton = tk.Button(text='QUITTER', command=close, bg='red', fg='white', font=('helvetica',10, 'bold'))
canvas1.create_window(500,300, window=exitButton)
killgphoto2Process()            
win.mainloop() # Loops forever

pour finir , une petite video de démo/test