Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ValueError: invalid literal for int() with base 10: '' when using InfraredSensor in Threading #746

Open
AntoniLuongPham opened this issue Jul 3, 2020 · 6 comments

Comments

@AntoniLuongPham
Copy link

AntoniLuongPham commented Jul 3, 2020

  • ev3dev version: 4.14.117-ev3dev-2.3.5-ev3
  • ev3dev-lang-python version:
    ||/ Name Version Architecture Description
    +++-====================================-=======================-=======================-==============================================================================
    ii micropython-ev3dev2 2.1.0 all Python language bindings for ev3dev for MicroPython
    ii python3-ev3dev 1.2.0 all Python language bindings for ev3dev
    ii python3-ev3dev2 2.1.0 all Python language bindings for ev3dev

I've got an error in a parallel Thread that uses the InfraredSensor when running the below program. The error message is not easy to understand, so I'm not sure what the problem is. May I have some help troubleshooting this case? Thank you very much.

#!/usr/bin/env python3


from ev3dev2.motor import LargeMotor, MediumMotor, MoveTank, OUTPUT_A, OUTPUT_B, OUTPUT_C
from ev3dev2.sensor import INPUT_1, INPUT_3, INPUT_4
from ev3dev2.sensor.lego import TouchSensor, ColorSensor, InfraredSensor

from random import randint
from threading import Thread


class Ev3rstorm:
    def __init__(
            self,
            left_foot_motor_port: str = OUTPUT_B, right_foot_motor_port: str = OUTPUT_C,
            ir_sensor_port: str = INPUT_4, ir_beacon_channel: int = 1):
        self.tank_driver = MoveTank(left_motor_port=left_foot_motor_port,
                                    right_motor_port=right_foot_motor_port,
                                    motor_class=LargeMotor)

        self.ir_sensor = InfraredSensor(address=ir_sensor_port)
        self.ir_beacon_channel = ir_beacon_channel


    def drive_once_by_ir_beacon(self, speed: float = 100):
        # forward
        if self.ir_sensor.top_left(self.ir_beacon_channel) and self.ir_sensor.top_right(self.ir_beacon_channel):
            self.tank_driver.on(
                left_speed=speed,
                right_speed=speed)

        # backward
        elif self.ir_sensor.bottom_left(self.ir_beacon_channel) and self.ir_sensor.bottom_right(self.ir_beacon_channel):
            self.tank_driver.on(
                left_speed=-speed,
                right_speed=-speed)

        # turn left on the spot
        elif self.ir_sensor.top_left(self.ir_beacon_channel) and self.ir_sensor.bottom_right(self.ir_beacon_channel):
            self.tank_driver.on(
                left_speed=-speed,
                right_speed=speed)

        # turn right on the spot
        elif self.ir_sensor.top_right(self.ir_beacon_channel) and self.ir_sensor.bottom_left(self.ir_beacon_channel):
            self.tank_driver.on(
                left_speed=speed,
                right_speed=-speed)

        # turn left forward
        elif self.ir_sensor.top_left(self.ir_beacon_channel):
            self.tank_driver.on(
                left_speed=0,
                right_speed=speed)

        # turn right forward
        elif self.ir_sensor.top_right(self.ir_beacon_channel):
            self.tank_driver.on(
                left_speed=speed,
                right_speed=0)

        # turn left backward
        elif self.ir_sensor.bottom_left(self.ir_beacon_channel):
            self.tank_driver.on(
                left_speed=0,
                right_speed=-speed)

        # turn right backward
        elif self.ir_sensor.bottom_right(self.ir_beacon_channel):
            self.tank_driver.on(
                left_speed=-speed,
                right_speed=0)

        # otherwise stop
        else:
            self.tank_driver.off(brake=False)

    def keep_driving_by_ir_beacon(self, speed: float = 100):
        while True:
            self.drive_once_by_ir_beacon(speed=speed)


    def dance_whenever_ir_beacon_pressed(self):
        while True:
            while self.ir_sensor.beacon(channel=self.ir_beacon_channel):
                self.tank_driver.on_for_seconds(
                    left_speed=randint(-100, 100),
                    right_speed=randint(-100, 100),
                    seconds=1,
                    brake=False,
                    block=True)
        
    
    def main(self, driving_speed: float = 100):
        # ERROR
        # Traceback (most recent call last):
        # File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner
        #   self.run()
        # File "/usr/lib/python3.5/threading.py", line 862, in run
        #   self._target(*self._args, **self._kwargs)
        # File "/home/robot/Ev3rstorm/Ev3rstorm-Super.EV3Dev2.Python3.Threading.py", line 170, in dance_whenever_ir_beacon_pressed
        #   while self.ir_sensor.beacon(channel=self.ir_beacon_channel):
        # File "/usr/lib/python3/dist-packages/ev3dev2/sensor/lego.py", line 909, in beacon
        #   return 'beacon' in self.buttons_pressed(channel)
        # File "/usr/lib/python3/dist-packages/ev3dev2/sensor/lego.py", line 919, in buttons_pressed
        #   return self._BUTTON_VALUES.get(self.value(channel), [])
        # File "/usr/lib/python3/dist-packages/ev3dev2/sensor/__init__.py", line 203, in value
        #   self._value[n], value = self.get_attr_int(self._value[n], 'value' + str(n))
        # File "/usr/lib/python3/dist-packages/ev3dev2/__init__.py", line 307, in get_attr_int
        #   return attribute, int(value)
        # ValueError: invalid literal for int() with base 10: ''
        Thread(target=self.dance_whenever_ir_beacon_pressed,
               daemon=True).start()

        self.keep_driving_by_ir_beacon(speed=driving_speed)


