Diferència entre revisions de la pàgina «API de Python per a l'IoT-Vertebrae»

De binefa.com
Salta a la navegació Salta a la cerca
 
(Hi ha 75 revisions intermèdies del mateix usuari que no es mostren)
Línia 1: Línia 1:
Hi ha dos arxius per a interactuar en Python des de la Raspberry Pi amb l'IoT-Vertebrae: '''i2c_iotv.py''' (iotv.py) i '''can_iotv.py'''.
+
Hi ha dues biblioteques per a interactuar en Python des de la Raspberry Pi amb l'IoT-Vertebrae: '''i2c_iotv.py''' (abans ''iotv.py'') i '''can_iotv.py'''.
  
'''i2c_iotv.py''': funciona amb qualsevol versió de cap. Es comunica mitjançant I2C.
+
'''can_iotv.py''': funciona a partir de la [[Cap (Head v2.0) - IoT-Vertebrae|versió 2.0 del cap]]. Es comunica mitjançant el bus CAN, això permet controlar vèrtebres connectades remotament a una cua.
  
'''can_iotv.py''': funciona a partir de la versó 2.0 del cap. Es comunica mitjançant el bus CAN, això permet controlar vèrtebres connectades remotament a una cua.
+
'''i2c_iotv.py''': funciona amb qualsevol versió de cap. Es comunica mitjançant el bus I2C.
 
= Ús de les biblioteques des del terminal =
 
= Ús de les biblioteques des del terminal =
 
== Ús de ''can_iotv.py'' des del terminal ==
 
== Ús de ''can_iotv.py'' des del terminal ==
Fent servir el bus CAN cal obrir-ho al principi i podem tancar-ho al final. L'obertura i tancament del bus CAN es fa mitjançant ordres de terminal (molt més lentes d'executar que les instruccions Python). En canvi, l'obertura i tancament del bus I2C es fa mitjançant instruccions de Python.
+
Cal obrir el bus CAN cal al principi del codi i podem tancar-ho al final. L'obertura i tancament del bus CAN es fa mitjançant ordres de terminal (molt més lentes d'executar que les instruccions Python).
 +
 
 
  pi@raspberrypi:~ $ '''python'''
 
  pi@raspberrypi:~ $ '''python'''
 
  Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] on linux
 
  Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] on linux
Línia 19: Línia 20:
 
  >>>  
 
  >>>  
 
  pi@raspberrypi:~ $
 
  pi@raspberrypi:~ $
 +
 
== Ús de ''i2c_iotv.py'' des del terminal ==
 
== Ús de ''i2c_iotv.py'' des del terminal ==
No cal obrir el bus I2C al principi i tancar-ho al final perquè cada funció l'obre i el tanca.  
+
No cal obrir el bus I2C al principi i tancar-ho al final perquè cada funció l'obre i el tanca mitjançant instruccions de Python.  
 
  pi@raspberrypi:~ $ '''python'''
 
  pi@raspberrypi:~ $ '''python'''
 
  Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] on linux
 
  Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] on linux
Línia 33: Línia 35:
 
  >>>  
 
  >>>  
 
  pi@raspberrypi:~ $
 
  pi@raspberrypi:~ $
 +
 +
= canOn() =
 +
'''Obertura del bus CAN''' (tan sols té sentit amb el paquet ''can_iotv''. No pas amb el paquet ''i2c_iotv''):
 +
>>> '''iotv.canOn()'''
 +
Es posa a l'inici de qualsevol programa que vulgui fer servir el paquet ''can_iotv''. Aquesta funció tramet al sistema aquesta ordre de terminal:
 +
''sudo ip link set up can0 type can bitrate 100000''
 +
 +
= canOff() =
 +
'''Tancament del bus CAN''' (tan sols té sentit amb el paquet ''can_iotv''. No pas amb el paquet ''i2c_iotv''):
 +
>>> '''iotv.canOff()'''
 +
Es pot posar al final de qualsevol programa que vulgui fer servir el paquet ''can_iotv''. Aquesta funció tramet al sistema aquesta ordre de terminal:
 +
''sudo ifconfig can0 down''
 +
 
= dversion(''addr'') =
 
= dversion(''addr'') =
 
L'argument ''addr'' és l'adreça de la vèrtebra digital expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'[[Vertebra_digital_(dvert2_v2.1)_-_IoT-Vertebrae#Configuracions |explicació de les adreces de la vèrtebra digital]].
 
L'argument ''addr'' és l'adreça de la vèrtebra digital expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'[[Vertebra_digital_(dvert2_v2.1)_-_IoT-Vertebrae#Configuracions |explicació de les adreces de la vèrtebra digital]].
Línia 48: Línia 63:
 
L'argument ''addr'' és l'adreça de la vèrtebra analògica expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'[[Vertebra analògica (avert2 v2.1) - IoT-Vertebrae#Configuracions |explicació de les adreces de la vèrtebra analògica]].
 
L'argument ''addr'' és l'adreça de la vèrtebra analògica expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'[[Vertebra analògica (avert2 v2.1) - IoT-Vertebrae#Configuracions |explicació de les adreces de la vèrtebra analògica]].
  
Retorna la versió de microprogramari (''firmware'') de la vèrtebra amb l'adreça passada com a argument.
+
Retorna la '''versió de microprogramari (''firmware'') de la vèrtebra amb l'adreça passada com a argument'''.
 +
 
 
* can_iotv:
 
* can_iotv:
 
  >>> '''iotv.aversion("0000")'''
 
  >>> '''iotv.aversion("0000")'''
Línia 56: Línia 72:
 
  Analog rib version: 1.3
 
  Analog rib version: 1.3
 
  '0000000100000011'
 
  '0000000100000011'
 +
= getdsetup(''addr'') =
 +
L'argument ''addr'' és l'adreça de la vèrtebra digital expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'[[Vertebra_digital_(dvert2_v2.1)_-_IoT-Vertebrae#Configuracions |explicació de les adreces de la vèrtebra digital]].
 +
 +
Retorna la '''configuració de la vèrtebra digital amb l'adreça passada com a argument'''. Les vèrtebres digitals s'han de configurar amb la funció ''dsetup(addr, modeA, modeB)'' per a indicar que es connecta a cada costat.
 +
 +
* can_iotv:
 +
>>> '''iotv.getdsetup("0000")'''
 +
'A:dout, B:din'
 +
* i2c_iotv:
 +
>>> '''iotv.getdsetup("0000")'''
 +
A digital output, B digital input
 +
'00010010'
 +
 +
Configuracions possibles als dos costats ('''A''' i '''B'''):
 +
 +
'''ain''': Entrades digitals al costat '''A'''
 +
 +
'''aout''': Sortides digitals al costat '''A'''
 +
 +
