Sessions Robòtica Extraescolar. Curs 2016-2017

De Wikijoan
Dreceres ràpides: navegació, cerca

Contingut

Sessió 1

Objectiu

Desenvolupament

Moviment Maker

És un moviment cultural que es va popularitzar als 50´s. Movimient o cultura Maker s'identifica amb DIY (Do It Yourself: fés-ho tu mateix).

Avui dia, amb la democratització de l'accés a la tecnologia i als miniordinadors, i l'accés a documentació i recursos, el moviment Maker ha tornat a ressorgir amb més força que mai.

Enllaços d'interès:

Paraules clau: open software, open hardware, Raspberry Pi, Arduino, IoT (Internet of Things), DIY,...

Raspberry PI

La Raspberry Pi és un petit ordinador amb les dimensions de una targeta de crèdit. Té els components necessaris d’un ordinador comú.

La placa conté varis ports, dos USB, un de Ethernet i sortida HDMI. Aquests ports permeten connectar el miniordinador a altres dispositius com ara teclats, mouse i pantalla.

A més a més disposa d’una sèrie de connexions GPIO (General Purpose Input/Output) per a comunicar-se amb dispositius externs.

Projectes:

Presentació del projecte SIMON

Simon-Game l.jpg

Instalació i configuració de la Raspberry Pi

Baixar la imatge de Raspbian:

Descomprimir:

$ unzip 2016-11-25-raspbian-jessie-lite.zip

Copiem la imatge en una targeta SD:

$ dd if=/ruta/2016-11-25-raspbian-jessie-lite.img of=/dev/sdb....

Configuració. Necessitem la IP. La primera vegada entrem amb la Raspberry connectada a un monitor i teclat, i fem:

$ ifconfig

per saber la IP. Les dades inicials per entrar a la Raspberry Pi són:

Configuració inicial:

$ sudo raspi-config

A l'opció 7, activem el servidor de SSH (Secure Shell), que ens permetrà connectar-nos remotament des de qualsevol client SSH (un altre ordinador).

Connexió remota a la Raspberry Pi

$ ssh pi@IP, per ex,
$ ssh pi@192.168.1.244

Amb un navegador web també podem fer a la barra d'adreces:

ssh://IP (per a transferir fitxers)

IPs fixes a la Raspberry Pi i a l'aula 44

dhcpcd és un client que es comunica amb el servidor de DHCP, encarregat de donar les IPs de la xarxa. Podem dir-li que volem una IP fixa.

A sota de tot, després de la línia:

nohook lookup-hostname

posem:

$ sudo joe /etc/dhcpcd.conf

interface eth0
static ip_address=192.168.44.11/24
static routers=192.168.44.1
static domain_name_servers=8.8.8.8 4.2.2.1

Feina per la propera setmana

El codi en què ens basarem per programar el SIMON és:

Està escrit en Python. Pots mirar el codi i mirar d'identificar les diferents parts del codi. Ho comentarem i treballarem la propera setmana.

Sessió 2

Objectiu

