How to read data from rosbag2 in ros2 - c++

I am writing a program to read data from rosbag directly without playing it in ros2. Sample code snippet is below. The intention of the code is that it checks for a ros2 topic and fetches only message in that topic. I am not able to fetch the data from the bag. When printed the console is printing hexadecimal values.
auto read_only_storage = factory.open_read_only(bag_file_path, storage_id);
while(read_only_storage->has_next())
{
auto msg = read_only_storage->read_next();
if(msg->topic_name == topic)
{
cout << msg->serialized_data<<endl;
}
}
Any help in this regard would be appreciable.

You have to deserialize "msg->serialized_data" data. If you are using data serialized "cdr" format, please look below code.
// deserialization and conversion to ros message
my_pkg::msg::Msg msg;
auto ros_message = std::make_shared<rosbag2_introspection_message_t>();
ros_message->time_stamp = 0;
ros_message->message = nullptr;
ros_message->allocator = rcutils_get_default_allocator();
ros_message->message = &msg;
auto type_support = rosbag2::get_typesupport("my_pkg/msg/Msg", "rosidl_typesupport_cpp");
rosbag2::SerializationFormatConverterFactory factory;
std::unique_ptr<rosbag2::converter_interfaces::SerializationFormatDeserializer> cdr_deserializer_;
cdr_deserializer_ = factory.load_deserializer("cdr");
cdr_deserializer_->deserialize(msg, type_support, ros_message);
Full code: https://github.com/Kyungpyo-Kim/ROS2BagFileParsing

Related

In ArduinoJson how can one check if an error occured when creating a JSON document?

In the ArduinoJson library, it is easy to create JSON entries as shown below.
StaticJsonDocument<512> json_doc;
String some_string = "Hello there!";
json_doc["some_string"] = some_string;
The question is what is the best way to check whether the entry was successfully created? This would allow error handling to be implemented and the error to be found quickly if the entries that are created change and grow over time.
Simply test to see whether the added node has a non-null value. If after you've tried to create a node, that node has a null value, the node was not created.
Here's a simple Sketch to illustrate this test:
#include <ArduinoJson.h>
StaticJsonDocument<100> json_doc;
int nodeNumber = 0;
boolean ranOut = false;
void setup() {
Serial.begin(9600);
}
void loop() {
if (ranOut) return;
String nodeName(nodeNumber++);
String nodeContent = nodeName + " thing";
json_doc[nodeName] = nodeContent;
if (!json_doc[nodeName]) {
ranOut = true;
Serial.print("Ran out at ");
Serial.println(nodeNumber);
}
}
When I ran this Sketch on my Arduino Uno, it produced:
Ran out at 6
That is, it created successfully created nodes json_doc["0"] through json_doc["5"] and ran out of space when it tried to create json_doc["6"].

Arduino can NOT send JSON

