abstrakraft / cwiid

Linux Nintendo Wiimote interface
cwiid.org
GNU General Public License v2.0
287 stars 100 forks source link

Unable to detect loss of signal/input from Python program #23

Open alexellis opened 9 years ago

alexellis commented 9 years ago

Hi, I'm using this library on a Raspberry PI with Python 2.7 to control a robot/car. This works brilliantly with a high range until the range is too far at which point I can't detect loss of signal/input and the car continues off into the distance etc.

Is there a way to resolve this?

Thanks

tal-zvon commented 8 years ago

I am also running into this problem. So far, the only thing I can think of is to run a separate thread with something like:

while True:
    if global_vars.wiimote is not None:
        try:
            global_vars.wiimote.request_status()
        except ValueError: 
            # Wiimote object is closed - don't worry about it
            pass
        except RuntimeError:
            print "Disconnected suddenly"
            stop_moving()
    time.sleep(1)

Unfortunately, this is a pretty bad solution - during testing, if I unplug the batteries to my wiimote all of a sudden while the robot's motors (wheels) are running, the request_status() function won't error out for over 20 seconds. The robot could have run into all sorts of things in 20 seconds.

Is there a better way to do this?

furbrain commented 7 years ago

Hi folks, I think I have solved this problem. The underlying issue is that bluetooth is a pretty tolerant protocol - it expects people with bluetooth devices to wander away and come back and find everything reconnects happily. This is fine if you're playing music or using a keyboard, but not so great if you're controlling a robot car (which I am also implementing :+1: ). I can't find an easy way to change the timeout in cwiid

However, the command line tool hcitool gives us a way of changing the timeout (at least on linux):

hcitool (from the man page) \<snip> lst [value] With no value, displays link supervision timeout for the connec‐ tion to the device with Bluetooth address bdaddr. If value is given, sets the link supervision timeout for that connection to value slots, or to infinite if value is 0.

So, I have devised a connection strategy:

import re
import cwiid
import subprocess

# set bluetooth timeout in ms
BLUETOOTH_TIMEOUT = 1000 

def connect():
    wm = cwiid.Wiimote()
    # get all connected bluetooth devices
    connected_devices = subprocess.check_output(("hcitool","con"))
    # extract bluetooth MAC addresses
    addresses = re.findall(r"(([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2}))",connected_devices)
    for i in addresses:
        name = subprocess.check_output(("hcitool","name",i[0]))
        # identify Wiimotes. You may need to change this if looking for balance boards
        # we are also assuming that you only have one Wiimote attached at one time,
        # or that we want to set them all to have the same timeout
        if name.strip()=="Nintendo RVL-CNT-01":
            subprocess.call(("hcitool","lst",i[0],str(BLUETOOTH_TIMEOUT*16/10)))
    return wm

We can then implement @terminator14 's strategy of having a background thread to monitor the response from the wiimote.

I have implemented all the above for my project and everything stops within a couple of seconds of removing the batteries

Hope this helps,

Phil

alexellis commented 7 years ago

@furbrain this thread is two years old already but great to hear you found a potential solution. I'd like to try it out next time I fire up my robot. http://blog.alexellis.io/piwars-v2-0/

moppymopperson commented 6 years ago

@furbrain That worked really well, you're a life saver!