Mirem el codi original del programa en el qual ens basem (https://pierskennedy.wordpress.com/2013/03/04/rpi-simon-game-with-sound/), i n'identifiquem les parts. Executem parts per separat, no cal que sigui a la Rpi, es pot executar directament a Linux/Ubuntu.

Desenvolupament

generar_random.py:

##!/usr/bin/env python
#______________________________
#

import random

#Variables
max     = 100               #No. of rounds in game
RoundNo = 1
RED     = 1
GREEN   = 2
YELLOW  = 3
BLUE    = 4

colour=[]
for n in range(1,max+2):
    colour.append(random.choice([RED,GREEN,YELLOW,BLUE]))
 
for n in range(1,max+1):
    print colour[n]

generar_fitxers_so.py:

##!/usr/bin/env python

import numpy
import wave

SAMPLERATE = 44100

def createSignal(frequency, duration):
    samples = int(duration*SAMPLERATE)
    period = SAMPLERATE / frequency
    omega = numpy.pi * 2 / period
    xaxis = numpy.arange(samples, dtype=numpy.float) * omega
    yaxis = 32800 * numpy.sin(xaxis) #estem creant una ona senoidal
    return yaxis.astype('int16').tostring()

def createWAVFile(filename, signal):
    file = wave.open(filename, 'wb')
    file.setparams((1, 2, SAMPLERATE, len(signal), 'NONE',
    'noncompressed'))
    file.writeframes(signal)
    file.close()

#blue sound 209Hz
bluesound = '/tmp/blue.wav'
signal = createSignal(frequency=209, duration=.4)
print signal
createWAVFile(bluesound, signal)
#yellow sound 252Hz
yellowsound = '/tmp/yellow.wav'
signal = createSignal(frequency=252, duration=.4)
createWAVFile(yellowsound, signal)
#red sound 310Hz
redsound = '/tmp/red.wav'
signal = createSignal(frequency=310, duration=.4)
createWAVFile(redsound, signal)
#green sound 415Hz
greensound = '/tmp/green.wav'
signal = createSignal(frequency=415, duration=.4)
createWAVFile(greensound, signal)

#losing tone 42 Hz
losingtone = '/tmp/losingtone.wav'
signal = createSignal(frequency=42, duration=3)
createWAVFile(losingtone, signal)

# $ ls /tmp/*.wav
# $ cat /tmp/yellow.wav
# man aplay
# aplay /tmp/yellow.wav

En el següent exercici hem de tenir instal.lat el mòdul pygame per poder fer sonar els arxius d'àudio:

ImportError: No module named pygame

$ sudo apt-get install python-pygame

generar_i_play_fitxers_so.py:

##!/usr/bin/env python

import time
import numpy
import wave
import pygame
import subprocess
 
#Set up sounds
#This avoids any delay before sound starts
pygame.mixer.pre_init(44100,-16,2,2048)
#Initialise mixer
pygame.mixer.init()
subprocess.Popen('amixer cset numid=3 1',shell=True)

SAMPLERATE = 44100

def createSignal(frequency, duration):
    samples = int(duration*SAMPLERATE)
    period = SAMPLERATE / frequency
    omega = numpy.pi * 2 / period
    xaxis = numpy.arange(samples, dtype=numpy.float) * omega
    yaxis = 32800 * numpy.sin(xaxis) #estem creant una ona senoidal
    return yaxis.astype('int16').tostring()

def createWAVFile(filename, signal):
    file = wave.open(filename, 'wb')
    file.setparams((1, 2, SAMPLERATE, len(signal), 'NONE',
    'noncompressed'))
    file.writeframes(signal)
    file.close()

def playWAVFile(filename):
    sound = pygame.mixer.Sound(filename)
    sound.play()

#blue sound 209Hz
bluesound = '/tmp/blue.wav'
signal = createSignal(frequency=209, duration=.4)
createWAVFile(bluesound, signal)

#yellow sound 252Hz
yellowsound = '/tmp/yellow.wav'
signal = createSignal(frequency=252, duration=.4)
createWAVFile(yellowsound, signal)

#red sound 310Hz
redsound = '/tmp/red.wav'
signal = createSignal(frequency=310, duration=.4)
createWAVFile(redsound, signal)

#green sound 415Hz
greensound = '/tmp/green.wav'
signal = createSignal(frequency=415, duration=.4)
createWAVFile(greensound, signal)

#losing tone 42 Hz
losingtone = '/tmp/losingtone.wav'
signal = createSignal(frequency=42, duration=3)
createWAVFile(losingtone, signal)

playWAVFile(redsound)
time.sleep(0.3)
playWAVFile(greensound)
time.sleep(0.3)
playWAVFile(yellowsound)
time.sleep(0.3)
playWAVFile(bluesound)
time.sleep(0.3)
playWAVFile(losingtone)
time.sleep(0.3)


Sessió 3

Objectiu

Per fer un prototipus del joc del Simon necessitarem com a mínim poder apretar uns botons i que s'iluminin unes llumetes. En aquesta sessió començarem a treballar amb els pins GPIO per fer entrades i sortides. És la manera com la RPi es pot comunicar amb el món físic.

Desenvolupament

GPIO pinout.png

Material que necessitarem:

Farem servir el ports GPIO com a portes de entrada i sortides digitals. Pots veure en la imatge el pinout de la Raspberry Pi, i el nom que tenen els pins.

Push button (pulsadors):

LED:

L'objectiu és muntar el següent circuint, parant atenció amb els pins.

Circuit push button led.jpg

Un cop muntat haurem d'executar codi (amb Python) que pugui escriure o llegir en els pins.

El primer codi que provaràs serà polsa0.py:

import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setup(23, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(24, GPIO.OUT )
while True:
  input_state = GPIO.input(23)
  if input_state == False:
    GPIO.output(24, True)      # Encen el LED
    print('Boto polsat')
    time.sleep(0.3)
    GPIO.output(24, False)     # Apaga el LED

NOTA. S'ha de posar una resistència entre la pota - del Led i GND. És a dir,s'ha de substituir el cable negre per una resistència. Això és perquè hem de limitar el corrent que passa pel LED.

ordinador:
$ scp polsa0.py pi@192.168.44.21:/home/pi/simon/
o bé millor (no caldrà que introdueixis el password):
$ sshpass -p 'raspberry' scp polsa0.py pi@192.168.44.21:/home/pi/simon/

rpi:
$ cd simon
$ ls
$ python polsa0.py

Exercicis proposats:

import RPi.GPIO as GPIO
import time    

GPIO.setmode(GPIO.BCM)
GPIO.setup(23, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(24, GPIO.OUT )
estat = False
GPIO.output(24, False)     # Apaga el LED, estat inicial

while True:
	input_state = GPIO.input(23)
	if input_state == False: #pitgem
		if estat==False:
			GPIO.output(24, True)      # Encen el LED
			time.sleep(0.3)
			estat = True
		else:
			GPIO.output(24, False)     # Apaga el LED
			time.sleep(0.3)
                        estat = False
import RPi.GPIO as GPIO
import time    

GPIO.setmode(GPIO.BCM)
GPIO.setup(23, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(24, GPIO.OUT )

estat = False

def pulsa():
	global estat
	input_state = GPIO.input(23)
	if input_state == False: #pitgem
		if estat==False:
			GPIO.output(24, True)      # Encen el LED
			time.sleep(0.3)
			estat = True
		else:
			GPIO.output(24, False)     # Apaga el LED
			time.sleep(0.3)
			estat = False	
	return(estat)

GPIO.output(24, False)     # Apaga el LED, estat inicial

while True:
	pulsa()
import RPi.GPIO as GPIO
import time    

GPIO.setmode(GPIO.BCM)
GPIO.setup(23, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(4, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(24, GPIO.OUT )

estat = False

def pulsa():
	global estat
	input_state = GPIO.input(23)
	if input_state == False: #pitgem
		if estat==False:
			GPIO.output(24, True)      # Encen el LED
			time.sleep(0.3)
			estat = True
		else:
			GPIO.output(24, False)     # Apaga el LED
			time.sleep(0.3)
			estat = False	
	return(estat)

GPIO.output(24, False)     # Apaga el LED, estat inicial

while True:
	pulsa()
	input_state2 = GPIO.input(4)
	if input_state2 == False:
		print ('Adeu!!!')
		break
GPIO.cleanup()

Sessió 4

Objectiu

En la sessió anterior vam fer les primeres proves per llegir i escriure en els pins GPIO. En aquesta sessió aprofundirem més en la programació de LEDs des de la Raspberry Pi.

Desenvolupament

Rpi leds.jpg

Disposem de quatre LEDs, que simularan els LEDs que tindrem en el joc del Simon. En la sessió anterior vam veure el codi bàsic per llegir i escriure en els pins GPIO, i així podíem llegir el valor dels interruptors i encendre i apagar els LEDs.

Avui no farem servir interruptors. Farem servir 4 LEDs, i podrem programar diferents seqüències.

Ex1. Amb la funció random.choice, encén i apaga de forma aleatòria els 4 LEDs de què disposes. Hauràs d'utilitzar 4 pins GPIO.

Ex 2. Comptador binari. Amb 4 LEDs (4 bits, estat encès/apagat) pots codificar digitalment 2^4=16 estats:

0 0 0 0
0 0 0 1
0 0 1 0
0 0 1 1
...
1 1 1 1  

Amb un bucle, fés un comptador del 0 al 15. Converteix el número a binari. Separa els bits, i encén el LED corresponent.

Ex 3. Fade in/out d'un LED. Amb la tecnologia PWM (Pulse Width Modulation), aconsegueix fer un fade d'un LED (Un LED que està encès, fer que s'apagui progressivament). Juga amb el duty cycle per tal de què la fusió vagi més ràpida o més lenta.

Ens hem basat en el següent codi:

Extra:

En la Raspberry Pi tenim bastants pins GPIO. Ara bé, què passa quan hem de redireccionar molts altres LEDs? Una solució és utilitzar el protocol I2C i el xip MCP23017, com s'explica en aquest article:

I el vídeo:

Solucions

##!/usr/bin/env python

import random
import RPi.GPIO as GPIO
import time

#Variables
LED1 = 15
LED2 = 18
LED3 = 23
LED4 = 24

GPIO.setmode(GPIO.BCM)
GPIO.setup(LED1, GPIO.OUT )
GPIO.setup(LED2, GPIO.OUT )
GPIO.setup(LED3, GPIO.OUT )
GPIO.setup(LED4, GPIO.OUT )

led = 0

for n in range(1,11):
     led = random.choice([LED1,LED2,LED3,LED4])
     GPIO.output(led, True)      # Encen el LED
     time.sleep(1)
     GPIO.output(led, False)     # Apaga el LED

GPIO.cleanup()
##!/usr/bin/env python

import RPi.GPIO as GPIO
import time

#Variables
LED = [15, 18, 23, 24]

GPIO.setmode(GPIO.BCM)
GPIO.setup(LED[0], GPIO.OUT )
GPIO.setup(LED[1], GPIO.OUT )
GPIO.setup(LED[2], GPIO.OUT )
GPIO.setup(LED[3], GPIO.OUT )

for n in range(0,16):
     #print(n)
     els_bits = map(int, '{0:04b}'.format(n))
     #print(els_bits)
     for i in range(0,4):
          #print(els_bits[i])
          GPIO.output(LED[i], els_bits[i])

     time.sleep(1)

     for i in range(0,4):
          #print(els_bits[i])
          GPIO.output(LED[i], 0)

GPIO.cleanup()
##!/usr/bin/env python

import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
ledPin = 23

GPIO.setup(ledPin, GPIO.OUT)
p = GPIO.PWM(ledPin, 50)  # channel=12 frequency=50Hz
p.start(0)
print("Here we go! Press CTRL+C to exit")
try:
   while 1:
      for dc in range(0, 101, 5):
         p.ChangeDutyCycle(dc)
         time.sleep(0.1)
      for dc in range(100, -1, -5):
         p.ChangeDutyCycle(dc)
         time.sleep(0.1)
except KeyboardInterrupt:
   pass
p.stop()
GPIO.cleanup()

Sessió 5

Objectiu

Volem que els botons del Simon siguin ben lluminosos. En la pràctica anterior encenies un LED controlat per un pin GPIO, però aquests pins només donen 3,3V. Està clar que si volem més llum necessitarem més tensió elèctrica.

L'objectiu serà encendre 6 LEDs blancs (que fan força llum), controlats per un pin GPIO de la Raspberry Pi.

Desenvolupament

Rpi transistor leds.png

La configuració que provarem és la que es mostra en el circuit. Has de tenir en compte que un LED, pel fet d'estar encès, té una caiguda de tenisó. Per als LEDs blancs són 3,1V. A més, hem de limitar el corrent que passa pel LED, doncs si no ràpidament es faria malbé. Hem de limitar a 20mA. Farem dos braços de 3 LEDs, alimentats per 12V. En el dibuix es mostren els càlculs per calcular la resistència que es necessita per tal de limitar el corrent.

6 leds blancs.png

Munta el circuit. Necessitem un alimentador de 12V. Els 6 LEDs blancs encesos tots a l'hora fan bastanta llum.

Ara volem encendre i apagar tots aquests LEDs amb un pin GPIO de la Raspberry Pi. El pin GPIO només dóna 3,3V i un valor molt limitat de corrent. La solució clàssica i senzilla per fer-ho és la que es mostra en el segon dibuix: és un transistor NPN que funciona com a interruptor o commutador.

GPIO to 12V.png

La configuració de transistor + 6 LEDs + resistències en direm mòdul LED. Cada botó del SIMON tindrà associat un mòdul LED.

Per enllaçar amb les pràctiques anteriors, programaràs i executaràs un petit script python que faci pampallugues del teu mòdul LED.

script GPIO_6LEDSs.py:

##!/usr/bin/env python

import RPi.GPIO as GPIO
import time

#Variables
PIN = 15

GPIO.setmode(GPIO.BCM)
GPIO.setup(PIN, GPIO.OUT )

for n in range(1,11):
     GPIO.output(PIN, True)      # Encen el LED
     time.sleep(1)
     GPIO.output(PIN, False)     # Apaga el LED
     time.sleep(1)

GPIO.cleanup()

Sessió 6

Objectiu

Avui fem una classe més tranquil.la. Discutim sobre la construcció del prototipus. Materials, dimensions,... Fem pluja d'idees i els alumnes aporten reflexions interessants.

Desenvolupament

Sketch simonpi.png

Fins ara hem estat fent proves amb LEDs, so, programació Python,... És hora de què pensem en la construcció del nostre Simon. Quins materials utilitzarem, quines dimensions tindrà, com s'alimentarà, com produirem el so,...

La idea general és que és millor fer un prototipus ben fet que no pas tres prototipus més senzills. Faríem un moble de fusta de pi vernissada, buscant un bon acabat. La principal dificultat és el disseny dels botons. Ens imaginem els botons ben rodons i ben grossos, amb metacril.lat de 4 colors diferents (blau, vermell, groc, verd). Aquest metacril.lat està retroil.luminat per sota (amb mòduls de 6 leds, similar al que vam fer en la sessió anterior). Quan pressionem el botó del Simon activarem un botó arcade de 28mm que hi ha amagat a sota. El principal problema de disseny és el retorn del botó. Ens imaginem dues possibles solucions: amb una molla (que hauria de ser grossa i de construcció pròpia), o bé amb una mena d'escuma.

S'haurà d'utilitzar una màquina CNC per mecanitzar la fusta i fer els forats i les incisions necessaris. Amb la CNC també farem els cercles de metacril.lat dels botons. Amb la impressora 3D farem les peces de plàstic per acabar de dissenyar els botons.

Hi ha bastantes coses que queden a l'aire. Haurem de comneçar a fer la versió 0 del prototipus per acabar de definir dimensions, materials,...

Sessió 7

Objectiu

Hem d'anar definit aspectes tècnics del nostre joc del Simon. Parlarem de com alimentem el nostre joc del Simon, i de com produirem el so.

Desenvolupament

Alimentació elèctrica

Hem vist que la Raspberry Pi s'alimenta per defecte amb 5V. Típicament necessitem un transformador de 5V i 2A, com el dels mòbils, però si pot ser una mica millor (el dels mòbils no donen 2A).

D'altra banda, vam veure que per alimentar els mòduls de 6 led's necessitem 12V. Aquell dia utilitzàvem dos transformadors: un de 12V per alimentar els LEDs, un altre de 5V per alimentar la RPi. Sembla una mica complicat, no? Es pot fer d'alguna altra manera?

Sí. La idea és utilitzar un sol transformador de 12V, i convertir els 12V a 5V per alimentar la RPi. Típicament això es fa amb els reguladors de tensió.

Cerquem a Google Images: voltage regulator 12v to 5v. Per exemple, tenim el regulador de tensió LM7805. Però aquesta és una solució antiga i ineficient (aquest component electrònic es calenta i ha de dissipar calor en el procés de convertir 12V a 5V). Ara es fa d'una altra manera. Amb la mateixa cerca a Google Images hem vist dispositius com ara:

És un DC Step Down Variable Voltage Regulator que vol dir que pot baixar una tensió continua a una altra més baixa. Admet fins a 36V d'entrada, i podem fer baixar la tensió fins a 3V (i sense que l'aparell s'escalfi). Per definir la tensió de sortida tenim un petit cargolet que gira... I veiem que és barato...

Aquesta és una bona opció.

Utilitzar una pila/bateria recarregable

Amb la solució anterior tenim un cable que va a l'alimentació elèctrica de 220V. Per tant el nostre Simon no és del tot portable. Llàstima... Hi ha alguna possibilitat de tenir una solució portable utilitzant una bateria recarregable? Sí, el tema de les bateries està progressant molt en els darrers anys. Els drons van amb bateires, els cotxes RC van amb bateries,...

Fem una cerca a Google: Raspberry Py battery powered. Tenim algunes idees:

El tema de les bateries LiPo és molt interessant. Aquestes són de 3,7V, i amb una tècnica electrònica molt interessant (step-up boost converter), es pot aconseguir arribar als 5V per alimentar la Raspberry Pi (que necessita 5V).

Recoredem, però, que no hem d'alimentar només la RPi, sinó que necessitem 12V per als mòduls LED.

Amplificador de so

La Rasberry Pi permet fer el playback de fitxers MP3. Té una sortida JACK d'àudio per connectar els auriculars o bé un amplificacor extern com ara uns altaveus d'ordinador. Mirar per exemple aquests dos projectes que funcionen amb Raspberry Pi i que el so és un tema important:

Aquests dos projectes utilitzen uns altaveus d'ordinador, que estan alimentats a 220V, tot i que ara són comuns els altaveus alimentats per USB.

Però per nosaltres això és massa gros, necessitem un so de qualitat, però no cal que sigui potent.

Si fem una cerca a Goolge Images per raspberry pi audio amplifier ens vénen al cap moltes idees. Fixem-nos en aquesta imatge:

De fet, tenim diferens xips que acompleixen la missió de ser un amplificador d'àudio de classe D, de per exemple 2,5W (wats):

Si cerquem a eBay per PAM8302, per ex:

especificacions tècniques:

Output Power: 2.5W at 4Ω, 10% THD,1.5W at 8Ω, 10% THD, with 5.5V Supply 50dB PSRR at 1KHz
Filterless design, with ferrite bead + capacitors on output.
Fixed 24dB gain, onboard trim potentiometer for adjusting input volume.
Thermal and short-circuit/over-current protection
Low current draw: 4mA quiescent and 1uA in shutdown mode

Veiem que s'alimenta a 5,5V, igual que la Raspberry Pi, i que dóna 2,5W de potència amb un altaveu de 4Ω (o bé 1,5W amb un altaveu de 8Ω).

Aquests altaveus són els petitons i fàcils d'aconseguir, i que van perfecte per al nostre Simon Pi, com podem veure en aquesta imatge:

Sessió 8

Objectiu

En la sessió 6 vam estar discutint sobre el disseny industrial del Simon. En especial ens preocupa el disseny dels botons grossos i el sistema de molla/retorn del botó. Avui treballarem amb LibreCAD el disseny dels botons per tal de mecanitzar-ho amb una màquina CNC. Estudiarem el flux de treball que es fa servir: disseny CAD > Generació del G-Code > Fresat CNC. És un procés similar al que utilitzaem per a imprimir amb 3D.

Desenvolupament

Cnc simon.jpg

FreeCAD

En comptes d'utilitzar FreeCAD que es el que utilitzem habitualment per a la impressora 3D, instal.larem i utilitzarm LibreCAD. Per instal.lar a Ubuntu:

$ sudo apt-get install librecad

Anem a dissenyar la part de fresat de la fusta de cadascun dels botons. (El professor porta a classe un primer prototipus). La figura que dissenyem consta de les següents parts:

Cadascuna d'aquestes parts la ficarem en una capa diferent.

Disseny botons CNC.png

Aspectes a tenir en compte:

Especifiquem amb més detall les capes:

Gravem i obtenim el fitxer dxf.

Dxf2gcode

Dxf2 gcode simon boto.png

Un cop tenim el fitxer dxf, hem de generar el fitxer gcode, que és el que entén la màquina CNC.

Pàgina web del projecte:

$ sudo apt-get install python-qt4 python-qt4-dev

Descàrrega:

$ svn checkout http://dxf2gcode.googlecode.com/svn/trunk/ dxf2gcode-read-only

Execució:

$ cd dxf2gcode-read-only/
$ cd source/
$ python dxf2gcode.py

El dxf2gcode és bastant intuïtiu, però hem de conèixer com funciona una màquina CNC.

Amb el dxf2gcode obtenim el codi G-Code. Per ex:

(Generated with: DXF2GCODE, Version: Py2.7.3 PyQt4.9.3, Date: $Date$)
(Created from file: /home/cnc/projectes/joc_simon/joc_simon_v2.dxf)
(Time: Mon Apr 24 13:51:57 2017)
G21 (Units in millimeters)  G90 (Absolute programming) G64 (Default cutting) G17 (XY plane) G40 (Cancel radius comp.) G49 (Cancel length comp.)
G0 Z  15.000 

(*** LAYER: arcs2 ***)
T1 M6
S6000

(* SHAPE Nr: 2 *)
G0 X  26.515 Y  26.515
M3 M8
G0 Z   3.000 
F150
G1 Z  -1.500
F400
G2 X  43.485 Y  43.485 I   8.485 J   8.485
G2 X  26.515 Y  26.515 I  -8.485 J  -8.485
F150
G1 Z  -3.000
F400
G2 X  43.485 Y  43.485 I   8.485 J   8.485
G2 X  26.515 Y  26.515 I  -8.485 J  -8.485
F150
G1 Z  -4.500
F400
G2 X  43.485 Y  43.485 I   8.485 J   8.485
G2 X  26.515 Y  26.515 I  -8.485 J  -8.485
F150
G1 Z  -6.000
F400
...

Software LinuxCNC

Tenim la CNC3040 i el software LinuxCNC. La màquina es connecta a l'ordinador amb un cable paral.lel http://www.linuxcnc.org/ videos:

Sessió 9

Objectiu

Anem a construir ja els prototipus dels alumnes. Aquesta setmana ens centrarem en la construcció, la setmana vinent ens centrarem ja en el codi. Els alumnes disposen de la RPi, 4 botons, 4 LEDs de colors, resistències, cables, grimpadora,...

Desenvolupament

GPIO pinout.png

Cada grup disposa de la Raspberry Pi, la protoboard, 4 LEDs grossos de colors (verd, groc, blau i vermell, com ha de ser), i 4 interruptors.

La idea és muntar ja de forma definitiva i permanent el cablejat amb les 4 entrades (interruptors) i les 4 sortides (LEDs). Hauràs de repassar les primeres sessions, on vam utilitzar els interruptors i els LEDs.

els pins GPIO que escollim són:

Entrades (interruptors):

Sortides (LEDs):

Amb el script python següent podrem testejar que tot funciona correctament. Si analitzes bé el codi, el que fa és senzillament que quan apretes un botó s'encén el LED, i sona el so corresponent. Amb aquest codi podem assegurar-nos de què totes les connexions estan ben fetes. Ara ja no desmuntarem aquest circuit fins al final del curs.

script test_v1.py:

import RPi.GPIO as GPIO
import time
import wave
import pygame
import subprocess

#Set up sounds
#This avoids any delay before sound starts
pygame.mixer.pre_init(44100,-16,2,2048)
#Initialise mixer
pygame.mixer.init()
subprocess.Popen('amixer cset numid=3 1',shell=True)

GPIO.setmode(GPIO.BCM)

#verd, vermell, groc, blau (G,R,Y,B)
INT_GREEN   = 4
INT_RED     = 17
INT_YELLOW  = 27
INT_BLUE    = 22

LED_GREEN   = 14
LED_RED     = 15
LED_YELLOW  = 18
LED_BLUE    = 23

GPIO.setup(INT_GREEN, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_RED, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_YELLOW, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_BLUE, GPIO.IN, pull_up_down = GPIO.PUD_UP)


GPIO.setup(LED_GREEN, GPIO.OUT )
GPIO.setup(LED_RED, GPIO.OUT )
GPIO.setup(LED_YELLOW, GPIO.OUT )
GPIO.setup(LED_BLUE, GPIO.OUT )

def playWAVFile(filename):
    sound = pygame.mixer.Sound(filename)
    sound.play()

greensound = '/tmp/green.wav'
bluesound = '/tmp/blue.wav'
yellowsound = '/tmp/yellow.wav'
redsound = '/tmp/red.wav'

while True:
  input_state_green = GPIO.input(INT_GREEN)
  input_state_red = GPIO.input(INT_RED)
  input_state_yellow = GPIO.input(INT_YELLOW)
  input_state_blue = GPIO.input(INT_BLUE)

  if input_state_green == False:
    GPIO.output(LED_GREEN, True)      # Encen el LED
    print('Boto verd polsat')
    playWAVFile(greensound)
    time.sleep(0.3)
    GPIO.output(LED_GREEN, False)     # Apaga el LED
  elif input_state_red == False:
    GPIO.output(LED_RED, True)      # Encen el LED
    print('Boto vermell polsat')
    playWAVFile(redsound)
    time.sleep(0.3)
    GPIO.output(LED_RED, False)     # Apaga el LED
  elif input_state_yellow == False:
    GPIO.output(LED_YELLOW, True)      # Encen el LED
    print('Boto groc polsat')
    playWAVFile(yellowsound)
    time.sleep(0.3)
    GPIO.output(LED_YELLOW, False)     # Apaga el LED
  elif input_state_blue == False:
    GPIO.output(LED_BLUE, True)      # Encen el LED
    print('Boto blau polsat')
    playWAVFile(bluesound)
    time.sleep(0.3)
    GPIO.output(LED_BLUE, False)     # Apaga el LED

Per tal de què funcioni el so, hauràs de descarregar-te aquests sons, pujar-los a la Raspberry Pi, descomprimir l'arxiu ZIP, i copiar-los a la carpeta /tmp.

Recordatori de comandes que necessitaràs:

A l'ordinador de l'aula:
$ unzip simon.zip
$ sshpass -p 'raspberry' scp simon/green.wav pi@192.168.44.X:/tmp
...

$ sshpass -p 'raspberry' scp test_v1.py pi@192.168.44.X:/home/pi/simon

$ sshpass -p  ssh pi@192.168.44.X

A la Raspberry Pi;
$ cd simon
$ python test_v1.py

Sessió 10

Objectiu

Ara que ja tenim construït el nostre prototip, anem ja a fer funcionar el Simon a partir d'un codi original de què disposem. Avui ja hem de jugar amb el Simon! Més endavant podrem fer modificacions i millores...

Desenvolupament

El codi que volem provar és el següent projecte:

El principal canvi que fem és modificar l'ordre dels colors (en el codi original és red, green, yellow, blue). Per nosaltres l'ordre de colors és: green, red, yellow, blue.

versió original

fitxer simon_original.py:

##!/usr/bin/env python
#______________________________
#
#Simon Game prototype
#Piers Kennedy
#12-07-2012 (update 27-02-2013)
#
#______________________________
 
import RPi.GPIO as GPIO
import random
import time
import numpy
import wave
import pygame
import subprocess
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
 
#Set up sounds
#This avoids any delay before sound starts
pygame.mixer.pre_init(44100,-16,2,2048)
#Initialise mixer
pygame.mixer.init()
subprocess.Popen('amixer cset numid=3 1',shell=True)
SAMPLERATE = 44100
 
def createSignal(frequency, duration):
    samples = int(duration*SAMPLERATE)
    period = SAMPLERATE / frequency
    omega = numpy.pi * 2 / period
    xaxis = numpy.arange(samples, dtype=numpy.float) * omega
    yaxis = 32800 * numpy.sin(xaxis)
    return yaxis.astype('int16').tostring()
 
def createWAVFile(filename, signal):
    file = wave.open(filename, 'wb')
    file.setparams((1, 2, SAMPLERATE, len(signal), 'NONE',
    'noncompressed'))
    file.writeframes(signal)
    file.close()
 
def playWAVFile(filename):
    sound = pygame.mixer.Sound(filename)
    sound.play()
 
#blue sound 209Hz
bluesound = '/tmp/blue.wav'
signal = createSignal(frequency=209, duration=.4)
createWAVFile(bluesound, signal)
#yellow sound 252Hz
yellowsound = '/tmp/yellow.wav'
signal = createSignal(frequency=252, duration=.4)
createWAVFile(yellowsound, signal)
#red sound 310Hz
redsound = '/tmp/red.wav'
signal = createSignal(frequency=310, duration=.4)
createWAVFile(redsound, signal)
#green sound 415Hz
greensound = '/tmp/green.wav'
signal = createSignal(frequency=415, duration=.4)
createWAVFile(greensound, signal)
 
#losing tone 42 Hz
losingtone = '/tmp/losingtone.wav'
signal = createSignal(frequency=42, duration=3)
createWAVFile(losingtone, signal)
 
#Variables
max     = 100               #No. of rounds in game
RoundNo = 1
GREEN     = 1
RED   = 2
YELLOW  = 3
BLUE    = 4
correct = True
 
#Setup GPIO switches
GPIOSwitch=[0,4,17,27,22]
GPIO.setup(4, GPIO.IN)      #green    GPIO 7
GPIO.setup(17, GPIO.IN)     #red  GPIO 0
GPIO.setup(27, GPIO.IN)     #yellow GPIO 2
GPIO.setup(22, GPIO.IN)     #blue   GPIO 3
 
#Setup GPIO LEDs
GPIOLED=[0,14,15,18,23]
GPIO.setup(14, GPIO.OUT)    #green    GPIO 1
GPIO.setup(15, GPIO.OUT)    #red  GPIO 4
GPIO.setup(18, GPIO.OUT)    #yellow GPIO 5
GPIO.setup(23, GPIO.OUT)    #blue   GPIO 6
 
#Connect the ground to pin 6 and the positive to pin 1 (3V3)
 
#Generate a random list of LED outputs
colour=[]
for n in range(1,max+2):
    colour.append(random.choice([RED,GREEN,YELLOW,BLUE]))
 
#Function to switch LEDs on then off
def LEDout(val):
    if (val==1):
        playWAVFile(greensound)
    elif (val==2):
        playWAVFile(redsound)
    elif (val==3):
        playWAVFile(yellowsound)
    elif (val==4):
        playWAVFile(bluesound)
    while pygame.mixer.get_busy():
        GPIO.output(GPIOLED[val], True)
    GPIO.output(GPIOLED[val],False)
    time.sleep(0.15)
    return[]
 
#Function to check when switch is pressed
def SwitchChosen():
    while True:
            if (GPIO.input(GPIOSwitch[GREEN])):
                return RED
            if (GPIO.input(GPIOSwitch[RED])):
                return GREEN
            if (GPIO.input(GPIOSwitch[YELLOW])):
                return YELLOW
            if (GPIO.input(GPIOSwitch[BLUE])):
                return BLUE
 
#Function to flash LEDs after mistake
def LoserLights():
    playWAVFile(losingtone)
    for cycle1 in range(0,6):
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], True)
        time.sleep(0.5)
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], False)
        time.sleep(0.2)
    return[]
 
#Main routine
while correct:
    print("Round %i" %RoundNo)
    #LED cycle
    for mout in range(1,RoundNo+1):
        LEDout(colour[mout])
    #Response
    for ans in range(1,RoundNo+1):
        push=SwitchChosen()
        LEDout(push)
        if(push!=colour[ans]):
            LoserLights()
            correct = False
            print("Unlucky!")
            print("You made it to round %i" %RoundNo)
            break
    RoundNo+=1
    if (RoundNo==max+1):
        print("WOW!! You Rock dude")
        break
    time.sleep(0.5)

versió 2

fitxer simon_original_v2.py:

##!/usr/bin/env python
#______________________________
#
#Simon Game prototype
#Piers Kennedy
#12-07-2012 (update 27-02-2013)
#
#______________________________
#Canvis Balmes extraescolar
#v2. Canviem el mode GPIO.setmode(GPIO.BOARD) a GPIO.BCM
#ja no cal createSignal i createWAVFile
#todo. que sigui mes aleatori?
#todo. que a lacabar no es quedi cap led ences

import RPi.GPIO as GPIO
import random
import time
import numpy
import wave
import pygame
import subprocess

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)


#Set up sounds
#This avoids any delay before sound starts
pygame.mixer.pre_init(44100,-16,2,2048)
#Initialise mixer
pygame.mixer.init()
subprocess.Popen('amixer cset numid=3 1',shell=True)
SAMPLERATE = 44100
 
def playWAVFile(filename):
    sound = pygame.mixer.Sound(filename)
    sound.play()
 
#blue sound 209Hz
bluesound = '/tmp/blue.wav'
#yellow sound 252Hz
yellowsound = '/tmp/yellow.wav'
#red sound 310Hz
redsound = '/tmp/red.wav'
#green sound 415Hz
greensound = '/tmp/green.wav'
 
#losing tone 42 Hz
losingtone = '/tmp/losingtone.wav'
 
#Variables
max     = 100               #No. of rounds in game
RoundNo = 1
GREEN     = 1
RED   = 2
YELLOW  = 3
BLUE    = 4
correct = True

#verd, vermell, groc, blau (G,R,Y,B)
INT_GREEN   = 4
INT_RED     = 17
INT_YELLOW  = 27
INT_BLUE    = 22

LED_GREEN   = 14
LED_RED     = 15
LED_YELLOW  = 18
LED_BLUE    = 23

#Setup GPIO switches
GPIOSwitch=[0,4,17,27,22]

GPIO.setup(INT_GREEN, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_RED, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_YELLOW, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_BLUE, GPIO.IN, pull_up_down = GPIO.PUD_UP)


 
#Setup GPIO LEDs
GPIOLED=[0,14,15,18,23]

GPIO.setup(LED_GREEN, GPIO.OUT )
GPIO.setup(LED_RED, GPIO.OUT )
GPIO.setup(LED_YELLOW, GPIO.OUT )
GPIO.setup(LED_BLUE, GPIO.OUT )

#Connect the ground to pin 6 and the positive to pin 1 (3V3)
 
#Generate a random list of LED outputs
colour=[]
for n in range(1,max+2):
    colour.append(random.choice([RED,GREEN,YELLOW,BLUE]))
 
#Function to switch LEDs on then off
def LEDout(val):
    if (val==1):
        playWAVFile(greensound)
    elif (val==2):
        playWAVFile(redsound)
    elif (val==3):
        playWAVFile(yellowsound)
    elif (val==4):
        playWAVFile(bluesound)
    while pygame.mixer.get_busy():
        GPIO.output(GPIOLED[val], True)
    GPIO.output(GPIOLED[val],False)
    time.sleep(0.15)
    return[]
 
#Function to check when switch is pressed
def SwitchChosen():
    while True:
            if (GPIO.input(GPIOSwitch[GREEN])):
                return GREEN
            if (GPIO.input(GPIOSwitch[RED])):
                return RED
            if (GPIO.input(GPIOSwitch[YELLOW])):
                return YELLOW
            if (GPIO.input(GPIOSwitch[BLUE])):
                return BLUE
 
#Function to flash LEDs after mistake
def LoserLights():
    playWAVFile(losingtone)
    for cycle1 in range(0,6):
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], True)
        time.sleep(0.5)
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], False)
        time.sleep(0.2)
    return[]
 
#Main routine
while correct:
    print("Round %i" %RoundNo)
    #LED cycle
    for mout in range(1,RoundNo+1):
        LEDout(colour[mout])
    #Response
    #for ans in range(1,RoundNo+1):
    #    push=SwitchChosen()
    #    LEDout(push)
    #    if(push!=colour[ans]):
    #        LoserLights()
    #        correct = False
    #        print("Unlucky!")
    #        print("You made it to round %i" %RoundNo)
    #        break
    RoundNo+=1
    if (RoundNo==max+1):
        print("WOW!! You Rock dude")
        break
    time.sleep(0.5)

Estat del Prototipus

Molbe simon.jpg

Aquesta setmana hem estat construïnt el moble. S'ha pres la decisió que tindrà 28 cm de costat, i amb aquesta geometria ja podem definir el tamany dels nostres botons.

Sessió 11

Objectiu

En aquesta sessió treballem el software, fins arribar a la versió que serà definitiva, i presentem l'estat del prototipus.

Desenvolupament

Presentem 3 noves versions, la 3, 4 i 5. Quan es programa (en qualsevol programa, en aquest cas en Python), és important versionar i documentar els canvis que es realitzen (pots veure els canvis en la capçalera dels scripts). La versió 4 ja és totalment funcional per jugar amb els prototipus que hem fet a classe. La versió 5 és funcional per jugar amb el moble del Simon que s'està construint.

