Forty-two Unos in a row

I am looking for some advice on how best to implement my project.

I am installing 42 large LED panels on a curving pedestrian bridge about 50 meters long. Each panel will respond to a passerby by changing color and fading back to the original color. This is a public art project in a hospital.

I have coded this project so that each Uno is in charge of one large panel, sensing the person and changing the color in response. While each Uno is independent, it can sense what it's immediate neighbor is doing and respond accordingly, for example if two people approach each other, the panel in the middle can turn a different color than it would normally with a single pedestrian.

I am currently trying to implement a system where all units can respond to the ambient light level on the bridge, for example, to adjust for day and night or changing weather conditions. This is necessary because one side of the bridge is a glass curtain wall exposed to the outside.

My question is about how best to communicate with all the Unos on the bridge. The information transmitted could be as simple as a single bit indicating day or night (as read and processed from a single "light meter" unit in the middle of the bridge), or as complex as an 8-bit light level transmitted to all panels.

To create an I2C network, I would have to use bus extenders due to the distances involved. This complicates my board design somewhat but I could do it if needed. The info to be transmitted could run at a VERY low rate.

I'm just not sure if a single TTL signal transmitted to all 42 units constitutes a "bus" and therefore would require bus extenders just like I2C. If that's the case, then I would just go with I2C and get all the extra capability.

Any advice or experience in a similar situation would be greatly appreciated!

I2C will make it hard, both the hardware and sofware.

Perhaps it is better to use something simple, like a serial bus. There are ways to cascade the serial data through the whole chain of devices. You could lower the baudrate if there are problems with the long wires. If you already have the Arduino Uno boards, the SoftwareSerial library could be used. With the SoftwareSerial library the serial port via the usb bus is still available to check the Uno via the usb.

Is there a computer connected ? or are they fully standalone ? With a computer connected you could send data via that cascaded serial line and send commands to a specific Uno. So you could create something special for a certain event.

Thanks for your ideas.

There is no full-time computer connected to the whole array, but I can access any Uno via USB to create a Master/Slave relationship. Since I was going down the I2C road, each custom shield has its own unique hardware address. I really wanted to send the same info to all of them, so this in itself seems a little bit of overkill. Here’s the loop that addresses all of them:

 for (int i = 0; i < 42; i++) {
  Wire.beginTransmission(i); // transmit to all devices
  Wire.write(x);              // sends one byte  
  Wire.endTransmission();    // stop transmitting
}

Since you only need a single bit for the photocell, just use an output from the one with a photocell, connected to an input on the adjacent Unos, then from those, use an output to input all the way to the ends.

I see what you mean. So instead of having the Master be the only output and all the rest being inputs (making the chain of drops too long), I can hopscotch my way to the end.

Just out of curiosity, is there a limit on the length of any one chain of drops? Is it about 5 meters or 400pF capacitance like the I2C?

Thanks!

Ansen: I see what you mean. So instead of having the Master be the only output and all the rest being inputs (making the chain of drops too long), I can hopscotch my way to the end.

Just out of curiosity, is there a limit on the length of any one chain of drops? Is it about 5 meters or 400pF capacitance like the I2C?

It's hard to say for sure, but the limiting factor would be noise on the line. Electical activity in the area would be the cause of the noise, and without trying it, prediction is difficult. You will need two pins on each Uno, and I don't know how many you have available, but if you can afford two, the distance between any two Arduinos would be about 1.3 metres, and noise should not be a problem.

Could you string a "signal" wire the length of the bridge and use one of the Arduinos to put a "high" voltage on it so that all the others could read it? Perhaps use 12v or 24v?

I suspect (with absolutely no experience) that if the voltage is maintained for long enough it would stabilize. Maybe flow a current through the wire so it behaves like it's a "power supply" to something?

...R

This sounds like a job for RS485 or RS422. If you have 1 master and the rest slaves then the MAX485 should be fine and only needs 3 wires the same as I2C (SCL, SDA & GND). You would connect it to the Arduino UART pins and just use Serial.print commands.

My question is about how best to communicate with all the Unos on the bridge. The information transmitted could be as simple as a single bit indicating day or night (as read and processed from a single “light meter” unit in the middle of the bridge), or as complex as an 8-bit light level transmitted to all panels.

what you could do is to have every UNO output a PWM signal that is read by analogRead() of the neighbour (low pass filter might be needed).

UNO1 → PWM → UNO2 ← PWM ← UNO3 …
UNO1 ← PWM ← UNO2 → PWM → UNO3
UNO1 — GND — UNO2 — GND — UNO3

this way you can communicate at least (I guess) 32 different levels, there is no handshake or buffer needed.

One thought might be mesh networking (802.15.4), or even wifi, but there the costs ramp up if you need to put the communications on each board.

