ROS2 reading bag files - c++

I have got a bag file in db3 format and I was trying to read its messages, deserialise them and access their fields. I couldn't find any appropriate document or working example anywhere. I only managed to load the file and display all its message types using the rosbag2_cpp API as follows:
#include <rclcpp/rclcpp.hpp>
#include <tf2_msgs/msg/tf_message.hpp>
#include <ament_index_cpp/get_package_share_directory.hpp>
#include <rosbag2_cpp/readers/sequential_reader.hpp>
#include <rosbag2_cpp/converter_interfaces/serialization_format_converter.hpp>
#include <rosbag2_storage/storage_options.hpp>
int main(int argc, char** argv)
{
(void) argc;
(void) argv;
rclcpp::init(argc, argv);
rclcpp::Node node("test");
rosbag2_storage::StorageOptions storage_options{};
auto file_path = ament_index_cpp::get_package_share_directory("test")
+ "/data/rosbag_autoware_receiver_0.db3";
storage_options.uri = file_path;
storage_options.storage_id = "sqlite3";
rosbag2_cpp::ConverterOptions converter_options{};
converter_options.input_serialization_format = "cdr";
converter_options.output_serialization_format = "cdr";
rosbag2_cpp::readers::SequentialReader reader;
reader.open(storage_options, converter_options);
const auto topics = reader.get_all_topics_and_types();
for (const auto topic : topics)
RCLCPP_INFO(node.get_logger(), topic.name.c_str());
return 0;
}
Any hint, help or guide on reading the actual messages and deserialising them is much appreciated.
Regards

What you're looking for is the has_next() property.
Declare a msg variable of the type(s) you're looking for (such as sensor_msgs::msg::Image msg), and deserialize as following:
while (reader.has_next())
{
// serialized data
auto serialized_message = reader.read_next();
rclcpp::SerializedMessage extracted_serialized_msg(*serialized_message->serialized_data);
auto topic = serialized_message->topic_name;
if (topic.find("whatever...") != std::string::npos)
{
serialization_info.deserialize_message(&extracted_serialized_msg, &msg);
}
}

Related

From a MessageDialog how to read variables when i use pango markup?

