jesus_malaga
Posts: 54
Joined: Sun Oct 18, 2015 6:15 pm

Using an I2C expander to connect multiple distance sensors?

Mon Mar 21, 2016 2:30 pm

I am working in a robot project. It will have a bunch of sensors, at first no less than three ultrasonic distance sensors and probably a couple light sensors (detect obstacles and follow a line, obviously).

I do not really need a very complex funcionallity nor a very fast detection process (let's say we do not want the robot to run too fast :lol: ), but I do not want to run out of GPIO pins. Apart of that, the system has some extra hardware, including a sense hat and an adafruit servo pwm hat, so yet a few already taken.

I think using some sort of I2C I/O expander can give me the answer. It could even offer the extra benefit of isolating the sensors from the GPIO. Something like the PCF8574 or the MCP23017:

http://www.ebay.com/itm/PCF8574-IO-Expa ... 1550089351
http://www.ebay.com/itm/INBOARD-MCP2301 ... 1349022571

Any similar experience? Any known to work alternatives to connect them?

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Using an I2C expander to connect multiple distance senso

Mon Mar 21, 2016 2:43 pm

it depends on how the sensors output.
if you can choose between the PCF and the MCP, the second is much, much, much, MUCH better

User avatar
joan
Posts: 14251
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Using an I2C expander to connect multiple distance senso

Mon Mar 21, 2016 2:49 pm

You will need to buy special ultrasonic sensors which come with an I2C interface. If you try to connect a HC-SR04 or similar (trigger/echo type) sensor to the Pi via a port expander I doubt you'll be able to get accurate ranges.

jesus_malaga
Posts: 54
Joined: Sun Oct 18, 2015 6:15 pm

Re: Using an I2C expander to connect multiple distance senso

Mon Mar 21, 2016 3:01 pm

joan wrote:You will need to buy special ultrasonic sensors which come with an I2C interface. If you try to connect a HC-SR04 or similar (trigger/echo type) sensor to the Pi via a port expander I doubt you'll be able to get accurate ranges.
Regarding I2C sensors, that is not an option. The price of such use to move in the around $50 area. Much more than actual budget. :)

Anyway I do not need "accurate" ranges in fact. I need "aproximated". Do not want them for exact measurement, but for obstacle avoiding, thus an error margin is acceptable.

Do you know what would it mean "not accurate"

User avatar
joan
Posts: 14251
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Using an I2C expander to connect multiple distance senso

Mon Mar 21, 2016 3:14 pm

jesus_malaga wrote: ...
Do you know what would it mean "not accurate"
I haven't tried via a port expander so can't be sure. I'd guess that instead of a range accurate to 1 cm you'd be looking at a range accurate to 30 cms or so.

edo1
Posts: 136
Joined: Sun Jun 15, 2014 3:33 pm
Location: Russia

Re: Using an I2C expander to connect multiple distance senso

Mon Mar 21, 2016 3:17 pm

I'm trying to use HC-SR04 over CAN bus (with MCP25020 GPIO expander). It seems to work, but I haven't tested it well yet.
And yes, I don't need so accurate measurement.

edo1
Posts: 136
Joined: Sun Jun 15, 2014 3:33 pm
Location: Russia

Re: Using an I2C expander to connect multiple distance senso

Mon Mar 21, 2016 3:21 pm

jesus_malaga wrote:but I do not want to run out of GPIO pins. Apart of that, the system has some extra hardware
IMHO you could connect time-sensitive things (like HC-SR04) directly to GPIO-pins, all others things - to expander.

jesus_malaga
Posts: 54
Joined: Sun Oct 18, 2015 6:15 pm

Re: Using an I2C expander to connect multiple distance senso

Mon Mar 21, 2016 4:06 pm

edo1 wrote:
jesus_malaga wrote:but I do not want to run out of GPIO pins. Apart of that, the system has some extra hardware
IMHO you could connect time-sensitive things (like HC-SR04) directly to GPIO-pins, all others things - to expander.
The point here is that three HC-SR04 mean dedicate 6 GPIO ports. And eventually a fourth (could be an option) would take two more. If you add this to the three already taken by the sense hat... maybe too much. That's why I would like to study an alternative.

