Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat(ros2): migrate non-camera publishers to PublisherImpl templates
Rewrite Clock, Collision, GNSS, IMU, Radar, Lidar, SemanticLidar, and
Transform publishers to use BasePublisher + PublisherImpl<T> templates,
replacing the old PIMPL + manual FastDDS boilerplate pattern.

Add new shared base classes:
- CarlaPointCloudPublisher: abstract base for point cloud publishers
  (LiDAR, SemanticLiDAR, DVS, Radar)
- CarlaDVSPublisher: composite publisher (Image + PointCloud) replacing
  the old CarlaDVSCameraPublisher

Delete unused publishers and old base classes:
- CarlaLineInvasionPublisher (NoopSerializer, unused)
- CarlaMapSensorPublisher (NoopSerializer, unused)
- CarlaSpeedometerSensor (unused)
- CarlaPublisher.h (replaced by BasePublisher.h)
- CarlaSubscriber.h (replaced by BaseSubscriber.h)
- CarlaDVSCameraPublisher (replaced by CarlaDVSPublisher)

Signed-off-by: Yutaka Kondo <yutaka.kondo@youtalk.jp>
  • Loading branch information
youtalk committed Apr 2, 2026
commit 5827f51d033788675648a3ae552acb947583b7af
207 changes: 11 additions & 196 deletions LibCarla/source/carla/ros2/publishers/CarlaClockPublisher.cpp
Original file line number Diff line number Diff line change
@@ -1,203 +1,18 @@
#include "CarlaClockPublisher.h"

#include <string>

#include "carla/ros2/types/ClockPubSubTypes.h"
#include "carla/ros2/listeners/CarlaListener.h"

#include <fastdds/dds/domain/DomainParticipant.hpp>
#include <fastdds/dds/publisher/Publisher.hpp>
#include <fastdds/dds/topic/Topic.hpp>
#include <fastdds/dds/publisher/DataWriter.hpp>
#include <fastdds/dds/topic/TypeSupport.hpp>

#include <fastdds/dds/domain/qos/DomainParticipantQos.hpp>
#include <fastdds/dds/domain/DomainParticipantFactory.hpp>
#include <fastdds/dds/publisher/qos/PublisherQos.hpp>
#include <fastdds/dds/topic/qos/TopicQos.hpp>

#include <fastrtps/attributes/ParticipantAttributes.h>
#include <fastrtps/qos/QosPolicies.h>
#include <fastdds/dds/publisher/qos/DataWriterQos.hpp>
#include <fastdds/dds/publisher/DataWriterListener.hpp>
// Copyright (c) 2025 Computer Vision Center (CVC) at the Universitat Autonoma de Barcelona (UAB).
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.

#include "CarlaClockPublisher.h"