Versió 3

fitxer simon_v3.py:

##!/usr/bin/env python
#______________________________
#
#Simon Game prototype
#Piers Kennedy
#12-07-2012 (update 27-02-2013)
#
#______________________________
#Canvis Balmes extraescolar
#v2. Canviem el mode GPIO.setmode(GPIO.BOARD) a GPIO.BCM
#ja no cal createSignal i createWAVFile
#v3
#a lacabar no es quedi cap led ences
#todo. guardar en un fitxer el record
#un so per quan aconsegueixi un nou record
#todo. versio moble. Necessito un boto per comencar el joc

import RPi.GPIO as GPIO
import random
import time
import numpy
import wave
import pygame
import subprocess

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)


#Set up sounds
#This avoids any delay before sound starts
pygame.mixer.pre_init(44100,-16,2,2048)
#Initialise mixer
pygame.mixer.init()
subprocess.Popen('amixer cset numid=3 1',shell=True)
SAMPLERATE = 44100
 
def playWAVFile(filename):
    sound = pygame.mixer.Sound(filename)
    sound.play()
 
#blue sound 209Hz
bluesound = '/tmp/blue.wav'
#yellow sound 252Hz
yellowsound = '/tmp/yellow.wav'
#red sound 310Hz
redsound = '/tmp/red.wav'
#green sound 415Hz
greensound = '/tmp/green.wav'
 
