forked from Archive/PX4-Autopilot
src/modules/uxrce_dds_client: set system clock from agent CLOCK_REALTIME (#22290)
* Added parameter UXRCE_DDS_SYNCC to enable system clock synchronization. Refactored and cleaned up. Only set system time if it's off by more than 5 seconds (same as mavlink and gps).
This commit is contained in:
parent
86fbeb8a20
commit
6cc38776c8
|
@ -137,6 +137,7 @@ else()
|
|||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMPILE_FLAGS
|
||||
#-O0
|
||||
# -DDEBUG_BUILD
|
||||
${MAX_CUSTOM_OPT_LEVEL}
|
||||
SRCS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/dds_topics.h
|
||||
|
|
|
@ -95,3 +95,13 @@ parameters:
|
|||
category: System
|
||||
reboot_required: true
|
||||
default: 1
|
||||
|
||||
UXRCE_DDS_SYNCC:
|
||||
description:
|
||||
short: Enable uXRCE-DDS system clock synchronization
|
||||
long: When enabled along with UXRCE_DDS_SYNCT, uxrce_dds_client will
|
||||
set the system clock using the agents UTC timestamp.
|
||||
type: boolean
|
||||
category: System
|
||||
reboot_required: true
|
||||
default: 1
|
||||
|
|
|
@ -108,11 +108,9 @@ void on_request(
|
|||
}
|
||||
|
||||
UxrceddsClient::UxrceddsClient(Transport transport, const char *device, int baudrate, const char *agent_ip,
|
||||
const char *port, bool localhost_only, bool custom_participant, const char *client_namespace,
|
||||
bool synchronize_timestamps) :
|
||||
const char *port, const char *client_namespace) :
|
||||
ModuleParams(nullptr),
|
||||
_localhost_only(localhost_only), _custom_participant(custom_participant),
|
||||
_client_namespace(client_namespace), _synchronize_timestamps(synchronize_timestamps)
|
||||
_client_namespace(client_namespace)
|
||||
{
|
||||
if (transport == Transport::Serial) {
|
||||
|
||||
|
@ -124,7 +122,7 @@ UxrceddsClient::UxrceddsClient(Transport transport, const char *device, int baud
|
|||
if (fd < 0) {
|
||||
PX4_ERR("open %s failed (%i)", device, errno);
|
||||
// sleep before trying again
|
||||
usleep(1'000'000);
|
||||
px4_usleep(1_s);
|
||||
|
||||
} else {
|
||||
break;
|
||||
|
@ -164,10 +162,14 @@ UxrceddsClient::UxrceddsClient(Transport transport, const char *device, int baud
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
PX4_ERR("UDP not supported");
|
||||
#endif
|
||||
}
|
||||
|
||||
_participant_config = static_cast<ParticipantConfig>(_param_uxrce_dds_ptcfg.get());
|
||||
_synchronize_timestamps = _param_uxrce_dds_synct.get() > 0;
|
||||
}
|
||||
|
||||
UxrceddsClient::~UxrceddsClient()
|
||||
|
@ -249,6 +251,39 @@ void UxrceddsClient::handleMessageFormatRequest()
|
|||
}
|
||||
}
|
||||
|
||||
void UxrceddsClient::syncSystemClock(uxrSession *session)
|
||||
{
|
||||
struct timespec ts = {};
|
||||
px4_clock_gettime(CLOCK_REALTIME, &ts);
|
||||
|
||||
// UTC timestamps in microseconds
|
||||
int64_t system_utc = int64_t(ts.tv_sec) * 1000000LL + int64_t(ts.tv_nsec / 1000L);
|
||||
int64_t agent_utc = int64_t(hrt_absolute_time()) + (session->time_offset / 1000LL); // ns to us
|
||||
|
||||
uint64_t delta = abs(system_utc - agent_utc);
|
||||
|
||||
if (delta < 5_s) {
|
||||
// Only set the time if it's more than 5 seconds off (matches Mavlink and GPS logic)
|
||||
PX4_DEBUG("agents UTC time is %s by %lld us, not setting clock", agent_utc > system_utc ? "ahead" : "behind",
|
||||
abs(system_utc - agent_utc));
|
||||
return;
|
||||
}
|
||||
|
||||
ts.tv_sec = agent_utc / 1_s;
|
||||
ts.tv_nsec = (agent_utc % 1_s) * 1000;
|
||||
|
||||
if (px4_clock_settime(CLOCK_REALTIME, &ts)) {
|
||||
PX4_ERR("failed setting system clock");
|
||||
|
||||
} else {
|
||||
char buf[40];
|
||||
struct tm date_time;
|
||||
localtime_r(&ts.tv_sec, &date_time);
|
||||
strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", &date_time);
|
||||
PX4_INFO("successfully set system clock: %s", buf);
|
||||
}
|
||||
}
|
||||
|
||||
void UxrceddsClient::run()
|
||||
{
|
||||
if (!_comm) {
|
||||
|
@ -278,7 +313,7 @@ void UxrceddsClient::run()
|
|||
|
||||
// Session
|
||||
// The key identifier of the Client. All Clients connected to an Agent must have a different key.
|
||||
const uint32_t key = (uint32_t)_param_xrce_key.get();
|
||||
const uint32_t key = (uint32_t)_param_uxrce_key.get();
|
||||
|
||||
if (key == 0) {
|
||||
PX4_ERR("session key must be different from zero");
|
||||
|
@ -316,11 +351,11 @@ void UxrceddsClient::run()
|
|||
// Create entities
|
||||
uxrObjectId participant_id = uxr_object_id(0x01, UXR_PARTICIPANT_ID);
|
||||
|
||||
uint16_t domain_id = _param_xrce_dds_dom_id.get();
|
||||
uint16_t domain_id = _param_uxrce_dds_dom_id.get();
|
||||
|
||||
uint16_t participant_req{};
|
||||
|
||||
if (_custom_participant) {
|
||||
if (_participant_config == ParticipantConfig::Custom) {
|
||||
// Create participant by reference (XML not required)
|
||||
participant_req = uxr_buffer_create_participant_ref(&session, reliable_out, participant_id, domain_id,
|
||||
"px4_participant", UXR_REPLACE);
|
||||
|
@ -329,7 +364,7 @@ void UxrceddsClient::run()
|
|||
// Construct participant XML and create participant by XML
|
||||
char participant_xml[PARTICIPANT_XML_SIZE];
|
||||
int ret = snprintf(participant_xml, PARTICIPANT_XML_SIZE, "%s<name>%s/px4_micro_xrce_dds</name>%s",
|
||||
_localhost_only ?
|
||||
(_participant_config == ParticipantConfig::LocalHostOnly) ?
|
||||
"<dds>"
|
||||
"<profiles>"
|
||||
"<transport_descriptors>"
|
||||
|
@ -350,7 +385,7 @@ void UxrceddsClient::run()
|
|||
_client_namespace
|
||||
:
|
||||
"",
|
||||
_localhost_only ?
|
||||
(_participant_config == ParticipantConfig::LocalHostOnly) ?
|
||||
"<useBuiltinTransports>false</useBuiltinTransports>"
|
||||
"<userTransports><transport_id>udp_localhost</transport_id></userTransports>"
|
||||
"</rtps>"
|
||||
|
@ -404,19 +439,19 @@ void UxrceddsClient::run()
|
|||
|
||||
uxr_set_request_callback(&session, on_request, this);
|
||||
|
||||
// Synchronize with the Agent
|
||||
bool synchronized = false;
|
||||
|
||||
while (_synchronize_timestamps && !synchronized) {
|
||||
synchronized = uxr_sync_session(&session, 1000);
|
||||
|
||||
if (synchronized) {
|
||||
// Spin until sync with the Agent
|
||||
while (_synchronize_timestamps) {
|
||||
if (uxr_sync_session(&session, 1000)) {
|
||||
PX4_INFO("synchronized with time offset %-5" PRId64 "us", session.time_offset / 1000);
|
||||
//sleep(1);
|
||||
|
||||
} else {
|
||||
usleep(10000);
|
||||
if (_param_uxrce_dds_syncc.get() > 0) {
|
||||
syncSystemClock(&session);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
px4_usleep(10_ms);
|
||||
}
|
||||
|
||||
hrt_abstime last_sync_session = 0;
|
||||
|
@ -473,6 +508,10 @@ void UxrceddsClient::run()
|
|||
if (uxr_sync_session(&session, 100)) {
|
||||
//PX4_INFO("synchronized with time offset %-5" PRId64 "ns", session.time_offset);
|
||||
last_sync_session = hrt_absolute_time();
|
||||
|
||||
if (_param_uxrce_dds_syncc.get() > 0) {
|
||||
syncSystemClock(&session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -735,8 +774,8 @@ int UxrceddsClient::print_status()
|
|||
PX4_INFO("Using transport: udp");
|
||||
PX4_INFO("Agent IP: %s", _agent_ip);
|
||||
PX4_INFO("Agent port: %s", _port);
|
||||
PX4_INFO("Custom participant: %s", _custom_participant ? "yes" : "no");
|
||||
PX4_INFO("Localhost only: %s", _localhost_only ? "yes" : "no");
|
||||
PX4_INFO("Custom participant: %s", _participant_config == ParticipantConfig::Custom ? "yes" : "no");
|
||||
PX4_INFO("Localhost only: %s", _participant_config == ParticipantConfig::LocalHostOnly ? "yes" : "no");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -771,9 +810,6 @@ UxrceddsClient *UxrceddsClient::instantiate(int argc, char *argv[])
|
|||
const char *device = nullptr;
|
||||
int baudrate = 921600;
|
||||
|
||||
bool localhost_only = false;
|
||||
bool custom_participant = false;
|
||||
|
||||
const char *client_namespace = nullptr;//"px4";
|
||||
|
||||
while ((ch = px4_getopt(argc, argv, "t:d:b:h:p:n:", &myoptind, &myoptarg)) != EOF) {
|
||||
|
@ -855,19 +891,6 @@ UxrceddsClient *UxrceddsClient::instantiate(int argc, char *argv[])
|
|||
static_cast<uint8_t>(ip_i & 0xff));
|
||||
}
|
||||
|
||||
int32_t participant_config = 0;
|
||||
param_get(param_find("UXRCE_DDS_PTCFG"), &participant_config);
|
||||
|
||||
switch (participant_config) {
|
||||
case 1:
|
||||
localhost_only = true;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
custom_participant = true;
|
||||
break;
|
||||
}
|
||||
|
||||
#endif // UXRCE_DDS_CLIENT_UDP
|
||||
|
||||
if (error_flag) {
|
||||
|
@ -881,17 +904,7 @@ UxrceddsClient *UxrceddsClient::instantiate(int argc, char *argv[])
|
|||
}
|
||||
}
|
||||
|
||||
// determines if timestamps should be synchronized
|
||||
int32_t synchronize_timestamps = 0;
|
||||
param_get(param_find("UXRCE_DDS_SYNCT"), &synchronize_timestamps);
|
||||
|
||||
if ((synchronize_timestamps != 1) && (synchronize_timestamps != 0)) {
|
||||
PX4_ERR("UXRCE_DDS_SYNCT must be either 0 or 1");
|
||||
}
|
||||
|
||||
|
||||
return new UxrceddsClient(transport, device, baudrate, agent_ip, port, localhost_only, custom_participant,
|
||||
client_namespace, synchronize_timestamps);
|
||||
return new UxrceddsClient(transport, device, baudrate, agent_ip, port, client_namespace);
|
||||
}
|
||||
|
||||
int UxrceddsClient::print_usage(const char *reason)
|
||||
|
|
|
@ -57,7 +57,7 @@ public:
|
|||
};
|
||||
|
||||
UxrceddsClient(Transport transport, const char *device, int baudrate, const char *host, const char *port,
|
||||
bool localhost_only, bool custom_participant, const char *client_namespace, bool synchornize_timestamps);
|
||||
const char *client_namespace);
|
||||
|
||||
~UxrceddsClient();
|
||||
|
||||
|
@ -115,10 +115,18 @@ private:
|
|||
uORB::Publication<message_format_response_s> _message_format_response_pub{ORB_ID(message_format_response)};
|
||||
uORB::Subscription _message_format_request_sub{ORB_ID(message_format_request)};
|
||||
|
||||
const bool _localhost_only;
|
||||
const bool _custom_participant;
|
||||
/** Synchronizes the system clock if the time is off by more than 5 seconds */
|
||||
void syncSystemClock(uxrSession *session);
|
||||
|
||||
const char *_client_namespace;
|
||||
const bool _synchronize_timestamps;
|
||||
|
||||
enum class ParticipantConfig {
|
||||
Default,
|
||||
LocalHostOnly,
|
||||
Custom,
|
||||
} _participant_config{ParticipantConfig::Default};
|
||||
|
||||
bool _synchronize_timestamps;
|
||||
|
||||
// max port characters (5+'\0')
|
||||
static const uint8_t PORT_MAX_LENGTH = 6;
|
||||
|
@ -148,7 +156,10 @@ private:
|
|||
Timesync _timesync{timesync_status_s::SOURCE_PROTOCOL_DDS};
|
||||
|
||||
DEFINE_PARAMETERS(
|
||||
(ParamInt<px4::params::UXRCE_DDS_DOM_ID>) _param_xrce_dds_dom_id,
|
||||
(ParamInt<px4::params::UXRCE_DDS_KEY>) _param_xrce_key
|
||||
(ParamInt<px4::params::UXRCE_DDS_DOM_ID>) _param_uxrce_dds_dom_id,
|
||||
(ParamInt<px4::params::UXRCE_DDS_KEY>) _param_uxrce_key,
|
||||
(ParamInt<px4::params::UXRCE_DDS_PTCFG>) _param_uxrce_dds_ptcfg,
|
||||
(ParamInt<px4::params::UXRCE_DDS_SYNCC>) _param_uxrce_dds_syncc,
|
||||
(ParamInt<px4::params::UXRCE_DDS_SYNCT>) _param_uxrce_dds_synct
|
||||
)
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue