Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3b59906
copy from embeddedRTPS
guo-max Jul 8, 2026
bf22a30
add submodule
guo-max Jul 8, 2026
bc85052
update submodule
guo-max Jul 8, 2026
734c114
add example
guo-max Jul 8, 2026
f81ef55
WIP; add substrct layer for platform
guo-max Jul 9, 2026
c223c55
added thread pool; removed lwip and freertos
guo-max Jul 10, 2026
ea3f3a5
fix bug of sedp acknack; fix bug for parse topic data
guo-max Jul 13, 2026
939acff
removed sync and fix circular buffer bug
guo-max Jul 14, 2026
c3c7062
code clean up
guo-max Jul 14, 2026
a0edd0a
update to use base component
guo-max Jul 14, 2026
1738184
remove micro_CDR
guo-max Jul 16, 2026
c069ef6
add the forked micro-CDR
guo-max Jul 16, 2026
ed2e8e5
update micro cdr config
guo-max Jul 16, 2026
291ddd6
add pc test; fix heartbeat ping-pang bug
guo-max Jul 17, 2026
d9524eb
test with reliable and add some log for testing
guo-max Jul 21, 2026
9cdb1e6
fix documentation and add readme
guo-max Jul 21, 2026
ca54404
disable logging by default
guo-max Jul 21, 2026
aed1f3a
delete thread_pool
guo-max Aug 3, 2026
ac252c8
Merge branch 'main' into feat/embeddedRTPS_merge_espp
guo-max Aug 3, 2026
bd9e29f
update example to use ethernent kit
guo-max Aug 3, 2026
dbe3c42
update rtps example
guo-max Aug 4, 2026
99bb2cd
remove unused file
guo-max Aug 4, 2026
751f118
update kconfig
guo-max Aug 4, 2026
fb127cc
modify header file to use hpp
guo-max Aug 6, 2026
5f259bb
fix CodeQL scan result bug
guo-max Aug 6, 2026
eb2dcca
Merge branch 'main' into feat/embeddedRTPS_merge_espp
guo-max Aug 6, 2026
3a2c9e1
fix static code analysis errors
guo-max Aug 6, 2026
678a842
fix static analysis issue
guo-max Aug 7, 2026
7f8ff48
update based on AI review
guo-max Aug 7, 2026
e470aa1
fix based on AI review
guo-max Aug 7, 2026
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
# build folder for ESP-IDF
build/

# submodule configuration
components/rtps_embedded/thirdparty/Micro-CDR/include/ucdr/config.h

# we only version sdkconfig.defaults
sdkconfig
sdkconfig.old
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@
[submodule "components/gfps_service/detail/nearby"]
path = components/gfps_service/detail/nearby
url = https://github.com/esp-cpp/nearby
[submodule "components/rtps_embedded/thirdparty/Micro-CDR"]
path = components/rtps_embedded/thirdparty/Micro-CDR
url = git@github.com:esp-cpp/Micro-CDR.git
Comment thread
guo-max marked this conversation as resolved.
28 changes: 28 additions & 0 deletions components/rtps_embedded/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
idf_component_register(
SRCS
"src/ThreadPool.cpp"
"src/communication/EsppTransport.cpp"
"src/discovery/ParticipantProxyData.cpp"
"src/discovery/SEDPAgent.cpp"
"src/discovery/SPDPAgent.cpp"
"src/discovery/TopicData.cpp"
"src/entities/Domain.cpp"
"src/entities/Participant.cpp"
"src/entities/Reader.cpp"
"src/entities/StatelessReader.cpp"
"src/entities/Writer.cpp"
"src/messages/MessageReceiver.cpp"
"src/messages/MessageTypes.cpp"
"src/utils/Diagnostics.cpp"
"thirdparty/Micro-CDR/src/c/common.c"
"thirdparty/Micro-CDR/src/c/types/array.c"
"thirdparty/Micro-CDR/src/c/types/basic.c"
"thirdparty/Micro-CDR/src/c/types/sequence.c"
"thirdparty/Micro-CDR/src/c/types/string.c"
INCLUDE_DIRS
"include"
"thirdparty/Micro-CDR/include"
REQUIRES
base_component task thread_pool socket
)
Comment thread
guo-max marked this conversation as resolved.

162 changes: 162 additions & 0 deletions components/rtps_embedded/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# rtps_embedded

ESPP component that integrates the [embeddedRTPS](https://github.com/embedded-software-laboratory/embeddedRTPS)
RTPS/DDS stack into the ESPP ecosystem.
Any platform that can build ESPP — including ESP32, Linux, and desktop PCs —
can use this component to discover and exchange typed messages with ROS 2 nodes
or any other DDS participant on the same network using the standard RTPS wire
protocol.

The original embeddedRTPS library has hard dependencies on FreeRTOS and lwIP.
`rtps_embedded` removes those dependencies by replacing all socket, task, and
synchronisation calls with ESPP's platform-agnostic `UdpSocket`, `Task`, and
`ThreadPool` primitives. When built for ESP32, ESPP uses FreeRTOS and lwIP
under the hood; on other platforms it uses the host OS equivalents — the RTPS
code itself is unchanged in either case.

---

## Architecture

```
user code
rtps::Domain — routes packets to participants; owns discovery threads
├── rtps::Participant — groups writers and readers
│ ├── rtps::Writer — publishes CacheChange samples
│ └── rtps::Reader — delivers samples to a user callback
├── rtps::ThreadPool — espp::ThreadPool workers that drain the four
│ incoming/outgoing meta/user traffic queues
└── rtps::EsppTransport — one espp::UdpSocket per open UDP port,
each with its own receive task
```

`EsppTransport` is the sole platform-specific adapter. It wraps ESPP's
`UdpSocket` and `Task`, which in turn map to:

| Build target | Socket backend | Task backend |
|---|---|---|
| ESP32 | lwIP (via ESP-IDF) | FreeRTOS |
| Linux / PC | POSIX sockets | `std::thread` |

---

## Quick-start

```cpp
#include "rtps/entities/Domain.h"

// 1. Construct the domain with the local interface IP.
rtps::Domain domain(local_ip);

// 2. Create a participant *before* completeInit().
rtps::Participant *part = domain.createParticipant();

// 3. Add user-defined writer and reader endpoints.
rtps::Writer *writer = domain.createWriter(*part, "my/topic",
"std_msgs::msg::String", false);
rtps::Reader *reader = domain.createReader(*part, "my/topic",
"std_msgs::msg::String", false);

// 4. Register a receive callback on the reader.
reader->registerCallback(
[](void *, const rtps::ReaderCacheChange &change) {
// process change.getData() / change.copyInto(...)
}, nullptr);

// 5. Start discovery (SPDP/SEDP) and worker threads.
domain.completeInit();

// 6. Publish a sample.
const char *payload = "hello";
writer->newChange(rtps::ChangeKind_t::ALIVE,
reinterpret_cast<const uint8_t *>(payload),
static_cast<rtps::DataSize_t>(strlen(payload) + 1));
```

> **Note**: `createParticipant()` **must** be called before `completeInit()`.
> No new participants can be added after init is complete.

---

## Configuration

Two built-in config headers are provided. Select one by defining
`RTPS_CONFIG_HEADER`, or let `include/rtps/config.h` pick automatically based
on the build target.

| Header | Target |
|---|---|
| [`include/rtps/config_esp32.h`](include/rtps/config_esp32.h) | ESP32 (ESP-IDF) |
| [`include/rtps/config_desktop.h`](include/rtps/config_desktop.h) | Linux / PC |

All tunable constants follow the same layout in both files:

| Constant | Default | Description |
|---|---|---|
| `DOMAIN_ID` | 0 | RTPS domain number (0–230 with UDP) |
| `MAX_NUM_PARTICIPANTS` | 1 | Participant pool size |
| `NUM_STATEFUL_WRITERS` | 5 | User writer endpoint pool |
| `NUM_STATEFUL_READERS` | 5 | User reader endpoint pool |
| `NUM_STATELESS_WRITERS` | 5 | Discovery writer endpoint pool |
| `NUM_STATELESS_READERS` | 5 | Discovery reader endpoint pool |
| `NUM_WRITERS_PER_PARTICIPANT` | 10 | Max writers per participant |
| `NUM_READERS_PER_PARTICIPANT` | 10 | Max readers per participant |
| `HISTORY_SIZE_STATEFUL` | 10 | Per-endpoint history depth |
| `THREAD_POOL_NUM_WRITERS` | 2 | Writer worker threads |
| `THREAD_POOL_NUM_READERS` | 2 | Reader worker threads |
| `THREAD_POOL_WRITER_STACKSIZE` | 4096 B | Writer task stack |
| `THREAD_POOL_READER_STACKSIZE` | 6144 B | Reader / UDP-receive task stack |
| `MAX_NUM_UDP_CONNECTIONS` | 10 | UDP socket pool size |
| `SPDP_RESEND_PERIOD_MS` | 2000 | Discovery announce period |
| `SF_WRITER_HB_PERIOD_MS` | 4000 | Reliable-writer heartbeat period |

The `OVERALL_HEAP_SIZE` constant at the bottom of that file estimates the
total stack RAM consumed by all internal tasks.

---

## ESPP component dependencies

| Component | Purpose |
|---|---|
| `base_component` | ESPP base class with integrated `espp::Logger` |
| `socket` | ESPP `UdpSocket` used by `EsppTransport` |
| `task` | ESPP `Task` for per-port UDP receive loops |
| `thread_pool` | ESPP `ThreadPool` for writer/reader workers |
| `cdr` | CDR serialization helpers |

These components abstract away all OS and network-stack details, so
`rtps_embedded` itself has no direct dependency on FreeRTOS, lwIP, or any
other platform library.

Third-party (vendored in `thirdparty/`):

| Library | Purpose |
|---|---|
| `Micro-CDR` | eProsima CDR (de)serialization for discovery messages |

---

## Example

See [`example/`](example/) for a two-node **initiator / responder** demo.

The same logic runs on any ESPP-supported platform. For ESP32, flash one board
as *Initiator* and a second as *Responder* via menuconfig
(`idf.py menuconfig → RTPS Example Configuration`). The initiator periodically
publishes numbered request messages; the responder echoes each message back on
the response topic.

Key menuconfig options (ESP32 example):

| Option | Description |
|---|---|
| `RTPS_EXAMPLE_ROLE` | `Initiator` or `Responder` |
| `RTPS_EXAMPLE_TOPIC_PREFIX` | Shared topic prefix (e.g. `espp/rtps_example`) |
| `RTPS_EXAMPLE_PUBLISH_PERIOD_MS` | Initiator publish interval |
| `ESP_WIFI_SSID` / `ESP_WIFI_PASSWORD` | Wi-Fi credentials |
21 changes: 21 additions & 0 deletions components/rtps_embedded/example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.20)

set(ENV{IDF_COMPONENT_MANAGER} "0")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)

set(EXTRA_COMPONENT_DIRS
"../../../components/"
)

set(
COMPONENTS
"main esptool_py logger rtps_embedded esp32-ethernet-kit"
CACHE STRING
"List of components to include"
)

project(rtps_embedded_example)

set(CMAKE_CXX_STANDARD 20)
3 changes: 3 additions & 0 deletions components/rtps_embedded/example/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
idf_component_register(SRC_DIRS "."
INCLUDE_DIRS "."
)
10 changes: 10 additions & 0 deletions components/rtps_embedded/example/main/Kconfig.projbuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
menu "RTPS Example Configuration"

config RTPS_EXAMPLE_ANNOUNCE_PERIOD_MS
int "Publish period (ms)"
range 200 60000
default 1500
help
Period between outgoing messages published by the MCU.

endmenu
Loading