Conversion from a Collection to an Integer

Dear users,

From a USB proximity sensor (MB1403 HRUSB-MaxSonar-EZ0 |),
SerialPort in SC receives the following ASCII numbers:

-> 82
-> 48
-> 51
-> 48
-> 48
-> 13

The first and the last number is fixed, and the others are variable from 48 to 57.
I only need the values from the second one to the fifth one.

Converting these series with Code I

~port = SerialPort(	"/dev/ttyUSB0", baudrate: 57600, databits: 8, stopbit: 1, parity: 0 );

fork{ 4.do { var received = 6.collect{~port.next.asAscii}; ~val = received[1..4].postln;  4.reciprocal.wait}};

returns the followings:

For example,

[ 0, 3, 0, 0 ]
[ 0, 3, 0, 1 ]
[ 0, 3, 0, 2 ]
[ 0, 3, 0, 3 ]

However, what I need is not these arrays but the numbers such as 300, 301, 302, 303, etc.

I made the following two algorithms to get those numbers:

The first algorithm is as follows:
Code II

~received = [ 1, 5, 0, 8]
~converted1 = (b = ""; ~received.collect{|item| b = b ++ item.asString;}; b.asInteger)

The second algorithm is as follows:
Code III

~received = [ 1, 5, 0, 8]
~converted2 = (~received * [1000,100,10,1]).sum

I think the second algorithm is better than the first one because the second one is simpler and shorter than the first one.

The following code block is the result of combining Code I with each algorithm

(
fork{
	4.do { 
		var received = 6.collect{~port.read.asAscii};
		~val = received[1..4].postln;
		~converted1 = (b = ""; ~val.collect{|item| b = b ++ item.asString;}; b.asInteger).postln;
		~converted2 = (~val.collect{ |val| val.asString.asInteger} * [1000,100,10,1]).sum.postln;
		4.reciprocal.wait}};
)

The second algorithm could not be directly combined with Code I, so I used some conversions.

I think it works but would like to know if there would be a more sophisticated way to do this.
The code above seems a bit clumsy.

My codes above seem not to be correctly working.
SC does not receive the series of values from the first number 82.
Sometimes SC begins to read from 48 (the second number) or other numbers.
How could SC let correctly parse the series of numbers?

In answer to your first question, SC has some useful methods, eg.

x = [48, 51, 48, 49].collect({|item, i| item.asAscii.digit;});
x.convertDigits;

1 Like

It just occurred to me that you can do this also by accumulating the values. Then there is no need for an intermediate array, and it will adapt transparently to any number of digits received between the 82 and 13 (up to the 32-bit integer limit of course)

// fake input data stream
(
p = Pseq([
	82,
	Pwhite(48, 53, { rrand(2, 5) }),
	13
], inf).trace(prefix: "ascii: ").asStream;
)

(
a = { |int| "Got integer %\n".postf(int) };

r = Routine { |inChar|
	var current = 0;
	loop {
		case
		{ inChar == 82 } {
			current = 0;
		}
		{ inChar == 13 } {
			a.value(current);
			current = 0;
		}
		// digit:
		// 1. Shift the existing digits left by one place: 2 --> 20
		// 2. Add in the new unit digit: 20 + 5 --> 25
		{ inChar.inclusivelyBetween(48, 53) } {
			current = current * 10 + (inChar - 48);
		};
		inChar = true.yield;
	}
};
)

20.do { r.next(p.next) };

ascii: 82
ascii: 51
ascii: 48
ascii: 53
ascii: 51
ascii: 49
ascii: 13
Got integer 30531
ascii: 82
ascii: 50
ascii: 50
ascii: 48
ascii: 13
Got integer 220
ascii: 82
ascii: 53
ascii: 50
ascii: 52
ascii: 53
ascii: 49
ascii: 13
Got integer 52451
ascii: 82

hjh

1 Like

Thank you for letting me know about these methods!
It helps a lot!

Thank you for helping me!
It helps a lot!
It perfectly works on macOS.

On Raspberry Pi 4B, the values from the sensor are often skipped.
For example, the values are correctly received as follows:

82
51
48
53
51
49
13

Sometimes, some values are not present, as follows:

82
49
13

I am checking the reason, but it is not easy.

Thanks sincerely for sharing this. You always help me with excellent examples!