Closed player500 closed 9 years ago
The first thing to do is confirm that the hardware is fast enough. What LCD device are you using?
For example, while not a lcdproc-compatible device, the ColdTears LCDSysInfo unit is a good example for demonstrating the issue because it does non-monospace font rendering on a bult-in microcontroller and it's flat-out impossible to do atomic screen updates or to update faster than about 200ms per API call.
(I'm not sure, but I may also have another LCD somewhere that's old enough for RS232 bitrate issues to limit the update rate.)
The LCd is hd44780 connected to RPi model B. I'm OK with whole screen refresh rates of 200-250ms but what I'm getting instead is that each of the 16 vbar widgets are updated at that rate sequentially, resulting in x16 slower animation...
Directly to the RasPi's expansion header, I'm guessing?
If you're willing to send me your code, I have an HD44780 at the heart of my USB-attached drive bay LCD and I could test to see if something in the RasPi or its drivers is a significant contributor to the latency.
Yes, via i2c. Sure, below's the code. Appreciate your help!
#!/usr/bin/env python
from lcdproc.server import Server
def main():
lcd = Server(debug=False)
lcd.start_session()
screen = lcd.add_screen("Screen1")
screen.set_heartbeat("off")
screen.set_duration(10)
screenHeight = lcd.get_server_info()['screen_height']
screenWidth = lcd.get_server_info()['screen_width']
cellHeight = lcd.get_server_info()['cell_height']
cellWidth = lcd.get_server_info()['cell_width']
totalHeight = screenHeight * cellHeight
vBarWidgets = []
for xs in range(1, screenWidth + 1):
vBarWidgets.append(screen.add_vbar_widget("vBarWidget" + str(xs), x = xs, y = 2, length = totalHeight))
number = 0
try:
while True:
for vBarWidget in vBarWidgets:
vBarWidget.set_length(number % totalHeight)
number += 1
#time.sleep(0.1)
finally:
lcd.del_screen(screen.ref)
# Run
if __name__ == "__main__":
main()
It may be better to write a barGraphWidget
that combines the widget_set
commands from all the vBarWidget.set_length
into a newline separated string to send as a single server request. The lcdproc
server polls its' socket in a timed loop at 32Hz so it is impossible to update faster than that.
Sorry for not responding. The last couple of days have been a mess and it wasn't helped by my inability to track down the lcdproc module you're using.
("lcdproc" on PyPI seems to have the same API, but it gives me AttributeError: 'Server' object has no attribute 'get_server_info'
and I haven't been able to find time to move beyond that.)
The package on PyPI is out of date see: https://github.com/jinglemansweep/lcdproc
@emteejay Thanks for pointing me in the right direction. A single server request like you suggested did the trick, however the program crashes after a while with socket.error: [Errno 32] Broken pipe
@ssokolow You have to enable i2c modules on RPi + configure LCDd.conf properly and it should work. http://www.stuart-taylor.net/adafruit-i2c-rgb-16x2-lcdkeypad-raspberry-pi/
Are you reading all the replies? Every command in the request should return a success
response.
Yes, I'm getting "success" responses right until the crash:
success
success
success
success
success
Traceback (most recent call last):
File "main.py", line 41, in <module>
main()
File "main.py", line 36, in main
lcd.del_screen(screen.ref)
File "/home/pi/projects/LCDaudio/lcdproc/server.py", line 90, in del_screen
self.request("screen_del %s" % (ref))
File "/home/pi/projects/LCDaudio/lcdproc/server.py", line 45, in request
self.tn.write((command_string + "\n").encode())
File "/usr/lib/python2.7/telnetlib.py", line 280, in write
self.sock.sendall(buffer)
File "/usr/lib/python2.7/socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 32] Broken pipe
here is the updated code:
#!/usr/bin/env python
from lcdproc.server import Server
import time
def main():
lcd = Server(debug=False)
lcd.start_session()
screen = lcd.add_screen("Screen1")
screen.set_heartbeat("off")
screenHeight = lcd.get_server_info()['screen_height']
screenWidth = lcd.get_server_info()['screen_width']
cellHeight = lcd.get_server_info()['cell_height']
cellWidth = lcd.get_server_info()['cell_width']
totalHeight = screenHeight * cellHeight
vBarWidgets = []
for xs in range(1, screenWidth + 1):
vBarWidgets.append(screen.add_vbar_widget("vBarWidget" + str(xs), x = xs, y = 2, length = totalHeight))
number = 0
try:
while True:
serverRequest = ""
for vBarWidget in vBarWidgets:
serverRequest += "widget_set %s %s %s %s %s\n" % (screen.ref, vBarWidget.ref, vBarWidget.x, vBarWidget.y, number % totalHeight)
print lcd.request(serverRequest)
number += 1
time.sleep(0.1)
finally:
lcd.del_screen(screen.ref)
# Run
if __name__ == "__main__":
main()
Edit: rebooting the Pi seems to have solved the problem... Thanks again for your help
@emteejay Ahh. That makes sense. Sorry I couldn't get around to helping before you solved your problem. The last few days have had me out and about far more than usual.
@player500 I'm not on a RasPi. I offered to try it on an hd44780-based USB device that my desktop LCDproc instance is configured to use in order to rule out the RasPi's i2c as a significant source of delay.
Thanks for making this useful wrapper. I'm implementing a spectrum analyzer with 16 vbar widgets and all of them update individually after length adjustments in a loop, resulting in a very slow refresh. Would be very useful to have the capability to update them manually all at once. Thanks!