« STIC:STIC III (2020)/Forces rouge, rose, vert, jaune ou bleu ! » : différence entre les versions

De EduTech Wiki
Aller à la navigation Aller à la recherche
Ligne 128 : Ligne 128 :
[[Fichier:CPX firstproto.jpg|vignette|droite|Une étape dans le test du code - 5 binomes de noël! ]]
[[Fichier:CPX firstproto.jpg|vignette|droite|Une étape dans le test du code - 5 binomes de noël! ]]
La solution présentée ici s'occupe du niveau 1, soit la création de groupe aléatoire à l'aide d'un CPX Bluefruit.
La solution présentée ici s'occupe du niveau 1, soit la création de groupe aléatoire à l'aide d'un CPX Bluefruit.
Elle a été codée en CircuitPython. Nous n'avons pas utilisé de code existant, et la première partie de dictionnaire a été finalisée grâce à l'aimable contribution de notre collègue Jérôme.
Elle a été codée en CircuitPython. Nous avons rédigé le code nous-mêmes, avec deux supports : la création du dictionnaire pour la randomisation été possible grâce à l'aimable contribution de notre collègue Jérôme. Concernant l'envoi et la réception de données par Bluetooth, nous nous sommes basés sur les [https://learn.adafruit.com/circuitpython-nrf52840/bluetooth-basics tutoriels Adafruit], ainsi que deux projets utilisant des fonctionnalités se rapprochant de notre projet :
* [https://learn.adafruit.com/circuit-playground-bluefruit-neopixel-animation-and-color-remote-control projet 1]
* [https://learn.adafruit.com/color-remote-with-circuit-playground-bluefruit projet 2]


'''Code pour le CPB Emetteur'''
<syntaxhighlight lang="python">
<syntaxhighlight lang="python">
# Groupify !
# Groupify !
# Un projet de S!m & Dja
# Un projet de S!m & Dja
# Code CircuitPython pour la répartition dans les groupes (MASTER)


# code python pur pour la répartition dans les groupes
"""
SETUP GENERAL
"""
 
# LIBRAIRIES
import random
import random
import time


# Librairie pour gérer la bande neopixel du bluefruit
# Librairie pour gérer la bande neopixel du bluefruit
from adafruit_circuitplayground import cp
from adafruit_circuitplayground.bluefruit import cpb
 
# Librairies pour gérer la transmission bluetooth
from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService
 
# Librairie pour envoyer la couleur
from adafruit_bluefruit_connect.color_packet import ColorPacket
 
# Helper function pour gérer la connexion entre plusieurs Bluefruits
# reprise sur https://learn.adafruit.com/circuit-playground-bluefruit-neopixel-
# animation-and-color-remote-control/remote-control-code
def send_packet(uart_connection_name, packet):
    """Returns False if no longer connected."""
    try:
        uart_connection_name[UARTService].write(packet.to_bytes())
    except:  # pylint: disable=bare-except
        try:
            uart_connection_name.disconnect()
        except:  # pylint: disable=bare-except
            pass
        return False
    return True


participants = int(input("Combien y a de participants : "))
groupe = int(input("Combien tu veux de groupes : "))


liste_part = list(range(1, participants + 1))
# Input utilisateur
liste_groupe = list(range(1, groupe + 1))
participants = int(input("Nombre de participants : "))
groupe = int(input("Nombre de groupes : "))


"""
CREATION DES GROUPES
"""
# création listes à long. variable (+ 1 pour compenser la numération depuis 0)
liste_part = list(range(1, participants + 1))  # print(liste_part)
nb_part = len(liste_part) + 1
liste_groupe = list(range(1, groupe + 1))  # print(liste_groupe)
# Déf. grille (dict. de listes) combinations possibles
clé_tableau = str(participants) + "_" + str(groupe)
clé_tableau = str(participants) + "_" + str(groupe)
# ajouter combinaisons pas possible --> genre un tour de roue lumineuse/un son pourri
# !!! ajouter combinaisons pas possible : eg. tour de roue lumineuse/son pourri !!!
grille_repartition = {"10_5": [2, 2, 2, 2, 2], "10_4": [2, 2, 3, 3], "10_3": [3, 3, 4]}
grille_repartition = {
 
    "10_5": [2, 2, 2, 2, 2],
    "10_4": [2, 2, 3, 3],
    "10_3": [3, 3, 4],
    "10_2": [5, 5],
    "9_4": [2, 2, 2, 3],
    "9_3": [3, 3, 3],
    "9_2": [4, 5],
    "8_4": [2, 2, 2, 2],
    "8_3": [2, 3, 3],
    "8_2": [4, 4],
    "7_3": [2, 2, 3],
    "7_2": [4, 3],
    "6_3": [2, 2, 2],
    "6_2": [3, 3],
    "5_2": [2, 3],
    "4_2": [2, 2],
}
# détermination du nb et taille des groupes à créer
taille_groupe = grille_repartition[clé_tableau]
taille_groupe = grille_repartition[clé_tableau]
print(taille_groupe)


dict_repartition = {}
# création (dict) répartition aléatoire
dict_repartition = {} # initialisation
for i in range(0, len(taille_groupe)):
for i in range(0, len(taille_groupe)):
     dict_repartition[liste_groupe[i]] = []
     dict_repartition[liste_groupe[i]] = [] # création des items du dictionnaire
     for j in range(0, taille_groupe[i]):
     for j in range(0, taille_groupe[i]):
         etu = liste_part[random.randint(0, len(liste_part) - 1)]
         etu = liste_part[random.randint(0, len(liste_part) - 1)]
         dict_repartition[liste_groupe[i]].append(etu)
         dict_repartition[liste_groupe[i]].append(etu)
         liste_part.remove(etu)
         liste_part.remove(etu)
        # print (liste_part)
        # print (dict_repartition)
print(dict_repartition)
print(dict_repartition)


# Définition des groupes avec couleurs
# Définition des groupes avec couleurs
groupeTotal = dict_repartition.values()
groupeList = list(dict_repartition.values())
groupeList = list(groupeTotal)
print(groupeList)
print(groupeList)


# créer un test pour si existe pas --> ignorer / boucle sur la base de len(groupeList)
# GESTION NEOPIXEL
groupe1 = groupeList[0]
cpb.pixels.brightness = 0.05
groupe2 = groupeList[1]
 
groupe3 = groupeList[2]
# Grille de définition des couleurs de groupe
groupe4 = groupeList[3]
dict_couleur = {
groupe5 = groupeList[4]
    "gr1": (0, 255, 0),
    "gr2": (255, 0, 255),
    "gr3": (255, 255, 0),
    "gr4": (0, 255, 255),
    "gr5": (255, 0, 0),
}
#  print(dict_couleur)
 
# transf. dict -> list
liste_couleur = list(dict_couleur.values())
print("liste de couleur totale: ", liste_couleur)
 
# définition des couleurs selon nb de groupe
dict_neopix = {}
for i in range(0, len(taille_groupe)):
    codecouleur = liste_couleur[i]
    dict_neopix[i] = codecouleur
# print(dict_neopix)
 
# transf. dict -> list
liste_neopix = list(dict_neopix.values())
print("liste de couleur spécifique: ", liste_neopix)
 
# Attribution des couleurs par pixel
liste_pixels = []
for i in range(0, nb_part):
    for j in range(0, len(taille_groupe)):
        if i in groupeList[j]:
            pix = liste_neopix[j]
            liste_pixels.append(pix)
print("couleurs des pixels : ", liste_pixels)
 
"""
TRANSMISSION AUX BLUEFRUITS PARTICIPANTS (SLAVES)
"""
# Setup de la transmission
ble = BLERadio()
uart_service = UARTService()
advertisement = ProvideServicesAdvertisement(uart_service)


# Gestion des LEDs
uart_connection = None
cp.pixels.brightness = 0.05
# Controle sur des connexions disponibles
if ble.connected:
    for connection in ble.connections:
        if UARTService in connection:
            uart_connection = connection
        break


groupe1_color = (0, 255, 0)
while True:
groupe2_color = (255, 0, 255)
    # Allumage de la bnde neopixel / visualisation des groupes formés
groupe3_color = (255, 255, 0)
    for i in range(0, nb_part - 1):
groupe4_color = (0, 255, 255)
        cpb.pixels[i] = liste_pixels[i]
groupe5_color = (255, 0, 0)


# recherche des participants (LED) dans les groupes
    # Gestion de la transmission
if 1 in groupe1:
    if not uart_connection or not uart_connection.connected:
    pix1 = groupe1_color
        # Condition : pas de connexion > scan
elif 1 in groupe2:
        print("Scanning...")
    pix1 = groupe2_color
        for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=5): # Scan...
elif 1 in groupe3:
            if UARTService in adv.services: # si periphérique existe
    pix1 = groupe3_color
                print("Found a UARTService advertisement.")
elif 1 in groupe4:
                uart_connection = ble.connect(adv)  # crée une connexion
    pix1 = groupe4_color
                break
elif 1 in groupe5:
        # Arrêt du scannage de l'environnement
    pix1 = groupe5_color
        ble.stop_scan()


if 2 in groupe1:
    # si connexion existante :
     pix2 = groupe1_color
     while uart_connection and uart_connection.connected:
elif 2 in groupe2:
        if cpb.button_a: # Transmission des données neopixels avec A
    pix2 = groupe2_color
            print("Bouton A - envoi données")
elif 2 in groupe3:
            color = cpb.pixels[0]
    pix2 = groupe3_color
            if not send_packet(uart_connection, ColorPacket(color)):
elif 2 in groupe4:
                uart_connection = None
    pix2 = groupe4_color
                continue
elif 2 in groupe5:
        time.sleep(0.1)  # Delay to prevent sending packets too quickly.
    pix2 = groupe5_color
</syntaxhighlight>


if 3 in groupe1:
'''Code pour le CPB Récepteur (participants)'''
    pix3 = groupe1_color
<syntaxhighlight lang="python">
elif 3 in groupe2:
"""
    pix3 = groupe2_color
Code pour les bluefruits participants
elif 3 in groupe3:
"""
    pix3 = groupe3_color
import time
elif 3 in groupe4:
    pix3 = groupe4_color
elif 3 in groupe5:
    pix3 = groupe5_color


if 4 in groupe1:
from adafruit_circuitplayground.bluefruit import cpb
    pix4 = groupe1_color
elif 4 in groupe2:
    pix4 = groupe2_color
elif 4 in groupe3:
    pix4 = groupe3_color
elif 4 in groupe4:
    pix4 = groupe4_color
elif 4 in groupe5:
    pix4 = groupe5_color


if 5 in groupe1:
from adafruit_ble import BLERadio
    pix5 = groupe1_color
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
elif 5 in groupe2:
from adafruit_ble.services.nordic import UARTService
    pix5 = groupe2_color
elif 5 in groupe3:
    pix5 = groupe3_color
elif 5 in groupe4:
    pix5 = groupe4_color
elif 5 in groupe5:
    pix5 = groupe5_color


if 6 in groupe1:
from adafruit_bluefruit_connect.packet import Packet
    pix6 = groupe1_color
from adafruit_bluefruit_connect.color_packet import ColorPacket
elif 6 in groupe2:
    pix6 = groupe2_color
elif 6 in groupe3:
    pix6 = groupe3_color
elif 6 in groupe4:
    pix6 = groupe4_color
elif 6 in groupe5:
    pix6 = groupe5_color


if 7 in groupe1:
num_pixels = 10
    pix7 = groupe1_color
elif 7 in groupe2:
    pix7 = groupe2_color
elif 7 in groupe3:
    pix7 = groupe3_color
elif 7 in groupe4:
    pix7 = groupe4_color
elif 7 in groupe5:
    pix7 = groupe5_color


if 8 in groupe1:
# animation initiale - "chase" est une animation de base dans les librairies
    pix8 = groupe1_color
# d'animation pour neopixel (cf neopixel überguide)
elif 8 in groupe2:
def color_chase(color, wait):
     pix8 = groupe2_color
     for i in range(num_pixels):
elif 8 in groupe3:
        cpb.pixels[i] = color
    pix8 = groupe3_color
        time.sleep(wait)
elif 8 in groupe4:
        cpb.pixels.show()
    pix8 = groupe4_color
     time.sleep(0.5)
elif 8 in groupe5:
     pix8 = groupe5_color


if 9 in groupe1:
    pix9 = groupe1_color
elif 9 in groupe2:
    pix9 = groupe2_color
elif 9 in groupe3:
    pix9 = groupe3_color
elif 9 in groupe4:
    pix9 = groupe4_color
elif 9 in groupe5:
    pix9 = groupe5_color


if 10 in groupe1:
# Grille des couleurs de groupe pour animation
     pix10 = groupe1_color
dict_couleur = {
elif 10 in groupe2:
    "gr1": (0, 255, 0),
     pix10 = groupe2_color
     "gr2": (255, 0, 255),
elif 10 in groupe3:
    "gr3": (255, 255, 0),
    pix10 = groupe3_color
    "gr4": (0, 255, 255),
elif 10 in groupe4:
     "gr5": (255, 0, 0),
    pix10 = groupe4_color
}
elif 10 in groupe5:
 
    pix10 = groupe5_color
liste_couleur = list(dict_couleur.values())
print(liste_couleur)
 
# Setup standard pour la réception
ble = BLERadio()
uart = UARTService()
advertisement = ProvideServicesAdvertisement(uart)
 
cpb.pixels.brightness = 0.05
receptionGroupe = False


# Gestion de l'allumage de la bande neopixel
while True:
while True:
     cp.pixels[0] = pix1
     ble.start_advertising(advertisement)
     cp.pixels[1] = pix2
 
    cp.pixels[2] = pix3
     while not cpb.switch:
     cp.pixels[3] = pix4
        for i in range(0, len(liste_couleur)):
    cp.pixels[4] = pix5
            couleurCode = liste_couleur[i]
    cp.pixels[5] = pix6
            color_chase(couleurCode, 0.05)
    cp.pixels[6] = pix7
 
    cp.pixels[7] = pix8
     if cpb.switch:
    cp.pixels[8] = pix9
        while not ble.connected:
    cp.pixels[9] = pix10
            pass
        ble.stop_advertising()
 
        while ble.connected:
            if uart.in_waiting:
                packet = Packet.from_stream(uart)
                if isinstance(packet, ColorPacket):
                    cpb.pixels.fill(packet.color)
</syntaxhighlight>
</syntaxhighlight>



Version du 4 septembre 2021 à 10:37

Projet réalisé par Djamileh & Simon

Introduction

Durant la dernière année, le passage forcé à la téléformation, soit la formation synchrone à distance, a eu comme effet positif de pousser certains spécialistes de l’éducation à revisiter leurs scénarios pédagogiques pour revenir aux fondamentaux : comment aider les élèves à apprendre ce qu’ils sont sensés apprendre et comment les accompagner au mieux dans leur apprentissage ? Souvent, les difficultés relevées lors des bilans des derniers mois de distantiel ont fait émerger des problèmes qui existaient déjà en présence, mais qui restaient latents ou ignorés.

En ce sens, l’apprentissage est fortement influencé par les émotions par lesquelles passent les élèves au cours de la formation, et en particulier pendant les moments synchrones. Pourtant, il est très complexe de détecter, mesurer, ou même faire exprimer les étudiant-es sur leur ressenti.

En donnant leurs cours en visioconférence, nombreux formateurs et formatrices ont exprimé leur frustration de ne pas réussir à évaluer l’état émotionnel et autres indices non verbaux de leurs participant.e.s, retours essentiels pour adapter une explication ou ajuster le rythme. Et cet effet est loin d’être limité à la distance : il est également bien présent dans une salle de classe où il reste complexe de capter en temps réel les émotions d’un étudiant, processus complexe et dynamique.

Notre projet prend sa racine dans ce constat. Deux questions ont alors émergé :

  • comment mesurer l'état émotionnel d'un-e apprenant-e,
  • et surtout, pour quel usage ?

Dans ce contexte, nous avons pensé un dispositif de partage des ressentis de la classe à destination de l'équipe enseignante, et une utilisation de cette donnée comme retour au groupe.

Problème

Le but de ce projet est de proposer une solution ludique à la constitution de groupes en classe, que cela soit en présence, à distance ou de manière comodale. En utilisant un Arduino Uno ou des CPX, la phase de constitution de groupes sera ainsi rapide, aléatoire et "fun" !

Le Problem Statement peut s’exprimer ainsi : « Comment peut-on aider les formateurs et formatrices à identifier rapidement les difficultés dans l’apprentissage et, le cas échéant, à réagir ? »

Cahier des charges

Contexte et public

Le public cible est composé de formateurs et formatrices d’adultes, en entreprise ou en institut. Il pourrait également être élargi aux enseignante.s du scolaire, mais la conscientisation et l’expression d’une émotion sont suffisamment complexes pour limiter notre premier dispositif à des adultes, disposant, à priori, d’une compréhension plus fine de leur état émotionnel. De plus, l’asymétrie dans la relation est supposée moins forte dans un groupe d’adultes en formation que dans une classe avec un enseignant et des enfants ou adolescents.

Objectifs

Le but du dispositif est de :

  • permettre la communication d'un niveau émotionnel perçu par l'étudiant.e à l'enseignant.e
  • faire émerger un état général de la classe et les différences dans l'acquisition du contenu
  • de manière plus pragmatique, de créer des groupes sur la base des éléments communiqués

Besoins et contraintes

L'idée du projet a beaucoup évolué entre la phase d'identification des besoins et les constatations sur les possibilités offertes par la technologie et l'expertise à disposition. Nous détaillons ci-dessous les besoins et contraintes qui nous ont menés à la solution présentée plus bas.

Partant au début d’une idée de jauge émotionnelle dynamique, donnant en tout temps l’état émotionnel d’un groupe de participants, nous avons rapidement détecté, en phase d'idéation avec plusieurs spécialistes en éducation, un aspect extrêmement anxiogène pour le formateur dont le groupe enverrait des signaux d’ennui ou de frustration, durant une explication.

Afin de juguler cet effet, tout en conservant la possibilité de communiquer un message sur l’état, nous avons adapté le dispositif pour permettre aux étudiants de transmettre leur état à des moments spécifiques de la formation, intégrés dans le scénario pédagogique. L'émotion étant un élément sensible à conscientiser, exprimer et partager au sein d'un groupe, nous avons estimé plus judicieux de faire exprimer son niveau d'aisance face à un contenu qui vient d'être transmis. Ainsi, un-e enseignant-e scénarisera des moments d'autodiagnostic des étudiant-es sur leur perception de compétence sur la thématique. Cette information peut être utilisée pour réaliser des groupes de travail : (1) les personnes qui ont compris peuvent être orientées sur un contenu plus avancé, en échange pendant que l'enseignant organiser une séance de question-réponse avec les personnes en difficulté ou (2) des groupes peuvent être créés pour intégrer des étudiant-es qui ont compris avec des étudiant-es qui ont besoin d'aide.

Le dispositif est donc pensé comme un outil de sondage à certains moments du cours, pour évaluer les besoins du groupe, dans son ensemble. Il est souvent difficile de récolter des informations sincères lors d’évaluations à chaud, les étudiants réticents à communiquer publiquement leurs difficultés ou désintérêts pour le contenu. Par la technique de transmission, les étudiants pourraient communiquer leur émotion de manière anonyme, favorisant l'authenticité.

De manière intéressante au fur et à mesure de l'avance du projet, il est ressorti des discussions avec un échantillon du public cible que l'aspect de notre projet qui les intéressait était moins la communication des émotions, mais la création facilitée des groupes. En effet, les formateurs et formatrices ayant travaillé à distance durant la dernière année se sont habitués à disposer d'une fonction de création de groupe aléatoire, selon un nombre total de participants et un nombre de groupe visé. Cette fonction serait très utile également en présence, en utilisant une carte Arduino ou un CPX pour calculer une répartition des élèves par groupe, avec en entrée le nombre d'élèves et les sous-groupes. Une fois les groupes constitués, l'étape suivante est de communiquer ces groupes à l'ensemble de la classe au travers de Lilypad ou autres technologies portables qui s'allument selon la couleur de leur groupe.

Apports

  • Cohésion et sentiment d'appartenance au groupe comme soutien à l'apprentissage
  • Expression d'un état émotionnel épistémique comme bénéfique à l'apprentissage

Présentation du projet

Suite aux premières itérations dans l'empathie et la définition du projet, nous avons identifié plusieurs points clés qui ont réorienté notre projet :

  • la création d'un réseau de cartes Bluetooth contrôlées par Arduino s'est révélée trop ambitieuse, suite au manque de projets existants ou d'expertise sur lesquels s'appuyer,
  • l'envie marquée de notre échantillon cible qui s'est dirigée sur l'aspect création de groupe plus que sur la connaissance des états affectifs.

Nous avons donc revu le projet en le divisant en 3 niveaux de difficulté, afin de réaliser un prototype utilisable, puis de l'améliorer en fonction des retours et du temps à disposition.

  • Niveau 1 : Création de groupe aléatoire : intérêts : facilitation de la création des groupes (demande reçue d'un formateur : "parce que Zoom nous a bien aidé pour cela à distance, je veux la même chose en présence!")
  • Niveau 2 : Communication du groupe à l’apprenant : intérêts : gamification, sentiment d’appartenance, coopération, cohésion
  • Niveau 3 : Communication de son sentiment de compétence  : intérêts : plus facile que d'exprimer ses émotions, et plus facile à gérer par l'enseignant.e, par exemple les gens qui ont compris avec celles-ceux qui n'ont pas compris

Nous avons réalisé complètement le niveau 1, ainsi que prototypé et testé le niveau 2 avec des cables avant de pouvoir gérer par Bluetooth un Bluefruit spécifique dans un réseau comprenant plusieurs Bluefruits. Les solutions avec code et prototypes sont décrites dans la section suivante.

Solutions explorées

1er prototype

La première solution envisagée comporte deux objets :

  • Un émetteur : facile d’utilisation et agréable à porter, nous penchons pour la solution d’un bracelet contenant un micro circuit type Lilypad, Arduino Gemma ou Tinyduino. L’apprenant disposerait de 4 boutons-pressoirs pour 4 émotions majeures à transmettre (intérêt, confusion, frustration, incompréhension), symbolisés par des logos ou émoticônes. Les messages sont transmis par Bluetooth.
  • Un récepteur : Une jauge, comprenant une bande Neopixels, connectée à un Arduino Uno. Les LED symboliseraient deux dimensions fournies : la couleur pour le type d'émotion et le nombre pour la quantité d'étudiant.e.s ayant transmis l'information. L'Arduino pourrait gérer l'information, en émettant un son lors du dépassement d'un seuil prédéfini sur une émotion par exemple.

Maquettes

1ère itération

Maquette n°1 du projet

2e itération

L'Arduino Uno lance une séquence de randomisation de couleur, en affiche une, puis les participant.e.s font de même sur leur CPX. Si les couleurs affichées "matchent", le groupe est constitué et on peut ainsi passer à la constitution aléatoire du groupe suivant.

Maquette n°2 du projet

Code

Version 1.0 du code CPX :

input.buttonA.onEvent(ButtonEvent.Click, function () {
    light.setPhotonPenHue(color2)
    durée = 30
    tonalité = 200
    for (let i = 0; i < Math.randomRange(20, 100); i++) {
        light.photonForward(1)
        music.playTone(tonalité, durée)
        pause(40)
        color2 += Math.randomRange(1, 3)
        light.setPhotonPenHue(color2)
    }
    light.photonFlip()
})
input.buttonsAB.onEvent(ButtonEvent.Click, function () {
    control.reset()
})
input.buttonB.onEvent(ButtonEvent.Click, function () {
    light.setPhotonPenHue(color2)
    durée = 30
    tonalité = 300
    for (let i = 0; i < Math.randomRange(20, 100); i++) {
        color2 += 3
        light.photonForward(1)
        music.playTone(tonalité, durée)
        pause(50)
    }
})
let tonalité = 0
let durée = 0
let color2 = 0
light.setBrightness(158)
music.setVolume(167)
forever(function () {
	
})

2e prototype

Maquette

Boîte émettrice

Plan découpe boîte émettrice CPX
Etiquettes boîte CPX
Rendu de la boîte
Boîte en cours de réalisation

Cadrans récepteurs

Cadrans récepteurs

Code

Une étape dans le test du code - 5 binomes de noël!

La solution présentée ici s'occupe du niveau 1, soit la création de groupe aléatoire à l'aide d'un CPX Bluefruit. Elle a été codée en CircuitPython. Nous avons rédigé le code nous-mêmes, avec deux supports : la création du dictionnaire pour la randomisation été possible grâce à l'aimable contribution de notre collègue Jérôme. Concernant l'envoi et la réception de données par Bluetooth, nous nous sommes basés sur les tutoriels Adafruit, ainsi que deux projets utilisant des fonctionnalités se rapprochant de notre projet :

Code pour le CPB Emetteur

# Groupify !
# Un projet de S!m & Dja
# Code CircuitPython pour la répartition dans les groupes (MASTER)

"""
SETUP GENERAL
"""

# LIBRAIRIES
import random
import time

# Librairie pour gérer la bande neopixel du bluefruit
from adafruit_circuitplayground.bluefruit import cpb

# Librairies pour gérer la transmission bluetooth
from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService

# Librairie pour envoyer la couleur
from adafruit_bluefruit_connect.color_packet import ColorPacket

# Helper function pour gérer la connexion entre plusieurs Bluefruits
# reprise sur https://learn.adafruit.com/circuit-playground-bluefruit-neopixel-
# animation-and-color-remote-control/remote-control-code
def send_packet(uart_connection_name, packet):
    """Returns False if no longer connected."""
    try:
        uart_connection_name[UARTService].write(packet.to_bytes())
    except:  # pylint: disable=bare-except
        try:
            uart_connection_name.disconnect()
        except:  # pylint: disable=bare-except
            pass
        return False
    return True


# Input utilisateur
participants = int(input("Nombre de participants : "))
groupe = int(input("Nombre de groupes : "))

"""
CREATION DES GROUPES
"""

# création listes à long. variable (+ 1 pour compenser la numération depuis 0)
liste_part = list(range(1, participants + 1))  # print(liste_part)
nb_part = len(liste_part) + 1
liste_groupe = list(range(1, groupe + 1))  # print(liste_groupe)

# Déf. grille (dict. de listes) combinations possibles
clé_tableau = str(participants) + "_" + str(groupe)
# !!! ajouter combinaisons pas possible : eg. tour de roue lumineuse/son pourri !!!
grille_repartition = {
    "10_5": [2, 2, 2, 2, 2],
    "10_4": [2, 2, 3, 3],
    "10_3": [3, 3, 4],
    "10_2": [5, 5],
    "9_4": [2, 2, 2, 3],
    "9_3": [3, 3, 3],
    "9_2": [4, 5],
    "8_4": [2, 2, 2, 2],
    "8_3": [2, 3, 3],
    "8_2": [4, 4],
    "7_3": [2, 2, 3],
    "7_2": [4, 3],
    "6_3": [2, 2, 2],
    "6_2": [3, 3],
    "5_2": [2, 3],
    "4_2": [2, 2],
}
# détermination du nb et taille des groupes à créer
taille_groupe = grille_repartition[clé_tableau]
print(taille_groupe)

# création (dict) répartition aléatoire
dict_repartition = {}  # initialisation
for i in range(0, len(taille_groupe)):
    dict_repartition[liste_groupe[i]] = []  # création des items du dictionnaire
    for j in range(0, taille_groupe[i]):
        etu = liste_part[random.randint(0, len(liste_part) - 1)]
        dict_repartition[liste_groupe[i]].append(etu)
        liste_part.remove(etu)
        # print (liste_part)
        # print (dict_repartition)
print(dict_repartition)

# Définition des groupes avec couleurs
groupeList = list(dict_repartition.values())
print(groupeList)

# GESTION NEOPIXEL
cpb.pixels.brightness = 0.05

# Grille de définition des couleurs de groupe
dict_couleur = {
    "gr1": (0, 255, 0),
    "gr2": (255, 0, 255),
    "gr3": (255, 255, 0),
    "gr4": (0, 255, 255),
    "gr5": (255, 0, 0),
}
#  print(dict_couleur)

# transf. dict -> list
liste_couleur = list(dict_couleur.values())
print("liste de couleur totale: ", liste_couleur)

# définition des couleurs selon nb de groupe
dict_neopix = {}
for i in range(0, len(taille_groupe)):
    codecouleur = liste_couleur[i]
    dict_neopix[i] = codecouleur
# print(dict_neopix)

# transf. dict -> list
liste_neopix = list(dict_neopix.values())
print("liste de couleur spécifique: ", liste_neopix)

# Attribution des couleurs par pixel
liste_pixels = []
for i in range(0, nb_part):
    for j in range(0, len(taille_groupe)):
        if i in groupeList[j]:
            pix = liste_neopix[j]
            liste_pixels.append(pix)
print("couleurs des pixels : ", liste_pixels)

"""
TRANSMISSION AUX BLUEFRUITS PARTICIPANTS (SLAVES)
"""
# Setup de la transmission
ble = BLERadio()
uart_service = UARTService()
advertisement = ProvideServicesAdvertisement(uart_service)

uart_connection = None
# Controle sur des connexions disponibles
if ble.connected:
    for connection in ble.connections:
        if UARTService in connection:
            uart_connection = connection
        break

while True:
    # Allumage de la bnde neopixel / visualisation des groupes formés
    for i in range(0, nb_part - 1):
        cpb.pixels[i] = liste_pixels[i]

    # Gestion de la transmission
    if not uart_connection or not uart_connection.connected:
        # Condition : pas de connexion > scan
        print("Scanning...")
        for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=5):  # Scan...
            if UARTService in adv.services:  # si periphérique existe
                print("Found a UARTService advertisement.")
                uart_connection = ble.connect(adv)  # crée une connexion
                break
        # Arrêt du scannage de l'environnement
        ble.stop_scan()

    # si connexion existante :
    while uart_connection and uart_connection.connected:
        if cpb.button_a:  # Transmission des données neopixels avec A
            print("Bouton A - envoi données")
            color = cpb.pixels[0]
            if not send_packet(uart_connection, ColorPacket(color)):
                uart_connection = None
                continue
        time.sleep(0.1)  # Delay to prevent sending packets too quickly.

Code pour le CPB Récepteur (participants)

"""
Code pour les bluefruits participants
"""
import time

from adafruit_circuitplayground.bluefruit import cpb

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService

from adafruit_bluefruit_connect.packet import Packet
from adafruit_bluefruit_connect.color_packet import ColorPacket

num_pixels = 10

# animation initiale - "chase" est une animation de base dans les librairies
# d'animation pour neopixel (cf neopixel überguide)
def color_chase(color, wait):
    for i in range(num_pixels):
        cpb.pixels[i] = color
        time.sleep(wait)
        cpb.pixels.show()
    time.sleep(0.5)


# Grille des couleurs de groupe pour animation
dict_couleur = {
    "gr1": (0, 255, 0),
    "gr2": (255, 0, 255),
    "gr3": (255, 255, 0),
    "gr4": (0, 255, 255),
    "gr5": (255, 0, 0),
}

liste_couleur = list(dict_couleur.values())
print(liste_couleur)

# Setup standard pour la réception
ble = BLERadio()
uart = UARTService()
advertisement = ProvideServicesAdvertisement(uart)

cpb.pixels.brightness = 0.05
receptionGroupe = False

while True:
    ble.start_advertising(advertisement)

    while not cpb.switch:
        for i in range(0, len(liste_couleur)):
            couleurCode = liste_couleur[i]
            color_chase(couleurCode, 0.05)

    if cpb.switch:
        while not ble.connected:
            pass
        ble.stop_advertising()

        while ble.connected:
            if uart.in_waiting:
                packet = Packet.from_stream(uart)
                if isinstance(packet, ColorPacket):
                    cpb.pixels.fill(packet.color)

Test(s) de la solution

Cognitive walkthrough

Pour produire ce cognitive walkthrough, nous nous sommes basés sur les principes du Fluid Project.

Persona

En cours de création...

Objectifs

  • Créer des groupes grâce au dispositif émetteur
  • Communiquer ces groupes aux dispositifs récepteurs

Scénario d'utilisation

  1. (en amont) Réfléchir à un combien de groupes seront créés en fonction du nombre de participant.e.s disponible.s
  2. Allumage du dispositif
  3. Lancement du dispositif
  4. Réalisation d'une séquence de composition de groupe
  5. Lancement et réalisation de la séquence suivante de communication avec envoi des groupes constitués aux dispositifs distants
  6. Mise hors tension du dispositif

Tests utilisateur·trice·s

Restant à réaliser...

Ébauche du scénario

Le test utilisateur est une méthode utilisée pour évaluer l’expérience utilisateur d’un système, mais également les forces et les faiblesses de celui-ci. Cette méthode, consiste à mettre l’utilisateur·trice en situation « réelle » afin d’observer ses comportements et ses actions lorsqu’il exécute des tâches prédéfinies qui lui sont administrées sous la forme d’un scénario. Il leur est alors demandé de nous renseigner sur leurs expériences.

Lors de cette phase, un prototype du projet est présenté à des utilisateur·trices recrutés au sein du public cible. A ce stade, le prototype devrait être suffisamment abouti pour offrir les principales fonctionnalités constitutives de la version finale. Néanmoins, il diffère de celle-ci puisque certaines fonctionnalités accessoires ne pourraient ne pas être encore implémentées. En présentant assez tôt un produit relativement proche de la version finale, nous entendons nous assurer que les directions prises dans les précédentes phases de conception soient les plus à même de répondre aux besoins des utilisateur·trice·s. Le prototype sera modifié en fonction des retours formulés par les observations réalisées ainsi que par les analyses des résultats des tests.

Le test utilisateur se déroulera en 3 étapes :

  1. Accueil des participants
  2. Réalisation des tâches
  3. Entretien succinct

Dans la première étape, le participant sera accueilli, le contexte et le test utilisateur lui seront alors présentés de manière générale. Lors du test, l’utilisateur·trice « découvrira » le dispositif en réalisant des tâches préparées au préalable (scénario des tâches). Ici, nous éprouverons l’expérience de l’utilisateur·trice.

Après avoir exposé le contexte dans lequel le scénario prend place, nous demanderons à la personne d’accomplir les tâches décrites dans le tableau "scénario des tâches" (encore en cours de réalisation). De plus, nous encouragerons le/la participant·e à formuler à voix haute ses pensées et ressentis lors de l’utilisation de l’outil.

Les participant·e·s seront accueillis avec la consigne suivante :

Merci d’avoir accepté de faire ce test avec moi aujourd'hui. Je travaille sur le développement d’un outil pour la constitution aléatoire de groupes de travail dans une classe. Cette technique permet de constituer des groupes rapidement et de communiquer ceux-ci aux participant.e.s quasi instantanément.

Le scénario des tâches se composera de deux éléments : le contexte et les tâches à effectuer par le/la participant.e. Le contexte aura pour but de mettre l’utilisateur·trice dans une situation réaliste qui se rapprochera de son quotidien et/ou du contexte pendant lequel il pourrait être mené à utiliser le dispositif. Le contexte sera formulé de la manière suivante :

En cours d'édition...

Après avoir exposé le contexte dans lequel le scénario prend place, nous demanderons au participant d’accomplir les tâches décrites dans le tableau "scénario des tâches" (encore en cours de réalisation).

Pour l’étape des tâches, nous donnerons les consignes suivantes :

En cours d'édition...

Chaque tâche sera expliquée au fur et à mesure au participant.

Scénario des tâches
Tâche 1 Tâche 2
En cours de création... En cours de création...

Discussion

Cette partie inclus deux sous parties :

  • Discussion du design (et si c'était à refaire ou à améliorer),
  • Discussion des résultats de vos tests utilisateurs

Licence, fichiers et documentation

By-nc.png Cette œuvre est mise à disposition selon les termes de la Licence Creative Commons Attribution - Pas d’Utilisation Commerciale 4.0 International.

  • Fichiers :

Insérer ici vos fichiers ou les liens vers vos fichiers

  • Documentation :

Insérer ici une petite documentation pour l'utilisation de l'objet si nécessaire

Bibliographie

  • Blair, C., Calkins, S., & Kopp, L. (2010). Self-regulation as the interface of emotional and cognitive development: Implications for education and academic achievement.
  • Pekrun, R., Goetz, T., Titz, W., & Perry, R. P. (2002). Academic emotions in students' self-regulated learning and achievement: A program of qualitative and quantitative research. Educational psychologist, 37(2), 91-105.