如何实现两个机器时间同步-计算rtt+offset

news/2024/11/15 18:58:16/文章来源:https://www.cnblogs.com/xcywt/p/18411849

背景:

之前的项目大致可以分为两层,逻辑层和设备层,运行在同一个主机上。
最近在着手搭建一个仿真平台,在另外一台主机上部署机器人机器相关硬件设备,比如陀螺仪,轮机,雷达等。

由于两台主机的时间戳不同步问题,导致定位系统有问题,为此需要实现两个主机的时间同步。

具体分两步:
1)测量两主机的网络延迟(round trip time,RTT)。
2)根据RTT计算时间偏移offset。

一、计算RTT

参考:https://blog.csdn.net/ingnight/article/details/100518409#:~:text=%E4%B8%80%E3%80%81roun
用于测量两台机器之间的网络延迟,即“往返时间(round trip time,RTT)”,原理如下:

大致逻辑图:

 相关proto:

/*
定时运行,比如每5分钟执行一次。
1. A->B. 发3个TimestampRTT_Req
2. B会收到3个TimestampRTT_Req. B-A:再回复3个TimestampRTT_Res
3. A收到TimestampRTT_Res后,记录下收到的时间戳A_ts2. RTT1 = ((A_ts2 - A_ts1) - (B_ts2 - B_ts1)) / 2;
4. 再求平均 RTT_Avg
5. 求 offsetTs = A_ts1 - (B_ts1 - RTT_Avg) = A_ts1 + RTT_Avg - B_ts1如何使用 offsetTs:
B_ts转换成A的时间戳 Ats = offsetTs + B_ts
*/
message TimestampRTT_Req{int64 A_ts1 = 1; // GetNow_Steady
}message TimestampRTT_Res{int64 A_ts1 = 1; // 接收端赋值。就是收到的 A_ts1int64 A_ts2 = 2; // 接收端不用赋值。收到回复后,再记录一下时间戳。int64 B_ts1 = 3; // 接收端赋值。GetNow_Steady recv timeint64 B_ts2 = 4; // 接收端赋值。GetNow_Steady res time
}

伪代码:

主机A:

    
// 发送端:实际调用时,需要连续发5-10个void sendSync(){printf("[%s] EcalPubManager::sendSync() 发送 TimestampRTT_Req +++++++++++++++  \n", dros::utils::GetCurTimeStamp_MilSec().c_str());m_startSyncTs = dros::utils::GetNow_Steady();static eCAL::protobuf::CPublisher<dros::pb::timestampTest::TimestampRTT_Req> pub(m_DROS_DOMAIN + "TimestampRTT_Req");dros::pb::timestampTest::TimestampRTT_Req data;data.set_a_ts1(dros::utils::GetNow_Steady());pub.Send(data);}// 接收void ProtoCallbackRecvTimestampRTT_Res(const dros::pb::timestampTest::TimestampRTT_Res& message) {printf("[%s] EcalPubManager::ProtoCallbackRecvTimestampRTT_Res() 收到 TimestampRTT_Res:[%s]  \n", dros::utils::GetCurTimeStamp_MilSec().c_str(), message.DebugString().c_str());dros::pb::timestampTest::TimestampRTT_Res message1;message1.CopyFrom(message);message1.set_a_ts2(dros::utils::GetNow_Steady());m_vecTimestampRTT_Res.push_back(message1);  // 放到一个数组里,主要为了取平均值,提高精度。}// 计算offsetlong long GetTsOffset(){    if(!m_bComputeOffset){auto diff = dros::utils::GetNow_Steady() - m_startSyncTs;if(diff > 5000){printf("[%s] EcalPubManager::GetTsOffset() 同步指令已经接收完成, 正在计算offset ...  \n", dros::utils::GetCurTimeStamp_MilSec().c_str());m_bComputeOffset = true;if(m_vecTimestampRTT_Res.size() > 2){long long rttCount = 0;int mCount = 0;for(auto iii: m_vecTimestampRTT_Res){mCount++;auto rtt = ((iii.a_ts1() - iii.a_ts2()) - (iii.b_ts1() - iii.b_ts2())) / 2;rttCount += rtt;printf("[%s] EcalPubManager::GetTsOffset() 正在计算offset iii:[%s] rtt:%lld $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  \n", dros::utils::GetCurTimeStamp_MilSec().c_str(), iii.DebugString().c_str(), rtt);}long long avgRTT = rttCount / mCount;   // 求平均值,提高精度long long offset = m_vecTimestampRTT_Res[0].a_ts1() + avgRTT - m_vecTimestampRTT_Res[0].b_ts1();m_TsOffset = offset;printf("[%s] EcalPubManager::GetTsOffset() 新 offset:[%lld] avgRTT:[%lld] $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  \n", dros::utils::GetCurTimeStamp_MilSec().c_str(), offset, avgRTT);}else {printf("[%s] EcalPubManager::GetTsOffset() m_vecTimestampRTT_Res 为空。将重新开始发送Req $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  \n", dros::utils::GetCurTimeStamp_MilSec().c_str());startSyncTime();}}else{printf("[%s] EcalPubManager::GetTsOffset() m_bComputeOffset is false, 正在接收 RTT_Res $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  \n", dros::utils::GetCurTimeStamp_MilSec().c_str());}}else{printf("[%s] EcalPubManager::GetTsOffset() m_bComputeOffset is true, 无需计算offset $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  \n", dros::utils::GetCurTimeStamp_MilSec().c_str());}return m_TsOffset;}

 

