
Nous pouvions déjà citer l'interface TI-Innovator Hub, le robot pilotable TI-Innovator Rover, la grille programmable TI-RGB Array ou encore l'adaptateur TI-SensorLink pour capteurs analogiques Vernier.
Tous ces éléments ont de plus l'avantage d'être utilisables directement avec le langage Python des calculatrices concernées, faisant de l'écosystème Texas Instruments le seul Python connecté !

Un superbe support pour les enseignements scientifiques au lycée surtout maintenant que tous partagent le même langage de programmation, notamment en SNT, spécialité NSI, SI et Physique-Chimie, avec le gros avantage de la mobilité. En effet, les programmes produits et données collectées restent présents dans la calculatrice apportée par chaque élève à chaque cours, ce qui allège la charge logistique de l'enseignant. Données et algorithmes pourront donc être traités / travaillés à la prochaine séance, en devoir à la maison ou même de façon transdisciplinaire en collaboration avec un autre enseignant !




Le nom rend hommage au précédent succès du groupe dans ce domaine, le microordinateur à vocation pédagogique BBC Micro des années 1980, l'équivalent britannique de par son adoption à nos microordinateurs Thomson MO5 et TO7 inondant écoles, collèges et lycées à la fin de cette décennie dans le cadre du plan IPT (Informatique Pour Tous).
Pour relier les deux une solution est d'adjoindre un adaptateur mini-USB.
- USB micro-B mâle ↔ USB mini-A mâle
- USB micro-B mâle ↔ USB mini-B OTG mâle
- processeur 32 bits ARM Cortex-M0 cadencé à 16 MHz
- mémoire de stockage Flash d'une capacité de 256 Kio
- mémoire de travail RAM d'une capacité de 16 Kio permettant un heap (tas) Python de 10,048 Ko
- un afficheur, grille programmable de 5×5= 25 diodes rouges adressables, bien adapté pour l'affichage de motifs éventuellement animés ou encore de texte défilant
- nombre de capteurs intégrés :
- capteur de luminosité (lié aux diodes)
- capteur de température (sur le processeur)
- 2 boutons poussoirs
A
etB
programmables de part et d'autre, comme sur les premières manettes et consoles de jeux portables de chez Nintendo - accéléromètre 3D, permettant de détecter les variations d'accélération et par conséquence diverses actions : secouer, pencher, chute libre, ...
- boussole magnétique 3D, pour détecter cette fois-ci les champs magnétiques
- connectivité Bluetooth 4.0 basse énergie 2,4 GHz maître/esclave
Elle utilise un tout nouveau microcontrôleur, le nRF52833, toujours de chez Nordic Semiconductor. Cette fois-ci nous avons des spécifications qui devraient nous permettre de respirer :
- processeur 32 bits ARM Cortex-M0 cadencé à 64 MHz au lieu de 16 MHz soit 4 fois plus rapide !
- mémoire de stockage Flash d'une capacité de 512 Kio au lieu de 256 Kio soit 2 fois plus grande !
- mémoire de travail RAM d'une capacité de 128 Kio au lieu de 16 Kio soit 8 fois plus grande, permettant un heap (tas) Python de 64,512 Ko !

- ajout d'un haut-parleur
- ajout d'un microphone MEMs
- bouton poussoir qui ne sert plus seulement à la réinitialisation (reset), mais permet désormais également d'éteindre la carte (appui long) et de la rallumer (appui court)
- l'antenne Bluetooth qui devient compatible BLE Bluetooth 5.0, contre seulement 4.0 auparavant
- ajout d'une diode DEL indiquant l'état du microphone
- ajout d'un bouton tactile sur le logo micro:bit, voici pourquoi il perd sa couleur au profit de contacts métalliques
Le solution se compose d'une part d'un fichier TI-Runtime unique à copier sur la carte micro:bit v1 ou v2 et qui lui permet d'être pilotée par la calculatrice. La bonne installation du fichier est aisément vérifiable, puisque faisant afficher à la carte le logo Texas Instruments.
La solution a un principe de fonctionnement très simple, mais non moins ingénieux pour autant. La carte micro:bit étant justement programmable en Python, une fois le TI-Runtime installé elle se met alors à écouter les commandes Python envoyées depuis la calculatrice et à les exécuter.
Depuis ta calculatrice, tu peux envoyer n'importe quelle commande Python à ta carte micro:bit et profiter pleinement de ses capacités grâce à la fonction ti_hub.send(), à condition d'encadrer la commande des bons caractères de contrôle. Voici une fonction mb_run() en ce sens :
- Code: Select all
from ti_hub import *
def mb_run(code):
send('\x05') # enter paste mode (Ctrl-E)
send(code)
send('\x04') # exit paste mode (Ctrl-D)
Pour afficher par exemple Pac-Man, il te suffit d'appeler
mb_run("display.show(Image.PACMAN)")
, conformément à la documentation du Python micro:bit.Toutefois en pratique dans le contexte scolaire, cette façon de faire n'était pas idéale. Elle rajoutait un niveau d'imbrication : tu devais produire du code Python qui lui-même devait construire le code Python à envoyer et exécuter par la carte micro:bit, une marche sans doute un peu haute pour bien des élèves débutants.


- microbit (générale, permet d'accéder aux menus des autres bibliothèques)
- mb_audio → microbit.audio (effets sonores - accessible via le menu Audio)
- mb_butns → microbit.buttons (boutons A, B et tactile intégrés - accessible via le menu Buttons ou Boutons)
- mb_disp → microbit.display (afficheur à 5×5=25 LEDs rouges intégré - accessible via le menu Display ou Affichage)
- mb_grove (capteurs et actionneurs Grove à rajouter - accessible via le menu Grove Devices)
- mb_log (enregistrement de données - accessible via le menu Data logging ou Enregistrement de données)
- mb_mic microbit.microphone (micro intégré - accessible via le menu Microphone)
- mb_music → microbit.music (haut-parleur à rajouter sur micro:bit v1 ou intégré sur micro:bit v2 - accessible via le menu Music ou Musique)
- mb_neopx → microbit.neopixel (rubans de LEDs programmables à rajouter - accessible via le menu NeoPixel)
- mb_notes (notes de musique - accessible via le menu Music ou Musique)
- mb_pins (contacts programmables intégrés - accessible via le menu Input/output pins ou Broches entrée/sortie)
- mb_radio → microbit.radio (communication radio intégrée - accessible via le menu Radio)
- mb_sensr (capteurs intégrés : boussole, accéléromètre, température - accessible via le menu Sensors and gestures ou Capteurs et gestes)
Texas Instruments nous sort aujourd'hui une nouvelle mise à jour de l'édition française de cette solution, découvrons-la ensemble.
1) Eléments et versions
Go to top

- D'une part, le TI-Runtime pour les micro:bit v2 passe de la version 2.1.0 à la version 2.4.0, comme on constate en interrogeant la carte micro:bit avec
microbit.runtime_version()
après mise à jour - D'autre part les bibliothèques Python et menus en Français associés pour les micro:bit v2 passent de la version 2.1.0 à la version 2.3.0
2) Changements microbit
Go to top

Dans la dernière version, l'entrée liée à la bibliothèque mb_grove pour les capteurs Grove n'avait pas été traduite et était restée intitulée en Anglais : Grove Devices.
C'est maintenant corrigé, l'entrée à été renommée en Capteurs Grove.
B3) Changements mb_grove
Go to top
Il permet toujours d'importer les bibliothèques mb_grove et mb_pins, et d'activer leurs menus respectifs.
Nous nous concentrerons ici sur la seule bibliothèque mb_grove. Elle permet pour sa part de contrôler des capteurs et actionneurs Grove connectés à ta carte micro:bit.




D'une part, l'entrée .read_sht() disparaît. Elle permettait d'interroger un capteur Grove de température et humidité et appelait en fait la méthode
grove.read_sht35()
, qui est supprimée dans cette nouvelle version.En effet les puces des capteurs compatibles SHT35 et DHT11 ont été placées en fin de vie par leurs fabricants et ne sont plus recommandées pour de nouveaux projets.

grove.read_dht20
pour interroger le capteur DHT20 les remplaçant.
grove.read_sgp30()
permettant d'interroger un capteur SGP30.Le capteur SGP30 effectue deux types de mesures de gaz différentes : le TVOC / COVT (Composés Organiques Volatils comme les hydrocarbures) et le CO2 (dioxyde de carbone équivalent). Plein d'applications pratiques pour des projets dans le contexte actuel.
Voici un exemple d'utilisation de cette bibliothèque :
- Code: Select all
from microbit import *
from mb_grove import *
from mb_pins import *
disp_clr()
while not escape():
T = grove.read_temperature(pin0)
print("Temperature = %.1f\u00b0C"%round(T,1))
p = 50
print("Pump On at %.1f"%round(p,1)+"% power")
grove.power(pin8,p)
sleep(2000)
p = 0
print("Pump On at %.1f"%round(p,1)+" % power")
grove.power(pin8,p)
disp_clr()
grove.power(pin8,0)
B4) Changements mb_log
Go to top

Cette bibliothèque permet de représenter en direct sous la forme d'un diagramme en ligne brisée, les valeurs retournées par le capteur micro:bit de ton choix, ou plus généralement par n'importe quel appel Python.


Aucun changement au menu, par contre si l'on fouille le contenu de la bibliothèque on note la disparition de la méthode
Data_Log.set_rate()
.
- Code: Select all
from microbit import *
from mb_log import *
from mb_sensr import *
data_log.set_duration(10)
data_log.set_sensor('accelerometer.get_x()')
data_log.set_range(-1200,1200)
data_log.start()
5) Changements mb_neopx
Go to top

Cette bibliothèque permet de piloter des rubans de diodes adressables à connecter à ta carte micro:bit.


Malheureusement dans l'édition française précédente avec le renommage de l'onglet setup en Configuration, il n'y avait plus suffisamment de place en largeur à l'écran pour ce 4ème onglet.



Plutôt qu'un 4ème onglet, les noms de broches nous sont ici rajoutés sous l'onglet Configuration, et en prime nous en avons beaucoup plus !

Peut-être également une correction ou contournement de bug, car on se rend compte que l'entrée np=NeoPixel(pin,pixels) de ce même onglet Configuration ne saisit plus
np=NeoPixel('pin0',16)
mais np=NeoPixel('pin1',20)
. Texas Insturments pousse donc soudainement à l'usage d'une broche différente, ce n'est pas anodin.Voici un exemple d'utilisation de cette bibliothèque :
- Code: Select all
from microbit import *
from mb_neopx import *
from random import *
np = NeoPixel(pin1, 20)
while not escape():
for id in range(len(np)):
red = randint(0,255)
green =randint(0,255)
blue =randint(0,255)
np[id]=(red, green, blue)
np.show()
sleep(100)
np.clear()
6) Changements mb_sensr
Go to top
Cette bibliothèque permet d'interroger les capteurs intégrés à ta carte micro:bit, dont notamment l'accéléromètre et la boussole.


Petit problème dans la version précédente, l'intitulé du menu associé à mb_sensr une fois activé souffrait d'une erreur de typographie : capteurs et estes.
L'intitulé est corrigé avec cette dernière mise à jour : capteurs et gestes.