how to use pango markup in messagedialog text using variable
For example this code
void usb_boot::creation(){
//Gtk::MessageDialog dialogue(*this, listeDeroulante.get_active_text());
std::string message("Type de formatage : " + type), type1, chemin1;
Gtk::MessageDialog *dialogue = new Gtk::MessageDialog("Résumé", true, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO);
dialogue->set_title("Résumé");
dialogue->set_message("<span weight='bold'>message</span>",true);
dialogue->set_secondary_text("<b>listeDeroulante.get_active_text()</b>", true);
dialogue->set_default_response(Gtk::RESPONSE_YES);
int result = dialogue->run();
set_message and set_secondary_text have to print variables but just "see" word.
Is there a way to read like variables ?
While the std::stringstream solution works, I would suggest using simple string concatenation, through std::string's operator+:
#include <gtkmm.h>
int main(int argc, char **argv)
{
auto app = Gtk::Application::create(argc, argv, "so.question.q63886899");
Gtk::Window w;
w.show_all();
{
// Unformatted messages:
std::string primaryMessage = "Some message...";
std::string secondaryMessage = "Some more message details...";
Gtk::MessageDialog dialog(w, "Message dialog", true, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO);
dialog.set_title("Title");
// Add pango markup tags through string concatenation:
dialog.set_message("<span weight='bold'>" + primaryMessage + "</span>", true);
dialog.set_secondary_text("<b>" + secondaryMessage + "</b>", true);
dialog.run();
}
return app->run(w);
}
With this solution, no need to introduce an extra type.

LLVM ORC V2 Symbol to Global Variable

I am trying to access a variable in the host program from LLVM IR, with a global variable, but I am having problems getting it to work. I am declaring a symbol with the required variable address in the main JitDylib. After that I create the Global variable with the same name, with external linkage so the linker can find it. But it does not work. Executing the Jit'ed functions crashes the host program.
Below is my test program based on the LLJIT example in the LLVM repository. I have tried many things such as using CreateGEP to get a valid pointer, or using a different JitDylib to declare the symbol. But none have worked for me. I suspect it is something linking related. Has anyone gotten it work using the new ORC V2 JIT API?
//===-- examples/HowToUseJIT/HowToUseJIT.cpp - An example use of the JIT --===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//===-- examples/HowToUseJIT/HowToUseJIT.cpp - An example use of the JIT --===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace llvm::orc;
ExitOnError ExitOnErr;
ThreadSafeModule createDemoModule()
{
auto Context = std::make_unique<LLVMContext>();
auto M = std::make_unique<Module>("test", *Context);
Function* Add1F =
Function::Create(FunctionType::get(Type::getInt64Ty(*Context),
{ }, false),
Function::ExternalLinkage, "add1", M.get());
BasicBlock* BB = BasicBlock::Create(*Context, "EntryBlock", Add1F);
IRBuilder<> builder(BB);
Value* One = builder.getInt32(1);
llvm::Type* arr_ty = builder.getInt32Ty()->getPointerTo();
llvm::GlobalVariable* g = new llvm::GlobalVariable(*M, arr_ty, true, llvm::GlobalValue::LinkageTypes::ExternalLinkage, nullptr, "_mptr");
g->setInitializer(ConstantPointerNull::get(cast<PointerType>(g->getType()->getPointerElementType())));
g->setExternallyInitialized(true);
auto g_loaded = builder.CreateLoad(g);
auto Val = builder.CreateLoad(g_loaded);
Value* Add = builder.CreateAdd(One, Val);
builder.CreateRet(Add);
return ThreadSafeModule(std::move(M), std::move(Context));
}
int main(int argc, char* argv[])
{
InitLLVM X(argc, argv);
InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
cl::ParseCommandLineOptions(argc, argv, "HowToUseLLJIT");
ExitOnErr.setBanner(std::string(argv[0]) + ": ");
auto J = ExitOnErr(LLJITBuilder().create());
uint32_t test = 5;
auto& ES = J->getExecutionSession();
auto& DL = J->getDataLayout();
MangleAndInterner Mangle(ES, DL);
auto& JD = J->getMainJITDylib();
JD.define(
llvm::orc::absoluteSymbols({
{ Mangle("_mptr"), { llvm::pointerToJITTargetAddress(&test), llvm::JITSymbolFlags::Exported } }
}));
auto M = createDemoModule();
ExitOnErr(J->addIRModule(std::move(M)));
auto Add1Sym = ExitOnErr(J->lookup("add1"));
int (*Add1)() = (int (*)())Add1Sym.getAddress();
int Result = Add1();
outs() << "add1(42) = " << Result << "\n";
return 0;
}
A JITDylib needs to be told to search for symbols in the host program like so:
JD.addGenerator(cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess(DL.getGlobalPrefix())))
Your method of defining absolute symbols should also work. However, I don't think you need to mangle the variable name in this case. You also might want to add the llvm::JITSymbolFlags::Absolute symbol flag. You could try this instead:
JD.define(
llvm::orc::absoluteSymbols({
{ ES->intern("_mptr"), { llvm::pointerToJITTargetAddress(&test), llvm::JITSymbolFlags::Exported | llvm::JITSymbolFlags::Absolute} }
}));
Finally, you could simply hard-code the address as a constant and not rely on any linking like so:
llvm::ConstantInt* addressConstant = llvm::ConstantInt::get(Context, llvm::APInt(sizeof(std::uintptr_t) * 8, reinterpret_cast<uint64_t>(&test), false));
llvm::Value* testPtr = builder->CreateIntToPtr(addressConstant, llvm::Type::getInt8PtrTy(Context));

parse json data in c++ with Qt library

I have exactly following json data as follows:
[
{
"id":"01323",
"name":"Json Roy",
"contacts":[
"CONTACT1=+917673267299",
"CONTACT2=+917673267292",
"CONTACT3=+917673267293",
"CONTACT4=+917673267294",
]
}
]
I want to parse above jsonData data and extract contacts of that data.
QJsonParseError jerror;
QJsonDocument jsonData = QJsonDocument::fromJson(jsonData.c_str(),&jerror);
QJsonArray jsonArray = jsonData.array();
QJsonObject jsonObject = jsonData.object();
foreach (const QJsonValue & value, jsonArray){
string contact=jsonObject["contacts"].toString().toUtf8().constData();
}
can anybody suggest me how can i accomplish this with same above library?
I removed latest comma in the contacts list.
Your mistake is treating QJsonValue as you want but QJsonValue is something like a wrapper so you should convert it to appropriate object ( array, object, string etc. ).
jsonData is not an object sojsonData.object() doesn't give you what you want.
Here is the code, it could be the starting point for you.
#include <QString>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
#include <QJsonParseError>
#include <QDebug>
#include <string>
int main(){
auto json_input = R"([
{
"id":"01323",
"name":"Json Roy",
"contacts":[
"CONTACT1=+917673267299",
"CONTACT2=+917673267292",
"CONTACT3=+917673267293",
"CONTACT4=+917673267294"
]
}
])";
QJsonParseError err;
auto doc = QJsonDocument::fromJson( QString::fromStdString( json_input ).toLatin1() , &err );
auto objects = doc.array();
if ( err.error != QJsonParseError::NoError )
{
qDebug() << err.errorString();
return 1;
}
for( auto obj_val : objects )
{
auto obj = obj_val.toObject();
auto contacts = obj.value( "contacts" ).toArray();
for ( auto contact_val : contacts )
{
auto cotact_str = contact_val.toString();
qDebug() << cotact_str;
}
}
}
Output :
CONTACT1=+917673267299
CONTACT2=+917673267292
CONTACT3=+917673267293
CONTACT4=+917673267294

load/save multiple images from/in a directory - opencv c++