#losing tone 42 Hz
losingtone = '/tmp/losingtone.wav'
 
#Variables
max     = 100               #No. of rounds in game
RoundNo = 1
GREEN     = 1
RED   = 2
YELLOW  = 3
BLUE    = 4
correct = True

#verd, vermell, groc, blau (G,R,Y,B)
INT_GREEN   = 4
INT_RED     = 17
INT_YELLOW  = 27
INT_BLUE    = 22

LED_GREEN   = 14
LED_RED     = 15
LED_YELLOW  = 18
LED_BLUE    = 23

#Setup GPIO switches
GPIOSwitch=[0,4,17,27,22]

GPIO.setup(INT_GREEN, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_RED, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_YELLOW, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_BLUE, GPIO.IN, pull_up_down = GPIO.PUD_UP)


 
#Setup GPIO LEDs
GPIOLED=[0,14,15,18,23]

GPIO.setup(LED_GREEN, GPIO.OUT )
GPIO.setup(LED_RED, GPIO.OUT )
GPIO.setup(LED_YELLOW, GPIO.OUT )
GPIO.setup(LED_BLUE, GPIO.OUT )

#Connect the ground to pin 6 and the positive to pin 1 (3V3)
 
#Generate a random list of LED outputs
colour=[]
for n in range(1,max+2):
    colour.append(random.choice([RED,GREEN,YELLOW,BLUE]))
 
#Function to switch LEDs on then off
def LEDout(val):
    if (val==1):
        playWAVFile(greensound)
    elif (val==2):
        playWAVFile(redsound)
    elif (val==3):
        playWAVFile(yellowsound)
    elif (val==4):
        playWAVFile(bluesound)
    while pygame.mixer.get_busy():
        GPIO.output(GPIOLED[val], True)
    GPIO.output(GPIOLED[val],False)
    time.sleep(0.15)
    return[]
 
#Function to check when switch is pressed
def SwitchChosen():
    while True:
        if not (GPIO.input(GPIOSwitch[GREEN])):
            return GREEN
        if not (GPIO.input(GPIOSwitch[RED])):
            return RED
        if not (GPIO.input(GPIOSwitch[YELLOW])):
            return YELLOW
        if not (GPIO.input(GPIOSwitch[BLUE])):
            return BLUE
 
#Function to flash LEDs after mistake
def LoserLights():
    playWAVFile(losingtone)
    for cycle1 in range(0,6):
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], True)
        time.sleep(0.5)
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], False)
        time.sleep(0.2)
    return[]
 
#Main routine
while correct:
    print("Round %i" %RoundNo)
    #LED cycle
    for mout in range(1,RoundNo+1):
        LEDout(colour[mout])
    #Response
    for ans in range(1,RoundNo+1):
        push=SwitchChosen()
        LEDout(push)
        if(push!=colour[ans]):
            LoserLights()
            correct = False
            print("Mala sort!")
            print("Has fet fins la ronda %i" %RoundNo)
            #apaguem tots els led
            for cycle in range(1,5):
                GPIO.output(GPIOLED[cycle],False)
            break
    RoundNo+=1
    if (RoundNo==max+1):
        print("WOW!! You Rock dude")
        break
    time.sleep(0.5)

Guardar el récord

Una de les coses que volem implementar és poder guardar el récord del número de rondes. El següent script és el codi mínim que ensenya com podem llegir d'un fitxer un número, i guardar un altre número. Cal destacar en aquest codi:

script gestio_record.py:

##!/usr/bin/env python

try:
    fh = open("record.txt", "r")
    record = int(fh.readline())
except IOError:
    fh = open("record.txt", "w") 
    fh.write("0")
    record = 0

#print record
fh.close()

record += 1
print record
fh = open("record.txt","w")
fh.write(str(record))  
fh.close() 

El que implementarem en la versió 4 és la gestió del record de rondes. A més, necessitarem una so i un joc de llums per tal de celebrar que hem fet un nou récord.

Versió 4

ja podem jugar!

fitxer simon_v4.py:

##!/usr/bin/env python
#______________________________
#
#Simon Game prototype
#Piers Kennedy
#12-07-2012 (update 27-02-2013)
#
#______________________________
#Canvis Balmes extraescolar
#v2. Canviem el mode GPIO.setmode(GPIO.BOARD) a GPIO.BCM
#ja no cal createSignal i createWAVFile
#v3
#a lacabar no es quedi cap led ences
#v4
#fiquem els fitxers de so a simon/sounds/
#guardem en un fitxer el record
#so per quan aconseguim un nou record
#todo. versio moble. Necessito un boto per comencar el joc

import RPi.GPIO as GPIO
import random
import time
import numpy
import wave
import pygame
import subprocess

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)


#Set up sounds
#This avoids any delay before sound starts
pygame.mixer.pre_init(44100,-16,2,2048)
#Initialise mixer
pygame.mixer.init()
subprocess.Popen('amixer cset numid=3 1',shell=True)
SAMPLERATE = 44100
 
def playWAVFile(filename):
    sound = pygame.mixer.Sound(filename)
    sound.play()
 
#blue sound 209Hz
bluesound = '/home/pi/simon/sounds/blue.wav'
#yellow sound 252Hz
yellowsound = '/home/pi/simon/sounds/yellow.wav'
#red sound 310Hz
redsound = '/home/pi/simon/sounds/red.wav'
#green sound 415Hz
greensound = '/home/pi/simon/sounds/green.wav'
 
#losing tone 42 Hz
losingtone = '/home/pi/simon/sounds/losingtone.wav' #canviar
#record
recordtone = '/home/pi/simon/sounds/losingtone.wav'

#Variables
max     = 100               #No. of rounds in game
RoundNo = 1
GREEN     = 1
RED   = 2
YELLOW  = 3
BLUE    = 4
correct = True