Autre léger problème, la traduction française n'était pas complète. Pour les fonctions attendant un nom de geste en paramètre, le menu suggérait en Anglais
"gesture"
.C'est ici aussi corrigé avec cette dernière mise à jour, le menu indique maintenant correctement
"geste"
7) Changements TI-Runtime
Go to topEt passons donc enfin au TI-Runtime pour BBC micro:bit v2. Avec un saut de version de 2.1.0 à 2.4.0, il pourrait bien apporter des changements majeurs. Mais surtout, avec une version 2.4.0 supérieure à la 2.3.0 des bibliothèque Python pour ta calculatrice, il pourrait bien inclure des fonctionnalités futures non encore présentes aux menus... 
Ici pas de menu à fouiller, mais on peut procéder autrement. On peut en effet ouvrir directement le fichier sur https://python.microbit.org/v/2 pour pouvoir lire son code source :

Tous les changements sont donc sous tes yeux.
Dans sa version précédente 2.1.0, le TI-Runtime contenait 2 images pour l'afficheur de la carte BBC micro:bit :
On peut remarquer effectivement l'ajout du support des capteurs SGP30 et DHT20 évoqués plus haut, mais également pas mal de changements concernant le capteur BME280. Peut-être une amélioration du support de ce dernier.
Mais surtout, grande découverte. Nous l'avions raté, mais la version 2.1.0 précédente comportait 3 fonctions partageant le nom tello :
Qu'est-ce que ça signifie ? Et bien c'est une découverte absolument fantastique ; Texas Instruments avait visiblement commencé à ajouter le support du drone Tello et serait donc maintenant sur le codage de fonctions te permettant de le configurer.
Dans une prochaine mise à jour tu devrais donc pouvoir piloter le drone Tello en Python directement depuis ta calculatrice Texas Instruments via la carte BBC micro:bit, pour des projets encore plus extraordinaires et ambitieux !

