Calculating RPM? Arduino & Firmata

I have a hall sensor that is right next to the shaft that haves two magnets (see the image below), and it is connected to the Arduino and Firmata...
image
I am curious how could I calculate the RPM of the shaft precisely...
So far I am only able to calculate up to 1ms between input by saving the timestamp of the input and then calculating the difference
I set up a sample flow with the inject node for emulating:

[{"id":"b1a8ffac.b96598","type":"group","z":"b075400f.e51258","name":"hall sensor input*","style":{"label":true},"nodes":["6bc358e5.ba1db8","a64fb2d8.015dc","9dab4746.7abac","c84255da.b00238","e7b1b3d2.1e802","abb9acb8.8a5188","5a1304af.505a94","248efa47.ad776e"],"x":94,"y":39,"w":1102,"h":122},{"id":"6bc358e5.ba1db8","type":"function","z":"b075400f.e51258","g":"b1a8ffac.b96598","name":"push time to array","func":"\nconst now = new Date()  \nvar a = []\na = flow.get('timearray')\na.push(now.getTime())\nflow.set('timearray', a )\nmsg.payload = a\nreturn msg;","outputs":1,"noerr":0,"initialize":"flow.set('timearray', [])","finalize":"","x":490,"y":80,"wires":[["a64fb2d8.015dc"]]},{"id":"a64fb2d8.015dc","type":"function","z":"b075400f.e51258","g":"b1a8ffac.b96598","name":"array of halfrevs","func":"var a = msg.payload\nvar e = a.length\nvar r\nvar halfrevs = []\nhalfrevs = flow.get('halfrev')\n\nconsole.log ( (e-1) + ' ' + (e-2))\n r= a[e-1] - a[e-2]\nif (!isNaN(r)){\nmsg.payload = r\nhalfrevs.push(r)\nflow.set('halfrev',halfrevs)\nreturn msg;\n}","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is deployed.\nflow.set('halfrev',[])","finalize":"","x":720,"y":80,"wires":[["9dab4746.7abac"]]},{"id":"9dab4746.7abac","type":"function","z":"b075400f.e51258","g":"b1a8ffac.b96598","name":"calc RPM","func":"var arr = flow.get('halfrev')\nvar e = arr.length \nvar revms\n\nrevms = arr[e-1] + arr[e-2]\nif (!isNaN(revms)){\n\nmsg.payload = ((1000/revms) * 60)\nflow.set('rpm1', (Math.round((1000/revms) * 60) ))\nreturn msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":900,"y":80,"wires":[["248efa47.ad776e"]]},{"id":"c84255da.b00238","type":"delay","z":"b075400f.e51258","g":"b1a8ffac.b96598","name":"","pauseType":"delayv","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":540,"y":120,"wires":[["abb9acb8.8a5188"]]},{"id":"e7b1b3d2.1e802","type":"function","z":"b075400f.e51258","g":"b1a8ffac.b96598","name":"restart if no input","func":"var i = context.get('i')\ni += 1 \ncontext.set('i',i)\nif (i == 1 ){\n    msg.delay = 1000\n    return msg;\n}\nelse {\n    msg.reset =''\n    node.send(msg)\n    delete msg.reset\n    msg.delay = 1000\n    node.send(msg)\n}\n","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is deployed.\ncontext.set('i',0)","finalize":"","x":425,"y":120,"wires":[["c84255da.b00238"]],"l":false},{"id":"abb9acb8.8a5188","type":"function","z":"b075400f.e51258","g":"b1a8ffac.b96598","name":"empty arrays","func":"\nflow.set('timearray',[])\nflow.set('halfrev', [])","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is deployed.\ncontext.set('i',0)","finalize":"","x":635,"y":120,"wires":[[]],"l":false},{"id":"5a1304af.505a94","type":"inject","z":"b075400f.e51258","g":"b1a8ffac.b96598","name":"Set RPM","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":"0.0001","topic":"","payload":"","payloadType":"date","x":200,"y":80,"wires":[["6bc358e5.ba1db8","e7b1b3d2.1e802"]]},{"id":"248efa47.ad776e","type":"debug","z":"b075400f.e51258","g":"b1a8ffac.b96598","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1100,"y":80,"wires":[]}]

I know this is not the most efficient way, but I couldn't think of a better more precise way...
Any thoughts on this, I tried creating a while loop inside a function, but it wasn't accurate, and values between inputs were never constant( i was debugging it with a delay node)...

I would potentially need the accuracy of 0.1 - 0.2 ms...

Could node-red-contrib-msg-speed help you calculate the rpm?

1 Like

It is not quite precise, (1ms (inject node input repeat) = 930-940 inputs per second (should be 1000) )and it can also capture inputs low as 1 ms, but thanks for the share :smiley:

I would be very surprised if the contrib-node is not carrying out the calculation correctly. It's more likely to be caused by delays in the system as node-RED is single threaded, and is struggling to handle data at this frequency.

1 Like

I probably guess this is the main issue, and I know that I am trying something impossible, I think the far better solution for me is to connect another Arduino with the hall sensor and communicate with it through a serial node. But wanted to give node-red a try for this task...

1 Like

It might be better to do the speed calc in the Arduino.

1 Like