#verd, vermell, groc, blau (G,R,Y,B)
INT_GREEN   = 4
INT_RED     = 17
INT_YELLOW  = 27
INT_BLUE    = 22

LED_GREEN   = 14
LED_RED     = 15
LED_YELLOW  = 18
LED_BLUE    = 23

#Setup GPIO switches
GPIOSwitch=[0,4,17,27,22]

GPIO.setup(INT_GREEN, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_RED, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_YELLOW, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_BLUE, GPIO.IN, pull_up_down = GPIO.PUD_UP)

#Setup GPIO LEDs
GPIOLED=[0,14,15,18,23]

GPIO.setup(LED_GREEN, GPIO.OUT )
GPIO.setup(LED_RED, GPIO.OUT )
GPIO.setup(LED_YELLOW, GPIO.OUT )
GPIO.setup(LED_BLUE, GPIO.OUT )

#Connect the ground to pin 6 and the positive to pin 1 (3V3)
 
#Generate a random list of LED outputs
colour=[]
for n in range(1,max+2):
    colour.append(random.choice([RED,GREEN,YELLOW,BLUE]))
 
#Function to switch LEDs on then off
def LEDout(val):
    if (val==1):
        playWAVFile(greensound)
    elif (val==2):
        playWAVFile(redsound)
    elif (val==3):
        playWAVFile(yellowsound)
    elif (val==4):
        playWAVFile(bluesound)
    while pygame.mixer.get_busy():
        GPIO.output(GPIOLED[val], True)
    GPIO.output(GPIOLED[val],False)
    time.sleep(0.15)
    return[]
 
#Function to check when switch is pressed
def SwitchChosen():
    while True:
        if not (GPIO.input(GPIOSwitch[GREEN])):
            return GREEN
        if not (GPIO.input(GPIOSwitch[RED])):
            return RED
        if not (GPIO.input(GPIOSwitch[YELLOW])):
            return YELLOW
        if not (GPIO.input(GPIOSwitch[BLUE])):
            return BLUE
 
#Function to flash LEDs after mistake
def LoserLights():
    playWAVFile(losingtone)
    for cycle1 in range(0,6):
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], True)
        time.sleep(0.5)
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], False)
        time.sleep(0.2)
    return[]

#Aconseguim un nou record
def RecordLights():
    playWAVFile(losingtone) #canviar
    for cycle1 in range(0,6):
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], True)
        time.sleep(0.5)
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], False)
        time.sleep(0.2)
    return[]

#llegim el record que esta en el fitxer
try:
    fh = open("/home/pi/simon/record.txt", "r")
    record = int(fh.readline())
except IOError:
    fh = open("/home/pi/simon/record.txt", "w") 
    fh.write("0")
    record = 0
#print record
fh.close()

#Main routine
while correct:
    print("Round %i" %RoundNo)
    #LED cycle
    for mout in range(1,RoundNo+1):
        LEDout(colour[mout])
    #Response
    for ans in range(1,RoundNo+1):
        push=SwitchChosen()
        LEDout(push)
        if(push!=colour[ans]): #hem perdut
            correct = False
            if (RoundNo > record):
                RecordLights()
                fh = open("/home/pi/simon/record.txt","w")
                fh.write(str(RoundNo))  
                fh.close() 
                print("Nou record! Has fet fins la ronda %i" %RoundNo)
            else:
                LoserLights()
                print("Has perdut! Has fet fins la ronda %i" %RoundNo)
            #apaguem tots els led
            for cycle in range(1,5):
                GPIO.output(GPIOLED[cycle],False)
            break
    RoundNo+=1
    if (RoundNo==max+1):
        print("WOW!! You Rock dude")
        break
    time.sleep(0.5)

Versió 5 (versió per al moble)

En la versió per al moble (no tenim ni teclat ni pantalla) el script s'executarà en l'inici del sistema, i aquest script s'haurà de continuar executant (en un bucle infinit) fins que traguem el corrent elèctric. Necessitem un botó de START per indicar que comença el joc. Quan fem START s'ha de reiniciar la seqüència de colors del joc, i s'han d'iniciar les variables. Recordem que en el moble no tindrem per pantalla (no serveix de res la comanda print), i per tant necessito informació extra per saber què està passant. Concretament, ens serà útil un so per saber que comença el joc, i un so per saber quan hem fet el récord, a més del so per saber quan hem perdut una partida.

fitxer simon_v5.py:

##!/usr/bin/env python
#______________________________
#
#Simon Game prototype
#Piers Kennedy
#12-07-2012 (update 27-02-2013)
#INS Jaume Balmes - 2017 (maig 2017)
#Extraescolar de Robotica 
#______________________________
#Canvis Balmes extraescolar
#v2. Canviem el mode GPIO.setmode(GPIO.BOARD) a GPIO.BCM
#ja no cal createSignal i createWAVFile
#v3
#a lacabar no es quedi cap led ences
#v4
#fiquem els fitxers de so a simon/sounds/
#guardem en un fitxer el record
#so per quan aconseguim un nou record
#v5
#Versio moble. Necessito un boto per comencar el joc
#funcio generar_sequencia. Quan torno a comencar, la sequencia es diferent
#starttone, un bip per saber que comenca el joc. Funcio StartLights()
#deteccio Ctrl-C per sortir be del programa, encara que amb el moble no tindrem teclat
#shan normalitzat els sons perque tots tinguin el mateix volum

#todo. espera despres de que soni el start
#todo. quan arrenco la rpi, el so readytone per indicar que ja estem a punt per jugar
#todo. Pitjar tres vegades seguides el boto de start fa reset del record

import RPi.GPIO as GPIO
import random
import time
import numpy
import wave
import pygame
import subprocess
#vull detectar ctrl-c:
import signal
import sys

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

#Set up sounds
#This avoids any delay before sound starts
pygame.mixer.pre_init(44100,-16,2,2048)
#Initialise mixer
pygame.mixer.init()
subprocess.Popen('amixer cset numid=3 1',shell=True)
SAMPLERATE = 44100
 
def playWAVFile(filename):
    sound = pygame.mixer.Sound(filename)
    sound.play()
 
#blue sound 209Hz
bluesound = '/home/pi/simon/sounds/blue.wav'
#yellow sound 252Hz
yellowsound = '/home/pi/simon/sounds/yellow.wav'
#red sound 310Hz
redsound = '/home/pi/simon/sounds/red.wav'
#green sound 415Hz
greensound = '/home/pi/simon/sounds/green.wav'
 
#losing tone 42 Hz
losingtone = '/home/pi/simon/sounds/losingtone.wav'
#record
recordtone = '/home/pi/simon/sounds/recordtone.wav'
#starttone
starttone = '/home/pi/simon/sounds/starttone.wav'

#Variables
max     = 100               #No. of rounds in game
RoundNo = 1
GREEN     = 1
RED   = 2
YELLOW  = 3
BLUE    = 4
START    = 5
correct = False
colour=[]

#verd, vermell, groc, blau (G,R,Y,B)
INT_GREEN   = 4
INT_RED     = 17
INT_YELLOW  = 27
INT_BLUE    = 22
INT_START   = 10

LED_GREEN   = 14
LED_RED     = 15
LED_YELLOW  = 18
LED_BLUE    = 23

#Setup GPIO switches
GPIOSwitch=[0,4,17,27,22,10]

GPIO.setup(INT_GREEN, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_RED, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_YELLOW, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_BLUE, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_START, GPIO.IN, pull_up_down = GPIO.PUD_UP)

#Setup GPIO LEDs
GPIOLED=[0,14,15,18,23]

GPIO.setup(LED_GREEN, GPIO.OUT )
GPIO.setup(LED_RED, GPIO.OUT )
GPIO.setup(LED_YELLOW, GPIO.OUT )
GPIO.setup(LED_BLUE, GPIO.OUT )

#Connect the ground to pin 6 and the positive to pin 1 (3V3)
 
#Generate a random list of LED outputs
def generar_sequencia():
    global colour
    colour=[]
    for n in range(1,max+2):
        colour.append(random.choice([RED,GREEN,YELLOW,BLUE]))
 
#Function to switch LEDs on then off
def LEDout(val):
    if (val==1):
        playWAVFile(greensound)
    elif (val==2):
        playWAVFile(redsound)
    elif (val==3):
        playWAVFile(yellowsound)
    elif (val==4):
        playWAVFile(bluesound)
    while pygame.mixer.get_busy():
        GPIO.output(GPIOLED[val], True)
    GPIO.output(GPIOLED[val],False)
    time.sleep(0.15)
    return[]
 
#Function to check when switch is pressed
def SwitchChosen():
    while True:
        if not (GPIO.input(GPIOSwitch[GREEN])):
            return GREEN
        if not (GPIO.input(GPIOSwitch[RED])):
            return RED
        if not (GPIO.input(GPIOSwitch[YELLOW])):
            return YELLOW
        if not (GPIO.input(GPIOSwitch[BLUE])):
            return BLUE
 
#Function to flash LEDs after mistake
def LoserLights():
    playWAVFile(losingtone)
    for cycle1 in range(0,6):
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], True)
        time.sleep(0.5)
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], False)
        time.sleep(0.2)
    return[]

#Aconseguim un nou record
def RecordLights():
    playWAVFile(recordtone)
    for cycle1 in range(0,6):
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], True)
        time.sleep(0.5)
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], False)
        time.sleep(0.2)
    return[]

#Aconseguim un nou record
def StartLights():
    playWAVFile(starttone)
    for cycle1 in range(0,1):
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], True)
        time.sleep(0.5)
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], False)
        time.sleep(0.2)
    return[]

#vull detectar ctrl-c
def signal_handler(signal, frame):
        print("Simon Balmes v5. Adeu!!")
        GPIO.cleanup()
        sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)

