Parsing serial output from the impulse-runner?

A bit similarly as I believe @Aisha asked here, I’d like to know if it’s possible for the CLI impulse-runner to send only the resulting classification instead of the verbiage now sent.
I’ve created a Python function trying to parse the serial output from the impulse runner, but it is trickier than I thought to parse serial output at 9600 baud or faster. The board I’m using is Silicon Labs xG24, but the question applies to other boards as well.

So, instead of this in the serial output:

Predictions (DSP: 16 ms., Classification: 1 ms., Anomaly: 2 ms.):
idle: 0.91016
snake: 0.08203
updown: 0.00391
wave: 0.00391
anomaly score: -0.067

is it possible to only get

idle: 0.91016 ?

You can edit edge-impulse-run-impulse.

  • In Ubuntu my EI CLI is in folder /home/user/.nvm/versions/node/v18.12.0/bin/.
  • Go there, right-click file, and select open with text editor. (Ubuntu knows this is a shortcut and will open the actual *.js file.
  • Near line 126 you will see serial data being collected into a data object.
    • This is data incoming as-is and is not gaurunteed to be all the data, aka the routine will exit and another serial.on() event will fire with more data.
  • In your case you can start collecting data in myBuffer[] when you see “Predictions” and end when you see “anomaly”
  • Then parse the myBuffer[] as desired.
2 Likes

On Windows find file

  • C:\Users\user\AppData\Roaming\npm\node_modules\edge-impulse-cli\build\cli\run-impulse.js
  • Then make edits at line 126.
1 Like

Thx @MMarcial, appreciated! And yes, I’m on WIndows. I’ll now try to wrap my head around this

@ThomasVikstrom

My output looks like:

Starting inferencing in 2 seconds...
Taking photo...
Predictions (DSP: 2 ms., Classification: 151 ms., Anomaly: 0 ms.):
    NotPet: 0.078125
    Pet: 0.921875
Starting inferencing in 2 seconds...
Taking photo...
Predictions (DSP: 2 ms., Classification: 151 ms., Anomaly: 0 ms.):
    NotPet: 0.031250
    Pet: 0.968750

Update the serial.on('data', data => {} with the following:

serial.on('data', data => {
	
	// Add incoming data to the buffer
	// myBuffer is a global variable.
	myBuffer += data.toString('ascii');

	const predictionsText = myBuffer; // Bring data local.

    // Split the text into individual lines
    const predictions = predictionsText.split('\n');

    // Loop through the lines and find the lines beginning with "NotPet" and "Pet"
    let notPetLine="", petLine="";
	//1234567890123456
	//NotPet: 0.023437 <-- String length will be checked later. This assumes 'scores' always have 6 decimals.
	//1234567890123
	//Pet: 0.976562
	const scoreLength = [16,13]; // <--Magic numbers be dammed.
	
	// Leave the last line in the buffer[], aka, `predictions.length-1`.
	// This allows for the case when a score is not completely in, e.g., "Pet: 0." <-- Need to wait on 6 more chars.
	for (let i = 0; i < predictions.length-1; i++)
	{
	  // Remove processed data from the buffer[].	
	  myBuffer = myBuffer.substring(predictions[i].length + 1);	
	  
	  predictions[i] = predictions[i].trim();
      if (predictions[i].startsWith('NotPet') && predictions[i].length == scoreLength[0])
	  {
        notPetLine = predictions[i];
      }
	  else if (predictions[i].startsWith('Pet') && predictions[i].length == scoreLength[1])
	  {
        petLine = predictions[i];
      }
	}

    // Print the scores beginning with "NotPet" and "Pet".
    if (notPetLine.length>0)
	{
	  process.stdout.write('+++' + notPetLine.toString('ascii') + '\n');
    }
    if (petLine.length>0)
	{
	  process.stdout.write('+++' + petLine.toString('ascii') + '\n');
    }

});

1 Like