If you daisy chain all of the UNOs, you run into the old Christmas tree light problem (when I was growing up, Christmas tree lights were all done in series, and if one light burned off, it would turn off all of the lights, or at least all of the lights after the burned out light). You would need to have all Uno's on and communicating all of the time.

It might be simpler, to group say 6 Uno's together that talk to each other via i2c. Then one Uno has RS-485/RS-422, ethernet, or wifi to the master host.

Only one wire is needed for the entire length. How about a really slow PWM. Like count how long the pin is high every 30 seconds. This would allow 31 values 0-30. Why limit this to integers?

lar3ry: Since you only need a single bit for the photocell, just use an output from the one with a photocell, connected to an input on the adjacent Unos, then from those, use an output to input all the way to the ends.

Sounds good, that way there would be no power loss though the wires as one wire wouldn't have to stretch the whole bridge, instead each wire would only have to travel from one Uno to the next. Seems the simplest, best solution.

Yes, I agree, simple is better. You could add protection resistors in case there is electrical noise on the lines, even if they are only short lines between the modules. For example 47 or 100 ohm at output pins and 470 ohm or 1k at input pins. Perhaps you could choose output and input pins that are compatible with the SoftwareSerial library, that way you can still upgrade some day to serial data and send commands down the chain.

i2c is fine as you can slow it down, have 1 master giving clock signals to all, use a optocoupler at each uno. on each uno have a opto going in and a opto going out on the unos both to sda on the bus to seperate lines so you will need 4 wires. 1 gnd 1 sclk 1 sdaout 1 sdain on the master swap connections keep it simple and use same resistors on network as i2c needs. now you can communicate anything you like. i used to have a rs232 connectionnetwork with behind every computer one small reedrelay.

This really is a textbook case for RS485. Two wires (differential), bus topology, good for long distances, resistant to noise and tolerant to differences in the power supplies. The only additional hardware you need is a suitable interface IC. The MAX485 is the go-to here, but it puts one unit load on the line per device, with a suggested maximum of 32. You can use an IC that has a higher input impedance to impose only 1/2 unit load per device, giving you a suggested max of 64 devices -- more than enough for 42 panels.

I expect video of this project when it's done! 8)

I know it won't be nice from an artistic point of view if one or two of the Unos stop functioning for some reasoning but I think it would be better than one failure preventing 20 of them from working.

Consequently I wouldn't use any communication system that relies on "a to b", "b to c", "c to d" etc. If "c" fails everything downstream will be affected.

If there is a "master" Uno sending out commands you might want to consider some redundancy there also.

...R

+1 for RS-485, this sort of thing is what it lives for. And you can get 1/4UL transceivers for 256 nodes if you like.


Rob

Thanks for all your good advice. I decided to go for RS-485 and am happy to report that it's up and running.

I'm using this chip because it has a half-unit load rating, thus giving me 64 possible nodes. http://www.ti.com/lit/ds/symlink/sn65hvd485e.pdf

Video of the project soon...

Thanks again!

Video of the project soon...

Looking forward to it.


Rob

PS: I'm definitely no code wizard. This code works great to set a hardware node address on my network, but I'm wondering if there's a more elegant solution, using fewer resources, faster, etc. etc. It's like a dip switch, only I'm doing it directly on the board, cutting the traces to create a permanent address for each shield.

 // Reads the Analog pins and sets a 6-bit address for each board.

  int boardAddress = 0;

void setup(){
  //start serial connection
  Serial.begin(9600);
  //configure Analog pins as inputs and enable the internal pull-up resistor
  pinMode(A0, INPUT_PULLUP);
  pinMode(A1, INPUT_PULLUP);
  pinMode(A2, INPUT_PULLUP);
  pinMode(A3, INPUT_PULLUP);
  pinMode(A4, INPUT_PULLUP);
  pinMode(A5, INPUT_PULLUP);
  
                             //read the pin values into a variable
  int A = digitalRead(A5);
  int B = digitalRead(A4);
  int C = digitalRead(A3);
  int D = digitalRead(A2);
  int E = digitalRead(A1);
  int F = digitalRead(A0);

  
  if (A == LOW) {
    A = 1;
  }
  else {
    A = 0;
  }

  if (B == LOW) {
    B = 2;
  }
  else {
    B = 0;
  }
  
  if (C == LOW) {
    C = 4;
  }
  else {
    C = 0;
  }
  
  if (D == LOW) {
    D = 8;
  }
  else {
    D = 0;
  }
  
  if (E == LOW) {
    E = 16;
  }
  else {
    E = 0;
  }
   
  if (F == LOW) {
    F = 32;
  }
  else {
    F = 0;
  }
    boardAddress = (A + B + C + D + E + F);
}

void loop(){

    Serial.println(boardAddress);
    delay(1000);
}