namespace carla {
namespace ros2 {
namespace efd = eprosima::fastdds::dds;
using erc = eprosima::fastrtps::types::ReturnCode_t;

struct CarlaClockPublisherImpl {
efd::DomainParticipant* _participant { nullptr };
efd::Publisher* _publisher { nullptr };
efd::Topic* _topic { nullptr };
efd::DataWriter* _datawriter { nullptr };
efd::TypeSupport _type { new rosgraph::msg::ClockPubSubType() };
CarlaListener _listener {};
rosgraph::msg::Clock _clock {};
};

bool CarlaClockPublisher::Init() {
if (_impl->_type == nullptr) {
std::cerr << "Invalid TypeSupport" << std::endl;
return false;
}
efd::DomainParticipantQos pqos = efd::PARTICIPANT_QOS_DEFAULT;
pqos.name(_name);
auto factory = efd::DomainParticipantFactory::get_instance();
_impl->_participant = factory->create_participant(0, pqos);
if (_impl->_participant == nullptr) {
std::cerr << "Failed to create DomainParticipant" << std::endl;
return false;
}
_impl->_type.register_type(_impl->_participant);

efd::PublisherQos pubqos = efd::PUBLISHER_QOS_DEFAULT;
_impl->_publisher = _impl->_participant->create_publisher(pubqos, nullptr);
if (_impl->_publisher == nullptr) {
std::cerr << "Failed to create Publisher" << std::endl;
return false;
}

efd::TopicQos tqos = efd::TOPIC_QOS_DEFAULT;
const std::string topic_name { "rt/clock" };
_impl->_topic = _impl->_participant->create_topic(topic_name, _impl->_type->getName(), tqos);
if (_impl->_topic == nullptr) {
std::cerr << "Failed to create Topic" << std::endl;
return false;
}

efd::DataWriterQos wqos = efd::DATAWRITER_QOS_DEFAULT;
efd::DataWriterListener* listener = (efd::DataWriterListener*)_impl->_listener._impl.get();
_impl->_datawriter = _impl->_publisher->create_datawriter(_impl->_topic, wqos, listener);
if (_impl->_datawriter == nullptr) {
std::cerr << "Failed to create DataWriter" << std::endl;
return false;
}
_frame_id = _name;
return true;
}

bool CarlaClockPublisher::Publish() {
eprosima::fastrtps::rtps::InstanceHandle_t instance_handle;
eprosima::fastrtps::types::ReturnCode_t rcode = _impl->_datawriter->write(&_impl->_clock, instance_handle);
if (rcode == erc::ReturnCodeValue::RETCODE_OK) {
return true;
}
if (rcode == erc::ReturnCodeValue::RETCODE_ERROR) {
std::cerr << "RETCODE_ERROR" << std::endl;
return false;
}
if (rcode == erc::ReturnCodeValue::RETCODE_UNSUPPORTED) {
std::cerr << "RETCODE_UNSUPPORTED" << std::endl;
return false;
}
if (rcode == erc::ReturnCodeValue::RETCODE_BAD_PARAMETER) {
std::cerr << "RETCODE_BAD_PARAMETER" << std::endl;
return false;
}
if (rcode == erc::ReturnCodeValue::RETCODE_PRECONDITION_NOT_MET) {
std::cerr << "RETCODE_PRECONDITION_NOT_MET" << std::endl;
return false;
}
if (rcode == erc::ReturnCodeValue::RETCODE_OUT_OF_RESOURCES) {
std::cerr << "RETCODE_OUT_OF_RESOURCES" << std::endl;
return false;
}
if (rcode == erc::ReturnCodeValue::RETCODE_NOT_ENABLED) {
std::cerr << "RETCODE_NOT_ENABLED" << std::endl;
return false;
}
if (rcode == erc::ReturnCodeValue::RETCODE_IMMUTABLE_POLICY) {
std::cerr << "RETCODE_IMMUTABLE_POLICY" << std::endl;
return false;
}
if (rcode == erc::ReturnCodeValue::RETCODE_INCONSISTENT_POLICY) {
std::cerr << "RETCODE_INCONSISTENT_POLICY" << std::endl;
return false;
}
if (rcode == erc::ReturnCodeValue::RETCODE_ALREADY_DELETED) {
std::cerr << "RETCODE_ALREADY_DELETED" << std::endl;
return false;
}
if (rcode == erc::ReturnCodeValue::RETCODE_TIMEOUT) {
std::cerr << "RETCODE_TIMEOUT" << std::endl;
return false;
}
if (rcode == erc::ReturnCodeValue::RETCODE_NO_DATA) {
std::cerr << "RETCODE_NO_DATA" << std::endl;
return false;
}
if (rcode == erc::ReturnCodeValue::RETCODE_ILLEGAL_OPERATION) {
std::cerr << "RETCODE_ILLEGAL_OPERATION" << std::endl;
return false;
}
if (rcode == erc::ReturnCodeValue::RETCODE_NOT_ALLOWED_BY_SECURITY) {
std::cerr << "RETCODE_NOT_ALLOWED_BY_SECURITY" << std::endl;
return false;
}
std::cerr << "UNKNOWN" << std::endl;
return false;
}

void CarlaClockPublisher::SetData(int32_t sec, uint32_t nanosec) {
_impl->_clock.clock().sec(sec);
_impl->_clock.clock().nanosec(nanosec);
}
bool CarlaClockPublisher::Write(int32_t seconds, uint32_t nanoseconds) {
_impl->GetMessage()->clock().sec(seconds);
_impl->GetMessage()->clock().nanosec(nanoseconds);

CarlaClockPublisher::CarlaClockPublisher(const char* ros_name, const char* parent) :
_impl(std::make_shared<CarlaClockPublisherImpl>()) {
_name = ros_name;
_parent = parent;
}

CarlaClockPublisher::~CarlaClockPublisher() {
if (!_impl)
return;

if (_impl->_datawriter)
_impl->_publisher->delete_datawriter(_impl->_datawriter);

if (_impl->_publisher)
_impl->_participant->delete_publisher(_impl->_publisher);

if (_impl->_topic)
_impl->_participant->delete_topic(_impl->_topic);

if (_impl->_participant)
efd::DomainParticipantFactory::get_instance()->delete_participant(_impl->_participant);
}

CarlaClockPublisher::CarlaClockPublisher(const CarlaClockPublisher& other) {
_frame_id = other._frame_id;
_name = other._name;
_parent = other._parent;
_impl = other._impl;
}

CarlaClockPublisher& CarlaClockPublisher::operator=(const CarlaClockPublisher& other) {
_frame_id = other._frame_id;
_name = other._name;
_parent = other._parent;
_impl = other._impl;

return *this;
}

CarlaClockPublisher::CarlaClockPublisher(CarlaClockPublisher&& other) {
_frame_id = std::move(other._frame_id);
_name = std::move(other._name);
_parent = std::move(other._parent);
_impl = std::move(other._impl);
}

CarlaClockPublisher& CarlaClockPublisher::operator=(CarlaClockPublisher&& other) {
_frame_id = std::move(other._frame_id);
_name = std::move(other._name);
_parent = std::move(other._parent);
_impl = std::move(other._impl);

return *this;
}
}
return true;
}

} // namespace ros2
} // namespace carla
47 changes: 27 additions & 20 deletions LibCarla/source/carla/ros2/publishers/CarlaClockPublisher.h
Original file line number Diff line number Diff line change
@@ -1,35 +1,42 @@
// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma de Barcelona (UAB).
// Copyright (c) 2025 Computer Vision Center (CVC) at the Universitat Autonoma de Barcelona (UAB).
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.