Ici pas de menu à fouiller, mais on peut procéder autrement. On peut en effet ouvrir directement le fichier sur https://python.microbit.org/v/2 pour pouvoir lire son code source :
- Code: Select all
from microbit import *
from machine import freq, reset, time_pulse_us
from time import ticks_us
from utime import sleep_us
#from time import sleep_ms, sleep
#check = Image("00000:""00009:""00090:""90900:""09000")
ti = Image("05500:""05595:""55555:""05550:""00500")
tello="TELLO-9EF498"
# Grove
#TX_pin = pin15
#RX_pin = pin1
# breadboard
#TX_pin = pin1
#RX_pin = pin2
# bitmaker
TX_pin = 'pin2'
RX_pin = 'pin1'
is_connected = False
def tello_read(cmd,TX=TX_pin,RX=RX_pin):
try:
uart.init(baudrate=115200,tx=TX_pin,rx=RX_pin)
uart.read()
udp_len=len(cmd)
uart.write('AT+CIPSEND=0,' + str(udp_len) + ',"192.168.10.1",8889\r\n')
sleep (100)
uart.read()
udp = bytes(cmd, 'utf-8')
uart.write(udp+"\r\n")
sleep(100)
timeout = 1
timer = 0
while not(uart.any()):
sleep(1)
timer += .001
if timer > timeout:
status = 'Error: timeout'
break
msg = str(uart.read())
start=msg.find(':')
end = msg.find('\\r\\n',start)
msg = msg[start+1:end]
if msg.find('Non')!=-1:
msg = '0'
uart.init(baudrate=115200)
return(msg)
except:
uart.init(baudrate=115200)
return("Error: communication")
def tello_control(cmd,TX=TX_pin,RX=RX_pin):
try:
timeout = 10
uart.init(baudrate=115200,tx=TX_pin,rx=RX_pin)
uart.read()
udp_len=len(cmd)
uart.write('AT+CIPSEND=0,' + str(udp_len) + ',"192.168.10.1",8889\r\n')
sleep(100)
uart.read()
udp = bytes(cmd, 'utf-8')
uart.write(udp)
timer = 0
sleep(100)
while not(uart.any()):
sleep(1)
timer += .001
if timer > timeout:
status ='Error: timeout'
break
msg = str(uart.read())
if msg.find('SEND OK')==-1:
uart.init(baudrate=115200)
return (False)
sleep(100)
uart.read()
timer = 0
while not(uart.any()):
sleep(1)
timer += .001
if timer > timeout:
status = 'Error: timeout'
break
sleep(100)
msg = str(uart.read())
start=msg.find('\\r\\n+IPD')
if msg.find('ok',start)!=-1:
status = "ok"
uart.init(baudrate=115200)
return(status)
except:
uart.init(baudrate=115200)
return("Error: communication link")
def tello_connect(ssid,pswd="",TX=TX_pin,RX=RX_pin):
display.show(ti)
try:
timeout = 30
global TX_pin
global RX_pin
TX_pin=locals()[TX]
RX_pin=locals()[RX]
uart.init(baudrate=115200,tx=TX_pin,rx=RX_pin)
uart.write('AT+CWQAP\r\n')
uart.write('AT+RST\r\n')
#uart.write('AT+RFPOWER=0\r\n')
uart.write('AT+CWMODE=3\r\n')
uart.read()
sleep(100)
the_ap ='AT+CWJAP=' + '"' + ssid +'"' + "," + '"' + pswd +'"\r\n'
uart.write(the_ap + '\r\n')
is_connected = False
timer = 0
sleep(100)
while is_connected == False:
timer = 0
while not(uart.any()):
sleep(1)
timer += .002
if timer > timeout:
tello_AT('AT+RST')
reset()
msg = str(uart.read())
if msg.find("WIFI GOT IP") !=-1:
is_connected = True
uart.write('AT+CIFSR\r\n')
sleep(100)
timer = 0
while not(uart.any()):
sleep(1)
timer >.002
if timer == timeout:
tello_AT('AT+RST')
reset()
msg = str(uart.read())
if msg.find("192.168.10") !=-1:
status = 'got IP'
uart.write('AT+CIPMUX=1\r\n')
sleep(100)
msg = uart.read()
uart.write('AT+CIPSTART=0,"UDP","192.168.10.1",8889,8889,2\r\n')
sleep(100)
msg = uart.read()
sleep(100)
cmd='command'
udp_len=len(cmd)
uart.write('AT+CIPSEND=0,' + str(udp_len) + ',"192.168.10.1",8889\r\n')
sleep(200)
uart.read()
udp = bytes(cmd, 'utf-8')
uart.write(udp)
msg = str(uart.read())
if msg.find('SEND OK')==-1 and status =='got IP':
status = "Tello Connected"
display.show(Image.HAPPY)
else:
status = "Tello not responding"
display.show(Image.SAD)
uart.init(baudrate=115200)
return (False)
uart.init(baudrate=115200)
#print(status)
return(status)
except:
uart.init(baudrate=115200)
display.show(Image.SAD)
return("Error: communication link")
def ismb():
return(True)
def ranger(pin=pin0,time = True):
timeout_us=30000
pin.write_digital(0)
sleep_us(2)
pin.write_digital(1)
sleep_us(10)
pin.write_digital(0)
pin.read_digital()
duration = time_pulse_us(pin, 1, timeout_us)/1e6 # t_echo in seconds
distance = 343 * duration/2 * 100
if time:
return duration
else:
return distance
# this function only works on V2
def time_pulses(pin,pulses):
try:
pin.read_digital()
# wait for one trigger pulse
while not pin.read_digital():
pass
while pin.read_digital():
pass
while not pin.read_digital():
pass
# begin timing pulses
t0=ticks_us()
for n in range(pulses-1):
while (not pin.read_digital()):
pass
while pin.read_digital():
pass
tf=ticks_us()
pulses_time = (tf-t0)/1000000
return(str(pulses_time))
except:
pass
def time_H_to_L(pin):
pin.read_digital()
while (pin.read_digital()):
pass
t0=ticks_us()
while not (pin.read_digital()):
pass
tf=ticks_us()
pulse_time = (tf-t0)/1000000
return(str(pulse_time))
def time_L_to_H(pin):
pin.read_digital()
while not (pin0.read_digital()):
pass
t0=ticks_us()
while (pin.read_digital()):
pass
tf=ticks_us()
pulse_time = (tf-t0)/1000000
return(str(pulse_time))
IDRegister = 0xD0 # ID holds 0x60, always readable
RESET = 0xE0 # Reset only executed by writing 0xB6
CTRL_HUM = 0xF2 # Selects humidity measurement and oversampling
STATUS = 0xF3 # Indicates data availability
CTRL_MEAS = 0xF4 # Temperature, pressure oversampling, selects normal, forced or sleep mode
CONFIG = 0xF5 # Controls normal mode standby time, IRR filter, SPI mode
t_fine = 0
ConfigurationData = bytearray(6)
CalData00_25 = bytearray(25)
CalData00_25BaseAddress = bytearray(1)
CalData00_25BaseAddress[0] = 0x88
CalData26_41 = bytearray(7)
CalData26_41BaseAddress = bytearray(1)
CalData26_41BaseAddress[0] = 0xE1
RawSensorData = bytearray(8)
RawSensorDataBaseAddress = bytearray(1)
RawSensorDataBaseAddress[0] = 0xF7
def BuildS16(msb, lsb):
sval = ((msb << 8) | lsb)
if sval > 32767:
sval -= 65536
return sval
def BuildU16(msb, lsb):
return ((msb << 8) |lsb)
def BuildS8(b):
if b > 127:
return (b-256)
else:
return b
def CalculateTemperature(TRAW):
global t_fine
Traw = float(TRAW)
v1 = (Traw/ 16384.0 - float(dig_T1) / 1024.0) * float(dig_T2)
v2 = ((Traw / 131072.0 - float(dig_T1) / 8192.0) * (
Traw / 131072.0 - float(dig_T1) / 8192.0)) * float(dig_T3)
t_fine = int(v1 + v2)
T = (v1 + v2) / 5120.0
return T
def CalculatePressure(PRAW):
Praw = float(PRAW)
v1 = float(t_fine) / 2.0 - 64000.0
v2 = v1 * v1 * float(dig_P6) / 32768.0
v2 = v2 + v1 * float(dig_P5) * 2.0
v2 = v2 / 4.0 + float(dig_P4) * 65536.0
v1 = (float(dig_P3) * v1 * v1 / 524288.0 + float(dig_P2) * v1) / 524288.0
v1 = (1.0 + v1 / 32768.0) * float(dig_P1)
if v1 == 0:
return 0
p = 1048576.0 - Praw
p = ((p - v2 / 4096.0) * 6250.0) / v1
v1 = float(dig_P9) * p * p / 2147483648.0
v2 = p * float(dig_P8) / 32768.0
p = p + (v1 + v2 + float(dig_P7)) / 16.0
return p
def CalculateHumidity(HRAW):
global t_fine
Hraw = float(HRAW)
h = float(t_fine) - 76800.0
h = (Hraw - (float(dig_H4) * 64.0 + float(dig_H5) / 16384.0 * h)) * (
float(dig_H2) / 65536.0 * (1.0 + float(dig_H6) / 67108864.0 * h * (
1.0 + float(dig_H3) / 67108864.0 * h)))
h = h * (1.0 - float(dig_H1) * h / 524288.0)
if h > 100:
h = 100
elif h < 0:
h = 0
return h
try:
IDAddress = bytearray(1)
IDAddress[0] = IDRegister
i2c.write(0x76, IDAddress, repeat = False)
id = i2c.read(0x76, 1, repeat = False)
i2c.write(0x76, CalData00_25BaseAddress, repeat = False) # Send base address
CalData00_25 = i2c.read(0x76, 25, repeat = False)
i2c.write(0x76, CalData26_41BaseAddress, repeat = False) # Send base address
CalData26_41 = i2c.read(0x76, 7, repeat = False)
dig_T1 = BuildU16(CalData00_25[1], CalData00_25[0]) # unsigned short
dig_T2 = BuildS16(CalData00_25[3], CalData00_25[2]) # signed short
dig_T3 = BuildS16(CalData00_25[5], CalData00_25[4]) # signed short
dig_P1 = BuildU16(CalData00_25[7], CalData00_25[6]) # unsigned short
dig_P2 = BuildS16(CalData00_25[9], CalData00_25[8]) # signed short
dig_P3 = BuildS16(CalData00_25[11], CalData00_25[10]) # signed short
dig_P4 = BuildS16(CalData00_25[13], CalData00_25[12]) # signed short
dig_P5 = BuildS16(CalData00_25[15], CalData00_25[14]) # signed short
dig_P6 = BuildS16(CalData00_25[17], CalData00_25[16]) # signed short
dig_P7 = BuildS16(CalData00_25[19], CalData00_25[18]) # signed short
dig_P8 = BuildS16(CalData00_25[21], CalData00_25[20]) # signed short
dig_P9 = BuildS16(CalData00_25[23], CalData00_25[22]) # signed short
dig_H1 = CalData00_25[24] # unsigned char
dig_H2 = BuildS16(CalData26_41[1],CalData26_41[0])
dig_H3 = CalData26_41[2]
dig_H4 = (BuildS8(CalData26_41[3]) << 4) | (CalData26_41[4] & 0x0F) # signed short presented in 12 bits
dig_H5 = (BuildS8(CalData26_41[5]) << 4) | ((CalData26_41[4] >> 4) & 0x0F) # signed short presented in 12 bits
dig_H6 = BuildS8(CalData26_41[6]) # signed char
ConfigurationData[0] = CTRL_HUM # Register address
ConfigurationData[1] = 0b00000101 # Hunidity sampling on: x16
ConfigurationData[2] = CTRL_MEAS # Register address
ConfigurationData[3] = 0b10110111 # Temperature and pressure x16, normal mode
ConfigurationData[4] = CONFIG # Register address
ConfigurationData[5] = 0b01000000 # Normal mode standby 125ms, IRR off, SPI irrelevant
i2c.write(0x76,ConfigurationData, repeat=False)
except:
pass
# the Grove bme_280 has the SDO pulled low and the address is 0x76. Pulling high changes to 0x77. Adafruit is 0x77
def read_bme280():
i2c.write(0x76, RawSensorDataBaseAddress, repeat = False)
RawSensorData = i2c.read(0x76, 8, repeat = False)
TRAW = ((RawSensorData[3] << 16) | (RawSensorData[4] << 8) | RawSensorData[5]) >> 4
PRAW = ((RawSensorData[0] << 16) | (RawSensorData[1] << 8) | RawSensorData[2]) >> 4
HRAW = (RawSensorData[6] << 8) | RawSensorData[7]
return CalculateTemperature(TRAW),CalculatePressure(PRAW),CalculateHumidity(HRAW)
def get_version():
print ("TI-Runtime Version 2.1.0")
display.show(ti)
- Code: Select all
from microbit import *
from machine import freq, reset, time_pulse_us
from time import ticks_us, sleep_ms
from utime import sleep_us
# ------------------------------------------- Tello Drone -----------------------------------------------------------
#tello="TELLO-9EF498"
TX_pin = 'pin1' # yellow grove wire
RX_pin = 'pin15' # white grove wire
is_connected = False
def tello_read(cmd,TX=TX_pin,RX=RX_pin):
try:
uart.init(baudrate=115200,tx=TX_pin,rx=RX_pin)
uart.read()
udp_len=len(cmd)
uart.write('AT+CIPSEND=0,' + str(udp_len) + ',"192.168.10.1",8889\r\n')
sleep (100)
uart.read()
udp = bytes(cmd, 'utf-8')
uart.write(udp+"\r\n")
sleep(100)
timeout = 1
timer = 0
while not(uart.any()):
sleep(1)
timer += .001
if timer > timeout:
status = 'Error: timeout'
break
msg = str(uart.read())
start=msg.find(':')
end = msg.find('\\r\\n',start)
msg = msg[start+1:end]
if msg.find('Non')!=-1:
msg = '0'
uart.init(baudrate=115200)
return(msg)
except:
uart.init(baudrate=115200)
return(False)
def tello_control(cmd,TX=TX_pin,RX=RX_pin):
try:
timeout = 10
uart.init(baudrate=115200,tx=TX_pin,rx=RX_pin)
uart.read()
udp_len=len(cmd)
uart.write('AT+CIPSEND=0,' + str(udp_len) + ',"192.168.10.1",8889\r\n')
sleep(100)
uart.read()
udp = bytes(cmd, 'utf-8')
uart.write(udp)
timer = 0
sleep(100)
while not(uart.any()):
sleep(1)
timer += .001
if timer > timeout:
status ='Error: timeout'
break
msg = str(uart.read())
if msg.find('SEND OK')==-1:
uart.init(baudrate=115200)
return (False)
sleep(100)
uart.read()
timer = 0
while not(uart.any()):
sleep(1)
timer += .001
if timer > timeout:
status = 'Error: timeout'
break
sleep(100)
msg = str(uart.read())
start=msg.find('\\r\\n+IPD')
if msg.find('ok',start)!=-1:
status = "ok"
uart.init(baudrate=115200)
#print("ok")
#sleep(100)
#print("ok")
#sleep(100)
return(status)
except:
uart.init(baudrate=115200)
return(False)
def tello_connect(ssid,pswd="",TX=TX_pin,RX=RX_pin):
#display.show(ti)
try:
timeout = 30
global TX_pin
global RX_pin
TX_pin=locals()[TX]
RX_pin=locals()[RX]
uart.init(baudrate=115200,tx=TX_pin,rx=RX_pin)
#uart.write('AT+CWQAP\r\n')
uart.write('AT+RST\r\n')
#uart.write('AT+RESTORE\r\n')
uart.write('AT+RFPOWER=30\r\n')
uart.write('AT+CWMODE=3\r\n')
uart.read()
#sleep(100)
the_ap ='AT+CWJAP=' + '"' + ssid +'"' + "," + '"' + pswd +'"\r\n'
uart.write(the_ap + '\r\n')
is_connected = False
timer = 0
sleep(100)
while is_connected == False:
timer = 0
while not(uart.any()):
sleep(1)
timer += .002
if timer > timeout:
tello_AT('AT+RST\r\n')
reset()
msg = str(uart.read())
if msg.find("WIFI GOT IP") !=-1:
is_connected = True
uart.write('AT+CIFSR\r\n')
sleep(100)
timer = 0
while not(uart.any()):
sleep(1)
timer >.002
if timer == timeout:
tello_AT('AT+RST')
reset()
msg = str(uart.read())
if msg.find("192.168.10") !=-1:
status = 'got IP'
uart.write('AT+CIPMUX=1\r\n')
sleep(100)
msg = uart.read()
uart.write('AT+CIPSTART=0,"UDP","192.168.10.1",8889,8889,2\r\n')
sleep(100)
msg = uart.read()
sleep(100)
cmd='command'
udp_len=len(cmd)
uart.write('AT+CIPSEND=0,' + str(udp_len) + ',"192.168.10.1",8889\r\n')
sleep(200)
uart.read()
udp = bytes(cmd, 'utf-8')
uart.write(udp)
msg = str(uart.read())
if msg.find('SEND OK')==-1 and status =='got IP':
status = "Tello Connected"
display.show(Image.HAPPY)
else:
status = "Tello not responding"
display.show(Image.SAD)
uart.init(baudrate=115200)
return (False)
uart.init(baudrate=115200)
#print(status)
return(status)
except:
uart.init(baudrate=115200)
display.show(Image.SAD)
return(False)
def discover_tello(TX_pin,RX_pin):
count = 0
uart.init(baudrate=115200,tx=TX_pin,rx=RX_pin)
uart.write('AT+CWLAPOPT=1,2\r\n')
while count < 15:
uart.write('AT+CWLAP\r\n')
while not(uart.any()):
sleep(10)
uart.read()
sleep(1000)
msg = str(uart.read())
start=msg.find('TELLO')
if start != -1:
end = msg.find('"',start)
msg = msg[start:end]
uart.init(baudrate=115200)
return(msg)
else:
count += 1
uart.init(baudrate=115200)
return(False)
def write_tello_setup(ssid,tx,rx,number):
try:
cfg=open('tello.cfg','w')
cfg.write(ssid + "@" + tx + "$" + rx + "%" + number)
cfg.close()
return(True)
except:
print (False)
def read_tello_setup():
cfg=open('tello.cfg','r')
msg = cfg.read()
d1 = msg.find('@')
d2 = msg.find('$')
d3 = msg.find('%')
ssid = msg[:d1]
tx = msg[d1+1:d2]
rx = msg[d2+1:d3]
number = msg[d3+1:]
display.show(number)
return ssid, tx,rx, number
# ------------------------------------------- ultrasonic ranger -----------------------------------------------------------
def ranger(pin=pin0,time = True):
timeout_us=30000
pin.write_digital(0)
sleep_us(2)
pin.write_digital(1)
sleep_us(10)
pin.write_digital(0)
pin.read_digital()
duration = time_pulse_us(pin, 1, timeout_us)/1e6 # t_echo in seconds
distance = 343 * duration/2 * 100
if time:
return duration
else:
return distance
# ------------------------------------------- pulse timer ----------------------------------------------------------------
def time_pulses(pin,pulses):
try:
pin.read_digital()
# wait for one trigger pulse
while not pin.read_digital():
pass
while pin.read_digital():
pass
while not pin.read_digital():
pass
# begin timing pulses
t0=ticks_us()
for n in range(pulses-1):
while (not pin.read_digital()):
pass
while pin.read_digital():
pass
tf=ticks_us()
pulses_time = (tf-t0)/1000000
return(str(pulses_time))
except:
pass
def time_H_to_L(pin):
pin.read_digital()
while (pin.read_digital()):
pass
t0=ticks_us()
while not (pin.read_digital()):
pass
tf=ticks_us()
pulse_time = (tf-t0)/1000000
return(str(pulse_time))
def time_L_to_H(pin):
pin.read_digital()
while not (pin0.read_digital()):
pass
t0=ticks_us()
while (pin.read_digital()):
pass
tf=ticks_us()
pulse_time = (tf-t0)/1000000
return(str(pulse_time))
# -------------------------------------------BME280 Barometric Pressure -----------------------------------------------------------
class BME280():
def __init__(self):
self.ready = False
self.IDRegister = 0xD0
self.CTRL_HUM = 0xF2
self.CTRL_MEAS = 0xF4
self.CONFIG = 0xF5
self.t_fine = 0
self.dig_T1 = 0
self.dig_T2 = 0
self.dig_T3 = 0
self.dig_P1 = 0
self.dig_P2 = 0
self.dig_P3 = 0
self.dig_P4 = 0
self.dig_P5 = 0
self.dig_P6 = 0
self.dig_P7 = 0
self.dig_P8 = 0
self.dig_P9 = 0
self.dig_H1 = 0
self.dig_H2 = 0
self.dig_H3 = 0
self.dig_H4 = 0
self.dig_H5 = 0
self.dig_H6 = 0
self.TRAW = 0
self.PRAW = 0
self.HRAW = 0
self.ConfigurationData = bytearray(6)
self.CalData00_25 = bytearray(25)
self.CalData00_25BaseAddress = bytearray(1)
self.CalData00_25BaseAddress[0] = 0x88
self.CalData26_41 = bytearray(7)
self.CalData26_41BaseAddress = bytearray(1)
self.CalData26_41BaseAddress[0] = 0xE1
self.RawSensorData = bytearray(8)
self.RawSensorDataBaseAddress = bytearray(1)
self.RawSensorDataBaseAddress[0] = 0xF7
def init(self):
try:
IDAddress = bytearray(1)
IDAddress[0] = self.IDRegister
i2c.write(0x76, IDAddress, repeat = False)
id = i2c.read(0x76, 1, repeat = False)
i2c.write(0x76, self.CalData00_25BaseAddress, repeat = False)
self.CalData00_25 = i2c.read(0x76, 25, repeat = False)
i2c.write(0x76, self.CalData26_41BaseAddress, repeat = False)
self.CalData26_41 = i2c.read(0x76, 7, repeat = False)
self.dig_T1 = self.BuildU16(self.CalData00_25[1], self.CalData00_25[0])
self.dig_T2 = self.BuildS16(self.CalData00_25[3], self.CalData00_25[2])
self.dig_T3 = self.BuildS16(self.CalData00_25[5], self.CalData00_25[4])
self.dig_P1 = self.BuildU16(self.CalData00_25[7], self.CalData00_25[6])
self.dig_P2 = self.BuildS16(self.CalData00_25[9], self.CalData00_25[8])
self.dig_P3 = self.BuildS16(self.CalData00_25[11], self.CalData00_25[10])
self.dig_P4 = self.BuildS16(self.CalData00_25[13], self.CalData00_25[12])
self.dig_P5 = self.BuildS16(self.CalData00_25[15], self.CalData00_25[14])
self.dig_P6 = self.BuildS16(self.CalData00_25[17], self.CalData00_25[16])
self.dig_P7 = self.BuildS16(self.CalData00_25[19], self.CalData00_25[18])
self.dig_P8 = self.BuildS16(self.CalData00_25[21], self.CalData00_25[20])
self.dig_P9 = self.BuildS16(self.CalData00_25[23], self.CalData00_25[22])
self.dig_H1 = self.CalData00_25[24]
self.dig_H2 = self.BuildS16(self.CalData26_41[1],self.CalData26_41[0])
self.dig_H3 = self.CalData26_41[2]
self.dig_H4 = (self.BuildS8(self.CalData26_41[3]) << 4) | (self.CalData26_41[4] & 0x0F)
self.dig_H5 = (self.BuildS8(self.CalData26_41[5]) << 4) | ((self.CalData26_41[4] >> 4) & 0x0F)
self.dig_H6 = self.BuildS8(self.CalData26_41[6])
self.ConfigurationData[0] = self.CTRL_HUM
self.ConfigurationData[1] = 0b00000101
self.ConfigurationData[2] = self.CTRL_MEAS
self.ConfigurationData[3] = 0b10110111
self.ConfigurationData[4] = self.CONFIG
self.ConfigurationData[5] = 0b01000000
i2c.write(0x76,self.ConfigurationData, repeat=False)
sleep(100)
self.ready = True
except:
pass
def BuildS16(self,msb, lsb):
sval = ((msb << 8) | lsb)
if sval > 32767:
sval -= 65536
return sval
def BuildU16(self,msb, lsb):
return ((msb << 8) |lsb)
def BuildS8(self,b):
if b > 127:
return (b-256)
else:
return b
def CalculateTemperature(self):
self.t_fine
Traw = float(self.TRAW)
v1 = (Traw/ 16384.0 - float(self.dig_T1) / 1024.0) * float(self.dig_T2)
v2 = ((Traw / 131072.0 - float(self.dig_T1) / 8192.0) * (
Traw / 131072.0 - float(self.dig_T1) / 8192.0)) * float(self.dig_T3)
self.t_fine = int(v1 + v2)
T = (v1 + v2) / 5120.0
return T
def CalculatePressure(self):
Praw = float(self.PRAW)
v1 = float(self.t_fine) / 2.0 - 64000.0
v2 = v1 * v1 * float(self.dig_P6) / 32768.0
v2 = v2 + v1 * float(self.dig_P5) * 2.0
v2 = v2 / 4.0 + float(self.dig_P4) * 65536.0
v1 = (float(self.dig_P3) * v1 * v1 / 524288.0 + float(self.dig_P2) * v1) / 524288.0
v1 = (1.0 + v1 / 32768.0) * float(self.dig_P1)
if v1 == 0:
return 0
p = 1048576.0 - Praw
p = ((p - v2 / 4096.0) * 6250.0) / v1
v1 = float(self.dig_P9) * p * p / 2147483648.0
v2 = p * float(self.dig_P8) / 32768.0
p = p + (v1 + v2 + float(self.dig_P7)) / 16.0
return p
def CalculateHumidity(self):
self.t_fine
Hraw = float(self.HRAW)
h = float(self.t_fine) - 76800.0
h = (Hraw - (float(self.dig_H4) * 64.0 + float(self.dig_H5) / 16384.0 * h)) * (
float(self.dig_H2) / 65536.0 * (1.0 + float(self.dig_H6) / 67108864.0 * h * (
1.0 + float(self.dig_H3) / 67108864.0 * h)))
h = h * (1.0 - float(self.dig_H1) * h / 524288.0)
if h > 100:
h = 100
elif h < 0:
h = 0
return h
def read(self):
if self.ready:
try:
i2c.write(0x76, self.RawSensorDataBaseAddress, repeat = False)
sleep(100)
self.RawSensorData = i2c.read(0x76, 8, repeat = False)
sleep(100)
self.TRAW = ((self.RawSensorData[3] << 16) | (self.RawSensorData[4] << 8) | self.RawSensorData[5]) >> 4
self.PRAW = ((self.RawSensorData[0] << 16) | (self.RawSensorData[1] << 8) | self.RawSensorData[2]) >> 4
self.HRAW = (self.RawSensorData[6] << 8) | self.RawSensorData[7]
return self.CalculateTemperature(),self.CalculatePressure(),self.CalculateHumidity()
except:
pass
else:
self.init()
if self.ready:
return (self.read())
else:
return None
# -------------------------------------------DHT20 Temperature and Humidity -----------------------------------------------------------
class DHT20():
def __init__(self):
self.ready = False
def init(self):
try:
i2c.write(0x38, bytes([0xa8,0x00,0x00]))
sleep_ms(100)
i2c.write(0x38, bytes([0xbe,0x08,0x00]))
sleep(100)
self.ready = True
except:
pass
def read(self):
if self.ready:
try:
i2c.write(0x38, bytes([0xac,0x33,0x00]))
sleep(100)
raw = i2c.read(0x38, 7, True)
sleep(100)
data = []
for i in raw[:]:
data.append(i)
temperature = 0
temperature = (temperature | data[3]) << 8
temperature = (temperature | data[4]) << 8
temperature = temperature | data[5]
temperature = temperature & 0xfffff
temperature = (temperature * 200 * 10 / 1024 / 1024 - 500)/10
humidity = 0
humidity = (humidity | data[1]) << 8
humidity = (humidity | data[2]) << 8
humidity = humidity | data[3]
humidity = humidity >> 4
humidity = (humidity * 100 * 10 / 1024 / 1024)/10
return temperature, humidity
except:
pass
else:
self.init()
if self.ready:
return (self.read())
else:
return None
# -------------------------------------------SGP30 VOC and CO2 -----------------------------------------------------------
class SGP30:
def __init__(self):
self.ready = False
def init(self):
try:
i2c.write(0x58,bytes([0x36, 0x82]))
self.iaq_init()
self.ready = True
except:
pass
def TVOC(self):
return self.iaq_measure()[1]
def baseline_TVOC(self):
return self.get_iaq_baseline()[1]
def eCO2(self):
return self.iaq_measure()[0]
def baseline_eCO2(self):
return self.get_iaq_baseline()[0]
def iaq_init(self):
self.run(['iaq_init',[0x20,0x03],0,10])
def iaq_measure(self):
return self.run(['iaq_measure',[0x20,0x08],2,50])
def get_iaq_baseline(self):
return self.run(['iaq_get_baseline',[0x20,0x15],2,10])
def set_iaq_baseline(self,eCO2,TVOC):
if eCO2==0 and TVOC==0:raise RuntimeError('Invalid baseline')
b=[]
for i in [TVOC,eCO2]:
a=[i>>8,i&0xFF]
a.append(self.g_crc(a))
b+=a
self.run(['iaq_set_baseline',[0x20,0x1e]+b,0,10])
def set_iaq_humidity(self,PM3):
b=[]
for i in [int(PM3*256)]:
a=[i>>8,i&0xFF]
a.append(self.g_crc(a))
b+=a
self.run(['iaq_set_humidity',[0x20,0x61]+b,0,10])
def run(self,profile):
n,cmd,s,d=profile
return self.get(cmd,d,s)
def get(self,cmd,d,rs):
i2c.write(0x58,bytearray(cmd))
sleep(d)
if not rs:return None
cr=i2c.read(0x58,rs*3)
o=[]
for i in range(rs):
w=[cr[3*i],cr[3*i+1]]
c=cr[3*i+2]
if self.g_crc(w)!=c:raise RuntimeError('CRC Error')
o.append(w[0]<<8|w[1])
return o
def g_crc(self,data):
c=0xFF
for byte in data:
c^=byte
for _ in range(8):
if c&0x80:c=(c<<1)^0x31
else:c<<=1
return c&0xFF
def read(self):
if self.ready:
try:
return self.eCO2(), self.TVOC()
except:
pass
else:
self.init()
if self.ready:
return (self.read())
else:
return None
# ------------------------------------------- start up -----------------------------------------------------------
def ismb():
return(True)
def get_version():
print ("TI-Runtime Version 2.4.0")
bme280 = BME280()
dht20 = DHT20()
sgp30 = SGP30()
ti = Image("05500:""05595:""55555:""05550:""00500")
display.show(ti)