You say you are working on a CAN bus expander. ¿Is there any reason you know to consider using CAN better than I2C?

User avatar
joan
Posts: 14251
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Using an I2C expander to connect multiple distance senso

Tue Mar 22, 2016 11:29 am

I was unduly pessimistic about the use of a port expander.

Using sequential reads you can achieve a decent resolution in the centimetre region. It's definitely worth trying. My prototype is below. You will need to refer to the MCP23017 specification to understand the whys and whats of the script.

Code: Select all

#!/usr/bin/env python

# i2c_sonar.py
# 2016-03-22
# Public Domain

import time

import pigpio # http://abyz.co.uk/rpi/pigpio/python.html

# To get fast sequential reads we use banked mode.  If banked mode isn't
# used then only half the accuracy will be achieved.

IODIRA=0
IPOLA=1
GPINTENA=2
DEFVALA=3
INTCONA=4
IOCON1=5
GPPUA=6
INTFA=7
INTCAPA=8
GPIOA=9
OLATA=10

IODIRB=16
IPOLB=17
GPINTENB=18
DEFVALB=19
INTCONB=20
IOCON2=21
GPPUB=22
INTFB=23
INTCAPB=24
GPIOB=25
OLATB=26

BANK=128
SEQOP=32

MODE = BANK + SEQOP

MCP_ADDR=0x27 # All address bits strapped high.

BUS_BYTE_TIME=90 # 90 for 100 kbps I2C bus, 22.5 for 400 kbps bus

TIME=30.0

pi=pigpio.pi() # Connect to local Pi.

if not pi.connected:
   exit(0)

h = pi.i2c_open(1, MCP_ADDR)

# Check to see if already initialised.

m1 = pi.i2c_read_byte_data(h, IOCON1)
m2 = pi.i2c_read_byte_data(h, IOCON2)

if (m1 != MODE) or (m2 != MODE):
   # Initialise to BANK + SEQOP
   pi.i2c_write_byte_data(h, 10, MODE)

# Initialise A0 as input, rest as outputs.

# A0 is used for the echo.
# B0 is used for the trigger.

pi.i2c_write_byte_data(h, IODIRA, 0x01)  # A0 is input
pi.i2c_write_byte_data(h, IODIRB, 0x00)  # everything else are outputs.

stop = time.time() + TIME

while time.time() < stop:

   # Send trigger on B0 then do 200 sequential reads of A0.

   count, data = pi.i2c_zip(h, 
      [7, 3, GPIOB, 1, 0, 7, 1, GPIOA, 6, 200])

   if data[0] == 0: # Ignore data if trigger start missed.
      f = False
      for i in range(count):
         v = data[i]  & 1 # Mask off all but echo bit.
         if f:
            if not v:
               print(int(round(i*BUS_BYTE_TIME/58.8)))
               break
         else:
            if v:
               f = True

   time.sleep(0.2)

pi.i2c_close(h)

pi.stop()
Data from test run moving a board in front of a sensor.

Code: Select all

# $ /code/i2c_sonar.py  
57
58
57
58
57
57
58
58
58
57
58
57
57
57
54
55
57
58
57
57
58
58
58
57
35
32
31
28
24
23
21
20
18
17
15
14
14
14
14
12
14
14
21
23
24
26
28
29
31
32
32
34
35
37
38
40
41
43
44
46
47
49
49
49
49
38
37
35
35
34
32
31
29
28
26
24
23
21
20
18
17
15
15
14
12
12
12
12
15
17
17
18
18
20
21
23
24
26
28
29
31
34
35
37
40
41
44
Plot
i2cson.png
i2cson.png (29.65 KiB) Viewed 3592 times
Last edited by joan on Tue Mar 22, 2016 12:02 pm, edited 1 time in total.

jesus_malaga
Posts: 54
Joined: Sun Oct 18, 2015 6:15 pm