#pragma once

#include <memory>
#include <vector>

#include "CarlaPublisher.h"
#include "carla/ros2/publishers/BasePublisher.h"
#include "carla/ros2/publishers/PublisherImpl.h"

#include "carla/ros2/types/Clock.h"
#include "carla/ros2/types/ClockPubSubTypes.h"

namespace carla {
namespace ros2 {

struct CarlaClockPublisherImpl;

class CarlaClockPublisher : public CarlaPublisher {
class CarlaClockPublisher : public BasePublisher {
public:
CarlaClockPublisher(const char* ros_name = "", const char* parent = "");
~CarlaClockPublisher();
CarlaClockPublisher(const CarlaClockPublisher&);
CarlaClockPublisher& operator=(const CarlaClockPublisher&);
CarlaClockPublisher(CarlaClockPublisher&&);
CarlaClockPublisher& operator=(CarlaClockPublisher&&);

bool Init();
bool Publish();
void SetData(int32_t sec, uint32_t nanosec);
const char* type() const override { return "clock"; }
struct ClockMsgTraits {
using msg_type = rosgraph::msg::Clock;
using msg_pubsub_type = rosgraph::msg::ClockPubSubType;
};

CarlaClockPublisher() :
BasePublisher("rt/clock"),
_impl(std::make_shared<PublisherImpl<ClockMsgTraits>>()) {
_impl->Init(GetBaseTopicName());
}

bool Publish() {
return _impl->Publish();
}

bool Write(int32_t seconds, uint32_t nanoseconds);

private:
std::shared_ptr<CarlaClockPublisherImpl> _impl;
std::shared_ptr<PublisherImpl<ClockMsgTraits>> _impl;
};
}
}

} // namespace ros2
} // namespace carla
Loading