Note de ce sujet :
  • Moyenne : 0 (0 vote(s))
  • 1
  • 2
  • 3
  • 4
  • 5

[PROJET] Commande de projecteurs (pour spectacle) grâce au Raspberry
#1

Bonjour à tous,

Voici un billet à propos du projet qui m'occupe (pas à plein temps malheureusement !). Le but du projet est de commander les projecteurs d'un spectacle grâce à un Raspberry. Cela pour plusieurs raisons
  • C'est drôle Wink
  • C'est pas cher
  • Cela permet d'avoir des fonctionnalités avancée (interface, gestion de la souris et du clavier,...)
  • C'est modulable en fonction des besoins et des préférences de chacun.

Je me suis fortement inspiré du post de VodkaOrange pour son projet de surveillance de piscine Smile

Principe
Le signal de commande sera envoyé par le port série vers les projecteurs qui le décoderont. Le signal doit être envoyé selon le protocole DMX 512 (Explications) et selon le standard RS 485 (250 KBauds).

Feuille de route
Cette feuille ce complétera avec le temps au fur et à mesure que les choses se précisent
Les tâches en vert sont terminées

Celles en orange sont en cours (ça peut durer Wink)
Et, vous l'aurez deviné, celles en rouge ne sont pas encore attaquées

Recherches
  • Protocole DMX
  • Liaison série
  • RS485

Partie matérielle
  • Création pupitre
  • Circuit convertisseur DMX
  • Faire beau Smile

Partie logicielle
  • Générateur de trames
  • Envoi de la trame sur le port série
  • Réception des informations du pupitre

Interface
  • Réglage des valeurs depuis le Raspberry
  • Affichage des valeurs envoyées
  • Programmation de sécances automatiques
  • Enregistrement de la position des curseurs et visualisation en temps réel de leur valeur

Télécommande
  • Choix transmission sans fil. Se sera du XBee.
  • Format des données
  • Boîtier

Ce post servira de time-line et vous pourrez suivre ma progression (ou mes cuisants échec, c'est le plus drôle avouez ]Big Grin ) ici. Des billets réguliers seront postés sur mon blog

Affaire à suivre
Nicolas

Projet en cours : Commande de projecteurs via un Raspberry
Mon blogTopic sur le forumDépôt GitHub
Répondre
#2

Bonjour

Merci pour ce topic Smile

On fera avec Jeoffrey un post sur le site pour parler de vos projets avec VodkaOrange Smile

Serial Organisateur d'aPIro
Bloggeur Bidouilleur
Ydle, domotique DIY basée sur un raspberry pi
Répondre
#3

Merci beaucoup Yaug ! Si tu veux des infos envoies moi un mail.


Pour l'avancement d'un projet je profite de mon aprèm de libre pour faire mon générateur de trame en Python. Je mettrais le. code en ligne ce soir.

Projet en cours : Commande de projecteurs via un Raspberry
Mon blogTopic sur le forumDépôt GitHub
Répondre
#4

Salut !!

Projet intéressant, je cogite aussi un projet similaire avec un pote.
Répondre
#5

Nekrofage a écrit :Salut !!

Projet intéressant, je cogite aussi un projet similaire avec un pote.
Ah génial ! Tiens moi au courant de ton avancement Wink

Projet en cours : Commande de projecteurs via un Raspberry
Mon blogTopic sur le forumDépôt GitHub
Répondre
#6

@Mafzst : sur Github j'espère Smile.
Répondre
#7

Tout naturellement !

Projet en cours : Commande de projecteurs via un Raspberry
Mon blogTopic sur le forumDépôt GitHub
Répondre
#8

Bonsoir,
Voici le travail de cet aprèm.
Petit code en Python, qui me permet, pour l'instant d'obtenir une trame DMX.
Cette trame est trop courte (la flemme) et je suis sûr que le programme n'est pas des plus efficaces ! Mais bon c'est un début.

Code :
def binaire (n):
    q = -1
    res=[0,0,0,0,0,0,0,0]
    l=len(bin(n)) - 3
    while q != 0:
        q = n // 2
        r = n % 2
        res[l]=r
        n = q
        l=l-1
        print(q,r,n,l, sep='....')
    print (res)
    return res

frame=[]

c1=int(input('Value Channel 1  '))
c2=int(input('Value Channel 2  '))
c3=int(input('Value Channel 3  '))
c4=int(input('Value Channel 4  '))

#BREAK and MAB bits
BMAB=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1]
#START CODE character
SC=[0,0,0,0,0,0,0,0]
#START BITS (only one)
BB=[0]
#STOP BITS
EB=[1,1]

CH1=binaire(c1)
CH2=binaire(c2)
CH3=binaire(c3)
CH4=binaire(c4)

frame=BMAB + BB + SC + EB + BB + CH1 + EB + BB + CH2 + EB + BB + CH3 + EB + BB + CH4 + EB

print (frame)

Je n'ai pas encore mis le code sut github (pas eu le temps).
Si vous voulez tester, faites attention c'est du Python 3 et donc non compatible avec Python 2.
@+
Nicolas.

Projet en cours : Commande de projecteurs via un Raspberry
Mon blogTopic sur le forumDépôt GitHub
Répondre
#9

Salut à tous,
Après un bonne semaine de silence (eh oui M Peillon veut que l'on aille à l'école), me revoila pour un petit bilan du projet.
J'avais posté le code permettant de générer une trame DMX. Il était vraiment moche et pas du tout fonctionnel. Je suis donc en train de le refaire.

En parallèle, je me renseigne sur le fonctionnement de la liaison série du Raspberry, et sur le format des données à envoyer.

Il y a aussi, le dépôt github qui traîne mais je n'ai pas eu trop de temps à lui consacrer.

Voila pour les infos de la semaine.

@+
Nicolas.

Projet en cours : Commande de projecteurs via un Raspberry
Mon blogTopic sur le forumDépôt GitHub
Répondre
#10

Tu t'es planté pour le lien, ce n'est pas mon projet ^^

Anciennement vodkaorange Wink
Forum français et communauté sur les caméras embarqués et dashcam : Dashcam-France.fr
Blog notes - Github
Répondre
#11

vodkaorange a écrit :Tu t'es planté pour le lien, ce n'est pas mon projet ^^
ah oui Big Grin je modifie ça tout de suite !

Projet en cours : Commande de projecteurs via un Raspberry
Mon blogTopic sur le forumDépôt GitHub
Répondre
#12

Salut,

Pourquoi n'utilise tu pas des bibliothèque pour la gestion DMX existant ?
Répondre
#13

Nekrofage a écrit :Salut,

Pourquoi n'utilise tu pas des bibliothèque pour la gestion DMX existant ?

Quoi ?!? Ça existe ?
J'avoue que je n'ai même pas cherché. En fait ça serait moins drôle ]Big Grin
Je vais quand même me renseigner.

@+
Nicolas.

Projet en cours : Commande de projecteurs via un Raspberry
Mon blogTopic sur le forumDépôt GitHub
Répondre
#14

Hello,
L'interface est faite et compilée Utilisation de Qt)
Je suis en train d'ecrire les différentes fonctions qui constituront le programme. Pour l'instant, trois sont opérationnelles et une est en cours de finition. D'autres sont bien avancées dans mon esprit, il suffit de les traduire en code.
Je galère toujours avec GitHub :mad:
Je met en parallèle en place un wiki (espérons que je n'aurai pas le même mésaventures que certains) . J'y rédigé actuellement une documentation de toutes les fonctions écrites et à venir. Le wiki c'est ici ! (François hollande)

@+
Nicolas.

Projet en cours : Commande de projecteurs via un Raspberry
Mon blogTopic sur le forumDépôt GitHub
Répondre
#15

Salut,

Il y a çà :
http://www.opendmx.net/index.php/Open_Lighting_Project
http://www.chromakinetics.com/DMX/StageConsole.html
http://playground.arduino.cc/DMX/Opendmx
http://blog.eliosoft.net/
Répondre
#16

Ok merci je vais aller voir un peu ce qu'il proposent.

Projet en cours : Commande de projecteurs via un Raspberry
Mon blogTopic sur le forumDépôt GitHub
Répondre
#17

Hello,
Petit bilan de l'avancement du projet.
. *Les fonctions permettant la fabrication de la trame sont faites.
*L'interface est en cours (bien avancée en fait)
ILfaut mainteant se concentrer sur l'envoi des données sur le bus. Après on pourra tester !
Plus d'infos ici !

@+
Nicolas

Projet en cours : Commande de projecteurs via un Raspberry
Mon blogTopic sur le forumDépôt GitHub
Répondre
#18

Hello,
Je viens de publier sur GitHub la librairie de gestion de la trame DMX (création, modification, lecture,...)
C'est ici Wink
Si vous avez des remarques notamment sur l'optimisation du code, je suis preneur n'étant pas un pro dans ce domaine.
@+
Nicolas.

Projet en cours : Commande de projecteurs via un Raspberry
Mon blogTopic sur le forumDépôt GitHub
Répondre
#19

Salut,

Perso, j'ai commencer çà : http://forum.raspfr.org/viewtopic.php?id=480
Ca m'évite de réinventer la roue et ainsi de mon concentrer sur le coeur du projet.
Répondre
#20

J'ai vu ton post. Je ne comprends pas bien l'utilité de ce que tu rajoutes au dessus de ton arduino.
Pour ma part, l'arduino ne me convient pas puisqu'il est impossible d'y mettre une souris, un clavier et un écran qui sont les points clé de mon projet.
Nicolas

Projet en cours : Commande de projecteurs via un Raspberry
Mon blogTopic sur le forumDépôt GitHub
Répondre
#21

Je te mets en commentaire mes remarques et suggestions par rapport à ton fichier.
Je me permets de te les faire vu que tu les demandes. Wink
Ne te crois pas obligé pour autant de reprendre tout ton code… Cool
J'espère que tu comprendras que mon objectif n'est pas de critiquer ton code à tout prix, mais de te montrer comment tu peux faire pour écrire un code plus facile à lire, donc à comprendre, et donc à maintenir et corriger en cas de bug.
Code :
[== Indéfini ==]
import numpy as np # c'est très pratique de mettre des noms courts, mais seulement à court terme au moment où tu codes et où tu sais ce que tu fais. Quand ton code va grandir, tu auras du mal à t'y repérer. Ne mets pas d'alias.
import os

# (2) (voir remarque plus bas)
SAVE_PATH = os.getcwd() + "\\Preps\\"
# (3) (idem)
DEFAULT_HEIGHT = 512

C=[]
T=[]

def binaire (n): # pour l'ensemble de la fonction ainsi que le reste du fichier, pense à mettre des noms de variable de plus d'une lettre, à part à la rigueur pour les indices.
    # Quand tu reviendras sur ton code dans trois mois, tu dois pouvoir le comprendre sans réfléchir.
    # Tu peux utiliser quotient et reste au lieu de q et r
    # De même, sortie n'est pas très explicite. C'est pas forcément facile de trouver un nom de variable, mais bits pourrait également faire l'affaire
    sortie = [0,0,0,0,0,0,0,0] # là, ça va (enfin ça commence déjà à être dur à lire) parce que tu as seulement 8 éléments, mais imagine, tu en veux 125. Qu'est-ce que tu fais ?
    # sortie = [0 for i in range(0,8)] serait plus lisible. Ceci dit, tu peux initialiser sortie à [] et la suite en (1)
    q = -1
    r = 0
    i = 0    # inutile, ligne à supprimer car la variable n'est pas lu avant d'être réaffectée
    
    for i in range (0,8):
        print i
        q = n / 2
        r = n % 2
        sortie[i] =  r # (1) tu pourrais alors faire sortie.append(r)
        n = q
        
    return sortie

class Trame:
    def __init__(self,n, h=512): # crée une constante dans ton module pour la valeur par défaut en (3) par exemple
        self.name = n
        self.height = h
        self.savepath = os.getcwd() + "\\Preps\\" # pas besoin d'embarquer cette valeur dans ton objet. Tu peux en faire une constante au niveau de ton module à mettre en (2) par exemple
    
    def new(self):
       self.content = np.zeros((self.height,11)) # Tu devrais créer une constante pour 11
       # tu devrais initialiser ton objet complètement et mettre la ligne ci-dessus plutôt dans __init__. Cette méthode devient alors inutile
       return self.content

    def nff(self, fic): # nom de fonction trop court loadFromFile serait meilleur ; pareil, fic est peu explicite : fileName serait préférable
        return np.load(self.savepath + fic + '.npy')
    
    def save(self):
        np.save(self.savepath + self.name,self.content)
        return True # pourquoi retourner une valeur si elle est toujours la même (à moins de devoir respecter une interface, ce qui n'est pas ton cas ici)
        

# j'ai un peu de mal à comprendre la finalité de la suite de ton code, donc j'ai du mal à le commenter, mais…
def modif_canal(Chn,Val):

    global C # … il est préférable d'éviter les variables globales…
    
    Set = binaire(Val)
    
    for j in range (0,8):
        C[Chn,j+1] = Set[j]


def trame_make():

    global C, T
    
    C = np.reshape(C,5632) # … j'ai une erreur ici à l'exécution : ValueError: total size of new array must be unchanged

    B = np.loadtxt('break')
    MAB = np.loadtxt('MAB')

    T = np.concatenate((B,MAB,C))

Sur la dernière partie de ton code, je vais essayer de fouiller dans le reste du code de ton projet pour voir comment tu l'utilises et te faire d'autres suggestions.
Si tu as des questions sur mes remarques ou bien ton code, n'hésites pas à en poser.

Au passage, puisque je suis dans la critique (constructive hein ! Tongue ), tu pourrais également améliorer ton commentaire de commit. Tu n'as pas besoin de dire que c'est un commit. C'est une évidence. L'objectif d'un commentaire de commit est de retrouver rapidement ce qui a été fait dans ledit commit. Tu aurais pu écrire simplement « Génération et formatage de trames DMX ». Ca dit la même chose que le tien, mais c'est court, et ça permet de comprendre d'un coup d'œil ce qui est dans le commit.
Répondre
#22

Mafzst a écrit :Je ne comprends pas bien l'utilité de ce que tu rajoutes au dessus de ton arduino.

Le shield qui se trouve sur l'Arduino s'appelle un shield Grove qui permet de brancher très facilement différent module, dans mon cas, c'est pour éviter une prise de tête pour certain périphérique Grove. Mais on peut enlever ce shield grove et brancher le module DMX512 directement sur les différents pin d'Arduino avec 3 fils.

Mafzst a écrit :Pour ma part, l'arduino ne me convient pas puisqu'il est impossible d'y mettre une souris, un clavier et un écran qui sont les points clé de mon projet.

L'arduino est contrôler avec l'IDE Arduino par l'intermédiaire du moniteur Série, peu pratique. D'où l'étape suivante est de développer une interface graphique en Python pour "manager" plus facilement le ou les DMX512.
Répondre
#23

Je me rends compte que j'ai stupidement commenté le code à l'état de ton commit et que tu as encore avancé depuis. C'aurait été mieux de le faire sur le code actuel, mais la plupart de mes remarques reste valable.
Répondre
#24

Bonjour à tous,
chevelu a écrit :Je te mets en commentaire mes remarques et suggestions par rapport à ton fichier.
Je me permets de te les faire vu que tu les demandes. wink
Ne te crois pas obligé pour autant de reprendre tout ton code… cool
J'espère que tu comprendras que mon objectif n'est pas de critiquer ton code à tout prix, mais de te montrer comment tu peux faire pour écrire un code plus facile à lire, donc à comprendre, et donc à maintenir et corriger en cas de bug.
Merci beaucoup pour tes remarques, c'est comme ça que l'on progresse.
chevelu a écrit :Je me rends compte que j'ai stupidement commenté le code à l'état de ton commit et que tu as encore avancé depuis. C'aurait été mieux de le faire sur le code actuel, mais la plupart de mes remarques reste valable.
Oui, entre temps j'ai fait quelques modifs mais ce que tu me donne reste pour la plus part valable.
Je te réponds point à point :

> Pour l'import de numpy, j'ai modifié. C'est en fait une habitude prise sur un tuto dans lequel, il mettait toujours cet alias
>
Code :
[== Indéfini ==]
def binaire (n): # pour l'ensemble de la fonction ainsi que le reste du fichier, pense à mettre des noms de variable de plus d'une lettre, à part à la rigueur pour les indices.
    # Quand tu reviendras sur ton code dans trois mois, tu dois pouvoir le comprendre sans réfléchir.
    # Tu peux utiliser quotient et reste au lieu de q et r
Pour le nom des variables, j'ai modifié pour quotient et reste, mais j'ai laissé n pour le nombre car, pour moi, n est une variable réservée qui ne contient que des nombres. De même, i sera toujours utilisé pour des boucles et jamais ailleurs et j sera utilisé pour des nombres complexes uniquement.
>
Code :
[== Indéfini ==]
sortie = [0,0,0,0,0,0,0,0]
J'ai en effet remplacé par ce que tu me conseillais. J'avais mis ça au départ pour être sûr d'avoir les huit bits pour le bus. Comme plus tard je génère tous les bits de la trame et que je les remplace un à uns il n'y a plus de problème.
> L'initialisation de i à été supprimée
>
Code :
[== Indéfini ==]
def __init__(self,n, h=512): # crée une constante dans ton module pour la valeur par défaut en (3) par exemple
Je ne vois pas l'intérêt de créer une constante pour l'affecter à une seule autre constante.
>
Code :
[== Indéfini ==]
self.savepath = os.getcwd() + "\\Preps\\" # pas besoin d'embarquer cette valeur dans ton objet. Tu peux en faire une constante au niveau de ton module à mettre en (2) par exemple
Cette variable va sauter puisque que l'interface me fournit déjà ce paramètre au moment de l'enregistrement.
>
Code :
[== Indéfini ==]
self.content = np.zeros((self.height,11)) # Tu devrais créer une constante pour 11
Ici, 11 ne variera jamais puisqu'il fait partie de la norme DMX et du découpage que j'ai fait (c'est-à-dire, par canal). Faire varier ce paramètre reviendrait à revoir au moins la moitié du mon code !
>
Code :
[== Indéfini ==]
def new(self):
       self.content = np.zeros((self.height,11)) # Tu devrais créer une constante pour 11
       # tu devrais initialiser ton objet complètement et mettre la ligne ci-dessus plutôt dans __init__. Cette méthode devient alors inutile
       return self.content
Cette méthode sert, à l'origine à écraser la trame courante pour la rendre vierge. Mais à y réfléchir, il suffit d'une méthode qui viendra mettre des 0 dans tous les canaux. Je transfert donc ça dans __init__(). Pour l'instant, je laisse cette méthode qui ne fera rien, car l'interface l'appelle.
>
Code :
[== Indéfini ==]
def nff(self, fic): # nom de fonction trop court loadFromFile serait meilleur ; pareil, fic est peu explicite : fileName serait préférable
        return np.load(self.savepath + fic + '.npy')
J'ai fait les modifications, c'est encore pour moi, de mauvaises habitudes à vouloir tout faire court.
>
Code :
[== Indéfini ==]
return True # pourquoi retourner une valeur si elle est toujours la même (à moins de devoir respecter une interface, ce qui n'est pas ton cas ici)
Complètement d'acord avec toi, ça n'a aucun sens. C'est en fait la trace d'un débugage que j'ai oublié d'enlever.
> La suite du code permet de modifier une ligne du tableau Trame, c'est-à-dire, une valeur pour un canal DMX. La dernière méthode est une ébauche de ce qui servira à envoyer la trame sur le bus (pour l'instant elle ne fait que mettre en forme le tableau, sur une seule ligne, et y ajoute l'entête du message pour le bus)
> Dans la dernière version, j'ai enlevé les variables globales.
>
Code :
[== Indéfini ==]
C = np.reshape(C,5632) # … j'ai une erreur ici à l'exécution : ValueError: total size of new array must be unchanged
J'ai eu le même bug, je l'ai corrigé dans la nouvelle version :
Code :
[== Indéfini ==]
def make(self):
        self.go = numpy.concatenate((numpy.loadtxt('break.dmx'),numpy.loadtxt('MAB.dmx'),numpy.reshape(self.content,self.lenght)))
        return self.go

> Pour ce qui est de Git, je vais modifier le nom.
Nouveau commit avec tes modifs



@Nekrofage :
D'accord, merci pour les précisions.
Bon courage pour ton projet.


@+
Nicolas.

Projet en cours : Commande de projecteurs via un Raspberry
Mon blogTopic sur le forumDépôt GitHub
Répondre
#25

Mafzst a écrit :Pour le nom des variables, j'ai modifié pour quotient et reste, mais j'ai laissé n pour le nombre car, pour moi, n est une variable réservée qui ne contient que des nombres. De même, i sera toujours utilisé pour des boucles et jamais ailleurs et j sera utilisé pour des nombres complexes uniquement.
Très bonne décision. En effet, n, i, j sont très utilisées pour ce genre d'usage.

Mafzst a écrit :
Code :
[== Indéfini ==]
def __init__(self,n, h=512): # crée une constante dans ton module pour la valeur par défaut en (3) par exemple
Je ne vois pas l'intérêt de créer une constante pour l'affecter à une seule autre constante.
Ca permet de nommer les choses, et de savoir à quoi elles correspondent. De plus, avec ton raisonnement, si tu veux modifier cette valeur, pour x ou y raison, tu sauras où elle est : en début de fichier. Là, tu sais où elle se trouve car ton code est encore tout frais dans ta tête et que ton projet est encore petit, mais dès qu'il va grandir, ce sera plus facile avec des constantes.


Mafzst a écrit :Pour ce qui est de Git, je vais modifier le nom.
Nouveau commit avec tes modifs
Je regarderai ça plus tard. Il va falloir que je parte travailler. Wink
Répondre


Atteindre :


Utilisateur(s) parcourant ce sujet : 1 visiteur(s)