Grove I2C motor driver and ultrasonic ranger

Hello!

I have rasberry pi 3B+ and grovepi+. I attached a grove i2c motor driver v. 1.3 to my system. If the motor driver is attached, the ultrasonic ranger freezes after every 10th or 20th read.
I tryed various combinations, and there are the same problem with other sensors as well, but this is the main issue.
The same program runs perfectly, if I disconnect the i2c port of the motor driver. If I press the reset button on the motor driver the program starts again well for 10-20 read, then it stops again. It is annoying, because a continuous work is impossible.
Can you, please, help me?
Istvan

This is the failure message I got:

Traceback (most recent call last):
  File "/home/pi/Desktop/GrovePi/Software/Python/grovepi.py", line 199, in read_i2c_block
    data = i2c.read_list(reg = None, len = no_bytes)
  File "/usr/local/lib/python3.5/dist-packages/Dexter_AutoDetection_and_I2C_Mutex-0.0.0-py3.5.egg/di_i2c.py", line 373, in read_list
    return self.transfer(outArr, len)
  File "/usr/local/lib/python3.5/dist-packages/Dexter_AutoDetection_and_I2C_Mutex-0.0.0-py3.5.egg/di_i2c.py", line 185, in transfer
    return_val = self.i2c_bus.transfer(self.address, outArr, inBytes)
  File "/usr/local/lib/python3.5/dist-packages/Dexter_AutoDetection_and_I2C_Mutex-0.0.0-py3.5.egg/di_i2c.py", line 475, in transfer
    raise IOError("[Errno 5] Input/output error")
OSError: [Errno 5] Input/output error

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/pi/Desktop/GrovePi/Software/Python/grove_ultrasonic.py", line 45, in <module>
    print(grovepi.ultrasonicRead(ultrasonic_ranger))
  File "/home/pi/Desktop/GrovePi/Software/Python/grovepi.py", line 269, in ultrasonicRead
    number = read_identified_i2c_block(uRead_cmd, no_bytes = 2)
  File "/home/pi/Desktop/GrovePi/Software/Python/grovepi.py", line 212, in read_identified_i2c_block
    data = read_i2c_block(no_bytes + 1)
  File "/home/pi/Desktop/GrovePi/Software/Python/grovepi.py", line 205, in read_i2c_block
    time.sleep(0.003)
KeyboardInterrupt
>>>

Hi @vidist,

Can you confirm me you are using this Grove I2C motor driver?

And also if you’re using this library for it?

I’m asking you this so I can be sure what needs to be tested in case I have to do that.

Next, can you show me your code for both things, for the ultrasonic sensor and the I2C motor driver? My gut tells me you are running both of them in separate threads/processes and depending on how rare each call to the resources is, you might get this delayed exception that only occurs after 10-20 reads.

Just to make it clear, the grovepi library is not thread-safe so you’re going to have to employ locks/mutexes around the resource calls to prevent getting into a blocked state.

Check this thread to find more about this:

And you can also check this part of the GrovePi’s documentation that says the library is not thread-safe.
https://dexterind.github.io/GrovePi/api/gpio/

Thank you!

Hello Robert Lucian,

Thank you for your answer.
My motor drive is Grove I2C Motor Driver v1.3, totally similar to the one at the link, just a newer release, and I used the linked library.
I also used Grove-LCD_RGB_Backlight v4.0 and grove button v1.2. in my system, here is my code:

from grove_rgb_lcd import*
import grovepi
from grovepi import *
import time
import grove_i2c_motor_driver

button = 3
ultrasonic_ranger = 4

grovepi.pinMode(button,"INPUT")
setRGB(80,100,20)


while True:
    try:
              
        buttonvalue = grovepi.digitalRead(button)
            
        if buttonvalue == 0:
            setText("Press button to start!")
            time.sleep(2)
        else:
            setText("Starting robot..")
            time.sleep(2)
                
            while True:
                try:
                    m = grove_i2c_motor_driver.motor_driver(0x0f)
                    distant = ultrasonicRead(ultrasonic_ranger)
                    time.sleep(0.1)
                                                
                    if distant >= 20:
                        setText_norefresh("Running forwards")
                        m.MotorSpeedSetAB(50,50)
                        m.MotorDirectionSet(0b1010)
                        
                    else:
                        m.MotorSpeedSetAB(0,0)
                        setText("Obstacle        Running back")
                        time.sleep(0.5)
                        m.MotorSpeedSetAB(50,50)
                        m.MotorDirectionSet(0b0101)
                        time.sleep(1)
                        m.MotorSpeedSetAB(0,0)
                        time.sleep(0.01)
                        m.MotorSpeedSetAB(50,50)
                        setText("Turning...")
                        m.MotorDirectionSet(0b0110)
                        time.sleep(0.3)
                        m.MotorSpeedSetAB(0,0)    
                    
                except (IOError, TypeError) as e:
                    print(str(e))
                    setText("IOError/TypError")
                    m.MotorSpeedSetAB(0,0)
                    time.sleep(1)
                    break
                except KeyboardInterrupt as e:
                    print(str(e))
                    setText("Keyboard stop")
                    m.MotorSpeedSetAB(0,0)
                    time.sleep(1)
                    setText("")
                    break
    except (IOError, TypeError) as e:
        print(str(e))
        setText("IOError/TypError")
        m.MotorSpeedSetAB(0,0)
        time.sleep(1)
        break        
    except KeyboardInterrupt as e:
        print(str(e))
        setText("Keyboard stop")
        m.MotorSpeedSetAB(0,0)
        time.sleep(1)
        setText("")
        break

m.MotorSpeedSetAB(0,0)
setText("");

Thanks once more if you can analyse it,
best regards:

Istvan

Okay. So you’re not doing anything in parallel, which is good. I’m gonna have this tested and get back to you with an answer.

Thank you!

I have tested it and I don’t see the same problem here.
I don’t see any conflicts in the address space of the I2C: the GrovePi is on address 0x04, the motor driver on address 0x0f and the RGB LCD on different addresses too.

And these 2 devices, the GrovePi (and by extension the Ultrasonic Sensor), and the motor driver are very independent devices, so they shouldn’t even interfere. The only issue could only come if multiple agents try to access a device on the I2C line at the same time. Have you ruled this out? Are you somehow running multiple scripts at the same time? This might explain why you showed me the error you get when you run grove_ultrasonic.py.

Thank you!

Hello!

Thank you for testing it.
You I right I have multiply libraries installed, which could cause multiplied script runing. I would never realise…I try to delete the supplementary one, and I refer about the results.
Best regards

Hello again!

I tryed several things. No multiplied files anymore, but the problem stays.
Appling the grove_ultrasonic.py (not even my code), even if I plug out everithing from the Grovepi (apart ultrasonc ranger), even using another digital port (D3), another cable, etc. the ultrasonic ranger stops after a while, and when it stops it freezes the python frame too, No Ctrl+C no interruption form menu is working. You have to kill running by closing the window.
I have a bad feeling, that the sensor is might be slightly damaged.
The other problem:
I also tryed to change the ultrasonic ranger (which was unplugged) with a Grove line finder v 1.1. It distinguishes surface and depth so I can run the robot on a platform, and instead of turning at the walls it turns at the edges (basically the same code is applyed).
Same problem with the motor again: sometimes the motor driver freezes and it is running wild, can be swithed off by reset button only - it is less often as it was with the ultrasonic ranger, but after 2-3 minutes of runnning it happens:

My “new” failure code:

Traceback (most recent call last):
  File "/home/pi/Desktop/Programok/black mark robot 1.py", line 40, in <module>
    m.MotorSpeedSetAB(50,50)
  File "/usr/local/lib/python3.5/dist-packages/grovepi-1.0.4-py3.5.egg/grove_i2c_motor_driver.py", line 57, in MotorSpeedSetAB
    bus.write_i2c_block_data(self.I2CMotorDriverAdd, self.MotorSpeedSet, [MotorSpeedA,MotorSpeedB])
  File "/usr/local/lib/python3.5/dist-packages/smbus_cffi-0.5.1-py3.5-linux-armv7l.egg/smbus/util.py", line 59, in validator
    return fn(*args, **kwdefaults)
  File "/usr/local/lib/python3.5/dist-packages/smbus_cffi-0.5.1-py3.5-linux-armv7l.egg/smbus/smbus.py", line 275, in write_i2c_block_data
    raise IOError(ffi.errno)
OSError: 121

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/pi/Desktop/Programok/black mark robot 1.py", line 58, in <module>
    m.MotorSpeedSetAB(0,0)
  File "/usr/local/lib/python3.5/dist-packages/grovepi-1.0.4-py3.5.egg/grove_i2c_motor_driver.py", line 57, in MotorSpeedSetAB
    bus.write_i2c_block_data(self.I2CMotorDriverAdd, self.MotorSpeedSet, [MotorSpeedA,MotorSpeedB])
  File "/usr/local/lib/python3.5/dist-packages/smbus_cffi-0.5.1-py3.5-linux-armv7l.egg/smbus/util.py", line 59, in validator
    return fn(*args, **kwdefaults)
  File "/usr/local/lib/python3.5/dist-packages/smbus_cffi-0.5.1-py3.5-linux-armv7l.egg/smbus/smbus.py", line 275, in write_i2c_block_data
    raise IOError(ffi.errno)