Re: Using an I2C expander to connect multiple distance senso

Tue Mar 22, 2016 12:01 pm

Well... you could not be clearer and more helping, thanks a lot - I think I will be ordering the MCP23017 module right today :D

The code is pretty clear and very illustrative.

I have discovered that the abelectronics guys in fact produce a hat that is nothing by exactly two MCP23017 controllers placed in a pi breakout board with all the pins there. They call it "IO pi". And they even have a constructed python library to get coding facts even simpler: https://www.abelectronics.co.uk/p/54/IO-Pi-Plus

Still not sure if I will be ordering a general usage module or will take the chance to have the full set and "pay" those guys for setting it all up done.

Thanks again for your help!!!

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Using an I2C expander to connect multiple distance senso

Tue Mar 22, 2016 2:58 pm

probably for the echo you could try with MCP23017 interrupt.

User avatar
mikronauts
Posts: 2720
Joined: Sat Jan 05, 2013 7:28 pm
Contact: Website

Re: Using an I2C expander to connect multiple distance senso

Tue Mar 22, 2016 4:52 pm

Massi wrote:probably for the echo you could try with MCP23017 interrupt.
That should work nicely.
http://Mikronauts.com - home of EZasPi, RoboPi, Pi Rtc Dio and Pi Jumper @Mikronauts on Twitter
Advanced Robotics, I/O expansion and prototyping boards for the Raspberry Pi

edo1
Posts: 136
Joined: Sun Jun 15, 2014 3:33 pm
Location: Russia

Re: Using an I2C expander to connect multiple distance senso

Tue Mar 22, 2016 9:26 pm

jesus_malaga wrote:The point here is that three HC-SR04 mean dedicate 6 GPIO ports.
you could use common output pin for all sensors and one input pin per sensor, couldn't you?
You say you are working on a CAN bus expander. ¿Is there any reason you know to consider using CAN better than I2C?
really CAN bus GPIO expander was used before for remote buttons and so on.
and when necessity to connect HC-SR04 occurred I tried this way.

Simple ~9Hz square wave generator was made. It was connected with HC-SR04 trigger pin. Both generator and HC-SR04 echo pin were connected (through OR gate) with MCP pin. MCP was tuned to generate CAN packet on falling edge on this pin. So there are two CAN packets on every measurement: one for emission start (end of pulse from generator which turns measurement on), another for echo receipt (end of pulse from HC-SR04).
I like the fact that the kernel keeps timestamp for every incoming CAN packet, so there is no requirement to be precise in userspace.
It is enough to listen packets on CAN bus and calculate difference between timestamps (like candump -t d does).

P.S. Sorry, my english is very bad, but I made a try.

User avatar
mikronauts
Posts: 2720
Joined: Sat Jan 05, 2013 7:28 pm
Contact: Website

Re: Using an I2C expander to connect multiple distance senso

Tue Mar 22, 2016 9:39 pm

No, you cannot use one output pin in common due to multi-path interference you can only use one sensor at a time.
http://Mikronauts.com - home of EZasPi, RoboPi, Pi Rtc Dio and Pi Jumper @Mikronauts on Twitter
Advanced Robotics, I/O expansion and prototyping boards for the Raspberry Pi

User avatar
joan
Posts: 14251
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Using an I2C expander to connect multiple distance senso

Tue Mar 22, 2016 9:48 pm