主机B:

// 收到req,立马回复void ProtoCallbackRecvSimTimestampRTT_Req(const dros::pb::timestampTest::TimestampRTT_Req& message) 
{printf("[%s] ProtoCallbackRecvSimTimestampRTT_Req() +++++++++++++++ message:[%s] \n",dros::utils::GetCurTimeStamp_MilSec().c_str(), message.DebugString().c_str());static eCAL::protobuf::CPublisher<dros::pb::timestampTest::TimestampRTT_Res> pub(m_DROS_DOMAIN + "TimestampRTT_Res");dros::pb::timestampTest::TimestampRTT_Res data;data.set_a_ts1(message.a_ts1());data.set_a_ts2(0);data.set_b_ts1(dros::utils::GetNow_Steady() + offsetTest); // 接收到数据时的时间戳std::this_thread::sleep_for(std::chrono::milliseconds(10));  // 这个可以取消,主要为了模拟处理消耗。data.set_b_ts2(dros::utils::GetNow_Steady() + offsetTest); // 处理完成后的时间戳pub.Send(data);
}

 

计算offset:

offset = ats1 + RTT - bts1;

二、如何使用offset:

主机A接收到B发来的时间戳加上offset就是转换后的时间戳
TsA = offset + TsB

三、总结及说明:

1.上述数据结构是用protobuf定义的。

2.数据传输通过ecal发送proto的方式。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/796567.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# 操作xml(转)

四、xml 1、概念:XML可扩展的标记语言类似于HTML XML:存储数据 注意: XM工是严格区分大小写的。 XML标签也是成对出现的。 2、通过代码来创建xML文档 1、引用命名空间 using System.Xml; 2、创建XML文档对象 XmlDocument doc = new XmlDocument(); 3、创建第一行描述信息,并且…

代码随想录突击版刷题

704.二分查找 https://leetcode.cn/problems/binary-search/description/ 59.螺旋矩阵IIhttps://leetcode.cn/problems/spiral-matrix-ii/description/、 参考题解写出54.螺旋矩阵https://leetcode.cn/problems/spiral-matrix/description/class Solution { public:vector<i…

高精地图(HD map)的简单介绍

高精度语义地图的动态构建-HDMapNet - 知乎 (zhihu.com)

fastDFS - 单机部署 + nginx

准备查看操作系统的版本信息[root@lab10 ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core)查看操作系统的网卡地址[root@lab10 ~]# ip address show ens32 2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group def…

python 获取163 邮箱的邮件信息

此案例是是获取的一个亚马逊的验证码 import time from imaplib import IMAP4_SSL import imaplib,email,datetime from lxml import etree from dateutil.parser import parsedef str_to_unicode(s, encoding=None):return str(s, encoding) if encoding else str(s)def get_x…

支付宝携手HarmonyOS SDK打造高效便捷的扫码支付体验

背景 在日常的购物转账、生活缴费等在线支付中,用户在正式拉起支付界面前,均需要至少经历一次"识别"+两次"寻找",即识别归属应用、寻找应用、寻找扫码入口,才能完成扫码、付款,每一步都带来不同程度的用户流失。如何将步骤繁琐的扫码支付做到最简化,…

基于Java+Springboot+Vue开发的鲜花商城管理系统

项目简介该项目是基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学…

基于Java+Springboot+Vue开发的体育用品商城管理系统

项目简介该项目是基于Java+Springboot+Vue开发的体育用品商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的体育用品商城管理系统项目,大学生可以在…

基于Java+Springboot+Vue开发的口腔牙科诊所预约管理系统

项目简介该项目是基于Java+Springboot+Vue开发的口腔牙科诊所预约管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的口腔预约管理系统项目,大学生可以在…