if __name__ == '__main__':
    EV3RSTORM = Ev3rstorm()
    EV3RSTORM.main()
@AntoniLuongPham AntoniLuongPham changed the title " ValueError: invalid literal for int() with base 10: '' " when using InfraredSensor in Threading ValueError: invalid literal for int() with base 10: '' when using InfraredSensor in Threading Jul 3, 2020
@WasabiFan
Copy link
Member

Sorry for the delay.

We saw this issue here too: ev3dev/ev3dev#1269

The reality is, having two threads concurrently attempt to access the same attribute is likely to cause problems -- there is no synchronization built into the library. If you could restructure your code so that one is always responsible for interacting with the sensor, that would likely solve it. Remember that you could have one thread retrieve data and save it, and the other process it, if that is helpful.

@dlech
Copy link
Member

dlech commented Jul 5, 2020

In addition to what @WasabiFan said...

The EV3 IR sensor does not like swapping modes frequently.

Using the IR beacon for heading/distance is one mode of operation and using the remote control buttons is another mode of operation (actually there are two different modes for remote control buttons).

Programs should only use one mode of operation or wait for several seconds after switching modes for best results.

@TheVinhLuong102
Copy link

@WasabiFan @dlech thanks for your diagnoses and suggestions.

@dlech is the Beacon button press detection under a different mode to the press detection of other buttons (top/bottom left/right)?

@dlech
Copy link
Member

dlech commented Jul 6, 2020

The beacon button press detection is the same mode as the other button press detection. See http://docs.ev3dev.org/projects/lego-linux-drivers/en/ev3dev-stretch/sensor_data.html#lego-ev3-ir for more info on the modes.

@TheVinhLuong102
Copy link

@dlech thank you. In that case, I think the above program actually does not make the IR sensor switch among multiple modes, because the program only checks for various button presses. So probably this issue is of the same nature as ev3dev/ev3dev#1269 -- i.e. resulting from multiple threads accessing the sensor values at the same time.

@WesleyJ-128
Copy link

This error is not exclusive to sensor reads- trying to get the motor encoder values from multiple threads yields the same error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants