Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Current »

PyFirmata by Tino de Bruijn is an amazing tool for combining the powers of the Raspberry Pi (full operating system, python, …) and the Arduino (high time precision, …). This will allow us to control the Arduino Mega from the Raspberry Pi. This is important, because of two reasons:

The Raspberry Pi has the input data from the ethereum node script.

If we want to use 16 PWM pins, the Arduino Mega only has 14 (or 15), but we could use one (or 2) of the RPI PWM pins.

Breaking it down, these are the questions to resolve:

  1. Can we read a slider position, from the RPi through the Arduino slave, using python?

  2. Can we move the slider?

  3. Can we do this with two sliders?

  4. Can we read data from a file, and move a slider?

  5. Can we move multiple sliders?

  6. Can we read multiple data points and move multiple sliders?

  7. Can we detect touch sensitivity? (is this useful?)

Overview of vinophonics.py

The vinophonics.py program follows this sequence:

  1. check the blockchain switch position:

    1. if the switch is set to LOCAL, do nothing 

    2. If the switch is in the middle position, execute the rest of the code every 180 seconds

    3. If the switch is set to REMOTE, execute the rest of the code continuously

      import RPi.GPIO as GPIO
      import time
      
      
      GPIO.setmode(GPIO.BCM)
      GPIO.setwarnings(False)
      GPIO.setup(22, GPIO.IN)
      GPIO.setup(23, GPIO.IN)
      
      while True:
          if GPIO.input(22) == 1:
       LOCAL - DO NOTHING         
          elif GPIO.input(23) == 1:
       MIDDLE - WAIT 3 MINUTES ... OR AT LEAST WAIT UNTIL THE SMART CONTRACT UPDATES         
          else:
       REMOTE - CONTINUE WITH THE REST OF THE CODE
              
          time.sleep(1)
          

       

  2. Create a “for” loop to execute sequentially for each of the sliders (1-16)
    FOR LOOP 

    1. read ALL the variables from the smart_contract

      import json
      import web3
      import time
      
      from web3 import Web3, HTTPProvider
      
      print("\n1) Connecting to the costaflores-node2 (http://10.112.48.25:8547) ...")
      
      w3 = Web3(HTTPProvider("http://10.112.48.25:8547"))
      
      print("2) Preparing contracts (Datastorage)...")
      
      with open('contracts.json') as json_file:
          compiled_sol = json.load(json_file)
      
      contract = w3.eth.contract(address = w3.toChecksumAddress("0x864d6819946dF8a763454627342bb3A7a2692805"), abi = compiled_sol['contracts']['contracts.sol:Datastorage']['abi'], )
      
      print("\n ================================================== \n")
      
      def handle_event(event):
      
          receipt = w3.eth.waitForTransactionReceipt(event['transactionHash'])
          result = contract.events.DataInserted().processReceipt(receipt)

          # => Sensor specific data.
          sensor2 = contract.functions.data(result[0]['args']['_identifier'].decode('utf-8').encode('utf-8'), 0).call()/100
          sensor1 = contract.functions.data(result[0]['args']['_identifier'].decode('utf-8').encode('utf-8'), 1).call()/100
          sensor05 = contract.functions.data(result[0]['args']['_identifier'].decode('utf-8').encode('utf-8'), 2).call()/100
          sensor005 = contract.functions.data(result[0]['args']['_identifier'].decode('utf-8').encode('utf-8'), 3).call()/100
          battery = contract.functions.data(result[0]['args']['_identifier'].decode('utf-8').encode('utf-8'), 4).call()/100
          temperature = contract.functions.data(result[0]['args']['_identifier'].decode('utf-8').encode('utf-8'), 5).call()/100
      
          # => Weather station data. (global data)
          wind_speed = contract.functions.data(result[0]['args']['_identifier'].decode('utf-8').encode('utf-8'), 7).call()/100
          wind_gust = contract.functions.data(result[0]['args']['_identifier'].decode('utf-8').encode('utf-8'), 8).call()/100
          wind_direction = contract.functions.data(result[0]['args']['_identifier'].decode('utf-8').encode('utf-8'), 9).call()/100
          pressure = contract.functions.data(result[0]['args']['_identifier'].decode('utf-8').encode('utf-8'), 10).call()/100
          rain = contract.functions.data(result[0]['args']['_identifier'].decode('utf-8').encode('utf-8'), 11).call()/100
          temperature = contract.functions.data(result[0]['args']['_identifier'].decode('utf-8').encode('utf-8'), 12).call()/100
          humidity = contract.functions.data(result[0]['args']['_identifier'].decode('utf-8').encode('utf-8'), 13).call()/100
      
          # Add communication with Vinophonics here, to do:
      
          # data = ... TREAT DATA HERE AS STRING
          # file = open("/var/tmp/data.txt", data)
      def log_loop(event_filter, poll_interval):
          while True:
              for event in event_filter.get_new_entries():
                  handle_event(event)
                  time.sleep(poll_interval)
      
      block_filter = w3.eth.filter({'fromBlock':'latest'})
      log_loop(block_filter, 2)

       

    2. map the variable values from the smart_contract in the range 0-1000

      The idea is to convert different sensor data scales to 0-1000 range.

      Sensor variableSliderMinMaxMeaningsensor210255soil moisture at 2m depthsensor120255soil moisture at 1m depthsensor0530255soil moisture at 50cm depthsensor00540255soil moisture at 5cm depthbattery524.5battery voltage for the vinduino (this will be replaced with the sunlight sensor data)temperature6035temperature reading from the vinduinowind_speed7030wind speed in knotswind_gust8050wind gusts in knotswind_direction90360wind direction in degreespressure108001000milibars of pressure (also needs to be calibrated)rain110100rainfall in milimeters (month)temperature12035temperature at the platformhumidity131090relative humidity (percentage)sensor2140255soil moisture at 2m depth (REPEAT OF SLIDER1)sensor1150255soil moisture at 1m depth(REPEAT OF SLIDER2)sensor5160255soil moisture at 50cm depth (REPEAT OF SLIDER3)

      In Python, this is done like this: 

      def map(x, in_min, in_max, out_min, out_max):
       

    3. For slider(1) 

      1. read slider(1) position

        slider1 = slider_one.read()

         

      2. Decide whether to move the slider up or down

      3. Turn on the slider on for x amount of time

      4. Turn off the slider

      5. Read the slider position. If the position is still not correct, repeat this sequence until we reach the target. 

         if (slider1 - targetValue) > threshold and (slider1 > targetValue):
                slider_one_up.write(0)
                slider_one_down.write(1)
                slider_one_enable.write(speed)
             elif (targetValue - slider1) > threshold and (slider1 < targetValue):
                slider_one_up.write(1)
                slider_one_down.write(0)
                slider_one_enable.write(speed)
             else: 
                slider_one_enable.write(0)


        In other words: If the slider position is greater than the target, AND the slider position, minus the target, is greater than the threshold, then point slider south, and enable the motor for x amount of time, then turn off the motor. 

          

    4. Continue for slider(2-16)

  3. At the end of the 16 sliders, repeat from step 1 (reading the blockchain switch)

Installing PyFirmata

sudo apt-get -y install arduino python-serial mercurial
git clone https://github.com/tino/pyFirmata
cd pyFirmata
sudo python setup.py install

Using the Arduino IDE, upload the default PyFirmata firmware on the arduino (file → Examples → Firmata → Standard Firmata)

Test using PyFirmata "Hello World"

Download the script from GitHub:

wget https://github.com/JoBergs/RaspiContent/raw/master/pyfirmata_pwm.py

#!/usr/bin/python
#encoding:utf-8
#Tutorial: http://www.knight-of-pi.org/raspi-ardi-big-love-pyfirmata-introduction/
#Licence: http://creativecommons.org/licenses/by-nc-sa/3.0/
# Author: Johannes Bergs

import time
import pyfirmata
board = pyfirmata.Arduino('/dev/ttyACM0')  # arduino setup

iter8 = pyfirmata.util.Iterator(board)
iter8.start()

LED = board.get_pin('d:3:p')
STEPS = 10000.0
if __name__ == '__main__':
    # increase PWM output in STEPS increments
    for i in range(int(STEPS)):
        print i
        LED.write(i / STEPS)  # hardware-PWM accepts values 0.0 ... 1.0
        time.sleep(0.001)

Set the USB port in the following line to match the output from

dmesg | grep tty

pi@vinophonics:~/pyFirmata $ dmesg | grep tty
[    0.000000] Kernel command line: coherent_pool=1M 8250.nr_uarts=0 cma=64M cma=256M  smsc95xx.macaddr=DC:A6:32:1A:AB:AE vc_mem.mem_base=0x3ec00000 vc_mem.mem_size=0x40000000  dwc_otg.lpm_enable=0 console=ttyS0,115200 console=tty1 root=PARTUUID=4224e0ab-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
[    0.000714] console [tty1] enabled
[    0.855408] fe201000.serial: ttyAMA0 at MMIO 0xfe201000 (irq = 33, base_baud = 0) is a PL011 rev2
[ 1911.239197] cdc_acm 1-1.3:1.0: ttyACM0: USB ACM device

Edit pyfirmata_pwm.py to match the device name 

board = pyfirmata.Arduino('/dev/ttyACM0')

Then, connect the pin D3 of the Arduino to a LED and a 270Ω resistor on the breadboard, like this

PyFirmata test circuit

Now, start the script by typing:

python pyfirmata_pwm.py

The glow of the LED will increase slowly until the full capacity is reached:

  1. Can we read a slider position (from the RPi through the Arduino slave)

    Here is a good summary of reading and writing to pins through PyFirmata.

    Working from the previous example, we can test reading slider positions like this:

    import time
    import pyfirmata
    board = pyfirmata.ArduinoMega('/dev/ttyACM0')  # arduino setup
    
    # import only system from os 
    from os import system, name 
    
    # define our clear function 
    def clear(): 
    
     # for windows 
     if name == 'nt': 
     _ = system('cls') 
    
     # for mac and linux(here, os.name is 'posix') 
     else: 
     _ = system('clear') 
    
    
    it = pyfirmata.util.Iterator(board)
    it.start()
    
    slider_one  = board.get_pin('a:0:i')
    slider_two  = board.get_pin('a:1:i')
    slider_three  = board.get_pin('a:2:i')
    slider_four  = board.get_pin('a:3:i')
    slider_five  = board.get_pin('a:4:i')
    slider_six  = board.get_pin('a:5:i')
    slider_seven  = board.get_pin('a:6:i')
    slider_eight  = board.get_pin('a:7:i')
    slider_nine  = board.get_pin('a:8:i')
    slider_ten  = board.get_pin('a:9:i')
    slider_eleven  = board.get_pin('a:10:i')
    slider_twelve  = board.get_pin('a:11:i')
    slider_thirteen  = board.get_pin('a:12:i')
    slider_fourteen  = board.get_pin('a:13:i')
    slider_fifteen  = board.get_pin('a:14:i')
    slider_sixteen  = board.get_pin('a:15:i')
    
    while True:
    
         slider1 = slider_one.read()
         slider2 = slider_two.read()
         slider3 = slider_three.read()
         slider4 = slider_four.read()
         slider5 = slider_five.read()
         slider6 = slider_six.read()
         slider7 = slider_seven.read()
         slider8 = slider_eight.read()
         slider9 = slider_nine.read()
         slider10 = slider_ten.read()
         slider11 = slider_eleven.read()
         slider12 = slider_twelve.read()
         slider13 = slider_thirteen.read()
         slider14 = slider_fourteen.read()
         slider15 = slider_fifteen.read()
         slider16 = slider_sixteen.read()
    
         print "Slider 1:   ", slider1
         print "Slider 2:   ", slider2
         print "Slider 3:   ", slider3
         print "Slider 4:   ", slider4
         print "Slider 5:   ", slider5
         print "Slider 6:   ", slider6
         print "Slider 7:   ", slider7
         print "Slider 8:   ", slider8
         print "Slider 9:   ", slider9
         print "Slider 10:  ", slider10
         print "Slider 11:  ", slider11
         print "Slider 12:  ", slider12
         print "Slider 13:  ", slider13
         print "Slider 14:  ", slider14
         print "Slider 15:  ", slider15
         print "Slider 16:  ", slider16
    
         time.sleep(1)
    
         clear() 
    board.exit()
  2. Can we move the slider?

    Here is a code example moving two sliders, to an input "target value". This is written for python3.

    What is noticeable about this example, is the velocity and threshold for "overshooting" the target. If the speed is too fast (i.e. without using PWM) and the target threshold is too small, the slider can overshoot the target position, resulting in an infinite back-and-forth, searching the target. This could be corrected by throttling down the speed the closer the target becomes, or by using min() and max() as in the arduino sketch example SlideToValue. But this code gets us pretty close.

    #!/usr/bin/python3
    
    import time
    import pyfirmata
    board = pyfirmata.ArduinoMega('/dev/ttyACM0')  # arduino setup
    
    # import only system from os 
    from os import system, name 
    
    # define our clear function 
    def clear(): 
    
     # for windows 
     if name == 'nt': 
     _ = system('cls') 
    
     # for mac and linux(here, os.name is 'posix') 
     else: 
     _ = system('clear') 
    
    
    it = pyfirmata.util.Iterator(board)
    it.start()
    
    speed = 1
    threshold = 0.05
    
    # declare pin assignments for reading the potentiometer position
    
    slider_one  = board.get_pin('a:0:i')
    slider_two  = board.get_pin('a:1:i')
    slider_three  = board.get_pin('a:2:i')
    slider_four  = board.get_pin('a:3:i')
    slider_five  = board.get_pin('a:4:i')
    slider_six  = board.get_pin('a:5:i')
    slider_seven  = board.get_pin('a:6:i')
    slider_eight  = board.get_pin('a:7:i')
    slider_nine  = board.get_pin('a:8:i')
    slider_ten  = board.get_pin('a:9:i')
    slider_eleven  = board.get_pin('a:10:i')
    slider_twelve  = board.get_pin('a:11:i')
    slider_thirteen  = board.get_pin('a:12:i')
    slider_fourteen  = board.get_pin('a:13:i')
    slider_fifteen  = board.get_pin('a:14:i')
    slider_sixteen  = board.get_pin('a:15:i')
    
    # declar pin assignments to control the H-Bridge direction
    
    slider_one_enable = board.get_pin('d:2:p')
    slider_one_up = board.get_pin('d:22:o')
    slider_one_down = board.get_pin('d:24:o')
    slider_two_enable = board.get_pin('d:3:p')
    slider_two_up = board.get_pin('d:26:o')
    slider_two_down = board.get_pin('d:28:o')
    
    targetValue = float(input("Please enter a target value 0-9:  "))
    targetValue = targetValue/10
    
    while True:
         print("Desired position: ", targetValue)
    
         slider1 = slider_one.read()
         slider2 = slider_two.read()
         slider3 = slider_three.read()
         slider4 = slider_four.read()
         slider5 = slider_five.read()
         slider6 = slider_six.read()
         slider7 = slider_seven.read()
         slider8 = slider_eight.read()
         slider9 = slider_nine.read()
         slider10 = slider_ten.read()
         slider11 = slider_eleven.read()
         slider12 = slider_twelve.read()
         slider13 = slider_thirteen.read()
         slider14 = slider_fourteen.read()
         slider15 = slider_fifteen.read()
         slider16 = slider_sixteen.read()
    
         print("Slider 1:   ", slider1)
         print("Slider 2:   ", slider2)
         print("Slider 3:   ", slider3)
         print("Slider 4:   ", slider4)
         print("Slider 5:   ", slider5)
         print("Slider 6:   ", slider6)
         print("Slider 7:   ", slider7)
         print("Slider 8:   ", slider8)
         print("Slider 9:   ", slider9)
         print("Slider 10:  ", slider10)
         print("Slider 11:  ", slider11)
         print("Slider 12:  ", slider12)
         print("Slider 13:  ", slider13)
         print("Slider 14:  ", slider14)
         print("Slider 15:  ", slider15)
         print("Slider 16:  ", slider16)
    
         if (slider1 - targetValue) > threshold and (slider1 > targetValue):
            slider_one_up.write(0)
            slider_one_down.write(1)
            slider_one_enable.write(speed)
         elif (targetValue - slider1) > threshold and (slider1 < targetValue):
            slider_one_up.write(1)
            slider_one_down.write(0)
            slider_one_enable.write(speed)
         else: 
            slider_one_enable.write(0)
    
         if (slider2 - targetValue) > threshold and (slider2 > targetValue):
            slider_two_up.write(0)
            slider_two_down.write(1)
            slider_two_enable.write(speed)
         elif (targetValue - slider2) > threshold and (slider2 < targetValue):
            slider_two_up.write(1)
            slider_two_down.write(0)
            slider_two_enable.write(speed)
         else:
            slider_two_enable.write(0)
    
         clear() 
    
    board.exit()
  • No labels