Hello,
In my project, I want to do time measurement. I mean that i want to measure the time when my message is sending until it is receiving in the Subscriber. I want to print out this kind of measurement. What should i do in Publisher and in Subscriber?
Pc's are different, they are in connection by TCP protocol.
Would you please help me?
Best Regards,
Ehsan
Ehsan,
To measure latency from a publisher to a subscriber, you can do two different ways if pub/sub entities are located in different machines like your case.
The main issue is that time is not synchronized in different machines.
First, you can use Precise Time Protocol (PTP) to synchronize time on both machines, which guarantees more accurate time synchronization than NTP.
If you are using Ubuntu machines, it is easy to install and run on your machines like following. It uses multicast as a default, but if your network does not support multicast, you can use unicast option too.
# apt-get install ptpd
# ptpd
After installing PTP, what you can do is to get a timestamp on a publisher and stores the timestamp value in your message and send it to a subscriber.
In the subscriber, you can get a timestamp like the publisher and extract the timestamp value of the publisher from the received message and calculate latency with two timestamp values.
Second, you can measure round-trip time of a message and half the time to measure one-way latency. In this case, you do not need to synchronize time between machines as you use tiemstamps on a single machine.
RTI DDS Performance Test measures the time in this way. You can refer to this link to try it out.
https://community.rti.com/kb/example-performance-test-rti-message-service
Thanks,
Kyoungho
Thank you for your help. PTP is working on the PCs. But how can i access to the variables in the Subscriber?
I have 3 Data writers and i receive my data in Subscriber by order-group. for example, How can i access to variable 'w' which is read by DataReader2 in Subscriber?
my IDL file is:
const long CLOCK_MAX_STRING_SIZE = 256;
struct Type1 {
long x;
long y;
string<CLOCK_MAX_STRING_SIZE> message; //@key
};
struct Type2 {
long w;
long z;
string<CLOCK_MAX_STRING_SIZE> message; //@key
};
struct Type3 {
long p;
long t;
string<CLOCK_MAX_STRING_SIZE> message; //@key
};
struct ordered_group {
Type1 msg1;
Type2 msg2;
Type3 msg3;
};
Hi Ehsan,
I assume that your work is based on the ordered presentation group example in this link.
https://community.rti.com/examples/ordered-presentation-group
If so, the way to access variables in each type is simple like following.
I am not sure this would be an answer to your question. Please let me know if it was not the question you were asking.
Could I ask you one thing? For me, It looks like all 3 types (Type1, Type2, Type3) are the same. Why would you have three different types that define the same thing?
Thanks,
Kyoungho
Really Thanks. but there is problem. in each time that i want to show the received data, data which is received for exaple by DataReader1 is shown and the others are "0". I think it is because of the order of data which is received by darareaders. How can i show the real data without any "0"'s.
my output is like this:
msg1:
x: 0
y: 0
message: ""
msg2:
w: 0
z: 0
message: ""
msg3:
p: 880166
t: 30
message: ""
in this instance i want to show just msg3. What should i do?
About your Question i should say that, I want to send 3 different packets of variables. i thought that if i deffine 3 type it is easier to access to my data and each variable. What do you think? is it wrong?
Hello,
Can you describe your publishing scenario a little more? This may help with a better response to achieve what you are looking for. Are you publishing each message type independently? Do you need them grouped together for coherent access? Have you thought about having a different type that has the following structure:
struct msg {
string type; //@key
string message; //@key
long var1;
long var2;
};
That way you don't have the msg types that are in the payload that aren't being populated. You can just collect all messages from all types and have independent history on a per type basis.
Bert
Actually, I made a Test case on that way to understand what should i do. in that test case, In the Publisher i wanted to send 3 packages of Data as some Messages such as msg1 or msg2 or msg3. I decided to make DataWriters in the number of my Messages. I made one instance of my "ordered_group" struct for each message. i put the values to the variables which are related to each Message and then each Datawriter send each insatnce.
------------------------------------------------------------------------
instance1 = ordered_groupTypeSupport::create_data();
instance2 = ordered_groupTypeSupport::create_data();
instance3 = ordered_groupTypeSupport::create_data();
--------------------------------------------------------------------
instance1->msg1.y=10;
retcode = ordered_group_writer1->write(*instance1, instance_handle);
-------------------------------------------------------------------
But the real data which should publish or Subscribe is:
typedef uint16_t X;
typedef struct Y1 {
uint16_t bit_id;
uint8_t msg_class;
uint32_t message_code;
uint32_t occurrences;
uint8_t mode;
uint8_t msg_text[64];
uint8_t msg_text_length;
}Y1;
typedef struct Z1 {
uint16_t bit_id;
uint16_t func_id;
uint16_t n_objects;
uint16_t objects[256];
} Z1;
typedef struct Z2 {
uint16_t bit_id;
uint16_t func_id;
uint8_t msg_text[64];
uint8_t msg_text_length;
}Z2;
What do you think? How can i mannage it on the IDL file? I would really appreciate you if you help me.
If each DataWriter does not use variables in other types, here is my suggestion.
I've registered 3 Types in both Subscriber and publisher, I wrote my Subscriber part like this:
for(i=0; i<MyDataReaders.length(); i++){
bite_msg_tDataReader *ordered_group_reader = NULL;
bite_iam_cmd_tDataReader *ordered_group_reader2 = NULL;
bite_iam_reply_tDataReader *ordered_group_reader3 = NULL;
bite_iam_reply_t data3;
bite_iam_cmd_t data2;
bite_msg_t data;
DDS_SampleInfo info;
DDS_SampleInfo info2;
DDS_SampleInfo info3;
bite_msg_t_initialize(&data);
bite_iam_cmd_t_initialize(&data2);
bite_iam_reply_t_initialize(&data3);
ordered_group_reader =
bite_msg_tDataReader::narrow(MyDataReaders.get_at(i));
if (ordered_group_reader == NULL) {
printf("DataReader narrow error\n");
MyDataReaders.ensure_length(0,0);
subscriber->end_access();
return;
}
ordered_group_reader2 =
bite_iam_cmd_tDataReader::narrow(MyDataReaders.get_at(i+1));
if (ordered_group_reader2 == NULL) {
printf("DataReader narrow error\n");
MyDataReaders.ensure_length(0,0);
subscriber->end_access();
return;
}
ordered_group_reader3 =
bite_iam_reply_tDataReader::narrow(MyDataReaders.get_at(i+2));
if (ordered_group_reader2 == NULL) {
printf("DataReader narrow error\n");
MyDataReaders.ensure_length(0,0);
subscriber->end_access();
return;
}
retcode = ordered_group_reader->take_next_sample(data, info);
if (retcode == DDS_RETCODE_NO_DATA) {
continue;
} else if (retcode != DDS_RETCODE_OK) {
printf("take error %d\n", retcode);
continue;
}
retcode = ordered_group_reader2->take_next_sample(data2, info2);
if (retcode == DDS_RETCODE_NO_DATA) {
continue;
} else if (retcode != DDS_RETCODE_OK) {
printf("take error %d\n", retcode);
continue;
}
retcode = ordered_group_reader3->take_next_sample(data3, info3);
if (retcode == DDS_RETCODE_NO_DATA) {
continue;
} else if (retcode != DDS_RETCODE_OK) {
printf("take error %d\n", retcode);
continue;
}
/* Print data sample */
if (info.valid_data) {
bite_msg_tTypeSupport::print_data(&data);
}
if (info2.valid_data) {
bite_iam_cmd_tTypeSupport::print_data(&data2);
}
if (info3.valid_data) {
bite_iam_reply_tTypeSupport::print_data(&data3);
}
}
MyDataReaders.ensure_length(0,0);
subscriber->end_access();
And in the Output (I mean in subscriber side) I received this Error :
message: "Hey, I am X"
bite_id: 0
msg_class: <00>
fault_message_code: 0
nmuber_of_occurrences: 0
mode: <00>
message: "Hey, I am Y"
bite_id: 0
func_id: 0
number_of_objects: 0
message: "Hey, I am Z"
bite_id: 0
func_id: 0
TDataReader::narrow:ERROR: Bad parameter: wrong type reader
DataReader narrow error
DDSDataReaderSeq_get_reference:!assert index out of bounds
Segmentation fault (core dumped)
I've received just one sequence of each Type, and after that i faced with Sequence Error.!!!!!!!!
I don't know how to find a solution for the sequence error. The problem seems not so difficult, but i don't know how to solve it.
for(i=0; i<MyDataReaders.length(); i++){
shouldn't that be
for (i = 0; i < MyDataReaders.length(); i += 3) {
(from inspection, it looks like your MyDataReaders array is a 3 column, flat multi-dimensional array).
Dear Mr.Williamson,
It Doesn't Work !!!!!
I tried this one also after i said my problem here. I also Changed the value of "i" inside of the loop, But Doesn't work.
Hi,
call me rip.
Here's another problem:
ordered_group_reader3 =
bite_iam_reply_tDataReader::narrow(MyDataReaders.get_at(i+2));
if (ordered_group_reader2 == NULL) {
printf("DataReader narrow error\n");
MyDataReaders.ensure_length(0,0);
subscriber->end_access();
return;
}
cut+paste error.
I replaced all the index numbers with names so that I wouldn't get confused about what was what. Can you please inject that snippit into your code and test it. NOTE: I do not write c or c++ everyday, so I may have added some other errors here and there, you may need to debug the code a bit to get it to compile and/or run.
Although it was a logical error in the code, I don't think the previous comment was the problem. Can you please supply the output from the run using this rewritten code.
Thank you for your reply. I injected your solution to my code. The out put was like this :
Loop start, i=0
message: "Hey, I am X"
bite_id: 0
msg_class: <00>
fault_message_code: 0
nmuber_of_occurrences: 0
mode: <00>
message: "Hey, I am Y"
bite_id: 0
func_id: 0
number_of_objects: 0
message: "Hey, I am Z"
bite_id: 0
func_id: 0
ordered_group subscriber sleeping for 4 sec...
Loop start, i=0
DDSDataReaderSeq_get_reference:!assert index out of bounds
Segmentation fault (core dumped)
The iteration number of the Loop is not increased or mybe it is reseted.
I thought that the problem can be the Condition of The Loop, I wanted to know and wrote like this :
for (i = 0; i < MyDataReaders.length(); i= i+3) {
printf("Sequence of MyDataReaders, Seq=%d\n", MyDataReaders.length());
After that I got this result:
Sequence of MyDataReaders, Seq=3
message: "Hey, I am X"
bite_id: 0
msg_class: <00>
fault_message_code: 0
nmuber_of_occurrences: 0
mode: <00>
message: "Hey, I am Y"
bite_id: 0
func_id: 0
number_of_objects: 0
message: "Hey, I am Z"
bite_id: 0
func_id: 0
ordered_group subscriber sleeping for 4 sec...
Sequence of MyDataReaders, Seq=1
DDSDataReaderSeq_get_reference:!assert index out of bounds
Segmentation fault (core dumped)
I'm really confused.!!!!!!
Except Ordered Group soloution, Is there any other solution to sends different kinds of TYPEs with different kinds of Data Writers and receive all of them on the Subscriber?
I think the reason why the ordered group example uses the "for loop" is that it uses the same type for 3 data readers. However, because you made up 3 different data types and you already have the code for 3 data readers for 3 different data types, I don't think you need the "for loop" anymore.. Would you try it again with removing the loop?
Thanks,
Kyoungho
Regarding your question about a subscriber for multiple data wirters, you can have a subscriber for multiple readers and writers anywhere regardless of using ordered group QoS. I think the ordered group QoS can be used if you want to guarantee ordering of samples of grouped data writers and data readers.
Thank you for your answer, Tomorrow i will check your solution at work.
By the way, in any solution, the Subscriber should count the number of DataReaders and after that read each one, am i right?
I see. For testing purpose, let's use a hard coding way like following for indexing data readers.
I removed the Loop but i got the same result again:
DDSDataReaderSeq_get_reference:!assert index out of bounds
Segmentation fault (core dumped)
Would you attach your source code (idl file, publisher, subscirber) here if possible?
Here. I've attached. The IDL file also is there.
I modified the subscirber code and it works. Please see the attached. I keep the for loop, and add if statement for different typed data readers.
Yes, It works, Thank you so much for your help
Hello,
I am using Deadline, Lifespan, Reliability, Durability, Liveliness, Source Redundancy (Ownership) policies and I am implementing it on a CAN protocol which has a Publisher and a Subscriber. Can anyone please let me know how I can generate timestamps, Time synchronization between Pub/Sub and also Acknowledgement mechanisms I can use in order to implement Reliability and others. Also Source redundancy mechanisms. I will be working with virtual can interfaces for now.