#sequencia guanyadora
generar_sequencia()

#llegim el record que esta en el fitxer
try:
    fh = open("record.txt", "r")
    record = int(fh.readline())
except IOError:
    fh = open("record.txt", "w") 
    fh.write("0")
    record = 0
#print record
fh.close()

#Main routine, bucle sense fi
#Esperem a comencar el joc (boto START)
while True:
    if not (GPIO.input(GPIOSwitch[START])):
        correct = True
        time.sleep(0.5) #una mica despera
        StartLights()
        time.sleep(0.5) #una mica despera
    #ja podem comencar a jugar
    while correct:
        print("Round %i" %RoundNo)
        #LED cycle
        for mout in range(1,RoundNo+1):
            LEDout(colour[mout])
        #Response
        for ans in range(1,RoundNo+1):
            push=SwitchChosen()
            LEDout(push)
            if(push!=colour[ans]): #hem perdut
                correct = False
                if (RoundNo > record):
                    record = RoundNo
                    RecordLights()
                    fh = open("record.txt","w")
                    fh.write(str(RoundNo))  
                    fh.close() 
                    print("Nou record! Has fet fins la ronda %i" %RoundNo)
                else:
                    LoserLights()
                    print("Has perdut! Has fet fins la ronda %i" %RoundNo)
                RoundNo = 0
                generar_sequencia()
                #apaguem tots els led
                for cycle in range(1,5):
                    GPIO.output(GPIOLED[cycle],False)
                break
        RoundNo+=1
        if (RoundNo==max+1):
            print("WOW!! You Rock dude")
            break
        time.sleep(0.5)

Descàrrega dels sons

Estat del Prototipus

Simon balmes layout.jpg

Aquesta setmana hem estat treballant amb els botons, i ja estem bastant a la vora de la solució definitiva.

Sessió 12

Objectiu

Versió en principi definitiva del software, simon_v6.py. Implementem el reset i altres millores. Discutim l'estat actual del prototipus. Discutim possibles i futures millores, com ficar una pantalleta.

Desenvolupament

disseny per fresar a la CNC

Versió 6 (per al moble)

estat del prototipus

Les millores que s'han fet en la versió definitiva:

script simon_v6.py:

##!/usr/bin/env python
#______________________________
#
#Simon Game prototype
#Piers Kennedy
#12-07-2012 (update 27-02-2013)
#INS Jaume Balmes - 2017 (maig 2017)
#Extraescolar de Robotica 
#______________________________
#Canvis Balmes extraescolar
#v2. Canviem el mode GPIO.setmode(GPIO.BOARD) a GPIO.BCM
#ja no cal createSignal i createWAVFile
#v3
#a lacabar no es quedi cap led ences
#v4
#fiquem els fitxers de so a simon/sounds/
#guardem en un fitxer el record
#so per quan aconseguim un nou record
#v5
#Versio moble. Necessito un boto per comencar el joc
#funcio generar_sequencia. Quan torno a comencar, la sequencia es diferent
#starttone, un bip per saber que comenca el joc. Funcio StartLights()
#deteccio Ctrl-C per sortir be del programa, encara que amb el moble no tindrem teclat
#shan normalitzat els sons perque tots tinguin el mateix volum
#v6
#implementem el reset del record quan pitjem dues vegades seguides el boto de START.
#afegim el so resettone
#funcio ShowToneLights(tone), que inclou while pygame.mixer.get_busy(). Daquesta manera nomes tenim joc de llums
#   mentre esta sonant la musica
#Quan engego la rpi, el so readytone m indica que ja estem a punt per jugar.

import RPi.GPIO as GPIO
import random
import time
import numpy
import wave
import pygame
import subprocess
#vull detectar ctrl-c:
import signal
import sys

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

#Set up sounds
#This avoids any delay before sound starts
pygame.mixer.pre_init(44100,-16,2,2048)
#Initialise mixer
pygame.mixer.init()
subprocess.Popen('amixer cset numid=3 1',shell=True)
SAMPLERATE = 44100
 
def playWAVFile(filename):
    sound = pygame.mixer.Sound(filename)
    sound.play()
 
#blue sound 209Hz
bluesound = '/home/pi/simon/sounds/blue.wav'
#yellow sound 252Hz
yellowsound = '/home/pi/simon/sounds/yellow.wav'
#red sound 310Hz
redsound = '/home/pi/simon/sounds/red.wav'
#green sound 415Hz
greensound = '/home/pi/simon/sounds/green.wav'
 #losing tone 42 Hz
losingtone = '/home/pi/simon/sounds/losingtone.wav'

readytone = '/home/pi/simon/sounds/readytone.wav'
starttone = '/home/pi/simon/sounds/starttone.wav'
recordtone = '/home/pi/simon/sounds/recordtone.wav'
resettone = '/home/pi/simon/sounds/resettone.wav'

#Variables
max     = 100               #No. of rounds in game
RoundNo = 1
GREEN     = 1
RED   = 2
YELLOW  = 3
BLUE    = 4
START    = 5
correct = False
colour=[]

#verd, vermell, groc, blau (G,R,Y,B)
INT_GREEN   = 4
INT_RED     = 17
INT_YELLOW  = 27
INT_BLUE    = 22
INT_START   = 10

LED_GREEN   = 14
LED_RED     = 15
LED_YELLOW  = 18
LED_BLUE    = 23

#Setup GPIO switches
GPIOSwitch=[0,4,17,27,22,10]

GPIO.setup(INT_GREEN, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_RED, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_YELLOW, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_BLUE, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_START, GPIO.IN, pull_up_down = GPIO.PUD_UP)

#Setup GPIO LEDs
GPIOLED=[0,14,15,18,23]

GPIO.setup(LED_GREEN, GPIO.OUT )
GPIO.setup(LED_RED, GPIO.OUT )
GPIO.setup(LED_YELLOW, GPIO.OUT )
GPIO.setup(LED_BLUE, GPIO.OUT )
 
#Generate a random list of LED outputs
def generar_sequencia():
    global colour
    colour=[]
    for n in range(1,max+2):
        colour.append(random.choice([RED,GREEN,YELLOW,BLUE]))
 
#Function to switch LEDs on then off
def LEDout(val):
    if (val==1):
        playWAVFile(greensound)
    elif (val==2):
        playWAVFile(redsound)
    elif (val==3):
        playWAVFile(yellowsound)
    elif (val==4):
        playWAVFile(bluesound)
    while pygame.mixer.get_busy():
        GPIO.output(GPIOLED[val], True)
    GPIO.output(GPIOLED[val],False)
    time.sleep(0.15)
    return[]
 
#Function to check when switch is pressed
def SwitchChosen():
    while True:
        if not (GPIO.input(GPIOSwitch[GREEN])):
            return GREEN
        if not (GPIO.input(GPIOSwitch[RED])):
            return RED
        if not (GPIO.input(GPIOSwitch[YELLOW])):
            return YELLOW
        if not (GPIO.input(GPIOSwitch[BLUE])):
            return BLUE
 
def ShowToneLights(tone):
    playWAVFile(tone)
    while pygame.mixer.get_busy():
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], True)
        time.sleep(0.2)
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], False)
        time.sleep(0.2)
    for cycle2 in range(1,5):
        GPIO.output(GPIOLED[cycle2], False)
    return[]

#vull detectar ctrl-c
def signal_handler(signal, frame):
        print("Simon Balmes v6. Adeu!!")
        GPIO.cleanup()
        sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)

#sequencia guanyadora
generar_sequencia()

#llegim el record que esta en el fitxer
try:
    fh = open("record.txt", "r")
    record = int(fh.readline())
except IOError:
    fh = open("record.txt", "w") 
    fh.write("0")
    record = 0
#print record
fh.close()

ShowToneLights(readytone)

#Main routine, bucle sense fi
#Esperem a comencar el joc (boto START)
while True:
    if not (GPIO.input(GPIOSwitch[START])):
	time.sleep(0.3) #antirebot
        t0 = time.time()
        #print t0
	#bucle que espera una altra pulsacio del boto abans de 0,1s per tal de resetejar el reset
	while True:
	    t1 = time.time()
            if not (GPIO.input(GPIOSwitch[START])): #reset del record
		print "reset del record"
		record = 0
                fh = open("record.txt","w")
                fh.write(str(record))  
                fh.close() 
                ShowToneLights(resettone)
		break
	    if (t1-t0 > 1):
		break
	#print t1-t0
        correct = True
        ShowToneLights(starttone)
        time.sleep(0.5) #una mica despera
    #ja podem comencar a jugar
    while correct:
        print("Round %i" %RoundNo)
        #LED cycle
        for mout in range(1,RoundNo+1):
            LEDout(colour[mout])
        #Response
        for ans in range(1,RoundNo+1):
            push=SwitchChosen()
            LEDout(push)
            if(push!=colour[ans]): #hem perdut
                correct = False
                if (RoundNo > record):
                    record = RoundNo
                    ShowToneLights(recordtone)
                    fh = open("record.txt","w")
                    fh.write(str(RoundNo))  
                    fh.close() 
                    print("Nou record! Has fet fins la ronda %i" %RoundNo)
                else:
                    ShowToneLights(losingtone)
                    print("Has perdut! Has fet fins la ronda %i" %RoundNo)
                RoundNo = 0
                generar_sequencia()
                #apaguem tots els led
                for cycle in range(1,5):
                    GPIO.output(GPIOLED[cycle],False)
                break
        RoundNo+=1
        if (RoundNo==max+1):
            print("WOW!! You Rock dude")
            break
        time.sleep(0.5)

script que s'executa en l'inici del sistema

