# Serial port data at high rate problem with timestamp

**URL:** <https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499>\
**Category:** General\
**Created:** [13 March 2023 09:22 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499 "2023-03-13T09:22:11Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![yzerman](https://avatars.discourse-cdn.com/v4/letter/y/ce7236/32.png) [@yzerman](https://discourse.nodered.org/u/yzerman)\
**Post date:** [13 March 2023 09:22 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/1 "2023-03-13T09:22:11Z")

</div>

Hi, I receive data from the serial port at 50Hz frequency each message. I need to add timestamp to each message, so I do as follow:

`msg.timestamp = Date.now()`

So the timestamps of the messages needs to be at 20ms each other (because 50Hz frequency), but in the debug console I am receiving inconsistent timestamps as well as equal timestamps that overlaps etc...

Is there a way how to achieve consistent timestamps at 20ms distance each other?

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [13 March 2023 09:42 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/2 "2023-03-13T09:42:02Z")

</div>

Can you show us an example of what you are seeing?

Note though, that nodejs is not a realtime system. Occasionally it has to do stuff like memory garbage collection, so to get reliable 20ms sampling you would need a significantly powerful processor. You would probably be better doing the real time stuff in something like an Arduino or other mcu and sending the timestamped data to node-red via mqtt

---

<div class="post-metadata">

**Author:** ![yzerman](https://avatars.discourse-cdn.com/v4/letter/y/ce7236/32.png) [@yzerman](https://discourse.nodered.org/u/yzerman)\
**Post date:** [13 March 2023 10:45 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/3 "2023-03-13T10:45:41Z")

</div>

Hi, thanks for your answer. I am using raspberry pi with node-red. I need to read the serial data from external device, so I am using NR. I just need to add a timestamp to each packet from serial. The packets comes at 50Hz. I will make a screenshot of the debug window

---

<div class="post-metadata">

**Author:** ![yzerman](https://avatars.discourse-cdn.com/v4/letter/y/ce7236/32.png) [@yzerman](https://discourse.nodered.org/u/yzerman)\
**Post date:** [13 March 2023 11:40 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/4 "2023-03-13T11:40:32Z")

</div>

This is the output from the debug window. The timestamps isn't at 20ms distance each other.

```auto
{"timestamp":"1678573635206","P1":1.92,"P2":-0.51,"P3":4.86,"P4":-7.17}
{"timestamp":"1678573635270","P1":1.92,"P2":-0.51,"P3":4.74,"P4":-7.17}
{"timestamp":"1678573635270","P1":1.92,"P2":-0.51,"P3":4.74,"P4":-7.17}
{"timestamp":"1678573635270","P1":1.92,"P2":-0.51,"P3":4.74,"P4":-7.17}
{"timestamp":"1678573635270","P1":1.92,"P2":-0.51,"P3":4.74,"P4":-7.17}
{"timestamp":"1678573635328","P1":1.92,"P2":-0.51,"P3":4.74,"P4":-7.17}

```

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [13 March 2023 11:44 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/5 "2023-03-13T11:44:02Z")

</div>

Can you export the serial node and the nodes after it up to the debug node please?

---

<div class="post-metadata">

**Author:** ![yzerman](https://avatars.discourse-cdn.com/v4/letter/y/ce7236/32.png) [@yzerman](https://discourse.nodered.org/u/yzerman)\
**Post date:** [13 March 2023 12:05 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/6 "2023-03-13T12:05:01Z")

</div>

Of course here is the flow:

```auto
[
    {
        "id": "b39e02db3febcac7",
        "type": "tab",
        "label": "Flow 5",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "afe2a9717e167739",
        "type": "function",
        "z": "b39e02db3febcac7",
        "name": "function 18",
        "func": "let dataArr = msg.payload\nlet timestamp = Date.now()\nlet probeObj = {\n \"timestamp\":timestamp,\n \"P1\":dataArr[0],\n \"P2\":dataArr[1],\n \"P3\":dataArr[2],\n \"P4\":dataArr[3]\n}\nmsg.payload = probeObj\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 430,
        "y": 200,
        "wires": [
            [
                "9dcdf4f625098f97"
            ]
        ]
    },
    {
        "id": "6335ee0f34db9cd0",
        "type": "serial in",
        "z": "b39e02db3febcac7",
        "name": "",
        "serial": "8b47e599abd2db2c",
        "x": 170,
        "y": 200,
        "wires": [
            [
                "afe2a9717e167739"
            ]
        ]
    },
    {
        "id": "9dcdf4f625098f97",
        "type": "msg-speed",
        "z": "b39e02db3febcac7",
        "name": "",
        "frequency": "sec",
        "interval": 1,
        "estimation": false,
        "ignore": false,
        "pauseAtStartup": false,
        "topicDependent": false,
        "x": 650,
        "y": 200,
        "wires": [
            [],
            [
                "2a0df6e570152edc"
            ]
        ]
    },
    {
        "id": "2a0df6e570152edc",
        "type": "debug",
        "z": "b39e02db3febcac7",
        "name": "debug 15",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 840,
        "y": 200,
        "wires": []
    },
    {
        "id": "8b47e599abd2db2c",
        "type": "serial-port",
        "serialport": "/dev/ttyUSB3/",
        "serialbaud": "115200",
        "databits": "8",
        "parity": "none",
        "stopbits": "1",
        "waitfor": "0x80",
        "dtr": "none",
        "rts": "none",
        "cts": "none",
        "dsr": "none",
        "newline": "5",
        "bin": "bin",
        "out": "count",
        "addchar": "",
        "responsetimeout": "10000"
    }
]

```

 ![Node-RED](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/d/4/d4e43b38282091daa92d7659c97ccd5a947087e7.png)

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [13 March 2023 12:35 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/7 "2023-03-13T12:35:07Z")

</div>

I will have a look shortly. What is the speed node? Is it a contrib node, if so then which? Just in case it is corrupting messages and overlaying data from one onto the next one, disconnect it from the function node and connect the debug node direct to the function node to see what you are getting there. The fact that you see identical timestamps suggests that the message may be getting overwritten.

---

<div class="post-metadata">

**Author:** ![yzerman](https://avatars.discourse-cdn.com/v4/letter/y/ce7236/32.png) [@yzerman](https://discourse.nodered.org/u/yzerman)\
**Post date:** [13 March 2023 14:29 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/8 "2023-03-13T14:29:00Z")

</div>

I just put the speed node to measure the rate. Then I deleted it. The debug output is directly to the function

---

<div class="post-metadata">

**Author:** ![cameo69](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/cameo69/32/66593_2.png) [@cameo69](https://discourse.nodered.org/u/cameo69)\
**Post date:** [13 March 2023 14:41 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/9 "2023-03-13T14:41:40Z")

</div>

I just quickly ran this and for me it looks good. Probably it is the issue described by @Colin that it is not a realtime environment and if your pi is busy with other things it might become irregular.

Calculated the difference between consecutive timestamps and it looks like this:

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/7/3/73d37abcf9b53ea759948390d1c6cd2ec623d4fb.png)

You can see that no diff = 0 was recorded (blue numbers for the counter nodes).

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/e/7/e70eb25319d1d405cdd3ab698022dc1f51d4e63d.png)

The burst function from here (by @JGKK), slightly modified, but very useful for testing:

> [@Need to design aflow that every 30 min bursts X message with a 30ms interval](https://discourse.nodered.org/t/need-to-design-aflow-that-every-30-min-bursts-x-message-with-a-30ms-interval/30486/8):
>
> Something like this could do it, of course you would have to adapt it to your times and circumstances as I used way shorter periods to test it and its just a basic example flow. Play with it: [{"id":"6807ce07.123cd","type":"function","z":"35572fe7.e9aef8","name":"burst","func":"var myObj = msg.payload;\nfunction waitSixty () {\n setTimeout(()=\>{\n flow.set(\"timeout\", false);\n },1000);\n}\nfunction repeatThirty (variable) {\n var interval …

demo flow (edited, to clear chart before each run):

```auto
[{"id":"afe2a9717e167739","type":"function","z":"b39e02db3febcac7","name":"function 18","func":"let dataArr = msg.payload\nlet timestamp = Date.now()\nlet probeObj = {\n \"timestamp\":timestamp,\n \"P1\":dataArr[0],\n \"P2\":dataArr[1],\n \"P3\":dataArr[2],\n \"P4\":dataArr[3]\n}\nmsg.payload = probeObj\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":430,"y":200,"wires":[["9dcdf4f625098f97","6996523243997805"]]},{"id":"9dcdf4f625098f97","type":"msg-speed","z":"b39e02db3febcac7","name":"","frequency":"sec","interval":1,"estimation":false,"ignore":false,"pauseAtStartup":false,"topicDependent":false,"x":650,"y":200,"wires":[[],["2a0df6e570152edc"]]},{"id":"2a0df6e570152edc","type":"debug","z":"b39e02db3febcac7","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":850,"y":200,"wires":[]},{"id":"88212e65fc6862a8","type":"inject","z":"b39e02db3febcac7","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":220,"y":200,"wires":[["63f795e18b6cfb24","d6c00f0d1c836990"]]},{"id":"8db1084698ed70ff","type":"function","z":"b39e02db3febcac7","name":"burst","func":"var myObj = msg.payload;\nfunction waitSixty () {\n setTimeout(()=>{\n flow.set(\"timeout\", false);\n },10000);\n}\nfunction repeatThirty (variable) {\n var interval = setInterval(()=>{\n node.send({payload:variable});\n var timeout = flow.get(\"timeout\");\n if (!timeout) { clearInterval(interval) }\n },20);\n}\nflow.set(\"timeout\",true);\nwaitSixty();\nrepeatThirty(myObj);\nreturn;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":470,"y":260,"wires":[["4085a98fafaf9a0b","afe2a9717e167739"]]},{"id":"4085a98fafaf9a0b","type":"debug","z":"b39e02db3febcac7","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":630,"y":260,"wires":[]},{"id":"6996523243997805","type":"function","z":"b39e02db3febcac7","name":"calc diff","func":"let ts = msg.payload.timestamp;\nlet lastTS = flow.get('lastTS') || 0;\nflow.set('lastTS', ts);\nlet diff = ts - lastTS;\nif (diff < 10000000000) {\n msg.payload = diff;\n return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":660,"y":100,"wires":[["d344787c048eb17f","b54fd4d6c47d83a5","b2c2c61ed6d0c477"]]},{"id":"d344787c048eb17f","type":"ui_chart","z":"b39e02db3febcac7","name":"","group":"8b5cde76.edd58","order":2,"width":0,"height":0,"label":"chart","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"outputs":1,"useDifferentColor":false,"className":"","x":890,"y":100,"wires":[[]]},{"id":"b54fd4d6c47d83a5","type":"debug","z":"b39e02db3febcac7","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":910,"y":60,"wires":[]},{"id":"b2c2c61ed6d0c477","type":"switch","z":"b39e02db3febcac7","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"num"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":890,"y":140,"wires":[["b14466bec234beff"],["a0b79bd3e8916ba8"]]},{"id":"b14466bec234beff","type":"counter","z":"b39e02db3febcac7","name":"counter diff = 0","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1080,"y":140,"wires":[]},{"id":"a0b79bd3e8916ba8","type":"counter","z":"b39e02db3febcac7","name":"counter else","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1070,"y":200,"wires":[]},{"id":"63f795e18b6cfb24","type":"delay","z":"b39e02db3febcac7","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":300,"y":260,"wires":[["8db1084698ed70ff"]]},{"id":"d6c00f0d1c836990","type":"change","z":"b39e02db3febcac7","name":"clear chart","rules":[{"t":"set","p":"payload","pt":"msg","to":"[]","tot":"jsonata"},{"t":"set","p":"lastTS","pt":"flow","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":650,"y":40,"wires":[["d344787c048eb17f"]]},{"id":"8b5cde76.edd58","type":"ui_group","name":"","tab":"8f03e639.85956","order":1,"disp":true,"width":"12","collapse":false,"className":""},{"id":"8f03e639.85956","type":"ui_tab","name":"Home","icon":"dashboard","order":4,"disabled":false,"hidden":false}]

```

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [13 March 2023 15:27 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/10 "2023-03-13T15:27:01Z")

</div>

> [@yzerman](#):
>
> The debug output is directly to the function

Do you mean the debug you posted is not from the flow you posted?

---

<div class="post-metadata">

**Author:** ![dceejay](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/dceejay/32/38_2.png) [@dceejay](https://discourse.nodered.org/u/dceejay)\
**Post date:** [13 March 2023 15:43 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/11 "2023-03-13T15:43:57Z")

</div>

What happens if you use a change node configured to set msg.timestamp to timestamp rather than the function node ? and then debug `msg.timestamp`  
(IE not re-organise the rest of the object)

Next question - what hardware are you running this on ?

---

<div class="post-metadata">

**Author:** ![yzerman](https://avatars.discourse-cdn.com/v4/letter/y/ce7236/32.png) [@yzerman](https://discourse.nodered.org/u/yzerman)\
**Post date:** [13 March 2023 16:10 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/12 "2023-03-13T16:10:03Z")

</div>

I will try this. Thanks!

---

<div class="post-metadata">

**Author:** ![yzerman](https://avatars.discourse-cdn.com/v4/letter/y/ce7236/32.png) [@yzerman](https://discourse.nodered.org/u/yzerman)\
**Post date:** [13 March 2023 16:10 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/13 "2023-03-13T16:10:19Z")

</div>

Just ignore the speed node please

---

<div class="post-metadata">

**Author:** ![davidz](https://avatars.discourse-cdn.com/v4/letter/d/a88e57/32.png) [@davidz](https://discourse.nodered.org/u/davidz)\
**Post date:** [13 March 2023 19:11 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/14 "2023-03-13T19:11:44Z")

</div>

As other ppl indicated, Nodejs is asynchronous. You need to handle this issue through software.

If your input message rate is guaranteed at 50Hz by the hardware, then you can do the following:

1. Get the timestamp of the first message with Date.now(). Use context or flow variable to save the first time stamp.

2. For each subsequent message, read the saved time stamp from the previous message, simply add 20ms. This is the time stamp for your current message. Save the time stamp again for the next message.

This way, you can guarantee that the messages are separated by 20ms interval.

Background: Our sensor data could arrive in microsecond interval, and we process data this way to guarantee the correct time stamp. We use Microtime() function to get microsecond resolution.

---

<div class="post-metadata">

**Author:** ![ghayne](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ghayne/32/39_2.png) [@ghayne](https://discourse.nodered.org/u/ghayne)\
**Post date:** [13 March 2023 19:35 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/15 "2023-03-13T19:35:31Z")

</div>

> [@davidz](#):
>
> For each subsequent message, read the saved time stamp from the previous message, simply add 20ms. This is the time stamp for your current message. Save the time stamp again for the next message.

This is only the assumed timestamp, not the actual timestamp. This method does not compensate for OS delays.

---

<div class="post-metadata">

**Author:** ![davidz](https://avatars.discourse-cdn.com/v4/letter/d/a88e57/32.png) [@davidz](https://discourse.nodered.org/u/davidz)\
**Post date:** [13 March 2023 21:44 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/16 "2023-03-13T21:44:05Z")

</div>

This method assumes that the sampling rate is guaranteed, and gets rid of the effect of OS timing uncertainty.

---

<div class="post-metadata">

**Author:** ![yzerman](https://avatars.discourse-cdn.com/v4/letter/y/ce7236/32.png) [@yzerman](https://discourse.nodered.org/u/yzerman)\
**Post date:** [14 March 2023 08:29 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/17 "2023-03-14T08:29:50Z")

</div>

Thank you very much for your answer. Unfortunately the rate is not absolutely stable it's 48-52 Hz, randomly in this range. May be to measure the rate each second an update the variable that I will add to each timestamp?

---

<div class="post-metadata">

**Author:** ![davidz](https://avatars.discourse-cdn.com/v4/letter/d/a88e57/32.png) [@davidz](https://discourse.nodered.org/u/davidz)\
**Post date:** [16 March 2023 16:43 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/18 "2023-03-16T16:43:36Z")

</div>

A stable rate can be ensured with an external hardware buffer that feeds data to the RPI's serial port. If the hardware buffer detects that the serial port is not ready, then the buffer stores the incoming data. When the serial port is ready, then the buffer resumes sending data to the port.

For high speed data rate, the serial in node speed won't be stable no matter how powerful the processor is (because the OS is not real-time). An external hardware buffer is necessary to keep the rate stable.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [16 March 2023 17:12 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/19 "2023-03-16T17:12:50Z")

</div>

> [@davidz](#):
>
> If the hardware buffer detects that the serial port is not ready

I am pretty sure that the port will always be ready. It will accept the data at whatever rate it comes in and buffer it up. It is once it gets into node red that the timing problems arise.

---

<div class="post-metadata">

**Author:** ![davidz](https://avatars.discourse-cdn.com/v4/letter/d/a88e57/32.png) [@davidz](https://discourse.nodered.org/u/davidz)\
**Post date:** [17 March 2023 03:29 UTC](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499/20 "2023-03-17T03:29:08Z")

</div>

RPI has a small UART receive hardware buffer, and a larger software buffer provided by the driver. When the buffer is full, then data will be lost.

Sometimes, hardware UART handshaking is used to ensure no data loss (lower the speed automatically when the receiver can not handle the incoming data). But you will have jitter (varying data rate) in this case.

[Next page](https://discourse.nodered.org/t/serial-port-data-at-high-rate-problem-with-timestamp/76499.md?page=2)
