0

We have 7 raspberry pi's 3, each connected to the internet and an display. On each screen / raspberry pi is geeqie (image viewer_ running with an image slideshow. The goal is to have all raspberry pi's go to the next image with an mouse (scrollwheel) or any other kind of device, in syc, at the same time. An python app is running in the background to download the images (independent of this problem). All mentioned code is python 2.7.

We have 1 master raspberry which detects the mouse scroll via evdev (mousegrabber python script below) and sends GPIO.output over GPIO pins 22 and 23. GPIO pin 22 is connected to 1kΩ and after the resistor splitted to 7 and connected to each raspberry GPIO 17. For GPIO 23 the same, first an 1kΩ resistor, then splitted and connected to all 7 GPIO 18 pins. The ground is also connected of each one raspberry pi with one other.

The python detector script is below. This is all working. The input is detected via GPIO.add_event_detect() and an simulated mouse scroll event is send via uinput. Geeqie is running fullscreen and those python apps in the background, the scrolls up and down are detected by geeqie to go to the next or previous image.

The point is that all images need to switch to the next one, exactly in sync. This is not the case, there appears to be some sort of delay of about +- 50ms to 500ms of each detection. The switching of all geeqie iamges on the raspbarry are out of sync. What would be the best way to archive that all images are switching to the next one synchronous on command with some sort of input?

The is no particular reason this has to be via GPIO, the image switching just needs to be in sync. This means, when the mouse wheel is scrolled, all geeqie image slideshows needs to go to the next image. The pictures might make the image complete. The soldering is not that good, bud its working correctly. The goal is just to go to the next image at the same time on all raspberri pi's.

Any ideas? Thanks!

Extra information: We also tried this, bud it was way more lag then this above. The scroll detections were very out of sync. We also tried it with a construction of 7 mouses their rotary encoder soldered together, so the mouse itself was detected by each raspberry, only the input came from 1 mouse. This was in sync and was working, bud it broke.

Script which detects the GPIO input:

import RPi.GPIO as GPIO
import threading
import os
import random
import evdev
from evdev import UInput, AbsInfo, InputDevice, categorize, ecodes
from pprint import pprint
import sys
import time
import uinput


class InputFromMasterDetector:
    def __init__(self):
        self.config = None
        self.Enc_A = 17 # UP
        self.Enc_B = 18 # DOWN

        self.simulatedInputDevice = uinput.Device([
            uinput.REL_WHEEL,
            uinput.REL_X,
            uinput.REL_Y,
            uinput.BTN_LEFT,
            uinput.BTN_RIGHT,
        ])

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        GPIO.cleanup()
        print("InputFromMasterDetector - _exit_ cleanup\n")

    def init(self):
        GPIO.setwarnings(True)
        GPIO.setmode(GPIO.BCM) # Use BCM mode

        GPIO.setup(self.Enc_A, GPIO.IN) #, pull_up_down=GPIO.PUD_DOWN)
        GPIO.setup(self.Enc_B, GPIO.IN) #, pull_up_down=GPIO.PUD_DOWN)

        #GPIO.add_event_detect(self.Enc_A, GPIO.RISING, callback=self.rotary_interrupt)                 # NO bouncetime 
        #GPIO.add_event_detect(self.Enc_B, GPIO.RISING, callback=self.rotary_interrupt)                 # NO bouncetime 

        GPIO.add_event_detect(self.Enc_A, GPIO.RISING, callback=self.rotary_interrupt_A) #, bouncetime=200)                 # NO bouncetime 
        GPIO.add_event_detect(self.Enc_B, GPIO.RISING, callback=self.rotary_interrupt_B)

        try:
            print("InputFromMasterDetector - starting input detection\n")
            #GPIO.wait_for_edge(Enc_A, GPIO.FALLING)
            while True :
                #time.sleep(1)
                #print("looipiness")
                pass

        except KeyboardInterrupt:  
            print("InputFromMasterDetector - KeyboardInterrupt \n")

        except: 
            print "InputFromMasterDetector - Other error or exception occurred! \n"

        finally:  
            GPIO.cleanup() # this ensures a clean exit
            print("InputFromMasterDetector - Cleanup\n")

    def rotary_interrupt_A(self, signalA):
        self.uinput_scroll(1, 1)
        #print("InputFromMasterDetector - rotary_interrupt_A detected - signalA: " + str(signalA) + " - ***UP*** - Switch_A:" + str(Switch_A) + " - " + str(random.randint(1,101)) + "\n")
        print("InputFromMasterDetector - ***UP***\n")

    def rotary_interrupt_B(self, signalB):
        self.uinput_scroll(-1, 1)
        #print("InputFromMasterDetector - rotary_interrupt_B detected\n")
        print("InputFromMasterDetector - ***DOWN***\n")

    def uinput_scroll(self, direction, amount=1):
        self.simulatedInputDevice.emit(uinput.REL_WHEEL, direction * amount) # direction 1 = up, -1 = down

    def start(self):
        thread = threading.Thread(target = self.init)
        thread.setDaemon(True)
        thread.start()
        print('InputFromMasterDetector - started in new thread\n')

Script which sends the GPIO signal:

import RPi.GPIO as GPIO
import threading
import os
import random
import evdev
from evdev import UInput, AbsInfo, InputDevice, categorize, ecodes
from pprint import pprint
import sys
import time

class MousegrabberStandaloneSender:
    def __init__(self):
        self.config = None
        # GPIO Ports
        #17&18 or 22&23
        self.Enc_A = 22 # UP
        self.Enc_B = 23 # DOWN

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        GPIO.cleanup()
        print("MousegrabberStandaloneSender - _exit_ cleanup\n")

    def init(self):
        GPIO.setwarnings(True)
        GPIO.setmode(GPIO.BCM) # Use BCM mode
        GPIO.setup(self.Enc_A, GPIO.OUT, initial=GPIO.LOW)
        GPIO.setup(self.Enc_B, GPIO.OUT, initial=GPIO.LOW)

    def send_signal_A(self): #A == UP
        GPIO.output(self.Enc_A, GPIO.HIGH)
        time.sleep(0.1)
        GPIO.output(self.Enc_A, GPIO.LOW)
        print('MousegrabberStandaloneSender - sennd_signal_A - ***UP***' + str(random.randint(1,101)) + "\n")

    def send_signal_B(self): #B == DOWN
        GPIO.output(self.Enc_B, GPIO.HIGH)
        time.sleep(0.1)
        GPIO.output(self.Enc_B, GPIO.LOW)
        print('MousegrabberStandaloneSender - sennd_signal_B - ***DOWN***' + str(random.randint(1,101)) + "\n")


    def threaded_scrollwheeldetection(self):
        try:
            self.start_scrollwheeldetection()

        except KeyboardInterrupt:  
            print("MousegrabberStandaloneSender - KeyboardInterrupt \n")

        except:  
            print "MousegrabberStandaloneSender - Other error or exception occurred! \n"

        finally:  
            GPIO.cleanup() # this ensures a clean exit
            print("MousegrabberStandaloneSender - Cleanup\n")

    def start_scrollwheeldetection(self):
        self.init()

        devices = [evdev.InputDevice(path) for path in evdev.list_devices()]
        foundMouse = None
        for device in devices:
            if "mouse" in device.name.lower():
                foundMouse = device
                print("MousegrabberStandaloneSender - Mouse found, using: ", device.path, device.name, device.phys)
                break

        if foundMouse is None:
            print("MousegrabberStandaloneSender - No mouse found, exiting...\n")
            GPIO.cleanup()
            sys.exit()


        dev = InputDevice(device.path)    
        #pprint(dev.capabilities(verbose=True, absinfo=True))

        simulatedUserInput = UInput()

        dev.grab()

        scrollUps = 0
        scrollDowns = 0
        startingTime = time.time()
        amountOfScrollsToReactOn = 10

        for event in dev.read_loop():
            #pprint(str(event.type) + " " + str(event.code) + " " + str(event.value))
            #print("evdev.ecodes.EV_REL: " + str(evdev.ecodes.EV_REL) + " - evdev.ecodes.REL_WHEEL: " + str(evdev.ecodes.REL_WHEEL))
            #catch the scroll wheen
            if event.type == evdev.ecodes.EV_REL and event.code == evdev.ecodes.REL_WHEEL:
            #if event.type == 0x02 and event.code == 0x08:
                currentTime = time.time()
                #print((currentTime - startingTime))
                if event.value > 0:
                    scrollUps+=1
                    scrollDowns = 0
                elif event.value < 0:
                    scrollDowns+=1
                    scrollUps = 0
                if (currentTime - startingTime) > 10:
                    startingTime = time.time()
                    scrollUps = 0
                    scrollDowns = 0
                    #print("(currentTime - startingTime) > 10")
                elif (currentTime - startingTime) < 10 and (scrollUps > amountOfScrollsToReactOn or scrollDowns > amountOfScrollsToReactOn):
                    if scrollUps > amountOfScrollsToReactOn:
                        self.send_signal_A() #up
                    elif scrollDowns > amountOfScrollsToReactOn:
                        self.send_signal_B() #down
                    startingTime = time.time()
                    scrollDowns = 0
                    scrollUps = 0
            #print(categorize(event))
            else:
                #pprint("sending: " + str(event.type) + " " + str(event.code) + " " + str(event.value))
                #dev.write(e.EV_KEY, e.KEY_A, 0)
                simulatedUserInput.write(event.type, event.code, event.value)
                simulatedUserInput.syn()

    def start(self):
        thread = threading.Thread(target = self.threaded_scrollwheeldetection)
        thread.setDaemon(True)
        thread.start()
        #thread.join() #blocks untill the first thread finished
        print('MousegrabberStandaloneSender started\n')

mousegrabberstandalonesender = MousegrabberStandaloneSender()
mousegrabberstandalonesender.threaded_scrollwheeldetection()

Images about the situation: part1 part2 GPIO headers

BramscoChill
  • 113
  • 5

0 Answers0