Hardwares used : Arduino Yun board, USB type Keyboard and Serial LCD (2L, 16Char)
I am trying to display the keyboard entry in the LCD. I have used the attached programs for this.
Partially I'm getting result. Response to get display is very slow. That is due to the below lines in my python code.
for num in range(1,500):
__ print '*'__ 1. Actually I do not need these two lines for my task. But without these lines program did not respond me. 2. And it is not properly responding for fast typing. When I type 30 characters in a fast manner, it is missing some characters in the middle to display.
All because of the above two lines.
Please go through my coding, and help me to resolve this. It will help me a lot.
@sridevi,
in your sketch you have the serial line set to 9600
void setup()
{
mySerial.begin(9600); // begin Serial
:::
This is not very fast. Your LCD may NOT be able to work faster. If so, you must go slower or buffer your keyboard (in the python or the sketch). Try that, if you can.
sridevi:
Mr.Sonnyyu and Mr.Shapeshifter, last time you both helped a lot for me to establish USB Keyboard communication with Arduino Yun.
Kindly go through this and pls share your ideas to solve this.
I saw this thread yesterday, but I'm sorry that I don't think I have any help to offer, that's why I didn't respond.
It's not really my area of expertise, but I'm willing to take a look at the Python code. But I'm not willing to download a .doc file from an unknown source. If you post the python code again as a straight text file, I'll take a look at it.
jessemonroy650:
in your sketch you have the serial line set to 9600
No, that's not very fast, but it should be fast enough to echo typed characters. Even the fastest typist in the world types at less than 20 characters per second. Being able to only send 960 characters per second to the screen should not be the limiting factor.
I'm more concerned about the 10ms delay at the end of loop(). That limits the loop rate to no more than 100 times per second. The actual loop repetition rate will be less, since all of the other code in the loop takes some time. But even if the loop rate were much slower, that is made up by the while (p.available() > 0) loop that will take all available characters in one shot. So, the delay() statement and loop processing overhead may add some latency, but it shouldn't directly cause any dropped characters since the Process class does do some buffering of the data stream. I don't think the sketch loop speed is the issue.
sridevi:
for num in range(1,500):
print '*'
Actually I do not need these two lines for my task. But without these lines program did not respond me.
This sounds to me like a buffering issue. To increase throughput and reduce overhead, there is likely some buffering going on (by Python, by the process pipe, by the Bridge communications class, or...) Instead of sending each character one at a time, they are likely being buffered up until a sufficient number of characters are queued up, then they are all sent at once. This gives a higher overall throughput since the communications overhead doesn't need to be applied to each character, just each block of characters.
By putting a bunch of "*" characters in the stream (and ignoring them in the sketch) you are filling up the buffer enough that it is being sent. But of course, you are adding a lot of overhead that then limits your bandwidth.
Two possible solutions are to disable that buffering scheme, or to explicitly flush the output to force it to be sent earlier. Unfortunately, I don't know how to do either in this environment. (But maybe this statement will trigger an idea from someone else?)
Did you try putting a carriage return or newline character after the keystroke? Sometimes, that will flush a buffer early.
Hmmm... now that I've thought it through, and responded, maybe something here is helpful after all?
#loop
for event in dev.read_loop():
if event.type == ecodes.EV_KEY:
data = categorize(event) # Save the event temporarily to introspect it
if data.scancode == 42:
if data.keystate == 1:
caps = True
if data.keystate == 0:
caps = False
if data.keystate == 1: # Down events only
if caps:
key_lookup = u'{}'.format(capscodes.get(data.scancode)) or u'UNKNOWN:[{}]'.format(data.scancode) # Lookup or return UNKNOWN:XX
else:
key_lookup = u'{}'.format(scancodes.get(data.scancode)) or u'UNKNOWN:[{}]'.format(data.scancode) # Lookup or return UNKNOWN:XX
if (data.scancode != 42) and (data.scancode != 28):
x += key_lookup # Print it all out!
print key_lookup
if(data.scancode == 28):
print x
x = ''
[/code]
Regarding the last two posts: using Bridge.put/Bridge.get is a valid way of passing data from Python to the sketch, and should work around the buffering issue with sending data back through the Process object. But I don't feel it's a very good solution for this particular task.
A potential issue is timing and latency: it can probably keep up with average typing rates, but my gut feeling is that it's getting close enough that it may be a concern. But the biggest issue I have with it is the way that it works like a shared variable: there is no notification that the other side has written to that key. The only thing that the sketch will see is that the value has changed. (The posted example sketch doesn't do that, it will just keep displaying the last key typed, even if no more keys are typed.) If the typist types the same key twice, the sketch will have no way of knowing that.
I've used this method when passing strings read from a barcode reader. In my sketch, it continually reads the key, and looks for a non-blank value. If found, the received string is processed and Bridge.put() is called to clear that value. This both lets the sketch know that the value has already been processed, and it lets the sketch detect the same value twice in a row (because it will always be different from the blank empty string.)
But the problem with that here is that writing that blank value adds more time to the overall detection process, and in the case of fast typing could overwrite an incoming keystroke before it is read (if that keystroke happens to come in during that window of time after reading the previous keystroke and clearing it.) In my barcode reader sketch, that wasn't really a problem, since the reader can't process bar codes faster about once per second. But a typist can type faster than that, and it might become an issue.
In my mind, the first thing to try is to figure out a way to disable the buffering between Python and the Process object, or figure out a way to flush that stream. I think that falling back to bridge put/get is a "Plan B" scenario.
Going back to the sketch and Python code referenced in the original post, edit the Python script and:
Near the top of the script add [color=red]import sys[/color]
After printing the keystroke, replace the problematic loop that prints 1500 asterisks with [color=red]sys.stdout.flush()[/color]
That should be it. Now, instead of waiting for the output buffer to fill up before it gets sent to the Process object in the sketch, the output is flushed so it is sent right away.
I tested it with this Python script:
#!/usr/bin/python
import time
import sys
while 1:
for i in range(10):
print i,
sys.stdout.flush()
time.sleep(0.1)
The idea is that it (slowly, because of the sleep) prints out a series of digits. With the buffering, it would take a VERY long time before the sketch saw anything, and then it would display a large amount of data at once.
With the statement to flush the output, the sketch sees the output right away.
This is the corresponding sketch, which simply launches the Python code and echos everything to the serial port:
ShapeShifter:
This sounds to me like a buffering issue. To increase throughput and reduce overhead, there is likely some buffering going on (by Python, by the process pipe, by the Bridge communications class, or...)
BTW, it looks like the buffering is being done by Python and is not part of the Bridge or the Process class. Or more correctly, Python has opened stdout in buffered mode. I say this because running the above script directly from the command line outputs immediately with the flush statement in place, and takes a very long time before it blasts out a lot of data if the flush statement is not there.
I'm confused by this. You're printing the key_lookup value the stdout, and now flushing it, but your sketch code is not looking for incoming characters from the process object.
And I just noticed that the Python code puts the key_lookup value, and then immediately clears it out by using a blank value. How is the sketch supposed to see the key_lookup value? It would have to make the corresponding Bridge.get() call in that small window of opportunity between the two puts on the Python side, otherwise wouldn't it just see nothing?
When I used a similar manner of communications for my barcode scanner, the Python code put the string to the Bridge, and then when the sketch read the value it was the sketch that put the blank value to the key as a way of acknowledging the data. This made it easy for the sketch to detect new data, even if it was the same data twice in a row.
I don't see how the code posted immediately above would work. What is your intention with it?
Hmmm... I just made what I thought was a useful discovery, and I came back to post it in this thread which was very similar. And now I re-read Sonny's post which I didn't understand last week, and I see that it's pretty much the same thing.
I guess I shouldn't be surprised that sonnyyu was a step or three ahead of me.
But, at least, there is one small saving grace for my pride in that I think my idea is slightly simpler. The idea is to run the Python script with the "-u" option to run it in ubuffered mode, which eliminates the need to explicitly flush stdout. But that means you have to launch it with a special command line to include the "-u" option.
sonnyyu suggests to get rid of the hash-bang at the beginning of the script, but if it is kept and the "-u" option is added there, the unbuffered mode will automatically be always applied to the script, even if it is run by just typing the name of the script.
No other changes are needed to the script or the way it is called. Just change the first line this: