LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Scan from String: Error 85 (arg1) with valid input string

Solved!
Go to solution

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!

Download All
0 Kudos
Message 1 of 8
(4,839 Views)

Some comments:

  • I really like Scan from String and its inverse, Format Into String (I almost never use Concatenate Strings anymore).
  • Instead of putting the String Index into a Shift Register, I would have done the following:
    1. Strip off the initial ">" character.
    2. Put the resulting "pure data string" into a Shift Register.
    3. The output of Scan from String is "Remaining String", which goes both to complete the Shift Register and to an "Empty String?" function wired to the While Loop "Stop".
  • Instead of an empty "Gains" array being brought in solely for the purposes of defining the Cluster, make a Type Def of the Cluster (something you should almost always do) and use the Type Def as a Constant to define the Bundle elements.  This simplifies the wiring and the logic.

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

0 Kudos
Message 2 of 8
(4,811 Views)

Thanks for the reply, Bob.

 

  1. Absolutely agree! In this case it provides flexibility to make code portable.
  2. This I have already attempted as said in my opening post. It kept on returning the same error on the first attempt, even when I included the starting bracket in the character-set. In general I prefer working with pointers rather than manipulating the entire string, but either way it should lead to the same result..
    When I probe the index, it jumps to 55 (end of string) directly. It apparently cannot match my format string to the input string, though it works in the minimal-working-example.
  3. You're right, I will still do this when the VI works - but first fix the Scan from String before I change anything.

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.

0 Kudos
Message 3 of 8
(4,800 Views)

@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

0 Kudos
Message 4 of 8
(4,764 Views)

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..

 

 

0 Kudos
Message 5 of 8
(4,749 Views)

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.

0 Kudos
Message 6 of 8
(4,740 Views)

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.

Paolo
-------------------
LV 7.1, 2011, 2017, 2019, 2021
0 Kudos
Message 7 of 8
(4,734 Views)
Solution
Accepted by irPaul

 

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).

0 Kudos
Message 8 of 8
(4,731 Views)