'''aoutpwm''': Sortides digitals per modulació de pols (''PWM'') al costat '''A'''. Si hi ha ''aoutpwm'' no pot haver ''boutpwm'' (limitació pròpia de l'ESP32-S3).
 +
 +
'''bin''': Entrades digitals al costat '''B'''
 +
 +
'''bout''': Sortides digitals al costat '''B'''
 +
 +
'''boutpwm''': Sortides digitals per modulació de pols (''PWM'') al costat '''B'''. Si hi ha ''boutpwm'' no pot haver ''aoutpwm'' (limitació pròpia de l'ESP32-S3).
 +
 +
'''bintouch''': Entrades tàctils al costat '''B'''. No existeix ''aintouch'' perquè el maquinari no ho permet.
 +
 +
= getasetup(''addr'') =
 +
L'argument ''addr'' és l'adreça de la vèrtebra analògica expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'[[Vertebra analògica (avert2 v2.1) - IoT-Vertebrae#Configuracions |explicació de les adreces de la vèrtebra analògica]].
 +
 +
Retorna la '''configuració de la vèrtebra analògica amb l'adreça passada com a argument'''. Les vèrtebres analògiques no cal configurar-les, després del reset fan la lectura del que hi ha connectat a cada costat (ADC i/o DAC).
 +
 +
* can_iotv:
 +
>>> '''iotv.getasetup("0000")'''
 +
'A:ain, B:aout'
 +
* i2c_iotv:
 +
>>> '''iotv.getasetup("0000")'''
 +
respA: 0x1, respB: 0x2
 +
A rib is ADC, B rib is DAC.
 +
'00010010'
 +
= dsetup(''addr'',''modeA'',''modeB'') =
 +
L'argument ''addr'' és l'adreça de la vèrtebra digital expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'[[Vertebra_digital_(dvert2_v2.1)_-_IoT-Vertebrae#Configuracions |explicació de les adreces de la vèrtebra digital]].
 +
 +
L'argument ''modeA'' pot ser: '''ain''', '''aout''' o '''aoutpwm'''
 +
 +
L'argument ''modeB'' pot ser: '''bin''', '''bout''', '''boutpwm''' o '''bintouch'''
 +
 +
* can_iotv: <-- '''CAL VERIFICAR SI FUNCIONA COM S'ESPERA'''
 +
>>> '''iotv.dsetup('0000','aout','bin')'''
 +
a: aout, b: bin
 +
'A:dout, B:din'
 +
* i2c_iotv:
 +
>>> '''iotv.dsetup('0000','ain','bout')'''
 +
ain, bout
 +
True
 +
 +
Configuracions possibles als dos costats ('''A''' i '''B'''):
 +
 +
'''ain''': Entrades digitals al costat '''A'''
 +
 +
'''aout''': Sortides digitals al costat '''A'''
 +
 +
'''aoutpwm''': Sortides digitals per modulació de pols (''PWM'') al costat '''A'''. Si hi ha ''aoutpwm'' no pot haver ''boutpwm'' (limitació pròpia de l'ESP32-S3).
 +
 +
'''bin''': Entrades digitals al costat '''B'''
 +
 +
'''bout''': Sortides digitals al costat '''B'''
 +
 +
'''boutpwm''': Sortides digitals per modulació de pols (''PWM'') al costat '''B'''. Si hi ha ''boutpwm'' no pot haver ''aoutpwm'' (limitació pròpia de l'ESP32-S3).
 +
 +
'''bintouch''': Entrades tàctils al costat '''B'''. No existeix ''aintouch'' perquè el maquinari no ho permet.
 +
= dout(''addr'',''side'',''value'') =
 +
Funció a les dues  biblioteques '''i2c_iotv''' i '''can_iotv'''. La configuració de la vèrtebra ha de ser coherent (el costat i el tipus han de coincidir: '''aout''' pel costat '''A''' o '''bout''' pel costat '''B''').
 +
 +
L'argument ''addr'' és l'adreça de la vèrtebra digital expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'[[Vertebra_digital_(dvert2_v2.1)_-_IoT-Vertebrae#Configuracions |explicació de les adreces de la vèrtebra digital]].
 +
 +
L'argument ''side'' és ''''A'''' o ''''B''''.
 +
 +
L'argument ''value'' és 0 o 1.
 +
 +
>>> '''iotv.dout('0000','A',0xFF)''' # Es tramet 0xFF (11111111) al costat '''A''' de la vèrtebra digital amb adreça '0000'
 +
>>> iotv.'''dout'''('0000','A',0x5A) # Es tramet 0x5A (01011010) al costat '''A''' de la vèrtebra digital amb adreça '0000'
 +
>>> iotv.'''dout'''('0000','A',0xA5) # Es tramet 0xA5 (10100101) al costat '''A''' de la vèrtebra digital amb adreça '0000'
 +
>>> iotv.'''dout'''('0000','A',0x00) # Es tramet 0x00 (00000000) al costat '''A''' de la vèrtebra digital amb adreça '0000'
 +
= din(''addr'', ''side'') =
 +
Funció a les dues  biblioteques '''i2c_iotv''' i '''can_iotv'''. La configuració de la vèrtebra ha de ser coherent (el costat i el tipus han de coincidir: '''ain''' pel costat '''A''' o '''bin''' pel costat '''B''').
 +
 +
L'argument ''addr'' és l'adreça de la vèrtebra digital expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'[[Vertebra_digital_(dvert2_v2.1)_-_IoT-Vertebrae#Configuracions |explicació de les adreces de la vèrtebra digital]].
 +
 +
L'argument ''side'' és ''''A'''' o ''''B''''.
 +
>>> iotv.'''din'''('0000','B')
 +
'00100100'
 +
 +
= doutbit(''addr'', ''side'', ''posbyte'', ''value'') =
 +
Funció a les dues  biblioteques '''i2c_iotv''' i '''can_iotv'''. La configuració de la vèrtebra ha de ser coherent (el costat i el tipus han de coincidir: '''aout''' pel costat '''A''' o '''bout''' pel costat '''B''').
 +
 +
L'argument ''addr'' és l'adreça de la vèrtebra digital expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'[[Vertebra_digital_(dvert2_v2.1)_-_IoT-Vertebrae#Configuracions |explicació de les adreces de la vèrtebra digital]].
 +
 +
L'argument ''side'' és ''''A'''' o ''''B''''.
 +
 +
L'argument ''posbyte'' és un valor entre 0 i 7.
 +
 +
L'argument ''value'' és 0 o 1.
 +
 +
Un exemple d'ús:
 +
for i in range(10):
 +
    for bit in range(8):
 +
        iotv.'''doutbit'''('0000','A',bit,1)
 +
        sleep(.05)
 +
        iotv.'''doutbit'''('0000','A',bit,0)
 +
 +
= doutbitpwm(''addr'', ''side'', ''posbyte'', ''value'') =
 +
Funció de la biblioteca '''i2c_iotv'''. La configuració de la vèrtebra ha de ser coherent (el costat i el tipus han de coincidir: '''aoutpwm''' pel costat '''A''' o '''boutpwm''' pel costat '''B''').
 +
 +
L'argument ''addr'' és l'adreça de la vèrtebra digital expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'[[Vertebra_digital_(dvert2_v2.1)_-_IoT-Vertebrae#Configuracions |explicació de les adreces de la vèrtebra digital]].
 +
 +
L'argument ''side'' és ''''A'''' o ''''B''''.
 +
 +
L'argument ''posbyte'' és un valor entre 0 i 7.
 +
 +
L'argument ''value'' és un valor entre 0 i 255.
 +
= v2aout(''voltage0_10'') =
 +
Funció '''convertidora de tensió del ventall de 0V a 10V al ventall de 0 a 4095''' per al convertidor digital a analògic (DAC) de 12 bits. En cas que el valor a retornar sigui superior a 4095 retorna 4095. En cas que el valor a retornar sigui inferior a 0 retorna 0. Aquesta protecció es fa servir perquè trametre un valor superior a 4095 al DAC farà que la tensió quedi registrada a llur EEPROM al valor tramès menys 4095.
 +
>>> iotv.'''v2aout'''(10)
 +
4095
 +
>>> iotv.'''v2aout'''(10.5)
 +
4095
 +
>>> iotv.'''v2aout'''(5)
 +
2048
 +
>>> iotv.'''v2aout'''(0)
 +
0
 +
>>> iotv.'''v2aout'''(-0.2)
 +
0
 +
 +
= ain2v(''ainValue'') =
 +
Funció '''convertidora de tensió a partir del resultat del convertidor analògic a digital''' (ADC) de 16 bits retornant valors de -10V a +10V.
 +
>>> iotv.'''ain2v'''(26624)
 +
10.0
 +
>>> iotv.'''ain2v'''(0)
 +
-10.0
 +
>>> iotv.'''ain2v'''(13312)
 +
0.0
 +
>>> iotv.'''ain2v'''(20000)
 +
5.02
 +
 +
= aout(''addr'', ''side'', ''ndac'', ''value'') =
 +
Funció d''''escriptura d'un valor analògic ''value'' (entre 0 i 4095) al convertidor digital analògic ''ndac'' (entre 1 i 4) del costat ''side'' (''A'' o ''B'') de l'adreça ''addr'' (entre ''0000'' i ''1111'') de la vèrtebra analògica'''.
 +
 +
L'argument ''addr'' és l'adreça de la vèrtebra analògica expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'[[Vertebra analògica (avert2 v2.1) - IoT-Vertebrae#Configuracions |explicació de les adreces de la vèrtebra analògica]].
 +
 +
L'argument ''side'' és ''''A'''' o ''''B''''.
 +
 +
L'argument ''ndac'' és 1, 2, 3 o 4.
 +
 +
L'argument ''value'' és un valor entre 0 i 4095 (o 0x0000 i 0x0FFF). 0 és 0 volts. 4095 és 10 volts.
 +
 +
>>> iotv.ain2v(iotv.ain('0000','A',4)) # Lectura de l'entrada 4 de la costella analògica d'entrades connectada (amb adreça 0000) al costat A
 +
4.98
 +
>>> iotv.'''aout'''('0000','B',4,iotv.v2aout(9.3)) # Per a escriure 9.3 volts a la sortida 4 de la costella analògica de sortides connectada (amb adreça 0000) al costat B
 +
>>> iotv.ain2v(iotv.ain('0000','A',4)) # Lectura de l'entrada 4 de la costella analògica d'entrades connectada (amb adreça 0000) al costat A
 +
9.29
 +
'''És convenient fer servir un limitador de valor (màxim de 4095)''' com la funció ''v2aout()'' per a evitar enregistrar l'EEPROM quan no es vulgui.
 +
== Enregistrar el valor d'''aout()'' a l'EEPROM del DAC ==
 +
Per a tenir un valor concret a un DAC entre 0V i 10V quan s'engega l'IoT-Vertebrae (per exemple si interessa arrencar amb el llum apagat en el cas de fer controls de llum 0/1-10V), sense esperar que el cap o la Raspberry Pi s'iniciïn, cal '''escriure el valor desitjat de 12 bits sumant-li 4096'''. Això farà que el valor quedi enregistrat per defecte a l'EEPROM del DAC.
 +
>>> iotv.'''aout'''('0000','B',4,'''4096'''+iotv.v2aout(9.3)) # Per a escriure a l'EEPROM del DAC 9.3 volts a la sortida 4 de la costella analògica de sortides connectada (amb adreça 0000) al costat B
 +
 +
'''És convenient fer aquesta operació de manera excepcional''', no fer-ho de manera contínua. '''Es recomana no fer més de 20000 escriptures a l'EEPROM'''.
 +
 +
Aquesta solució és la que està implementada al microprogramari de la vèrtebra analògica i així no haver de posar més arguments a la funció ''aout()''. Per això '''és convenient fer servir un limitador de valor (màxim de 4095)''' com la funció ''v2aout()'' per a evitar enregistrar l'EEPROM quan no es vulgui.
 +
 +
= ain(''addr'', ''side'', ''nadc'') =
 +
Funció de '''lectura d'un valor analògic de 16 bits (representant un valor entre -10V i +10V) al convertidor analògic digital ''nadc'' (entre 1 i 4) del costat ''side'' (''A'' o ''B'') de l'adreça ''addr'' (entre ''0000'' i ''1111'') de la vèrtebra analògica'''.
 +
 +
L'argument ''addr'' és l'adreça de la vèrtebra analògica expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'[[Vertebra analògica (avert2 v2.1) - IoT-Vertebrae#Configuracions |explicació de les adreces de la vèrtebra analògica]].
 +
 +
L'argument ''side'' és ''''A'''' o ''''B''''.
 +
 +
L'argument ''nadc'' és 1, 2, 3 o 4.
 +
 +
'''Retorna un valor de 16 bits''' com a lectura d'un valor analògic entre -10V i +10V. Per a convertir-ho a tensió podeu emprar la funció ''ain2v()''.
 +
>>> iotv.ain2v(iotv.'''ain'''('0000','A',4)) # Lectura de l'entrada 4 de la costella analògica d'entrades connectada (amb adreça 0000) al costat A
 +
4.98
 +
>>> iotv.aout('0000','B',4,iotv.v2aout(9.3)) # Per a escriure 9.3 volts a la sortida 4 de la costella analògica de sortides connectada (amb adreça 0000) al costat B
 +
>>> iotv.ain2v(iotv.'''ain'''('0000','A',4)) # Lectura de l'entrada 4 de la costella analògica d'entrades connectada (amb adreça 0000) al costat A
 +
9.29
 +
= Recepció asíncrona de dades =
 +
* Codi d'exemple:
 +
#!/usr/bin/env python
 +
# can_async.py
 +
import can_iotv as iotv
 +
'''import can'''
 +
 +
def decodeCanMsg(md):
 +
    if len(md) == 5:
 +
        vertCfg = ""
 +
        aVal = bVal = ""
 +
        if md[0] & 0x01:
 +
            vertCfg += "A input "
 +
            aVal = "0x%X"%(0xFF&~md[3])
 +
        if md[0] & 0x02:
 +
            vertCfg += "A output "
 +
            aVal = "0x%X"%(md[3])
 +
        if md[0] & 0x04:
 +
            vertCfg += "A pwm "
 +
        if md[0] & 0x10:
 +
            vertCfg += "B input "
 +
            bVal = "0x%X"%(0xFF&~md[4])
 +
        if md[0] & 0x20:
 +
            vertCfg += "B output "
 +
            bVal = "0x%X"%(md[4])
 +
        if md[0] & 0x40:
 +
            vertCfg += "B pwm "
 +
        if md[0] & 0x80:
 +
            vertCfg += "B touch sensors "
 +
            bVal = "0x%X"%(md[4])
 +
        print("Digital vertebra 0x%X (can ID: 0x%X) has '%s'. Firmware version %d.%d"%(arb_id&0xFF,arb_id,vertCfg,md[1],md[2]))
 +
        print("A: %s, B: %s"%(aVal,bVal))
 +
 +
iotv.canOn()
 +
try:
 +
    '''bus = can.interface.Bus(channel = 'can0', bustype = 'socketcan')'''
 +
    while True:
 +
        '''message = bus.recv(10.0)''' # 10.0 seconds timeout
 +
        if message is None:
 +
            # print('Timeout occurred, no message received.')
 +
            pass
 +
        else:
 +
            arb_id = message.arbitration_id
 +
            if arb_id & '''0x400''': # Async data is sent from digital vertebra with this mask
 +
                '''decodeCanMsg(message.data)'''
 +
except KeyboardInterrupt:
 +
    iotv.canOff()
 +
 +
* Execució del codi:
 +
pi@raspberrypi:~ $ '''python can_async.py'''
 +
Digital vertebra 0x20 (can ID: 0x420) has 'A output B input '. Firmware version 1.5
 +
A: 0xFF, B: 0x25
 +
Digital vertebra 0x20 (can ID: 0x420) has 'A output B input '. Firmware version 1.5
 +
A: 0xFF, B: 0x24
 +
* Interpretació de l'execució:
 +
 +
Cada cop que hi ha un canvi a una costella d'entrada es tramet un missatge pel bus CAN. El missatge ens identifica de quina vèrtebra prové, la configuració de la vèrtebra, la versió del microprogramari i el valor a les dues costelles.
 +
 +
La primera recepció ens diu que a la costella d'entrada B hi ha hagut un canvi i ara hi ha 0x25 (0010010'''1'''). Mentre que a la costella A de sortida tot són 1: 0xFF (11111111):
 +
Digital vertebra 0x20 (can ID: 0x420) has 'A output B input '. Firmware version 1.5
 +
A: 0xFF, B: 0x25
 +
A la segona execució ens diu que a la costella d'entrada B hi ha hagut un canvi i ara hi ha 0x24 (0010010'''0'''). Mentre que a la costella A de sortida tot són 1: 0xFF (11111111):
 +
Digital vertebra 0x20 (can ID: 0x420) has 'A output B input '. Firmware version 1.5
 +
A: 0xFF, B: 0x24

Revisió de 11:08, 22 ago 2024

Hi ha dues biblioteques per a interactuar en Python des de la Raspberry Pi amb l'IoT-Vertebrae: i2c_iotv.py (abans iotv.py) i can_iotv.py.

can_iotv.py: funciona a partir de la versió 2.0 del cap. Es comunica mitjançant el bus CAN, això permet controlar vèrtebres connectades remotament a una cua.

i2c_iotv.py: funciona amb qualsevol versió de cap. Es comunica mitjançant el bus I2C.

Ús de les biblioteques des del terminal

Ús de can_iotv.py des del terminal

Cal obrir el bus CAN cal al principi del codi i podem tancar-ho al final. L'obertura i tancament del bus CAN es fa mitjançant ordres de terminal (molt més lentes d'executar que les instruccions Python).

pi@raspberrypi:~ $ python
Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import can_iotv as iotv
>>> iotv.canOn()
>>> iotv.dversion("0000")
'1.2'
>>> iotv.aversion("0000")
'1.3'
>>> iotv.canOff()
>>> 
pi@raspberrypi:~ $

Ús de i2c_iotv.py des del terminal

No cal obrir el bus I2C al principi i tancar-ho al final perquè cada funció l'obre i el tanca mitjançant instruccions de Python.

pi@raspberrypi:~ $ python
Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import i2c_iotv as iotv
>>> iotv.dversion("0000")
Digital rib version: 1.2
'0000000100000010'
>>> iotv.aversion("0000")
Analog rib version: 1.3
'0000000100000011'
>>> 
pi@raspberrypi:~ $

canOn()

Obertura del bus CAN (tan sols té sentit amb el paquet can_iotv. No pas amb el paquet i2c_iotv):

>>> iotv.canOn()

Es posa a l'inici de qualsevol programa que vulgui fer servir el paquet can_iotv. Aquesta funció tramet al sistema aquesta ordre de terminal:

sudo ip link set up can0 type can bitrate 100000

canOff()

Tancament del bus CAN (tan sols té sentit amb el paquet can_iotv. No pas amb el paquet i2c_iotv):

>>> iotv.canOff()

Es pot posar al final de qualsevol programa que vulgui fer servir el paquet can_iotv. Aquesta funció tramet al sistema aquesta ordre de terminal:

sudo ifconfig can0 down

dversion(addr)

L'argument addr és l'adreça de la vèrtebra digital expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'explicació de les adreces de la vèrtebra digital.

Retorna la versió de microprogramari (firmware) de la vèrtebra amb l'adreça passada com a argument.

  • can_iotv:
>>> iotv.dversion("0000")
'1.2'
  • i2c_iotv:
>>> iotv.dversion("0000")
Digital rib version: 1.2
'0000000100000010'

aversion(addr)

L'argument addr és l'adreça de la vèrtebra analògica expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'explicació de les adreces de la vèrtebra analògica.

Retorna la versió de microprogramari (firmware) de la vèrtebra amb l'adreça passada com a argument.

  • can_iotv:
>>> iotv.aversion("0000")
'1.3'
  • i2c_iotv:
>>> iotv.aversion("0000")
Analog rib version: 1.3
'0000000100000011'

getdsetup(addr)

L'argument addr és l'adreça de la vèrtebra digital expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'explicació de les adreces de la vèrtebra digital.

Retorna la configuració de la vèrtebra digital amb l'adreça passada com a argument. Les vèrtebres digitals s'han de configurar amb la funció dsetup(addr, modeA, modeB) per a indicar que es connecta a cada costat.

  • can_iotv:
>>> iotv.getdsetup("0000")
'A:dout, B:din'
  • i2c_iotv:
>>> iotv.getdsetup("0000")
A digital output, B digital input
'00010010'

Configuracions possibles als dos costats (A i B):

ain: Entrades digitals al costat A

aout: Sortides digitals al costat A

aoutpwm: Sortides digitals per modulació de pols (PWM) al costat A. Si hi ha aoutpwm no pot haver boutpwm (limitació pròpia de l'ESP32-S3).

bin: Entrades digitals al costat B

bout: Sortides digitals al costat B

boutpwm: Sortides digitals per modulació de pols (PWM) al costat B. Si hi ha boutpwm no pot haver aoutpwm (limitació pròpia de l'ESP32-S3).

bintouch: Entrades tàctils al costat B. No existeix aintouch perquè el maquinari no ho permet.

getasetup(addr)

L'argument addr és l'adreça de la vèrtebra analògica expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'explicació de les adreces de la vèrtebra analògica.

Retorna la configuració de la vèrtebra analògica amb l'adreça passada com a argument. Les vèrtebres analògiques no cal configurar-les, després del reset fan la lectura del que hi ha connectat a cada costat (ADC i/o DAC).

  • can_iotv:
>>> iotv.getasetup("0000")
'A:ain, B:aout'
  • i2c_iotv:
>>> iotv.getasetup("0000")
respA: 0x1, respB: 0x2
A rib is ADC, B rib is DAC.
'00010010'

dsetup(addr,modeA,modeB)

L'argument addr és l'adreça de la vèrtebra digital expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'explicació de les adreces de la vèrtebra digital.

L'argument modeA pot ser: ain, aout o aoutpwm

L'argument modeB pot ser: bin, bout, boutpwm o bintouch

  • can_iotv: <-- CAL VERIFICAR SI FUNCIONA COM S'ESPERA
>>> iotv.dsetup('0000','aout','bin')
a: aout, b: bin
'A:dout, B:din'
  • i2c_iotv:
>>> iotv.dsetup('0000','ain','bout')
ain, bout
True

Configuracions possibles als dos costats (A i B):

ain: Entrades digitals al costat A

aout: Sortides digitals al costat A

aoutpwm: Sortides digitals per modulació de pols (PWM) al costat A. Si hi ha aoutpwm no pot haver boutpwm (limitació pròpia de l'ESP32-S3).

bin: Entrades digitals al costat B

bout: Sortides digitals al costat B

boutpwm: Sortides digitals per modulació de pols (PWM) al costat B. Si hi ha boutpwm no pot haver aoutpwm (limitació pròpia de l'ESP32-S3).

bintouch: Entrades tàctils al costat B. No existeix aintouch perquè el maquinari no ho permet.

dout(addr,side,value)

Funció a les dues biblioteques i2c_iotv i can_iotv. La configuració de la vèrtebra ha de ser coherent (el costat i el tipus han de coincidir: aout pel costat A o bout pel costat B).

L'argument addr és l'adreça de la vèrtebra digital expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'explicació de les adreces de la vèrtebra digital.

L'argument side és 'A' o 'B'.

L'argument value és 0 o 1.

>>> iotv.dout('0000','A',0xFF) # Es tramet 0xFF (11111111) al costat A de la vèrtebra digital amb adreça '0000'
>>> iotv.dout('0000','A',0x5A) # Es tramet 0x5A (01011010) al costat A de la vèrtebra digital amb adreça '0000'
>>> iotv.dout('0000','A',0xA5) # Es tramet 0xA5 (10100101) al costat A de la vèrtebra digital amb adreça '0000'
>>> iotv.dout('0000','A',0x00) # Es tramet 0x00 (00000000) al costat A de la vèrtebra digital amb adreça '0000'

din(addr, side)

Funció a les dues biblioteques i2c_iotv i can_iotv. La configuració de la vèrtebra ha de ser coherent (el costat i el tipus han de coincidir: ain pel costat A o bin pel costat B).

L'argument addr és l'adreça de la vèrtebra digital expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'explicació de les adreces de la vèrtebra digital.

L'argument side és 'A' o 'B'.

>>> iotv.din('0000','B')
'00100100'

doutbit(addr, side, posbyte, value)

Funció a les dues biblioteques i2c_iotv i can_iotv. La configuració de la vèrtebra ha de ser coherent (el costat i el tipus han de coincidir: aout pel costat A o bout pel costat B).

L'argument addr és l'adreça de la vèrtebra digital expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'explicació de les adreces de la vèrtebra digital.

L'argument side és 'A' o 'B'.

L'argument posbyte és un valor entre 0 i 7.

L'argument value és 0 o 1.

Un exemple d'ús:

for i in range(10):
    for bit in range(8):
        iotv.doutbit('0000','A',bit,1)
        sleep(.05)
        iotv.doutbit('0000','A',bit,0)

doutbitpwm(addr, side, posbyte, value)

Funció de la biblioteca i2c_iotv. La configuració de la vèrtebra ha de ser coherent (el costat i el tipus han de coincidir: aoutpwm pel costat A o boutpwm pel costat B).

L'argument addr és l'adreça de la vèrtebra digital expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'explicació de les adreces de la vèrtebra digital.

L'argument side és 'A' o 'B'.

L'argument posbyte és un valor entre 0 i 7.

L'argument value és un valor entre 0 i 255.

v2aout(voltage0_10)

Funció convertidora de tensió del ventall de 0V a 10V al ventall de 0 a 4095 per al convertidor digital a analògic (DAC) de 12 bits. En cas que el valor a retornar sigui superior a 4095 retorna 4095. En cas que el valor a retornar sigui inferior a 0 retorna 0. Aquesta protecció es fa servir perquè trametre un valor superior a 4095 al DAC farà que la tensió quedi registrada a llur EEPROM al valor tramès menys 4095.

>>> iotv.v2aout(10)
4095
>>> iotv.v2aout(10.5)
4095
>>> iotv.v2aout(5)
2048
>>> iotv.v2aout(0)
0
>>> iotv.v2aout(-0.2)
0

ain2v(ainValue)

Funció convertidora de tensió a partir del resultat del convertidor analògic a digital (ADC) de 16 bits retornant valors de -10V a +10V.

>>> iotv.ain2v(26624)
10.0
>>> iotv.ain2v(0)
-10.0
>>> iotv.ain2v(13312)
0.0
>>> iotv.ain2v(20000)
5.02

aout(addr, side, ndac, value)

Funció d'escriptura d'un valor analògic value (entre 0 i 4095) al convertidor digital analògic ndac (entre 1 i 4) del costat side (A o B) de l'adreça addr (entre 0000 i 1111) de la vèrtebra analògica.

L'argument addr és l'adreça de la vèrtebra analògica expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'explicació de les adreces de la vèrtebra analògica.

L'argument side és 'A' o 'B'.

L'argument ndac és 1, 2, 3 o 4.

L'argument value és un valor entre 0 i 4095 (o 0x0000 i 0x0FFF). 0 és 0 volts. 4095 és 10 volts.

>>> iotv.ain2v(iotv.ain('0000','A',4)) # Lectura de l'entrada 4 de la costella analògica d'entrades connectada (amb adreça 0000) al costat A
4.98
>>> iotv.aout('0000','B',4,iotv.v2aout(9.3)) # Per a escriure 9.3 volts a la sortida 4 de la costella analògica de sortides connectada (amb adreça 0000) al costat B
>>> iotv.ain2v(iotv.ain('0000','A',4)) # Lectura de l'entrada 4 de la costella analògica d'entrades connectada (amb adreça 0000) al costat A
9.29

És convenient fer servir un limitador de valor (màxim de 4095) com la funció v2aout() per a evitar enregistrar l'EEPROM quan no es vulgui.

Enregistrar el valor d'aout() a l'EEPROM del DAC

Per a tenir un valor concret a un DAC entre 0V i 10V quan s'engega l'IoT-Vertebrae (per exemple si interessa arrencar amb el llum apagat en el cas de fer controls de llum 0/1-10V), sense esperar que el cap o la Raspberry Pi s'iniciïn, cal escriure el valor desitjat de 12 bits sumant-li 4096. Això farà que el valor quedi enregistrat per defecte a l'EEPROM del DAC.

>>> iotv.aout('0000','B',4,4096+iotv.v2aout(9.3)) # Per a escriure a l'EEPROM del DAC 9.3 volts a la sortida 4 de la costella analògica de sortides connectada (amb adreça 0000) al costat B

És convenient fer aquesta operació de manera excepcional, no fer-ho de manera contínua. Es recomana no fer més de 20000 escriptures a l'EEPROM.

Aquesta solució és la que està implementada al microprogramari de la vèrtebra analògica i així no haver de posar més arguments a la funció aout(). Per això és convenient fer servir un limitador de valor (màxim de 4095) com la funció v2aout() per a evitar enregistrar l'EEPROM quan no es vulgui.

ain(addr, side, nadc)

Funció de lectura d'un valor analògic de 16 bits (representant un valor entre -10V i +10V) al convertidor analògic digital nadc (entre 1 i 4) del costat side (A o B) de l'adreça addr (entre 0000 i 1111) de la vèrtebra analògica.

L'argument addr és l'adreça de la vèrtebra analògica expressada com un text de quatre zeros i uns. Aquí hi ha un enllaç a l'explicació de les adreces de la vèrtebra analògica.

L'argument side és 'A' o 'B'.

L'argument nadc és 1, 2, 3 o 4.

Retorna un valor de 16 bits com a lectura d'un valor analògic entre -10V i +10V. Per a convertir-ho a tensió podeu emprar la funció ain2v().

>>> iotv.ain2v(iotv.ain('0000','A',4)) # Lectura de l'entrada 4 de la costella analògica d'entrades connectada (amb adreça 0000) al costat A
4.98
>>> iotv.aout('0000','B',4,iotv.v2aout(9.3)) # Per a escriure 9.3 volts a la sortida 4 de la costella analògica de sortides connectada (amb adreça 0000) al costat B
>>> iotv.ain2v(iotv.ain('0000','A',4)) # Lectura de l'entrada 4 de la costella analògica d'entrades connectada (amb adreça 0000) al costat A
9.29

Recepció asíncrona de dades

  • Codi d'exemple:
#!/usr/bin/env python
# can_async.py
import can_iotv as iotv
import can

def decodeCanMsg(md):
   if len(md) == 5:
       vertCfg = ""
       aVal = bVal = ""
       if md[0] & 0x01:
           vertCfg += "A input "
           aVal = "0x%X"%(0xFF&~md[3])
       if md[0] & 0x02:
           vertCfg += "A output "
           aVal = "0x%X"%(md[3])
       if md[0] & 0x04:
           vertCfg += "A pwm "
       if md[0] & 0x10:
           vertCfg += "B input "
           bVal = "0x%X"%(0xFF&~md[4])
       if md[0] & 0x20:
           vertCfg += "B output "
           bVal = "0x%X"%(md[4])
       if md[0] & 0x40:
           vertCfg += "B pwm "
       if md[0] & 0x80:
           vertCfg += "B touch sensors "
           bVal = "0x%X"%(md[4])
       print("Digital vertebra 0x%X (can ID: 0x%X) has '%s'. Firmware version %d.%d"%(arb_id&0xFF,arb_id,vertCfg,md[1],md[2]))
       print("A: %s, B: %s"%(aVal,bVal))

iotv.canOn()
try:
   bus = can.interface.Bus(channel = 'can0', bustype = 'socketcan')
   while True:
       message = bus.recv(10.0) # 10.0 seconds timeout
       if message is None:
           # print('Timeout occurred, no message received.')
           pass
       else:
           arb_id = message.arbitration_id
           if arb_id & 0x400: # Async data is sent from digital vertebra with this mask
               decodeCanMsg(message.data)
except KeyboardInterrupt:
   iotv.canOff()
  • Execució del codi:
pi@raspberrypi:~ $ python can_async.py
Digital vertebra 0x20 (can ID: 0x420) has 'A output B input '. Firmware version 1.5
A: 0xFF, B: 0x25
Digital vertebra 0x20 (can ID: 0x420) has 'A output B input '. Firmware version 1.5
A: 0xFF, B: 0x24
  • Interpretació de l'execució:

Cada cop que hi ha un canvi a una costella d'entrada es tramet un missatge pel bus CAN. El missatge ens identifica de quina vèrtebra prové, la configuració de la vèrtebra, la versió del microprogramari i el valor a les dues costelles.

La primera recepció ens diu que a la costella d'entrada B hi ha hagut un canvi i ara hi ha 0x25 (00100101). Mentre que a la costella A de sortida tot són 1: 0xFF (11111111):

Digital vertebra 0x20 (can ID: 0x420) has 'A output B input '. Firmware version 1.5
A: 0xFF, B: 0x25

A la segona execució ens diu que a la costella d'entrada B hi ha hagut un canvi i ara hi ha 0x24 (00100100). Mentre que a la costella A de sortida tot són 1: 0xFF (11111111):

Digital vertebra 0x20 (can ID: 0x420) has 'A output B input '. Firmware version 1.5
A: 0xFF, B: 0x24