Dans sa version précédente 2.1.0, le TI-Runtime contenait 2 images pour l'afficheur de la carte BBC micro:bit :
- le logo Texas Instruments :
Image("05500:""05595:""55555:""05550:""00500")
- et une coche qui n'était pas utilisée puisque laissée en commentaire :
Image("00000:""00009:""00090:""90900:""09000")
On peut remarquer effectivement l'ajout du support des capteurs SGP30 et DHT20 évoqués plus haut, mais également pas mal de changements concernant le capteur BME280. Peut-être une amélioration du support de ce dernier.
Mais surtout, grande découverte. Nous l'avions raté, mais la version 2.1.0 précédente comportait 3 fonctions partageant le nom tello :
tello_connect(ssid,pswd="",TX=TX_pin,RX=RX_pin)
tello_control(cmd,TX=TX_pin,RX=RX_pin)
tello_read(cmd,TX=TX_pin,RX=RX_pin)
read_tello_setup()
write_tello_setup(ssid,tx,rx,number)
discover_tello(TX_pin,RX_pin)

Dans une prochaine mise à jour tu devrais donc pouvoir piloter le drone Tello en Python directement depuis ta calculatrice Texas Instruments via la carte BBC micro:bit, pour des projets encore plus extraordinaires et ambitieux !

Téléchargements
Go to top- TI-Runtime :
- bibliothèques Python complémentaires :
- 2.3.0 Français pour TI-83 Premium CE Edition Python, TI-84 Plus CE-T Python Edition ou TI-84 Plus CE Python avec BBC microbit v1/v2
- 2.1.0 English pour TI-83 Premium CE Edition Python, TI-84 Plus CE-T Python Edition ou TI-84 Plus CE Python avec BBC microbit v2
- 1.0.0 English pour TI-83 Premium CE Edition Python, TI-84 Plus CE-T Python Edition ou TI-84 Plus CE Python avec BBC microbit v1
- 2.34 Français English pour TI-Nspire CX II avec BBC microbit v1/v2
Source : https://resources.t3france.fr/t3france?resource_id=3078