Le Raspberry Pi comporte un connecteur GPIO permettant de gérer des entrées/sorties avec des composants extérieurs. Ici l’objectif de la manipulation et de voir comment on peut facilement utiliser les (GPIO] en simulant le fonctionnement d’un feu tricolore.

Le matériel

Il faut des composants électroniques comme des résistances (ici 220 ohms, mais 1 kohm serait plus approprié) et des LED des 3 couleurs, une plaque d’expérimentation, et de quoi connecter le tout.

Voici le schéma de câblage de la solution

Schéma

Et une vue réelle de la solution

Vue d'ensemble

Board

GPIO

La partie logicielle

Concernant le système d’exploitation j’utilise la Raspbian (Debian Jessie 8.x), et pour le code la Gem - ruby - pi_piper. Pour faire des tests en ligne de commande il faut installer aussi le package wiringpi qui fournit la commande gpio.

Sous root il faut lancer les commandes suivantes :

apt-get install ruby ruby-ffi ruby-dev wiringpi libssl-dev
gem install pi_piper

A noter que j’ai fait le schéma avec l’outil Fritzing, pour l’installer sur une Ubuntu 14.04, vous devez ajouter le ppa fritzing et installer le package.

Il faut lancer sous root :

apt-add-repository -y ppa:ehbello/fritzing
apt-get update 
apt-get install fritzing fritzing-parts-adafruit

Et voici le code ruby qui permet de simuler les feux. Il y a un mode France et un mode Suisse ;-).

Pour le lancer passer en paramètre le mode comme dans l’exemple ci-dessous :

./traflights france

ou

./traflights suisse

A noter que la méthode releasePort de la classe TrafficLights est un “workaround” pour éviter un plantage du programme. Je capture également le CTRL-C (SIGINT) et j’éteins les LED afin d’éviter qu’elles restent allumées.

#!/usr/bin/env ruby

require 'pi_piper'
include PiPiper

class TrafficLights

    COLOURS = [:red, :orange, :green]

    def initialize(name,red,orange,green)

        @name = name
        @colours = Hash.new

        @colours = Hash.new 
        @tmp = { :red => red, :orange => orange, :green => green}

        COLOURS.each do |colour|
            #puts "gpio -g mode #{@colours[colour]} out"
            releasePort(@tmp[colour])
        
                @colours[colour] = PiPiper::Pin.new(:pin => @tmp[colour].to_i, :direction => :out)
        end

        reset
    end

    def on(colour)
        @colours[colour].on
    end

    def off(colour)
        @colours[colour].off
    end

    def test

        COLOURS.each do |colour|
            puts "#{@name}->#{colour}"
            on(colour)
            sleep 1
            off(colour)

        end

    end

    def reset
        COLOURS.each do |colour|
            off(colour)
        end

    end

    def releasePort(port)
        puts "clean port '#{port}'"
        begin
            File.open("/sys/class/gpio/unexport", "w") do |f| 
                f.write("#{port}")
                f.close
            end
        rescue => e
            puts e
        end

        sleep 0.7
    end

end

class Simulation

    SHORT_WAIT = 1
    LONG_WAIT = 5

    def initialize(tfl1,tfl2)

        @tfl1 = tfl1
        @tfl2 = tfl2
        Signal.trap("SIGINT") do
            stop
        end

    end


    def simulate(mode)

        case mode

        when :france

            france

        when :suisse

            suisse

        end

    end

    def stop

        @tfl1.reset
        @tfl2.reset
        exit 0

    end

    private

    def france
        while true
            @tfl1.on(:red)
            sleep(SHORT_WAIT)
            @tfl2.off(:red)
            @tfl2.on(:green)
            sleep(LONG_WAIT)
            @tfl2.off(:green)
            @tfl2.on(:orange)
            sleep(SHORT_WAIT)
            @tfl2.off(:orange)
            @tfl2.on(:red)
            sleep(SHORT_WAIT)
            @tfl1.off(:red)
            @tfl1.on(:green)
            sleep(LONG_WAIT)
            @tfl1.off(:green)
            @tfl1.on(:orange)
            sleep(SHORT_WAIT)
            @tfl1.off(:orange)
        end
    end

    def suisse
        while true
            @tfl1.on(:red)
            sleep(SHORT_WAIT)
            @tfl2.on(:orange)
            @tfl2.on(:red)
            sleep(SHORT_WAIT)
            @tfl2.off(:red)
            @tfl2.off(:orange)
            @tfl2.on(:green)
            sleep(LONG_WAIT)
            @tfl2.off(:green)
            @tfl2.on(:orange)
            sleep(SHORT_WAIT)
            @tfl2.off(:orange)
            @tfl2.on(:red)
            sleep(SHORT_WAIT)
            @tfl1.on(:orange)
            @tfl1.on(:red)
            sleep(SHORT_WAIT)
            @tfl1.off(:red)
            @tfl1.off(:orange)
            @tfl1.on(:green)
            sleep(LONG_WAIT)
            @tfl1.off(:green)
            @tfl1.on(:orange)
            sleep(SHORT_WAIT)
            @tfl1.off(:orange)
        end
    end

end

sim = Simulation.new(TrafficLights.new("tfl 1",18,23,24),TrafficLights.new("tfl 2",22,4,17))
sim.simulate(ARGV.shift.to_sym)