hzeller / rpi-rgb-led-matrix

Controlling up to three chains of 64x64, 32x32, 16x32 or similar RGB LED displays using Raspberry Pi GPIO
GNU General Public License v2.0
3.66k stars 1.16k forks source link

How could I do a dynamic brightness control if I am using the GPIO to project images through the active adapter? #625

Open AG1023 opened 6 years ago

AG1023 commented 6 years ago

Hello everyone

Normally I used the TSL2651 / I2C to read the values of lux and depending on these values then vary the intensity of the LEDs.

In this case that the I2C is not available, is there any other way, other sensors etc, with which I could perform this function?

Thanks in advance!!

russdx commented 6 years ago

go old school with a LDR on a analog pin :D

KentWalker commented 6 years ago

If you have run out of GPIO pins, here's a suggestion: Use an Arduino Leonardo (or equivalent board that has access to the USB port). Attach an LDR to an analog input or use I2C to talk to your TSL2651 on the Leonardo/equiv board. Send current light readings via USB as an emulated mouse/keyboard/custom (depending on your coding skill level), update once every second/minute/whenever. Adapt your RPI_RGB_LED code to accept the USB input (key = ?/mouseX=?/etc) to control the intensity. Sorry I can't give coding examples, etc but Mr Google is your friend. You could even extend this to use UDP/HTTP and use remote light sensors over wifi/ethernet.

russdx commented 6 years ago

that is insane over kill :D keep it simple! :)

KentWalker commented 6 years ago

None of the GPIO pins are analog, so attaching an LDR directly isn't going to work. If you have a spare GPIO pin you could use an crude RC type of ADC:

You will need to select your LDR so its minimum light resistance is high enough so that it doesn't influence the charge voltage across capacitor eg for a minimum light resistance of 5k ohms, the capacitor can only charge to 3.0V whereas for 20k ohms it can charge to 3.2V. The downside is that it takes longer for the capacitor to discharge (200uS vs 50uS fully illuminated) and the dark resistance will also be higher too (typically 5k - 1M vs 20k - 20M ohms) so the dark discharge time might be 10mS vs 200mS.

Difficulty: hardware = easy, software = how well can you code?

KentWalker commented 6 years ago

If you don't have GPIO available or writing code for the ADC above is too difficult, using a MCU board isn't such a bad idea, after all they are better suited to sensor interfacing than a CPU...

Using a Leonardo Pro Micro (about US$5 on ebay), we can emulate a USB keyboard:

Firmware for the Leonardo: `

include "Keyboard.h"

const int ldrPin = A0; // input pin for LDR const int exitPin = 7; // input pin for exit button

void setup() { pinMode(exitPin, INPUT_PULLUP); Keyboard.begin(); }

void loop() { if(digitalRead(exitPin) == LOW) { // if exit button pressed, send exit character Keyboard.print("!"); // where '!' means exit in the RPi code while(1); // halt, will require POR or reset to restart } int ldrValue = analogRead(ldrPin); // read the value from the LDR: int result; map(result, 0, 1023, 65, 90); // scale our input to A..Z (or whatever we wish) Keyboard.print(char(result)); // send it out the USB port as a virtual keyboard delay(1000); // wait a second before reading again } `

In the Raspberry Pi, add some code that checks for keyboard input in your main loop:

russdx commented 6 years ago

If no analogue in, how about just using a simple SPI light sensor and just bit bang the spi from any free pins or use/share the hardware spi if possible.

KentWalker commented 6 years ago

The added advantage of of using an external MCU board attached via USB is it also allows the addition of extra sensors, all of which are stand-alone and not hogging valuable GPIO nor tying up the CPU while processing. Remember that this RPi to RGB matrix interface is very CPU intensive. Processing some extra keypress or keyboard string inputs doesn't take long.

If GPIO pin 10 is free (RXD) you could bypass using a virtual keyboard and send data via serial but in reality what is easier - connecting three wires between the RPi and Arduino or just plugging in a USB cable between the two? The firmware overhead is about the same regardless (since you need termios in C++ for both, can't answer that for Python, sorry).

Not so insane or overkill but actually really simple (and pretty cheap too) :@)

russdx commented 6 years ago

OP has not actually mentioned how many chains they are using! Maybe they are not even using all three and can use the i2c, If they are using all three can they just use 2? and put extra panels on the two chains?

There are plenty pins free to grab sensor data simply. Using a whole new MPU for this task is over kill! and connecting via USB is even worse! as now you have a whole usb stack/data running in the background (taking cpu time)

Bit banging spi on spare pins slowly would very little cpu and there are plenty of libs that do this for you.

My personal opinion is separate mpu + usb stack to receive a basic light level reading is bit crazy, there are simpler solutions, just need to explore them / find the best one.

You can buy simple light sensors that just give out little pulses depending on light level. I would personally use something like this and just monitor the pulses on 1 spare pin.

Would be helpful to have more information about the project. As might be other external factors that affect the solution.

KentWalker commented 6 years ago

Can you please supply a link to simple light sensors that just give out little pulses depending on light level. I couldn't find one but you could make one using a 555 timer, a couple of 10nF capacitors, a 4.7k ohm resistor and a LDR with a minimum light resistance of 5k ohms. That would give you pulses in the range of about 10mS (dark) and 100uS (light).