I want so send data via a JSON object. All 7 variables you can see in the code should be well defined.
I get the following "error message"/incomplete JSON from Arduino monitor:
{"topic":"Statistics","DrillDuration":"1000","SpeedToDrill":"20","SpeedWithObjectBefore":"100","SpeedWithObjectAfter":"100⸮⸮
Any idea? Is the package for my JSON too small?
I tested my function on a separate Arduino, where I cut my hole program. There it runs without any problems. This function "sendSummary" runs at the end of a bigger code, maybe this could lead to some issues?
Thanks a lot for your help!
void sendSummary()
{
const size_t capacity = JSON_OBJECT_SIZE(14);
DynamicJsonDocument doc(capacity);
doc["topic"] = "Statistics";
doc["DrillDuration"] = DrillDuration;
doc["SpeedToDrill"] = SpeedToDrill;
doc["SpeedWithObjectBefore"] = SpeedWithObjectBefore;
doc["SpeedWithObjectAfter"] = SpeedWithObjectAfter;
doc["SpeedWithoutObject"] = SpeedWithoutObject;
doc["DrillSpeed"] = DrillSpeedVar;
serializeJson(doc, Serial);
Serial.write("\n");
}

Replacing value of a member in rapidjson

I am currently working on a project in C++ using rapidjson.
My program receives some JSON data on a socket which includes some authentication details. I log the incoming message, but I want to hide the password so it can't be seen in the log file. So I am trying to get the JSON object, and replace each character of the string and put this replaced string back into the json object where the password was.
Below is the code that I have:
rapidjson::Document jsonObject;
jsonObject.Parse(command.c_str());
string method = jsonObject["method"].GetString();
if (jsonObject.HasMember("sshDetails"))
{
Value& sshDetails = jsonObject["sshDetails"];
string sshPassword = sshDetails["sshPassword"].GetString();
for (int i = 0; i < sshPassword.length(); i++)
{
sshPassword[i] = '*';
}
rapidjson::Value::Member* sshPasswordMember = sshDetails.FindMember("sshPassword");
sshPasswordMember->name.SetString(sshPassword.c_str(), jsonObject.GetAllocator());
//Convert it back to a string
rapidjson::StringBuffer buffer;
buffer.Clear();
rapidjson::Writer<rapidjson::StringBuffer>writer(buffer);
Document jsonDoc;
jsonDoc.Accept(writer);
string jsonString = string(buffer.GetString());
I'm getting an error on the following line:
rapidjson::Value::Member* sshPasswordMember = sshDetails.FindMember("sshPassword");
The error I am getting is:
No suitable conversion function from rapidjson::GenericMemberIterator<false, rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CtrlAllocator>> to rapidjson::GenericMember::UTF8<char>, myProject...SocketProcessor.cpp
rapidjson::MemoryPoolAllocator<rapidjson::CtrlAllocator>>*exists
I took the above from an example on another question on SO which was an accepted answer from rapidjson - change key to another value, so what am I missing.
I've managed to find the answer to this with a bit of playing round and luck.
I changed
rapidjson::Value::Member* sshPasswordMember = sshDetails.FindMember("sshPassword");
sshPasswordMember->name.SetString(sshPassword.c_str(), jsonObject.GetAllocator());
to be
rapidjson::Value::MemberIterator sshPasswordMember = sshDetails.FindMember("sshPassword");
sshPasswordMember->value.SetString(sshPassword.c_str(), jsonObject.GetAllocator());
using rapidjson in my project I found out that many of such problems can be omitted by the use of auto instead of specifying the type

Creating json string using json lib

I am using jsonc-libjson to create a json string like below.
{ "author-details": {
"name" : "Joys of Programming",
"Number of Posts" : 10
}
}
My code looks like below
json_object *jobj = json_object_new_object();
json_object *jStr1 = json_object_new_string("Joys of Programming");
json_object *jstr2 = json_object_new_int("10");
json_object_object_add(jobj,"name", jStr1 );
json_object_object_add(jobj,"Number of Posts", jstr2 );
this gives me json string
{
"name" : "Joys of Programming",
"Number of Posts" : 10
}
How do I add the top part associated with author details?
To paraphrase an old advertisement, "libjson users would rather fight than switch."
At least I assume you must like fighting with the library. Using nlohmann's JSON library, you could use code like this:
nlohmann::json j {
{ "author-details", {
{ "name", "Joys of Programming" },
{ "Number of Posts", 10 }
}
}
};
At least to me, this seems somewhat simpler and more readable.
Parsing is about equally straightforward. For example, let's assume we had a file named somefile.json that contained the JSON data shown above. To read and parse it, we could do something like this:
nlohmann::json j;
std::ifstream in("somefile.json");
in >> j; // Read the file and parse it into a json object
// Let's start by retrieving and printing the name.
std::cout << j["author-details"]["name"];
Or, let's assume we found a post, so we want to increment the count of posts. This is one place that things get...less tasteful--we can't increment the value as directly as we'd like; we have to obtain the value, add one, then assign the result (like we would in lesser languages that lack ++):
j["author-details"]["Number of Posts"] = j["author-details"]["Number of Posts"] + 1;
Then we want to write out the result. If we want it "dense" (e.g., we're going to transmit it over a network for some other machine to read it) we can just use <<:
somestream << j;
On the other hand, we might want to pretty-print it so a person can read it more easily. The library respects the width we set with setw, so to have it print out indented with 4-column tab stops, we can do:
somestream << std::setw(4) << j;
Create a new JSON object and add the one you already created as a child.
Just insert code like this after what you've already written:
json_object* root = json_object_new_object();
json_object_object_add(root, "author-details", jobj); // This is the same "jobj" as original code snippet.
Based on the comment from Dominic, I was able to figure out the correct answer.
json_object *jobj = json_object_new_object();
json_object* root = json_object_new_object();
json_object_object_add(jobj, "author-details", root);
json_object *jStr1 = json_object_new_string("Joys of Programming");
json_object *jstr2 = json_object_new_int(10);
json_object_object_add(root,"name", jStr1 );
json_object_object_add(root,"Number of Posts", jstr2 );

How to get data from Photon eventContent dictionary

We are receiving this callback using ExitGames Photon Realtime engine when an event is fired
customEventAction(int playerNr,
nByte eventCode,
const ExitGames::Common::Object& eventContent)
If the object is a string we use this code to extract it
ExitGames::Common::JString str =
ExitGames::Common::ValueObject<ExitGames::Common::JString>(eventContent).getDataCopy();
However, the object being sent is a dictionary. It's being sent from the server using BroadcastEvent.
How do we get data out of it ?
We've tried this, but it doesn't make any sense:
ExitGames::Common::Dictionary<byte,ExitGames::Common::Object> pdic
= ExitGames::Common::ValueObject<ExitGames::Common::Dictionary<byte,ExitGames::Common::Object>>(eventContent).getDataCopy();
I've found code to get the data from a hashtable, but that doesn't work either.
thanks
Shaun
ExitGames::Common::Dictionary<nByte, ExitGames::Common::Object> dic = ExitGames::Common::ValueObject<ExitGames::Common::Dictionary<nByte, ExitGames::Common::Object> >(eventContent).getDataCopy();
is absolutely correct and works for me.
The cause of your problem must be inside another line.
When you replace the implementations of sendEvent() and customEventAction() in demo_loadBalancing inside one of the Photon C++ client SDKs with the following snippets, then that demo successfully sends and receives a Dictionary:
send:
void NetworkLogic::sendEvent(void)
{
ExitGames::Common::ValueObject<ExitGames::Common::JString> obj(L"test");
ExitGames::Common::Dictionary<nByte, ExitGames::Common::Object> dic;
dic.put(1, obj);
mLoadBalancingClient.opRaiseEvent(false, dic, 0);
}
receive:
void NetworkLogic::customEventAction(int /*playerNr*/, nByte /*eventCode*/, const ExitGames::Common::Object& eventContent)
{
EGLOG(ExitGames::Common::DebugLevel::ALL, L"");
ExitGames::Common::Dictionary<nByte, ExitGames::Common::Object> dic = ExitGames::Common::ValueObject<ExitGames::Common::Dictionary<nByte, ExitGames::Common::Object> >(eventContent).getDataCopy();
const ExitGames::Common::Object* pObj = dic.getValue(1);
ExitGames::Common::JString str = ExitGames::Common::ValueObject<ExitGames::Common::JString>(pObj).getDataCopy();
mpOutputListener->write(L"received the following string as Dictionary value: " + str);
}
This gives me the following line of output on the receiving client:
received the following string as Dictionary value: test