09-25-2017 09:32 AM
Hi all,
I'm trying to use Scan from String to extract data from a string retrieved over a serial line to an Arduino that I programmed - meaning I know exactly what the strings look like. When I test the Scan from String with a minimal-working-example on an actual data string, it works fine. In the full VI however, it keeps throwing back Error 85 (arg1) already on the first iteration and I cannot find why.
The string ends with CR and contains data of multiple controllers, formatted as: ><name1>,<Kp>,<Ki>,<Kd><name2>,... An example string would be: >PRE, 1.000, 5.000, 0.000GAS, 1.000, 0.000, 0.000
Since the number of controllers is flexible, I use a while-loop to read the controller-data into an array of clusters - each cluster consisting of a string (name) and three floats (Kp, Ki, Kd) - using Scan From String. For each iteration, it scans the string for the sequence of %[A-Z],%f,%f,%f and continues on the last scan offset until the remainder string is empty.
I have tried not using the index but feeding the remainder string back into the loop/function, but that gave the same error - it always throws the error already on the first attempt. When I probe the input string and then copy it to the minimal-working-example, it works flawlessly...
Attached are the two VI's: one is the actual VI, with all the extra functionality with it. The second is a minimal-working-example with an actual datastring, and this works.
Am I missing something? Help would be appreciated!
Solved! Go to Solution.
09-25-2017 10:58 AM
Some comments:
So one "problem" with your Arduino string is that there is no "separator" (such as a comma) between sets of readings -- you have <Kd><name2>, "0.000GAS", which puts too much "responsibility" on the %f processing to know when to stop. If, however, you always have your floats in a 3-decimal format, you could use %.3f to specify where the scan stops.
In your Arduino code, I notice a VISA read of a fixed number of bytes. If you are using a Termination Character when sending the Strings from the Arduino, configure your VISA Read to use the same termination character and then do a VISA read of 1000 characters (or 100, but something more than you ever expect to see). Let VISA decide when to stop. This ensure "What You See Is What You Expect".
Bob Schor
09-25-2017 11:45 AM - edited 09-25-2017 11:49 AM
Thanks for the reply, Bob.
I have thought about separating the string, and the alternatives are not a lot nicer. In theory the float-scan should terminate upon detecting a non-numerical character, whether the readings are separated by comma, semicolon, or simply the next set of characters.
I thought about separating every loop with a semicolon, then first split the string on this and do Scan from String on the substrings, but it adds an unnecessary loop (not as clean). The other option would be to always separate by comma, but then there's a trailing comma to deal with at every reading.
I don't want to revert to fixed-width scanning since I might need more decimals later on (or it changes when ported to a different microcontroller).
In any case it does not change that for some reason, an input string that is valid in one VI is suddenly an invalid input in another.
Last part you're right - I should increase the read buffer. I'm only using two controllers now, but to be future proof I should have a buffer of 1025 bytes.
09-25-2017 04:43 PM
@irPaul wrote:
Last part you're right - I should increase the read buffer. I'm only using two controllers now, but to be future proof I should have a buffer of 1025 bytes.
1025 bytes? I'm worried you didn't understand my point -- you should specify a VISA Read that is guaranteed absolutely expected to never be reached! A "common number" is 1024 (a "round power of two", and much larger than a one-line string has any reason to be legal).
So it looks like the problem is handling a float right-up-against a String. Note that a perfectly legal combination is "0.003" next to "3-Phase Power" -- can you guess how %f will go crazy with this? Hence the need for "parsing terminators/separators", i.e. a non-numeric (typically a space, tab, or comma) after a numeric.
Bob Schor
09-26-2017 12:49 AM
The buffer size is arbitrary of course. In my case 1024 should suffice, since that's 2-4 times larger than the output buffers in my Arduino code. (I'm used to allocating a rounded power of two + 1, since C-strings need the NULL-terminator).
I see your point, though I know for sure that the name will never contain numerical characters. Anyway, I'll add the separator to test that. Still, it's strange that the exact same string works in one VI and not in the other..
09-26-2017 02:12 AM
Strangest thing this..
I plugged the string >PRE, 1.0000, 0.0000, 0.0000GAS, 1.0000, 5.0000, 0.0000 directly into the Scan from String instead of the read buffer (in the full VI) and it read the values flawlessly. Wired the read buffer back in, failed.
I then added the comma between the two datasets, so now the string is: >PRE, 1.0000, 0.0000, 0.0000,GAS, 1.0000, 5.0000, 0.0000
The first read set contains a trailing comma (separating the sets), the second does not. I thought I would handle this using an optional character, regex-style, but that does not work with Scan from String.
With the format strings %[a-zA-Z],%f,%f,%f%[,] or %[a-zA-Z],%f,%f,%f, it reads both data readings but then returns Error 85, since the trailing comma is missing in the second set. How would I define the optional character in the format string? From the documentation it seems impossible.
09-26-2017 02:43 AM
Believe me, if you find different behaviours, then the input strings are also different.
I suggest to compare the read buffer and your test string enabling Codes or even Hex display format: you certainly find a mismatch, surely difficult to see at glance.
09-26-2017 02:56 AM
Indeed pincpanter, that's what I realised a few minutes ago as well. I figured LabVIEW might append the termination character (CR) to the string and it's not visible in normal probing. When copying the string to another VI the CR is not copied. This is different from the Arduino library, where the termination-char is not added to the string, so I didn't think of it right away.
The solution is in the appended snippet. Instead of comparing to an empty string, I simply check the length of the remaining string, since a valid string should contain at least 3 comma's.
To deal with the optional trailing comma I simply increment the pointer by one to skip the trailing comma (I still prefer using pointers).