mikronauts wrote:No, you cannot use one output pin in common due to multi-path interference you can only use one sensor at a time.
...and all the sensors would be driving the output line (it's not open collector). Those not sensing would be driving it low. The one sensing would be trying to drive it high for the echo period.

edo1
Posts: 136
Joined: Sun Jun 15, 2014 3:33 pm
Location: Russia

Re: Using an I2C expander to connect multiple distance senso

Tue Mar 22, 2016 10:21 pm

mikronauts wrote:No, you cannot use one output pin in common due to multi-path interference you can only use one sensor at a time.
ok, it seems to be a bad idea.
joan wrote:...and all the sensors would be driving the output line (it's not open collector). Those not sensing would be driving it low. The one sensing would be trying to drive it high for the echo period.
we are speaking about the same?
I suggested to connect trigger pins, not echo pins.

New idea: we could connect each trigger pin separately, but connect all echo pins together through OR gate. So we need only N+1 pins for N sensors.

User avatar
mikronauts
Posts: 2720
Joined: Sat Jan 05, 2013 7:28 pm
Contact: Website

Re: Using an I2C expander to connect multiple distance senso

Wed Mar 23, 2016 7:01 pm

You are right, I forgot to specify that part.

I'd just use a diode per sensor, with a pull-up on the Pi side it is pretty easy to combine multiple sensor outputs.

Or better yet, a multi-input OR gate.
joan wrote:
mikronauts wrote:No, you cannot use one output pin in common due to multi-path interference you can only use one sensor at a time.
...and all the sensors would be driving the output line (it's not open collector). Those not sensing would be driving it low. The one sensing would be trying to drive it high for the echo period.
http://Mikronauts.com - home of EZasPi, RoboPi, Pi Rtc Dio and Pi Jumper @Mikronauts on Twitter
Advanced Robotics, I/O expansion and prototyping boards for the Raspberry Pi

User avatar
joan
Posts: 14251
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Using an I2C expander to connect multiple distance senso

Thu Mar 24, 2016 1:38 pm

mikronauts wrote:
Massi wrote:probably for the echo you could try with MCP23017 interrupt.
That should work nicely.
Well, it works, although I'm not convinced it is an outright winner.

All graphs show 60 seconds worth of plots at a nominal 10 per second.

Both interrupt and non-interrupt solutions pointing to a wall 122 centimetres away.
i2c-sonar-steady.png
i2c-sonar-steady.png (42.43 KiB) Viewed 3391 times
No interrupt solution pointing at a moving object.
i2c-sonar-moving-no-int.png
i2c-sonar-moving-no-int.png (32.86 KiB) Viewed 3391 times
Interrupt solution pointing at a moving object.
i2c-sonar-moving-int.png
i2c-sonar-moving-int.png (34.2 KiB) Viewed 3391 times
Example code at http://abyz.co.uk/rpi/pigpio/examples.h ... c_sonar_py

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Using an I2C expander to connect multiple distance senso

Thu Mar 24, 2016 1:54 pm

why didn't you use the INTFA in place of the GPIOA register?
this should avoid the risk of reading the register "too late" when the interrupt is worked by the PI. You indeed has only to be sure to read the INTFA register before of the "falling" interrupt (end of echo)

then in my opinion the advantage of the interrupted solution is to avoid i2c bus saturation, so a easy wrong timing issue if any other concurrent i2c call is made by the system..

Have you tried a "simple" GPIO Connection? just to see differences :)

Edit to add: and i see your code managing different i2c bus speed. is it better with a common 400kbps speed?

User avatar
joan
Posts: 14251
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Using an I2C expander to connect multiple distance senso

Thu Mar 24, 2016 2:22 pm

Massi wrote:why didn't you use the INTFA in place of the GPIOA register?
this should avoid the risk of reading the register "too late" when the interrupt is worked by the PI. You indeed has only to be sure to read the INTFA register before of the "falling" interrupt (end of echo)
...
You need to know when the echo goes high and the echo goes low. To get those times into the Pi I use the INTA line. INTA will only raise a new interrupt once the previous has been cleared.

So GPIOA is read to clear INTA and the trigger is sent. INTA will raise when the echo line goes high some time after the trigger (430 µs with my sensor). GPIOA must be read again to clear that interrupt so that the echo going low will raise another interrupt.

I couldn't find another way of reliably getting those two accurate timestamps into pigpio.

The bus speed determines how long each byte takes to transfer. For the non-interrupt solution that provides the echo line timing. For the interrupt solution I need to do enough byte reads of GPIOA to ensure that 430 µs has elapsed so the initial echo interrupt is cleared (so INTA is reset).

User avatar
joan
Posts: 14251
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Using an I2C expander to connect multiple distance senso

Thu Mar 24, 2016 3:02 pm

Massi wrote: ...
Have you tried a "simple" GPIO Connection? just to see differences :)
...
I monitored the echo and trigger lines during development. The interrupt solution will be as accurate as talking directly to the Pi.

Interrupt solution: Trigger 26, echo 21, INTA 20.
i2c_sonar-int.png
i2c_sonar-int.png (44.56 KiB) Viewed 3353 times
Multiple reads solution: Trigger 26, echo 21, INTA not used.
i2c_sonar-no-int.png
i2c_sonar-no-int.png (43.93 KiB) Viewed 3353 times

jesus_malaga
Posts: 54
Joined: Sun Oct 18, 2015 6:15 pm

Re: Using an I2C expander to connect multiple distance senso

Mon Jun 06, 2016 2:14 pm

I have been very busy, and had no time to do additional tests, but I finally was able to sucessfully use the MCP23017 to control 6 different distance sensors, that are read secuentially.

I have found an issue, I guess related to the way the full system work. As measuring is based in sound speed, things happen real fast. The air speed of sound, 343 m/s, means 34 cms per ms - that is, about 30 µseconds for a centimeter.

It seams that, at least in my system, while using perl with active background functions as camera, wifi link, sound, etc. the minimum time between reads in the MCP23017 bus is about 200 µseconds (around 5-6 reads per millisecond). That is, the minimum resolution is about 8-10cms. Distances under 8 seconds are never detected, and ranges are considered in about that leaps: 8 cms, 15 cms, 25 cms... or so.

For my actual usage, such resolution is enough - i want it all to cover obstacle detection for a robot, and 10 cms. should be either way "too close" for the robot - but some other usages could have to mind it.

Colleoni
Posts: 9
Joined: Fri Dec 16, 2016 11:41 pm

Re: Using an I2C expander to connect multiple distance senso

Fri Dec 16, 2016 11:51 pm

@joan I am currently testing the script you posted in your last message. But I have some troubles, basically 99% of the time I get an invalid measure. Debugging a little bit the code I found that the problem is caused by the following if condition that fails:

if (data[0] & (1<<ranger)) == 0: # Ignore data if trigger start missed.

Obviously I could remove it but then I get quite random measurement, I remember that on some tutorial people suggest to set the trig output for a while before clearing it and waiting for the echo, and at first it seemed strange not finding this in your code, but I tried it and I am still not able to figure out the problem. Basically I always miss the trigger start. Do you have any idea/suggestion?
I am using a raspberry 3 and at the moment I am not using the interrupt mode since I still have to figure out it a little bit more.

Thanks

User avatar
joan
Posts: 14251
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Using an I2C expander to connect multiple distance senso

Sat Dec 17, 2016 9:10 am

Colleoni wrote:@joan I am currently testing the script you posted in your last message. But I have some troubles, basically 99% of the time I get an invalid measure. Debugging a little bit the code I found that the problem is caused by the following if condition that fails:

if (data[0] & (1<<ranger)) == 0: # Ignore data if trigger start missed.
...
Could you capture some screenshots with http://abyz.co.uk/rpi/pigpio/piscope.html for targets at a known distance (say 10 cm).

Zoom in to the area of interest so we can see the timings from the trigger to the response (if any).

You will need to put jumper wires between the MCP23017 trigger and receiver and some spare GPIO.

Colleoni
Posts: 9
Joined: Fri Dec 16, 2016 11:41 pm

Re: Using an I2C expander to connect multiple distance senso

Sat Dec 17, 2016 9:38 am

Unfortuantely, I am not so skilled in hardware stuff, but I will try. That was only to say it will take some time, just one question if i correctly understand. You mean that I should connect the trigger and echo pin, both to the MCP23017 and the GPIO pin of the raspberry, right? So that I can pilot the hcsr04 with the MCP23013 and monitor it on the raspberry

Thanks for your support

Return to “Automation, sensing and robotics”