OSError: 121

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/pi/Desktop/Programok/black mark robot 1.py", line 73, in <module>
    m.MotorSpeedSetAB(0,0)
  File "/usr/local/lib/python3.5/dist-packages/grovepi-1.0.4-py3.5.egg/grove_i2c_motor_driver.py", line 57, in MotorSpeedSetAB
    bus.write_i2c_block_data(self.I2CMotorDriverAdd, self.MotorSpeedSet, [MotorSpeedA,MotorSpeedB])
  File "/usr/local/lib/python3.5/dist-packages/smbus_cffi-0.5.1-py3.5-linux-armv7l.egg/smbus/util.py", line 59, in validator
    return fn(*args, **kwdefaults)
  File "/usr/local/lib/python3.5/dist-packages/smbus_cffi-0.5.1-py3.5-linux-armv7l.egg/smbus/smbus.py", line 275, in write_i2c_block_data
    raise IOError(ffi.errno)
OSError: 121

So not too much result up to now…

Best regards:

Istvan

Hello!

I have made further tests, in all cases only the mentioned items were connected:
Motor driver + button or moisture sensor causes the known problem, after a few minutes (longer time).
Motor driver running alone - works fine, no freeze.
Surprisingly motor driver + grove servo!!! on port rpser works fine.
Motor driver + relay. Well the relay works only if the motor driver is unplugged.
Do you have any idea?

Best regards:
I.

Hi @vidist,

I might have an idea: leave the motor driver connected to the board, but don’t try actuating anything (like issuing commands to the motor driver) and see if the problem persists.

Apart from trying that out, can you also try changing the bus for the GrovePi? You can do that by calling the following function right after the grovepi module gets imported:

import grovepi
grovepi.set_bus("RPI_1")

Can you try that?

Hello Robert!

For the first thing:
I made a few test. Between the tests I pressed the reset button of the motor driver:

Test 1 – i2c motor driver & ultrasonic ranger attached – script: grove_ultrasonic.py (so motor does not run): ultrasonic ranger freezes within 1 minute – after pressing reset the script runs again (I tried a few times)

Test 2 – i2c motor driver & line finder attached – script: grove_line_finder.py (motor does not run again), line finder freezes within 2 minutes – after pressing reset the script continues running again

Test 3 – i2c motor driver & relay attached – script: grove_relay.py (motor does not run), relay does not switch after 2 minute – after pressing reset the script continues running again, relay works again

Test 4 – i2c motor driver & ledbar attached – script: grove_ledbar.py (motor does not run), ledbar freezes soon – after pressing reset the script continues running again but very soon it freezes again, reset had to be pressed 5-6times till the script was finished

I will try the other thing soon.

Best regards:
I.

Hello Robert!

Success!!!
Your second idea seem to work!
Continuous runnig for about ten minutes.
Thanks a lot!
I really would like to learn from the case. I am wondering if I still can bother you with the question what was wrong?

Best regards:

Istvan

That’s really great to hear :slight_smile:

Can you tell me what was my second idea? It’s not super clear to me when reading the old posts.

Thank you!

Changed the bus from RPI_1sw to RPI_1.
Can you tell me how it helped?

Yeah, so RPI_1SW is the bus on which the software implemented I2C operates and RPI_1 uses the hardware I2C.

Thing is, the HW I2C is really buggy, so that’s why we decided to go with the software-implemented one. The software implemented one has a low CPU usage and it’s actually quite a bit faster than the Raspberry Pi’s one, so there are only pros in using the SW I2C.

Anyhow, I suspect in this case, the SW I2C doesn’t restore the functionality of the HW I2C after each transfer, or if it does, there’s some delay coming from somewhere that might make subsequent calls fail. It’s quite weird since we know we’ve tested it for this sort of situation and we didn’t encounter it back then (like months ago). I think this may be avoidable by adding some delay between calls made with the HW I2C (all other devices) and the SW I2C (the GrovePi). This is of course unacceptable on the long term (to add delays), so we’ll have to fix this.

Thank you!

Hello Robert!

Thank you for explaining it. At the moment I am ok with this solution, but I will follow the developments of the topic.

Best regards:

Istvan

Yeah, and keep me posted if something bad happens. I know that the HW I2C’s implementation is buggy, so I’m curious to see if it works in your situation.

Thank you!

Ok. At the moment the system still works fine, but I’ll post you in case of any problem. Thank you.