[PYTHON] [Travail électronique] J'ai fabriqué un détecteur de son tactile Suica avec Raspberry Pi

introduction

Il y a environ cinq ans (vers 2015), quand je suis allé dîner avec une connaissance sourde ** Parfois, je n'entends pas le son tactile de Suica (de la carte IC de transport) et je suis inquiet si je pourrais le toucher ** J'ai entendu l'histoire. À ce moment-là, j'étais sur le point d'acheter un Raspberry Pi à Akihabara, et je me demandais si je pouvais faire quelque chose à ce sujet. ** Puis-je fabriquer une machine qui allume la LED lorsque je capte le son tactile de Suica (PASMO ou ICOCA, peu importe)? ** ** J'y ai pensé et j'ai essayé de réussir.

Il est bon de s'en souvenir, mais comme l'équipement (câblage) a déjà été démonté, je me demande comment je l'ai expliqué. Au fait, même si j'étais dans une telle situation au moment d'écrire cet article, je l'ai laissé encore deux ans jusqu'à ce que je le publie ...

équipement

  1. Raspberry Pi 1 Model B +: Ce que j'ai acheté à l'époque était la version 1. Je l'écrirai plus tard, mais c'était difficile en termes de performances. De nos jours, jusqu'à Razzpie 4 est sorti ...
  2. Microphone de bureau (MS-STM55): Un microphone prêt à l'emploi que j'ai acheté il y a longtemps. Connectez-vous au RPi et entrez le son. Compte tenu de l'utilisation pratique, quelque chose comme un microphone à broche peut être préférable.
  3. Convertisseur audio USB (BSHSAU01BK): Certainement, quand je l'ai connecté à la prise 3,5 pouces du RPi, il y avait du bruit et je ne pouvais pas bien enregistrer. Je me demande donc si j'ai décidé de me connecter via USB.
  4. Batterie mobile USB (Anker Astro Mini): J'ai essayé de prendre la puissance du RPi de la batterie mobile pour la portabilité. C'est une batterie qui ne peut produire que 1A, mais cela a bien fonctionné. 5.7 LED Seg (OSL40562-IR): Une partie qui est coincée dans la carte et affiche 0. Un gars qui peut afficher des nombres de 0 à 9. La raison pour laquelle ce n'est pas seulement une LED est que je voulais afficher le nombre de fois où le son tactile a été entendu.
  5. Fil de plomb ou carte universelle: Idéal pour les expériences car il peut être facilement inséré et retiré.
  6. Câble LAN: utilisé pour entrer des commandes à partir d'un PC via SSH. Si vous configurez le programme de détection pour qu'il démarre en tant que service, il devrait fonctionner sans PC, vous n'aurez donc pas besoin d'un câble LAN (bien que je ne l'ai pas essayé). Le Wi-Fi est maintenant installé à Raspeye, c'est donc aussi une tendance de l'époque.

Dans l'image ci-dessus, un vérificateur de courant / tension USB est également connecté. Je pense que c'était en veille (lorsque le programme de détection n'était pas en cours d'exécution), mais comme l'alimentation USB est d'environ 5V, elle fonctionne à environ 1,4W.

Câblage

Si vous regardez de près l'image de la carte plus tôt, il y a une résistance, mais c'est pour limiter le courant de la LED à 7 segments. En regardant la Fiche technique de la LED à 7 segments,

Donc, je l'ai connecté au GPIO de RPi via la résistance de 220Ω que j'avais. Pour GPIO, par exemple, veuillez consulter la page suivante. ON / OFF peut être contrôlé par des commandes et des programmes.

[^ 1]: Il y a une limite de 16 mA sur le courant qui peut être passé à travers la broche GPIO du Raspberry Pi, il est donc nécessaire de remplir cette condition ainsi que les pièces.

Soit dit en passant, le GPIO de RPi1 est de 3,3 V, donc si vous utilisez une résistance de 220 Ω, est-ce que cela passera environ 6 mA à la LED [^ 2]?

[^ 2]: Il y a une limite que le courant total qui peut être passé à travers la broche GPIO du Raspberry Pi est jusqu'à 50mA, mais dans ce cas, cela devrait être correct car il est de 42mA même si les 7 segments sont allumés.

話のネタにするために当時書いていたメモ

Si vous regardez un segment (éclairé), vous devriez voir un circuit comme celui-ci. En fait, il semble que les sept segments soient connectés en parallèle, comme l'expérience de l'ampoule miniature de la science. Cependant, il convient de noter que le côté + est en fait 3,3V uniquement dans le segment éclairé, et le segment éclairé est à 0V sur le côté +. Le segment off a 0V sur les côtés + et, donc aucun courant ne circule.

programme

Après cela, écrivez un programme qui s'exécute sur Python sur Raspbian. Largement divisé

-Où capturer le son du microphone --Où détecter le son tactile --Où allumer la LED

Vous devez réussir.

Enregistrement depuis le microphone

Un microphone connecté via un convertisseur audio USB peut être traité comme un périphérique ALSA, je l'ai donc écrit en utilisant le module alsaaudio. Je voulais également lire le fichier wav pour le débogage, donc je l'ai écrit d'une manière qui prend en charge les deux.

Une chose à noter à propos de Raspberry Pi est que l'écriture d'un mauvais programme est lourde et ne peut être aidée. Le traitement qui peut être effectué en un instant sur un PC est une tâche difficile pour RPi (surtout lorsque vous souhaitez opérer en temps réel comme cette fois). Alors que FFT doit traiter un nombre fixe d'images (2 carrés), l'entrée microphone ne peut pas toujours lire un nombre fixe d'images. C'est pourquoi il existe un processus tel que la création d'un tampon en anneau, la combinaison des données lues et la découpe à une certaine longueur pour FFT. Si je l'ai écrit en combinant des listes et en découpant sans penser à rien ici, cela aurait été trop lourd pour travailler en temps réel ...

pcmmod.py


# -*- coding: utf-8 -*-
import numpy
import alsaaudio
import wave
import collections

FrameArrayTuple = collections.namedtuple(
    "FrameArrayTuple",
    ["array", "nframes_read"])

# Based on https://scimusing.wordpress.com/2013/10/25/ring-buffers-in-pythonnumpy/
class RingBuffer:
    "A 1D ring buffer using numpy arrays"
    def __init__(self, length):
        pow2 = int(numpy.ceil(numpy.log2(length)))
        self.length = 2 ** pow2
        self.data = numpy.zeros(self.length, dtype='float64')
        self.index_top = 0
        self.index_bottom = 0

    def extend(self, x):
        "adds array x to ring buffer"
        if x.size > 0:
            x_index = (self.index_bottom + numpy.arange(x.size)) & (self.length-1)
            self.data[x_index] = x
            self.index_bottom = x_index[-1] + 1

    def get(self, n=None):
        "Returns the first-in-first-out data in the ring buffer"
        idx = (self.index_top + numpy.arange(min(n, self.count()) if n is not None else self.count())) & (self.length-1)
        self.index_top = idx[-1] + 1
        return self.data[idx]

    def count(self):
        c = (self.index_bottom - self.index_top + self.length) & (self.length-1)
        return c

class PCMInputStream:
    def __init__(self, maxNumFrame):
        #Ne peut pas être instancié indépendamment, mais peut être appelé à partir de la destination d'héritage
        self.maxNumFrame = maxNumFrame
        self.op_array = self.getFramesToArrayOperator()

    def readFrames(self):
        raise NotImplementedError("readFrames() must be implemented")

    def readFrameArray(self):
        frames = self.readFrames()
        return self.op_array(frames)

    def getNumChannels(self):
        raise NotImplementedError("getNumChannels() must be implemented")

    def getFrameRate(self):
        raise NotImplementedError("getFrameRate() must be implemented")

    def getSampleWidthInBytes(self):
        raise NotImplementedError("getSampleWidthInBytes() must be implemented")

    def getFramesToArrayOperator(self):
        sw = self.getSampleWidthInBytes()
        if sw == 1:
            fmt = "uint8"
            shift_amp = 128.0
            max_amp = 128.0
        elif sw == 2:
            fmt = "int16"
            shift_amp = 0.0
            max_amp = 32768.0
        else:
            raise ValueError("getSampleWidthInBytes() must be return 1 or 2")
            return

        return (lambda frames: (numpy.frombuffer(frames, dtype=fmt) - shift_amp) / max_amp)

    def getFrameArrayIterator(self):
        #Essayez de toujours renvoyer numMaxFrame à la fois.
        nframes_read = 0
        num_channels = self.getNumChannels()
        arr_buffer = RingBuffer(self.maxNumFrame * 10)
        l = -1
        while l != 0:
            if arr_buffer.count() >= self.maxNumFrame * num_channels:
                nframes_read += self.maxNumFrame
                #Diviser en canaux
                arr_channels = arr_buffer.get(self.maxNumFrame * num_channels).reshape(self.maxNumFrame, num_channels).T
                yield FrameArrayTuple(arr_channels, nframes_read)
            else:
                arr = self.readFrameArray()
                l = arr.shape[0]
                assert l % num_channels == 0
                #Combinez le contenu lu
                arr_buffer.extend(arr)

        #Renvoie les dernières données
        arr = arr_buffer.get()
        nframes_read += arr.shape[0] / num_channels
        arr_channels = arr.reshape(arr.shape[0] / num_channels, num_channels).T
        yield FrameArrayTuple(arr_channels, nframes_read)

    def close(self):
        pass

class PCMInputStreamFromWave(PCMInputStream):
    def __init__(self, filename, maxNumFrame):
        self.wv = wave.open(filename, "r")
        self.ch = self.wv.getnchannels()
        self.rate = self.wv.getframerate()
        self.sw = self.wv.getsampwidth()
        self.maxNumFrame = maxNumFrame
        PCMInputStream.__init__(self, maxNumFrame)

    def readFrames(self):
        return self.wv.readframes(self.maxNumFrame)

    def getNumChannels(self):
        return self.ch

    def getFrameRate(self):
        return self.rate

    def getSampleWidthInBytes(self):
        return self.sw

    def close(self):
        self.wv.close()

class PCMInputStreamFromMic(PCMInputStream):
    def __init__(self, rate, sampleWidth, maxNumFrame):
        self.ch = 1
        self.rate = rate
        self.sw = sampleWidth
        self.maxNumFrame = maxNumFrame

        #Initialisation du périphérique d'enregistrement
        self.pcm = alsaaudio.PCM(alsaaudio.PCM_CAPTURE)
        self.pcm.setchannels(self.ch)
        self.pcm.setrate(self.rate)
        #Lisez deux fois à la fois pour accélérer le traitement
        print self.pcm.setperiodsize(self.maxNumFrame * 4)
        if self.sw == 1:
            self.pcm.setformat(alsaaudio.PCM_FORMAT_U8)
        elif self.sw == 2:
            self.pcm.setformat(alsaaudio.PCM_FORMAT_S16_LE)
        else:
            raise ValueError("sampleWidth must be 1 or 2")

        PCMInputStream.__init__(self, maxNumFrame)

    def readFrames(self):
        length, frames = self.pcm.read()
        return frames

    def getNumChannels(self):
        return self.ch

    def getFrameRate(self):
        return self.rate

    def getSampleWidthInBytes(self):
        return self.sw

Détecter le son tactile

C'est aussi un souvenir assez difficile. Fondamentalement, le son a été analysé en fréquence par FFT, et si la fréquence donnée (du son tactile) avait plus de puissance que les autres fréquences, elle aurait été jugée "touchée" ... Cependant, si vous utilisez la boucle for facilement comme si vous écriviez un programme sur un PC, il sera trop lourd de travailler en temps réel lors du calcul de la puissance d'une fréquence spécifique à partir des composants du bac de fréquences, par exemple (si vous n'êtes pas bon dans ce domaine, le traitement de la FFT lui-même). Je me souviens avoir fait diverses choses, comme réécrire les parties qui peuvent être écrites avec des modules intégrés, NumPy et SciPy.

suicadetection.py


# -*- coding: utf-8 -*-

import numpy
import scipy.fftpack
import time
import bisect
import collections

DetectionHistoryTuple = collections.namedtuple(
    "DetectionHistoryTuple",
    ["cond_energy", "energy_peak", "freq_center_detected"])

#Constante représentant l'état de détection
DETECTION_ON = "on"
DETECTION_OFF = "off"

class SuicaDetection:
    #Rayon de fréquence du calcul d'énergie[Hz]
    FREQ_TOLERANCE = 50
    #Nombre d'histoires enregistrées
    NUM_HIST_SAVED = 3
    #Seuil du rapport d'énergie au moment du jugement d'augmentation
    THRES_ENERGY_RATIO = 0.25
    #Valeur minimale de float64
    EPS_FLOAT64 = numpy.finfo(numpy.float64).eps

    def freq_filter_vector(self, freq_center, freq_tolerance):
        freq_delta = self.freq_axis[1] - self.freq_axis[0]
        # freq_center +/- freq_L'énergie contenue dans la tolérance
        #Renvoie un vecteur de poids à calculer.
        energy_weight = numpy.array(
            [(lambda freq_min, freq_max:
                      (1.0 if freq_min <= f and f + freq_delta <= freq_max
                       else (freq_max - f) / freq_delta if freq_min <= f <= freq_max <= f + freq_delta
                       else (f + freq_delta - freq_min) / freq_delta if f <= freq_min <= f + freq_delta <= freq_max
                       else (freq_tolerance * 2 / freq_delta) if f <= freq_min and freq_max <= f + freq_delta
                       else 0.0))
                 (freq_center - freq_tolerance, freq_center + freq_tolerance)
                 for f in self.freq_axis])
        return energy_weight

    def __init__(self, center_freqs, freq_axis):
        self.ts = time.time()
        self.hist = []
        self.time_axis = []
        self.nframes_read = 0
        self.detected_freq = None
        self.init_energy = None
        self.freq_axis = freq_axis
        #Poids énergétique pour la fréquence centrale que vous souhaitez détecter
        self.center_freqs = center_freqs
        self.energy_weight_array = numpy.array([
                self.freq_filter_vector(center_freq, self.FREQ_TOLERANCE)
                for center_freq in center_freqs
            ]).T

    def input_array(self, arr):
        assert len(arr.shape) == 1
        num_frames = arr.shape[0]

        self.detect(arr)

        status = None
        if self.detected_freq:
            #Lorsqu'il y a un son, le son de cette bande de fréquences est entendu trois fois immédiatement avant-Fin lorsque 5 dB chute
            if all((t.energy_peak is None) or (t.energy_peak - self.init_energy) < -5 for t in self.hist[-3:]):
                self.detected_freq = None
                status = DETECTION_OFF
        else:
            #S'il n'y a pas de son, c'est OK si la condition d'énergie est remplie deux fois sur les trois dernières fois.
            if len([t for t in self.hist[-3:] if t.cond_energy]) >= 2:
                self.detected_freq = self.hist[-1].freq_center_detected
                self.init_energy = self.hist[-1].energy_peak
                status = DETECTION_ON

        self.nframes_read += num_frames

        return (self.nframes_read, status)
            
    def detect(self, arr):
        #print "start", time.time()
        assert len(arr.shape) == 1
        num_frames = arr.shape[0]

        # FFT
        f = scipy.fftpack.fft(arr)
        e = numpy.square(numpy.absolute(f))
        #Prévention des erreurs
        e = numpy.maximum(e, self.EPS_FLOAT64)

        #Énergie totale (temps constants)
        energy_total = e.sum()
        #Énergie pour chaque fréquence
        # +/-Combinez (double) l'énergie de la fréquence de
        energy_axis = 2 * e[0:num_frames/2]
        log_energy_axis = 10 * numpy.log10(energy_axis)

        #Calculer le rapport d'énergie près de la fréquence spécifiée
        energy_weighted = energy_axis.dot(self.energy_weight_array)
        energy_ratio_max, freq_center_detected = \
            max(zip(list(energy_weighted / energy_total), self.center_freqs),
                key=lambda t: t[0])

        #Conditions énergétiques
        #Concentrez-vous sur la fréquence la plus forte
        cond_energy = (energy_ratio_max >= self.THRES_ENERGY_RATIO)

        # +/-Basé sur la puissance maximale à moins de 100 Hz
        idx_low = bisect.bisect_left(self.freq_axis, freq_center_detected - 100)
        idx_high = bisect.bisect_right(self.freq_axis, freq_center_detected + 100)
        energy_peak = log_energy_axis[idx_low:idx_high+1].max()
        #Ajouter à l'histoire
        self.hist.append(DetectionHistoryTuple(cond_energy=cond_energy,
                                               energy_peak=energy_peak,
                                               freq_center_detected=freq_center_detected))
        #Supprimer l'ancienne histoire
        if len(self.hist) > self.NUM_HIST_SAVED:
            self.hist.pop(0)

Faire briller la LED

Contrôlez l'activation / désactivation du GPIO correspondant en fonction du numéro que vous souhaitez briller. Le GPIO à utiliser est défini par le programme appelant. Le module RPi.GPIO a été utilisé pour ce contrôle ON / OFF.

Il semble que GPIO ne peut être contrôlé que s'il est exécuté en tant que root, alors soyez prudent.

sevenseg.py


# -*- coding: utf-8 -*-
import sys
import RPi.GPIO as GPIO
import time

class GPIO7seg:
    sevenseg_on = [[0, 2, 3, 5, 6, 7, 8, 9],
                   [0, 1, 2, 3, 4, 7, 8, 9],
                   [0, 1, 3, 4, 5, 6, 7, 8, 9],
                   [0, 2, 3, 5, 6, 8, 9],
                   [0, 2, 6, 8],
                   [0, 4, 5, 6, 8, 9],
                   [2, 3, 4, 5, 6, 8, 9]]

    def __init__(self, id_pin_seg):
        self.id_pin_seg = id_pin_seg
        GPIO.setmode(GPIO.BCM)
        for i in id_pin_seg:
            GPIO.setup(i, GPIO.OUT)

    def digit(self, n):
        for i in xrange(7):
            GPIO.output(self.id_pin_seg[i], n not in self.sevenseg_on[i])

Partie principale

Lors de l'appel de chaque module depuis le programme principal, la LED s'allume en fonction du résultat du jugement.

Par exemple, 1 s'affiche lorsqu'un bip retentit et 2 s'affiche lorsqu'un bip retentit. Lors du passage à la porte du ticket, la signification est différente une fois et deux, essayons donc de le comprendre C'est un programme appelé.

Il s'agit d'un GPIO pour éclairer la LED 7 segments, mais cette fois, les broches 15 à 21 correspondent respectivement aux segments A à G (voir fiche technique) de la LED 7 segments.

Si vous exécutez ce programme principal en tant que root (pour le contrôle GPIO), nous espérons que les nombres changeront en réponse au son tactile capté par le microphone.

suica_main.py


#!/usr/bin/env python2
# -*- coding: utf-8 -*-

import sys
import numpy
import itertools

import pcmmod
import suicadetection
import sevenseg

# ================================

def main():
    #Longueur du signal (nombre d'échantillons)
    MAX_NUM_FRAMES = 512
    #Fréquence que vous souhaitez détecter
    FREQS_CENTER = [2550, 2700, 3000]

    #Fonction de fenêtre
    ham_window = numpy.hamming(MAX_NUM_FRAMES)

    #Lecture WAVE ou entrée microphone
    if len(sys.argv) == 1:
        #Microphone
        rate = 44100
        sw = 2
        sound = pcmmod.PCMInputStreamFromMic(rate, sw, MAX_NUM_FRAMES)
    else:
        # WAVE
        sound = pcmmod.PCMInputStreamFromWave(sys.argv[1], MAX_NUM_FRAMES)
        rate = sound.getFrameRate()

    #Axe de fréquence
    freq_axis = numpy.fft.fftfreq(MAX_NUM_FRAMES, 1.0/rate)[0:MAX_NUM_FRAMES/2]

    sd = suicadetection.SuicaDetection(FREQS_CENTER, freq_axis)

    #compteur(7SEG LED)
    counter_ring = 0
    id_pin_seg = [15, 16, 17, 18, 19, 20, 21]
    gpio7 = sevenseg.GPIO7seg(id_pin_seg)
    gpio7.digit(counter_ring)
    #Voir le dernier temps compté
    counted_last = None

    #Lire la forme d'onde
    #Utiliser jusqu'à la partie complète et lue
    for arr, nframes_read in itertools.takewhile(lambda t: t.array.shape[1] == MAX_NUM_FRAMES,
                                                 sound.getFrameArrayIterator()):
        #Utilisé pour le jugement:Prendre L pour 2ch
        time_frames, status = sd.input_array(arr[0] * ham_window)
        if status == suicadetection.DETECTION_ON:
            print float(time_frames) / rate, "ON"
            # 0.Ne comptez pas avant 1 seconde
            counted_last = time_frames
            pending = True
        elif status == suicadetection.DETECTION_OFF:
            print float(time_frames) / rate, "OFF"
            print
            pending = False

        if counted_last is not None:
            if time_frames > counted_last + rate * 2.0:
                #Réinitialisez la LED après 2 secondes
                gpio7.digit(counter_ring)
                counted_last = None
            elif time_frames > counted_last + rate * 1.0:
                #Aucun jugement de combo après 1 seconde (réinitialisation du compteur uniquement en interne)
                counter_ring = 0
            elif pending and time_frames > counted_last + rate * 0.1:
                counter_ring += 1
                gpio7.digit(counter_ring)
                pending = False

if __name__ == "__main__":
    main()

Résumé

Je pense que j'ai fait beaucoup d'ajustements pour juger du son tactile. Si vous le regardez simplement avec le pouvoir, il réagira dans une cour de gare bruyante.

Après cela, j'ai constaté que la fréquence du son tactile n'était pas unifiée de manière inattendue. ** Même si vous comparez le cas de la billetterie et le cas du caissier au dépanneur, la hauteur (fréquence) du son tactile est en fait différente **, donc cela devient de plus en plus compliqué quand on pense à permettre de détecter l'un ou l'autre. ….

À propos, je n'avais pas été préoccupé par la fréquence du son tactile auparavant, alors quand j'ai écrit ce programme, j'ai recherché des nombres spécifiques dans Audacity pour la première fois. Quand j'ai signalé à la connaissance au début que "le son tactile semble être de 2550 Hz ou 2700 Hz", j'étais convaincu que "je ne peux pas l'entendre".

Cela faisait longtemps que les gens ne disaient pas que c'était une conception sans obstacle ou universelle. ** Regardez-vous uniquement les étapes visibles? Concevez-vous le son avec la bande de fréquences à l'esprit? ** ** Je pense que j'ai remarqué cela. Cependant, si le son est faible, il peut être difficile à entendre à cause de la foule. c'est difficile.

Recommended Posts

[Travail électronique] J'ai fabriqué un détecteur de son tactile Suica avec Raspberry Pi
J'ai créé un moniteur de ressources pour Raspberry Pi avec une feuille de calcul
J'ai fait une caméra de surveillance avec Raspberry PI pour la première fois.
J'ai créé un serveur Web avec Razpai pour regarder des anime
Profitez du travail électronique avec GPIO de Raspberry Pi
[Pour les débutants] J'ai fait un capteur humain avec Raspberry Pi et notifié LINE!
J'ai fait une loterie avec Python.
J'ai créé un démon avec Python
Utiliser une webcam avec Raspberry Pi
Créer un environnement Tensorflow avec Raspberry Pi [2020]
J'ai fait un compteur de caractères avec Python
Capteur humain amélioré fabriqué avec Raspberry Pi
Faire une minuterie de lavage-séchage avec Raspberry Pi
J'ai fait une carte hexadécimale avec Python
J'ai fait un jeu de vie avec Numpy
J'ai fait un générateur Hanko avec GAN
Faites fonctionner l'oscilloscope avec le Raspberry Pi
Créez un compteur de voiture avec Raspberry Pi
J'ai fait un jeu rogue-like avec Python
J'ai fait un simple blackjack avec Python
J'ai créé un fichier de configuration avec Python
J'ai fait une application WEB avec Django
J'ai fait un simulateur de neurones avec Python
J'ai essayé de faire un signal avec Raspeye 4 (édition Python)
J'ai fait un robot de remplacement de tampon avec une ligne
J'ai fait une prévision météo de type bot avec Python.
J'ai créé une application graphique avec Python + PyQt5
J'ai essayé de créer un bloqueur de filles pourries sur Twitter avec Python ①
J'ai essayé L-Chika avec Razpai 4 (édition Python)
[Python] J'ai créé un téléchargeur Youtube avec Tkinter.
J'ai fait un simple portefeuille de Bitcoin avec pycoin
J'ai créé un Bot LINE avec Serverless Framework!
J'ai essayé de créer un bouton pour Slack avec Raspeye + Tact Switch
J'ai fait un graphique de nombres aléatoires avec Numpy
Application d'analyse des investissements boursiers avec tarte aux framboises
J'ai fait un jeu de cueillette avec Python
Made Mattermost Bot avec Python (+ Flask)
Serveur de partage de fichiers réalisé avec Raspberry Pi pouvant être utilisé pour le travail à distance
[AWS] J'ai créé un BOT de rappel avec LINE WORKS
J'ai fait un Twitter BOT avec GAE (python) (avec une référence)
J'ai créé un bot de livre de compte de ménage avec LINE Bot
J'ai créé un serveur syslog prêt à l'emploi avec Play with Docker
J'ai fait un jeu d'éclairage de sapin de Noël avec Python
J'ai créé une fenêtre pour la sortie du journal avec Tkinter
J'ai créé une application de notification de nouvelles en ligne avec Python
J'ai créé un environnement Python3 sur Ubuntu avec direnv.
Je veux travailler avec un robot en python.
J'ai essayé de faire LINE BOT avec Python et Heroku
Un mémorandum lors de la réalisation d'une caméra de surveillance avec Raspeye
J'ai fait un jeu mono tombé avec Sense HAT
〇✕ J'ai fait un jeu
DigitalSignage avec Raspberry Pi
J'ai essayé de créer une caméra de surveillance à détection de mouvement avec OpenCV en utilisant une caméra WEB avec Raspberry Pi
Une histoire qui a trébuché lorsque j'ai créé un bot de chat avec Transformer
J'ai fait un jeu de frappe simple avec tkinter de Python
Créez une caméra de surveillance WEB avec Raspberry Pi et OpenCV
J'ai créé un package pour filtrer les séries chronologiques avec python