Using a MCU (note microcontroller, not MPU or microprocessor) is doing exactly what it designed to do, convert forms of input into some other usable output. They are cheap, reliable and accurate. Buying an off the shelf board means no PCB/perf board to build and would cost not much more than the timer version above yet a lot more flexible. You could even program it to put out little pulses depending on light level and put it in that elusive spare GPIO pin.

I suggested using USB since there are instances where there are no spare GPIO pins available. As for your comment about having a whole usb stack/data running in the background - it's already there in the OS (otherwise your keyboard isn't going to work) so no gain/loss. We just need to tweak the terminal flags so we can trap our 'keyboard' input.

I'm not stating that my way is the best way, I'm just suggesting alternatives. People have different skill sets, some may be more comfortable with writing software, others may be more at home at a hardware level. What might look like using a sledgehammer to crack a walnut might be the best option or the only tool at hand. After all, sometimes you just need a bigger hammer :@)

AG1023 commented 6 years ago

First of all thank you very much for the collaboration and interest in this matter, I have been somewhat busy but now returning to what we like.

There is several points:

For our project 2 channels of the active adapter is enough so the idea of using any of the remaining pins to connect the TSL2651 / I2C lighting sensor would be very interesting.

BUT ! Mr. Zeller in the troubleshooting section says the following...

Don't run anything that messes in parallel with the GPIO pins, e.g. PiGPIO library/daemon or devices that use the i2c or 1-wire interface if they are on the same pins you need for the panel.

… and that is the reason why we had rejected the option of using the TSL2651 / I2C because our priority is the image quality.

Maybe Mr. Zeller had any recommendations on this? It would be possible to remap and use the leftover pins for other functions, such as the lighting sensor, GPS, gyroscope, etc. without affecting the image quality.

For now to take advantage of all the infrastructure we already have in python for reading sensors, gps and/or other functions we plan to use two PI3, one to collect and compile all the sensor data and communicate it with the second PI3 + Active Adapter that would control the Led Matrix with dynamic brightness control.

hzeller commented 6 years ago

If you don't use all parallel chains, you can use the other GPIO pins as you please.

KentWalker commented 6 years ago

If you are not using a 64 row matrix (HUB75E) then GPIO pin 10 (RXD) will be free, so serial interfacing might be an option. If you are using HUB75E then I would move the E line to one of the unused GPIO pins. You only need to receive data from the other board that's doing the sensor processing so no (other) changes would be required to Henner's GPIO map. Like the keyboard routines, serial handling is part of the OS so there is no real overhead as far as CPU is concerned, it's just a matter of changing the terminal flags. The only time taken up by the CPU will be in parsing the received data (which you will have to do, regardless of which method you use to transfer the sensor data).

(Just for interest sake...) I have a project where I send data to a remote RGB display (3 parallel chains of 3 x P10 1/8 scan 32x16 panels each to give a 96 x 48 pixel display, the display is monitored via video camera so speed is of the essence here otherwise lots of nasty scanning artifacts) via RS232 at 9600 baud, the distance is over 25m using cheap twin speaker wire (GND and TXD->RXD) [note transmission levels are at RS232 specification, not logic levels over that distance]. Since the display only changes once new data arrives and has been parsed, the display 'image' is rock solid. FYI the slower the baud rate, the greater the distance you can send serial data (teletype used to be sent at 50 baud and went all around the world). Basically the parsed incoming data is used to fill in an offscreen FrameCanvas and when the Raspberry Pi receives a refresh token (ie transmission of new data ends) the software calls the SwapOnVSync() function to push the frame onto the display.

I would seriously consider using a microcontroller to handle the sensor processing rather than another Raspberry Pi. Using a CPU for sensor processing is not very efficient, it's sort of like using an axe to cut a piece of wood when you should really be using a saw. There are a lot of examples of code available for Arduino based boards, they are really easy to use and there are plenty of cheap clones available.

Going down the serial path, you can feed the data from your GPS into the serial port of the Arduino (or second RPi if you decide) and transmit everything out the same serial port to the first Raspberry Pi, you don't need two serial ports. You can change the baud rates between transmit and receive, but you would have to be careful that data didn't get corrupted.

Don't forget to level shift from 5V -> 3V3 if using an Arduino running on 5V! A really simple level shifter requires only 2 resistors: 2k2 ohm from the Arduino TXD pin to the RPi RXD pin and 3k3 ohm from the RPi RXD pin to GND.

The advantage of using the Arduino solution is there is plenty of dedicated IO available: ADC inputs, SPI and I2C interfaces (all of which are hardware based, not emulated) and libraries for 1-wire, software serial (if you need more serial ports or don't want to handle different baud rates in one serial port), and a plethora of humidity, temperature, light, accelerometer, etc sensor libraries. A microcontroller is specifically designed to do this sort of stuff, so make the most of it.

tesla1989 commented 6 years ago

Unfortunately R pi dose not has any analog input, therefore I would recommend using external ADC analog to digital converter this using IC ADC0804 or TLC0820 but this will equipy 8 Pins of GPIO to read 8 bits, then you can convert it into the software to analog or any shape again.

Also you can use analog to serial converter which is much efficient IC to do it using single pin this IC from Texax instrument TLC548.

Good luck