En el moble no tenim ni teclat ni pantalla. El script simon_v5.py (versió definitiva) s'executa en l'inici del sistema. Aquest script és un bucle sense fi, en què espera el botó de START per començar una partida, i detecta quan perdem la partida, per tornar a esperar el botó de START. Per tal de què el script arrenqui a l'inici fiquem la següent línia al final del script .profile:

$ joe .profile
python /home/pi/simon/simon_v6.py

Sessió 13

Joc simon.jpg
Joc simon interior.jpg

Objectiu

Avui presentem el moble acabat. Mirem com han quedat connectats i soldats tots els components, i n'identifiquem totes les parts. Així mateix, hi ha un últim canvi en el software. I juguem!

Desenvolupament

Després d'un parell de setmanes que ja estem jugant al joc, ja tenim experiència en la jugabilitat i podem millorar el software. És a dir, tot software necessita testers per tal de millorar-lo. En el nostre cas, trobem a faltar saber quantes rondes hem fet, doncs és fàcil perdre el compte. Això ho fem en aquesta versió 7 programant la funció ShowNumberRounds, que el que fa és encendre els botons de forma cíclica, i així podem comptar el número de rondes.

scritp simon_v7.py:

##!/usr/bin/env python
#______________________________
#
#Simon Game prototype
#Piers Kennedy
#12-07-2012 (update 27-02-2013)
#INS Jaume Balmes - 2017 (maig 2017)
#Extraescolar de Robotica 
#______________________________
#Canvis Balmes extraescolar
#v2. Canviem el mode GPIO.setmode(GPIO.BOARD) a GPIO.BCM
#ja no cal createSignal i createWAVFile
#v3
#a lacabar no es quedi cap led ences
#v4
#fiquem els fitxers de so a simon/sounds/
#guardem en un fitxer el record
#so per quan aconseguim un nou record
#v5
#Versio moble. Necessito un boto per comencar el joc
#funcio generar_sequencia. Quan torno a comencar, la sequencia es diferent
#starttone, un bip per saber que comenca el joc. Funcio StartLights()
#deteccio Ctrl-C per sortir be del programa, encara que amb el moble no tindrem teclat
#shan normalitzat els sons perque tots tinguin el mateix volum
#v6
#implementem el reset del record quan pitjem dues vegades seguides el boto de START.
#afegim el so resettone
#funcio ShowToneLights(tone), que inclou while pygame.mixer.get_busy(). Daquesta manera nomes tenim joc de llums
#   mentre esta sonant la musica
#Quan engego la rpi, el so readytone m indica que ja estem a punt per jugar.
#v7
#ShowNumberRounds(num_rounds), per tal de saber en quina ronda mhe quedat

import RPi.GPIO as GPIO
import random
import time
import numpy
import wave
import pygame
import subprocess
#vull detectar ctrl-c:
import signal
import sys

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

#Set up sounds
#This avoids any delay before sound starts
pygame.mixer.pre_init(44100,-16,2,2048)
#Initialise mixer
pygame.mixer.init()
subprocess.Popen('amixer cset numid=3 1',shell=True)
SAMPLERATE = 44100
 
def playWAVFile(filename):
    sound = pygame.mixer.Sound(filename)
    sound.play()
 
#blue sound 209Hz
bluesound = '/home/pi/simon/sounds/blue.wav'
#yellow sound 252Hz
yellowsound = '/home/pi/simon/sounds/yellow.wav'
#red sound 310Hz
redsound = '/home/pi/simon/sounds/red.wav'
#green sound 415Hz
greensound = '/home/pi/simon/sounds/green.wav'
 #losing tone 42 Hz
losingtone = '/home/pi/simon/sounds/losingtone.wav'

readytone = '/home/pi/simon/sounds/readytone.wav'
starttone = '/home/pi/simon/sounds/starttone.wav'
recordtone = '/home/pi/simon/sounds/recordtone.wav'
resettone = '/home/pi/simon/sounds/resettone.wav'

#Variables
max     = 100               #No. of rounds in game
RoundNo = 1
GREEN     = 1
RED   = 2
YELLOW  = 3
BLUE    = 4
START    = 5
correct = False
colour=[]

#verd, vermell, groc, blau (G,R,Y,B)
INT_GREEN   = 4
INT_RED     = 17
INT_YELLOW  = 27
INT_BLUE    = 22
INT_START   = 10

LED_GREEN   = 14
LED_RED     = 15
LED_YELLOW  = 18
LED_BLUE    = 23

#Setup GPIO switches
GPIOSwitch=[0,4,17,27,22,10]

GPIO.setup(INT_GREEN, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_RED, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_YELLOW, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_BLUE, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(INT_START, GPIO.IN, pull_up_down = GPIO.PUD_UP)

#Setup GPIO LEDs
GPIOLED=[0,14,15,18,23]

GPIO.setup(LED_GREEN, GPIO.OUT )
GPIO.setup(LED_RED, GPIO.OUT )
GPIO.setup(LED_YELLOW, GPIO.OUT )
GPIO.setup(LED_BLUE, GPIO.OUT )
 
#Generate a random list of LED outputs
def generar_sequencia():
    global colour
    colour=[]
    for n in range(1,max+2):
        colour.append(random.choice([RED,GREEN,YELLOW,BLUE]))
 
#Function to switch LEDs on then off
def LEDout(val):
    if (val==1):
        playWAVFile(greensound)
    elif (val==2):
        playWAVFile(redsound)
    elif (val==3):
        playWAVFile(yellowsound)
    elif (val==4):
        playWAVFile(bluesound)
    while pygame.mixer.get_busy():
        GPIO.output(GPIOLED[val], True)
    GPIO.output(GPIOLED[val],False)
    time.sleep(0.15)
    return[]
 
#Function to check when switch is pressed
def SwitchChosen():
    while True:
        if not (GPIO.input(GPIOSwitch[GREEN])):
            return GREEN
        if not (GPIO.input(GPIOSwitch[RED])):
            return RED
        if not (GPIO.input(GPIOSwitch[YELLOW])):
            return YELLOW
        if not (GPIO.input(GPIOSwitch[BLUE])):
            return BLUE
 
def ShowToneLights(tone):
    playWAVFile(tone)
    while pygame.mixer.get_busy():
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], True)
        time.sleep(0.2)
        for cycle2 in range(1,5):
            GPIO.output(GPIOLED[cycle2], False)
        time.sleep(0.2)
    for cycle2 in range(1,5):
        GPIO.output(GPIOLED[cycle2], False)
    return[]

def ShowNumberRounds(num_rounds):
    for cycle in range(1,num_rounds+1):
        #print ((cycle-1)%4)+1
        GPIO.output(GPIOLED[((cycle-1)%4)+1], True)
        time.sleep(0.2)
        GPIO.output(GPIOLED[((cycle-1)%4)+1], False)
        time.sleep(0.2)
    for cycle in range(1,5):
        GPIO.output(GPIOLED[cycle], False)

#vull detectar ctrl-c
def signal_handler(signal, frame):
        print("Simon Balmes v6. Adeu!!")
        GPIO.cleanup()
        sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)

#sequencia guanyadora
generar_sequencia()

#llegim el record que esta en el fitxer
try:
    fh = open("record.txt", "r")
    record = int(fh.readline())
except IOError:
    fh = open("record.txt", "w") 
    fh.write("0")
    record = 0
#print record
fh.close()

ShowToneLights(readytone)

#Main routine, bucle sense fi
#Esperem a comencar el joc (boto START)
while True:
    if not (GPIO.input(GPIOSwitch[START])):
	time.sleep(0.3) #antirebot
        t0 = time.time()
        #print t0
	#bucle que espera una altra pulsacio del boto abans de 0,1s per tal de resetejar el reset
	while True:
	    t1 = time.time()
            if not (GPIO.input(GPIOSwitch[START])): #reset del record
		print "reset del record"
		record = 0
                fh = open("record.txt","w")
                fh.write(str(record))  
                fh.close() 
                ShowToneLights(resettone)
		break
	    if (t1-t0 > 1):
		break
	#print t1-t0
        correct = True
        ShowToneLights(starttone)
        time.sleep(0.5) #una mica despera
    #ja podem comencar a jugar
    while correct:
        print("Round %i" %RoundNo)
        #LED cycle
        for mout in range(1,RoundNo+1):
            LEDout(colour[mout])
        #Response
        for ans in range(1,RoundNo+1):
            push=SwitchChosen()
            LEDout(push)
            if(push!=colour[ans]): #hem perdut
                correct = False
                if (RoundNo > record):
                    record = RoundNo
                    ShowToneLights(recordtone)
                    fh = open("record.txt","w")
                    fh.write(str(RoundNo))  
                    fh.close() 
                    print("Nou record! Has fet fins la ronda %i" %RoundNo)
                    ShowNumberRounds(RoundNo)
                else:
                    ShowToneLights(losingtone)
                    print("Has perdut! Has fet fins la ronda %i" %RoundNo)
                    ShowNumberRounds(RoundNo)
                RoundNo = 0
                generar_sequencia()
                #apaguem tots els led
                for cycle in range(1,5):
                    GPIO.output(GPIOLED[cycle],False)
                break
        RoundNo+=1
        if (RoundNo==max+1):
            print("WOW!! You Rock dude")
            break
        time.sleep(0.5)

Millores per a una futura versió

El moble que hem fet no deixa de ser un prototipus. Possibles millores:

Video

Youtube:

Article al blog:


creat per Joan Quintana Compte, desembre 2016, juny 2017

Eines de l'usuari
Espais de noms
Variants
Accions
Navegació
Institut Jaume Balmes
Màquines recreatives
CNC
Informàtica musical
joanillo.org Planet
Eines