i want to load a lot of images (not sequential names though) from a directory. edit them and then save them in a different directory with their original names if possible.
I load them like that:
glob("/photos/field_new/*.jpg", fn, false);
size_t count = fn.size(); //number of jpg files in images folder
for (size_t i=0; i<count; i++)
images.push_back(imread(fn[i]));
any ideas how i can save them in the directory /photos/results/ ?
and if possible with their original names?
If you have C++17 it will be easy as there is filesystem library in standard (std::filesystem). Other wise I would recomend you to get boost::filesystem which is very similar (you should be good with replacing all of std::filesystem to boost::filesystem).
To load all images from certain folder there are 2 helper functions:
#include <filesystem> //for boost change this to #include <boost/filesystem> and all std:: to boost::
#include <opencv2/opencv.hpp>
bool isSupportedFileType(const std::filesystem::path& pathToFile,
const std::vector<std::string>& extensions)
{
auto extension = pathToFile.extension().string();
std::transform(extension.begin(), extension.end(), extension.begin(), [](char c)
{
return static_cast<char>(std::tolower(c));
});
return std::find(extensions.begin(), extensions.end(), extension) != extensions.end();
}
std::tuple<std::vector<cv::Mat>, std::vector<std::filesystem::path>> loadImages(const std::filesystem::path& path,
const std::vector<std::string>& extensions)
{
std::vector<cv::Mat> images;
std::vector<std::filesystem::path> names;
for (const auto& dirIt : filesystem::DirectoryIterator(path))
{
if (std::filesystem::is_regular_file(dirIt.path()) && isSupportedFileType(dirIt.path(), extensions))
{
auto mask = cv::imread(dirIt.path().string(), cv::IMREAD_UNCHANGED);
if (mask.data != nullptr) //there can be problem and image is not loaded
{
images.emplace_back(std::move(mask));
names.emplace_back(dirIt.path().stem());
}
}
}
return {images, names};
}
You can use it like this (assuming C++17):
auto [images, names] = loadImages("/photos/field_new/", {".jpg", ".jpeg"});
Or (C++11)
auto tupleImageName = loadImages("/photos/field_new/", {".jpg", ".jpeg"});
auto images = std::get<0>(tupleImageName);
auto names = std::get<1>(tupleImageName);
To save you can use this function:
void saveImages(const std::filesystem::path& path,
const std::vector<cv::Mat>& images,
const std::vector<std::filesystem::path>& names)
{
for(auto i = 0u; i < images.size(); ++i)
{
cv::imwrite((path / names[i]).string(), images[i]);
}
}
Like this:
saveImages("pathToResults",images,names);
In this save function it would be good to perform some validation if the number of images is the same as names, otherwise there might be a problem with stepping outside vector boundary.
Since C++ is compatible with C, and if you are using a Unix system, you could use dirent.h (https://pubs.opengroup.org/onlinepubs/7908799/xsh/dirent.h.html). It should be something like this:
#include <dirent.h>
#include <opencv2/opencv.hpp>
#include <string.h>
using namespace std;
using namespace cv;
int main(){
DIR *d;
struct dirent *dir;
string dirname_input="dirname/input";
string dirname_output="dirname/output";
d=opendir(dirname_input.c_str());
if (d){
while ((dir=readdir(d))!=NULL){
string filename=dir->d_name;
if (filename.substr(filename.size() - 4)==".jpg"){
Mat image;
string fullpath_input=dirname_input+'/'+filename;
string fullpath_output=dirname_output+'/'+filename;
image=imread(fullpath_input,1);
// process image
imwrite(fullpath_output,image);
}
}
}
return 0;
}

Serializing a vector of objects with FlatBuffers

I have a vector of objects, let's call them Plumbuses, that I want to serialize with FlatBuffers. My schema for this example would be
namespace rpc;
struct Plumbus
{
dinglebopBatch:int;
fleeb:double;
}
table PlumbusesTable {
plumbuses:[Plumbus];
}
root_type PlumbusesTable;
since the root type can't be a vector. Calling flatc --cpp on this file generates plumbus_generated.h with functions such as CreatePlumbusesTableDirect.
The generated GeneratePlumbusesTableDirect function expects an argument const std::vector<const Plumbus *> *plumbuses. My idea was to simply take the addresses of the objects in the vector pbs and store them in another vector, pbPtrs. Since the buffer is created and sent away before pbs goes out of scope, I thought this would not be a problem.
#include <vector>
#include <iostream>
#include "plumbus_generated.h"
void send_plumbus(std::vector<rpc::Plumbus> pbs) {
std::vector<const rpc::Plumbus *> pbPtrs;
pbPtrs.push_back(&(pbs[0]));
pbPtrs.push_back(&(pbs[1]));
flatbuffers::FlatBufferBuilder buf(1024);
auto msg = CreatePlumbusesTableDirect(buf, &pbPtrs);
buf.Finish(msg);
void *msg_buf = buf.GetBufferPointer();
// here, I'd normally send the data through a socket
const rpc::PlumbusesTable *pbt = rpc::GetPlumbusesTable(msg_buf);
auto *pbPtrs_ = pbt->plumbuses();
for (const auto pbPtr_ : *pbPtrs_) {
std::cout << "dinglebopBatch = " << pbPtr_->dinglebopBatch() << ", fleeb = " << pbPtr_->fleeb() << std::endl;
}
}
int main(int argc, char** argv) {
rpc::Plumbus pb1(1, 2.0);
rpc::Plumbus pb2(3, 4.0);
std::vector<rpc::Plumbus> pbs = { pb1, pb2 };
send_plumbus(pbs);
}
Running this, instead of 1, 2.0, 3, and 4.0, I get
$ ./example
dinglebopBatch = 13466704, fleeb = 6.65344e-317
dinglebopBatch = 0, fleeb = 5.14322e-321
Why does it go wrong?
This looks like this relates to a bug that was recently fixed: https://github.com/google/flatbuffers/commit/fee9afd80b6358a63b92b6991d858604da524e2b
So either work with the most recent FlatBuffers, or use the version without Direct: CreatePlumbusesTable. Then you call CreateVectorOfStructs yourself.