simple c++ dds publisher/subscriber added.
This commit is contained in:
parent
02a0496cb6
commit
cea501e2cb
|
@ -14,7 +14,7 @@ dist/
|
||||||
downloads/
|
downloads/
|
||||||
eggs/
|
eggs/
|
||||||
.eggs/
|
.eggs/
|
||||||
lib/
|
# lib/
|
||||||
lib64/
|
lib64/
|
||||||
parts/
|
parts/
|
||||||
sdist/
|
sdist/
|
||||||
|
@ -158,3 +158,4 @@ cython_debug/
|
||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
#.idea/
|
#.idea/
|
||||||
|
.vscode
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
# from unitree_go.msg.dds_ import LowState_, LowCmd_, MotorCmd_, BmsCmd_
|
||||||
|
from msgs import LowCmd
|
||||||
|
import cyclonedds.idl.types as types
|
||||||
|
from cyclonedds.domain import DomainParticipant
|
||||||
|
from cyclonedds.pub import DataWriter
|
||||||
|
from cyclonedds.topic import Topic
|
||||||
|
from cyclonedds.util import duration
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
# Create a DomainParticipant, your entrypoint to DDS
|
||||||
|
# Created in the default domain
|
||||||
|
dp = DomainParticipant(0)
|
||||||
|
# Create a Topic with topic name "Hello" and as datatype "HelloWorld" structs.
|
||||||
|
tp = Topic(dp, "go2py/lowcmd", LowCmd)
|
||||||
|
dw = DataWriter(dp, tp)
|
||||||
|
cmd = LowCmd(
|
||||||
|
q = 12*[0.],
|
||||||
|
dq = 12*[0.],
|
||||||
|
tau_ff = 12*[0.],
|
||||||
|
kp = 12*[0.],
|
||||||
|
kv = 12*[0.],
|
||||||
|
e_stop = 0
|
||||||
|
)
|
||||||
|
while True:
|
||||||
|
dw.write(cmd)
|
||||||
|
time.sleep(0.1)
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"cmake.configureOnOpen": true,
|
|
||||||
"files.associations": {
|
|
||||||
"thread": "cpp",
|
|
||||||
"chrono": "cpp",
|
|
||||||
"ostream": "cpp",
|
|
||||||
"list": "cpp"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,8 @@ cmake_minimum_required(VERSION 3.5)
|
||||||
SET(CMAKE_CXX_STANDARD 17)
|
SET(CMAKE_CXX_STANDARD 17)
|
||||||
add_library(msgs STATIC include/go2py/LowCmd.cpp include/go2py/LowState.cpp)
|
add_library(msgs STATIC include/go2py/LowCmd.cpp include/go2py/LowState.cpp)
|
||||||
|
|
||||||
include_directories(/usr/local/include/ddscxx /usr/local/include/iceoryx/v2.0.2)
|
include_directories(/usr/local/include/ddscxx /usr/local/include/iceoryx/v2.0.2 include)
|
||||||
link_libraries(unitree_sdk2 ddsc ddscxx rt pthread msgs)
|
link_libraries(unitree_sdk2 ddsc ddscxx rt pthread msgs)
|
||||||
|
|
||||||
add_executable(lowlevel_bridge src/lowlevel/bridge.cpp)
|
add_executable(lowlevel_bridge src/lowlevel/bridge.cpp)
|
||||||
|
add_executable(simple_test src/simple_test.cpp)
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef __DDS_PUBLISHER_HPP__
|
||||||
|
#define __DDS_PUBLISHER_HPP__
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <functional>
|
||||||
|
#include <dds/dds.hpp>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
using namespace dds::sub;
|
||||||
|
using namespace dds::domain;
|
||||||
|
using namespace dds::topic;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class DDSPublisher {
|
||||||
|
private:
|
||||||
|
dds::domain::DomainParticipant participant;
|
||||||
|
dds::topic::Topic<T> topic;
|
||||||
|
dds::pub::Publisher publisher;
|
||||||
|
dds::pub::DataWriter<T> writer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor
|
||||||
|
DDSPublisher(const std::string& topicName, const int id = 0)
|
||||||
|
: participant(dds::domain::DomainParticipant(id)),
|
||||||
|
topic(participant, topicName),
|
||||||
|
publisher(dds::pub::Publisher(participant)),
|
||||||
|
writer(dds::pub::DataWriter<T>(publisher, topic)) {}
|
||||||
|
|
||||||
|
// Method to publish a message
|
||||||
|
void publish(const T& message) {
|
||||||
|
writer.write(message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -0,0 +1,66 @@
|
||||||
|
#ifndef __DDS_SUBSCRIBER_HPP__
|
||||||
|
#define __DDS_SUBSCRIBER_HPP__
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <functional>
|
||||||
|
#include <dds/dds.hpp>
|
||||||
|
#include <thread>
|
||||||
|
using namespace dds::sub;
|
||||||
|
using namespace dds::domain;
|
||||||
|
using namespace dds::topic;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class DDSSubscriber {
|
||||||
|
public:
|
||||||
|
// Define a callback type for user-provided callbacks
|
||||||
|
using UserCallback = std::function<void(const T&)>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DomainParticipant participant;
|
||||||
|
Topic<T> topic;
|
||||||
|
Subscriber subscriber;
|
||||||
|
DataReader<T> reader;
|
||||||
|
T latestMessage;
|
||||||
|
UserCallback userCallback;
|
||||||
|
|
||||||
|
// Internal Listener class
|
||||||
|
class CustomListener : public NoOpDataReaderListener<msgs::LowCmd> {
|
||||||
|
private:
|
||||||
|
DDSSubscriber& parent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CustomListener(DDSSubscriber& parent) : parent(parent) {}
|
||||||
|
|
||||||
|
void on_data_available(DataReader<T>& reader) override {
|
||||||
|
// Take all available data
|
||||||
|
dds::sub::LoanedSamples<T> samples = reader.take();
|
||||||
|
if (samples.length() >0){
|
||||||
|
for (auto sample_iter = samples.begin();
|
||||||
|
sample_iter < samples.end();
|
||||||
|
++sample_iter){
|
||||||
|
parent.latestMessage = sample_iter->data(); // Update the latest message
|
||||||
|
// If a user callback is provided, execute it
|
||||||
|
if (parent.userCallback) {
|
||||||
|
parent.userCallback(parent.latestMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor
|
||||||
|
DDSSubscriber(const std::string& topicName, UserCallback callback = nullptr, const int id = 0)
|
||||||
|
: participant(id),
|
||||||
|
topic(participant, topicName),
|
||||||
|
subscriber(participant),
|
||||||
|
userCallback(callback),
|
||||||
|
reader(subscriber, topic, dds::sub::qos::DataReaderQos(), new CustomListener(*this), dds::core::status::StatusMask::data_available()) {}
|
||||||
|
|
||||||
|
// Method to get the latest message
|
||||||
|
msgs::LowCmd getLatestMessage() const {
|
||||||
|
return latestMessage;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
Binary file not shown.
Binary file not shown.
|
@ -10,11 +10,8 @@
|
||||||
#include <unitree/common/thread/thread.hpp>
|
#include <unitree/common/thread/thread.hpp>
|
||||||
#include <go2py/LowCmd.hpp>
|
#include <go2py/LowCmd.hpp>
|
||||||
#include <go2py/LowState.hpp>
|
#include <go2py/LowState.hpp>
|
||||||
#include "dds/dds.hpp"
|
|
||||||
#include "dds/dds.h"
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
using namespace unitree::common;
|
using namespace unitree::common;
|
||||||
using namespace unitree::robot;
|
using namespace unitree::robot;
|
||||||
using namespace org::eclipse::cyclonedds;
|
using namespace org::eclipse::cyclonedds;
|
||||||
|
@ -184,59 +181,8 @@ void Bridge::LowCmdWrite()
|
||||||
lowcmd_publisher->Write(low_cmd);
|
lowcmd_publisher->Write(low_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Go2PyListener: public dds::sub::NoOpDataReaderListener<msgs::LowCmd>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using callback_func = std::function<bool(dds::sub::DataReader<msgs::LowCmd>&,
|
|
||||||
dds::pub::DataWriter<msgs::LowState>&)>;
|
|
||||||
Go2PyListener() = delete;
|
|
||||||
Go2PyListener( const callback_func &f):
|
|
||||||
dds::sub::DataReaderListener<msgs::LowCmd>(), _f(f) { ; }
|
|
||||||
|
|
||||||
void on_data_available(dds::sub::DataReader<msgs::LowCmd>& rd,
|
|
||||||
dds::pub::DataWriter<msgs::LowState>& rw) {
|
|
||||||
(void)_f(rd, rw);
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
callback_func _f; // Private member variable to store the callback function
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool data_available(dds::sub::DataReader<msgs::LowCmd>& rd,
|
|
||||||
dds::pub::DataWriter<msgs::LowState>& rw)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
int main(int argc, const char** argv)
|
int main(int argc, const char** argv)
|
||||||
{
|
{
|
||||||
dds::domain::DomainParticipant participant(domain::default_id());
|
|
||||||
|
|
||||||
dds::topic::qos::TopicQos tqos;
|
|
||||||
tqos << dds::core::policy::Reliability::Reliable(dds::core::Duration::from_secs(10));
|
|
||||||
dds::topic::Topic<msgs::LowCmd> cmd_topic(participant, "go2py/lowcmd", tqos);
|
|
||||||
dds::topic::Topic<msgs::LowState> state_topic(participant, "go2py/lowstate", tqos);
|
|
||||||
|
|
||||||
dds::pub::qos::PublisherQos pqos;
|
|
||||||
pqos << dds::core::policy::Partition("pong");
|
|
||||||
dds::pub::Publisher publisher(participant, pqos);
|
|
||||||
|
|
||||||
dds::sub::qos::SubscriberQos sqos;
|
|
||||||
sqos << dds::core::policy::Partition("ping");
|
|
||||||
dds::sub::Subscriber subscriber(participant, sqos);
|
|
||||||
|
|
||||||
dds::pub::qos::DataWriterQos wqos;
|
|
||||||
wqos << dds::core::policy::WriterDataLifecycle::ManuallyDisposeUnregisteredInstances();
|
|
||||||
dds::pub::DataWriter<msgs::LowState> writer(publisher, state_topic, wqos);
|
|
||||||
|
|
||||||
Go2PyListener listener(&data_available);
|
|
||||||
|
|
||||||
dds::sub::DataReader<msgs::LowCmd>
|
|
||||||
reader(
|
|
||||||
subscriber,
|
|
||||||
cmd_topic,
|
|
||||||
dds::sub::qos::DataReaderQos(),
|
|
||||||
&listener,
|
|
||||||
dds::core::status::StatusMask::data_available());
|
|
||||||
|
|
||||||
if (argc < 2)
|
if (argc < 2)
|
||||||
{
|
{
|
||||||
std::cout << "Usage: " << argv[0] << " networkInterface" << std::endl;
|
std::cout << "Usage: " << argv[0] << " networkInterface" << std::endl;
|
||||||
|
@ -244,7 +190,6 @@ int main(int argc, const char** argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelFactory::Instance()->Init(0, argv[1]);
|
ChannelFactory::Instance()->Init(0, argv[1]);
|
||||||
|
|
||||||
Bridge bridge;
|
Bridge bridge;
|
||||||
bridge.Init();
|
bridge.Init();
|
||||||
while (1)
|
while (1)
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include "go2py/LowCmd.hpp"
|
||||||
|
#include <thread>
|
||||||
|
#include "utils/dds_subscriber.hpp"
|
||||||
|
#include "utils/dds_publisher.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
// User-defined callback function
|
||||||
|
void userDefinedCallback(const msgs::LowCmd& msg) {
|
||||||
|
// Do something with the received message
|
||||||
|
std::cout << "User callback executed with message: " << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Create a subscriber with a topic name and a user callback
|
||||||
|
DDSSubscriber<msgs::LowCmd> subscriber("go2py/lowcmd", userDefinedCallback);
|
||||||
|
|
||||||
|
// Create a publisher for the LowCmd message type on the topic "LowCmdTopic"
|
||||||
|
DDSPublisher<msgs::LowCmd> publisher("LowCmdTopic");
|
||||||
|
|
||||||
|
// Create a LowCmd message
|
||||||
|
msgs::LowCmd message;
|
||||||
|
|
||||||
|
// Initialize the message data
|
||||||
|
for(int i = 0; i < 12; i++) {
|
||||||
|
message.q()[i] = 0.0f;
|
||||||
|
message.dq()[i] = 0.0f;
|
||||||
|
message.tau_ff()[i] = 0.0f;
|
||||||
|
message.kp()[i] = 1.0f;
|
||||||
|
message.kv()[i] = 0.5f;
|
||||||
|
}
|
||||||
|
message.e_stop() = 0;
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
publisher.publish(message);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue