Skip to content

Commit 8eb910c

Browse files
authored
Merge pull request #153 from cogip/152-detector-enable-lidar-scan-delay-compensation
Detector: enable Lidar scan delay compensation
2 parents 2b3ca35 + 3ec3503 commit 8eb910c

File tree

16 files changed

+316
-9
lines changed

16 files changed

+316
-9
lines changed

cogip/cpp/libraries/models/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ add_library(
77
CoordsList.cpp
88
Polar.cpp
99
Pose.cpp
10+
PoseBuffer.cpp
1011
)
1112
target_include_directories(
1213
models_cpp
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright (C) 2025 COGIP Robotics association <cogip35@gmail.com>
2+
// This file is subject to the terms and conditions of the GNU Lesser
3+
// General Public License v2.1. See the file LICENSE in the top level directory.
4+
5+
#include "models/PoseBuffer.hpp"
6+
7+
#include <cmath>
8+
#include <cstring>
9+
10+
namespace cogip {
11+
12+
namespace models {
13+
14+
PoseBuffer::PoseBuffer(pose_buffer_t* data):
15+
data_(data),
16+
external_data_(data != nullptr)
17+
{
18+
if (!external_data_) {
19+
// Allocate memory if external pointer is not provided
20+
data_ = new pose_buffer_t();
21+
}
22+
data_->head = 0;
23+
data_->tail = 0;
24+
data_->full = false;
25+
26+
}
27+
28+
PoseBuffer::~PoseBuffer()
29+
{
30+
if (!external_data_) {
31+
delete data_;
32+
}
33+
};
34+
35+
double PoseBuffer::full() const
36+
{
37+
38+
};
39+
40+
std::size_t PoseBuffer::size() const
41+
{
42+
if (data_->full) return POSE_BUFFER_SIZE_MAX;
43+
if (data_->head >= data_->tail) return data_->head - data_->tail;
44+
return POSE_BUFFER_SIZE_MAX + data_->head - data_->tail;
45+
};
46+
47+
void PoseBuffer::push(float x, float y, float angle)
48+
{
49+
data_->poses[data_->head].x = x;
50+
data_->poses[data_->head].y = y;
51+
data_->poses[data_->head].angle = angle;
52+
if (data_->full) {
53+
data_->tail = (data_->tail + 1) % POSE_BUFFER_SIZE_MAX; // Advance tail if full
54+
}
55+
data_->head = (data_->head + 1) % POSE_BUFFER_SIZE_MAX;
56+
data_->full = (data_->head == data_->tail);
57+
};
58+
59+
Pose PoseBuffer::get(std::size_t n) const
60+
{
61+
if (n >= size()) {
62+
throw std::out_of_range("Requested index is out of bounds.");
63+
}
64+
65+
// Calculate index relative to head (reverse order)
66+
size_t index = (data_->head + POSE_BUFFER_SIZE_MAX - 1 - n) % POSE_BUFFER_SIZE_MAX;
67+
return Pose(&data_->poses[index]);
68+
};
69+
70+
} // namespace models
71+
72+
} // namespace cogip

cogip/cpp/libraries/models/binding.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "models/CoordsList.hpp"
66
#include "models/Pose.hpp"
7+
#include "models/PoseBuffer.hpp"
78
#include "models/binding.hpp"
89

910
#include <nanobind/nanobind.h>
@@ -165,6 +166,33 @@ NB_MODULE(models, m) {
165166
}
166167
)
167168
;
169+
170+
// Bind pose_buffer_t structure
171+
nb::class_<pose_buffer_t>(m, "PoseBufferT")
172+
.def_rw("head", &pose_buffer_t::head, "Next write pose")
173+
.def_rw("tail", &pose_buffer_t::tail, "Oldest pose")
174+
.def("__repr__", [](const pose_buffer_t& buffer) {
175+
std::ostringstream oss;
176+
oss << buffer;
177+
return oss.str();
178+
})
179+
;
180+
181+
// Bind PoseBuffer class
182+
nb::class_<PoseBuffer>(m, "PoseBuffer")
183+
.def(nb::init<pose_buffer_t*>(), "Constructor", "data"_a = nullptr)
184+
.def_prop_ro("head", &PoseBuffer::head, "Next write pose")
185+
.def_prop_ro("tail", &PoseBuffer::tail, "Oldest pose")
186+
.def("push", &PoseBuffer::push, "Get last pose pushed in the buffer", "x"_a, "y"_a, "angle"_a)
187+
.def_prop_ro("last", &PoseBuffer::last, "Get last pose pushed in the buffer")
188+
.def("get", &PoseBuffer::get, "Get the N-th position from head (0 is the most recent)", "n"_a)
189+
.def("__repr__", [](const PoseBuffer &buffer) {
190+
std::ostringstream oss;
191+
oss << buffer;
192+
return oss.str();
193+
})
194+
;
195+
168196
}
169197

170198
} // namespace models
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Copyright (C) 2025 COGIP Robotics association <cogip35@gmail.com>
2+
// This file is subject to the terms and conditions of the GNU Lesser
3+
// General Public License v2.1. See the file LICENSE in the top level directory.
4+
5+
/// @ingroup lib_models
6+
/// @{
7+
/// @file
8+
/// @brief PoseBuffer declaration
9+
/// @author Eric Courtois <eric.courtois@gmail.com>
10+
11+
#pragma once
12+
13+
#include "models/pose_buffer.hpp"
14+
#include "models/Pose.hpp"
15+
16+
#include <ostream>
17+
18+
namespace cogip {
19+
20+
namespace models {
21+
22+
class PoseBuffer {
23+
public:
24+
/// Constructor.
25+
PoseBuffer(
26+
pose_buffer_t* data ///< [in] Pointer to an existing data structure
27+
///< If nullptr, will allocate one internally
28+
);
29+
30+
/// Destructor
31+
~PoseBuffer();
32+
33+
/// Return the pointer to the underlying data structure.
34+
pose_buffer_t* data() { return data_; };
35+
36+
/// Return head.
37+
double head() const { return data_->head; };
38+
39+
/// Return tail.
40+
double tail() const { return data_->tail; };
41+
42+
/// Return true if the buffer is full, false otherwise.
43+
double full() const;
44+
45+
/// Get the number of stored positions
46+
std::size_t size() const;
47+
48+
/// Add a new pose to the buffer.
49+
void push(float x, float y, float angle);
50+
51+
/// Get last pose pushed in the buffer.
52+
Pose last() const { return get(0); };
53+
54+
/// Get the N-th position from head (0 is the most recent).
55+
Pose get(std::size_t n) const;
56+
57+
protected:
58+
pose_buffer_t* data_; ///< pointer to internal data structure
59+
bool external_data_; ///< Flag to indicate if memory is externally managed
60+
};
61+
62+
/// Overloads the stream insertion operator for `PoseBuffer`.
63+
/// Prints the PoseBuffer in a human-readable format.
64+
/// @param os The output stream.
65+
/// @param buffer The PoseBuffer to print.
66+
/// @return A reference to the output stream.
67+
inline std::ostream& operator<<(std::ostream& os, const PoseBuffer& buffer) {
68+
os << "PoseBuffer(size=" << buffer.size() << "/" << POSE_BUFFER_SIZE_MAX << ", head=" << buffer.head() << ", tail=" << buffer.tail() << ")";
69+
return os;
70+
}
71+
72+
} // namespace models
73+
74+
} // namespace cogip
75+
76+
/// @}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright (C) 2025 COGIP Robotics association <cogip35@gmail.com>
2+
// This file is subject to the terms and conditions of the GNU Lesser
3+
// General Public License v2.1. See the file LICENSE in the top level directory.
4+
5+
/// @ingroup lib_models
6+
/// @{
7+
/// @file
8+
/// @brief pose_buffer_t class declaration
9+
/// @author Eric Courtois <eric.courtois@gmail.com>
10+
11+
#pragma once
12+
13+
#include "models/pose.hpp"
14+
15+
#include <ostream>
16+
17+
namespace cogip {
18+
19+
namespace models {
20+
21+
constexpr std::size_t POSE_BUFFER_SIZE_MAX = 256;
22+
23+
/// A circular buffer to store pose_t.
24+
typedef struct {
25+
pose_t poses[POSE_BUFFER_SIZE_MAX]; ///< Poses list
26+
size_t head; ///< Next write pose
27+
size_t tail; ///< Oldest pose
28+
bool full; ///< Indicates if the buffer is full
29+
} pose_buffer_t;
30+
31+
/// Overloads the stream insertion operator for `pose_buffer_t`.
32+
/// Prints the pose in a human-readable format.
33+
/// @param os The output stream.
34+
/// @param buffer The buffer to print.
35+
/// @return A reference to the output stream.
36+
inline std::ostream& operator<<(std::ostream& os, const pose_buffer_t& buffer) {
37+
size_t size = 0;
38+
if (buffer.head >= buffer.tail){
39+
size = buffer.head - buffer.tail;
40+
}
41+
else {
42+
size = POSE_BUFFER_SIZE_MAX + buffer.head - buffer.tail;
43+
}
44+
45+
os << "pose_buffer_t(size=" << size << "/" << POSE_BUFFER_SIZE_MAX << ", head=" << buffer.head << ", tail=" << buffer.tail << ")";
46+
return os;
47+
}
48+
49+
} // namespace cogip_defs
50+
51+
} // namespace cogip
52+
53+
/// @}

cogip/cpp/libraries/shared_memory/SharedMemory.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ SharedMemory::SharedMemory(const std::string& name, bool owner):
5656
for (const auto& [lock, name] : lock2str) {
5757
locks_.emplace(lock, std::make_unique<WritePriorityLock>(name_ + "_" + name, owner_));
5858
}
59+
pose_current_buffer_ = new models::PoseBuffer(&data_->pose_current_buffer);
5960
pose_current_ = new models::Pose(&data_->pose_current);
6061
pose_order_ = new models::Pose(&data_->pose_order);
6162
detector_obstacles_ = new models::CoordsList(&data_->detector_obstacles);
@@ -73,6 +74,7 @@ SharedMemory::~SharedMemory() {
7374
delete detector_obstacles_;
7475
delete pose_order_;
7576
delete pose_current_;
77+
delete pose_current_buffer_;
7678

7779
if (data_ != nullptr) {
7880
munmap(data_, sizeof(shared_data_t));

cogip/cpp/libraries/shared_memory/binding.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ NB_MODULE(shared_memory, m) {
2525

2626
nb::class_<shared_data_t>(m, "SharedData")
2727
.def(nb::init<>())
28+
.def_rw("pose_current_buffer", &shared_data_t::pose_current_buffer)
2829
.def_rw("pose_current", &shared_data_t::pose_current)
2930
.def_rw("pose_order", &shared_data_t::pose_order)
3031
.def("__repr__", [](const shared_data_t &s) {
@@ -68,6 +69,8 @@ NB_MODULE(shared_memory, m) {
6869
"Get a lock for a specific part of the shared memory.")
6970
.def("get_data", &SharedMemory::getData, nb::rv_policy::reference,
7071
"Get the shared data.")
72+
.def("get_pose_current_buffer", &SharedMemory::getPoseCurrentBuffer, nb::rv_policy::reference_internal,
73+
"Get PoseBuffer object wrapping the shared memory pose_current_buffer structure.")
7174
.def("get_pose_current", &SharedMemory::getPoseCurrent, nb::rv_policy::reference_internal,
7275
"Get Pose object wrapping the shared memory pose_current structure.")
7376
.def("get_pose_order", &SharedMemory::getPoseOrder, nb::rv_policy::reference_internal,

cogip/cpp/libraries/shared_memory/include/shared_memory/SharedMemory.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "shared_memory/shared_data.hpp"
66
#include "shared_memory/WritePriorityLock.hpp"
77

8+
#include "models/PoseBuffer.hpp"
89
#include "obstacles/ObstacleCircleList.hpp"
910
#include "obstacles/ObstacleRectangleList.hpp"
1011

@@ -46,6 +47,9 @@ class SharedMemory {
4647
/// Retrieves a pointer to the shared memory data structure.
4748
shared_data_t* getData() { return data_; }
4849

50+
/// Retrieves a pointer to the PoseBuffer object wrapping the shared memory pose_current_buffer structure.
51+
models::PoseBuffer* getPoseCurrentBuffer() { return pose_current_buffer_; }
52+
4953
/// Retrieves a pointer to the Pose object wrapping the shared memory pose_current structure.
5054
models::Pose* getPoseCurrent() { return pose_current_; }
5155

@@ -73,6 +77,7 @@ class SharedMemory {
7377
int shm_fd_; ///< File descriptor for the shared memory.
7478
shared_data_t* data_; ///< Pointer to the shared memory data structure.
7579
std::map<LockName, std::shared_ptr<WritePriorityLock>> locks_; ///< Map of locks for synchronization.
80+
models::PoseBuffer* pose_current_buffer_; ///< Pointer to the PoseBuffer object wrapping the shared memory pose_current_buffer structure.
7681
models::Pose* pose_current_; ///< Pointer to the Pose object wrapping the shared memory pose_current structure.
7782
models::Pose* pose_order_; ///< Pointer to the Pose object wrapping the shared memory pose_order structure.
7883
models::CoordsList* detector_obstacles_; ///< Pointer to the CoordsList object wrapping the shared memory detector_obstacles structure.

cogip/cpp/libraries/shared_memory/include/shared_memory/shared_data.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "models/coords_list.hpp"
88
#include "models/pose.hpp"
9+
#include "models/pose_buffer.hpp"
910
#include "obstacles/obstacle_circle_list.hpp"
1011
#include "obstacles/obstacle_polygon_list.hpp"
1112

@@ -21,6 +22,7 @@ constexpr std::size_t NUM_ANGLES = 360;
2122

2223
/// Represents shared data in shared memory.
2324
typedef struct {
25+
models::pose_buffer_t pose_current_buffer; ///< The last current poses.
2426
models::pose_t pose_current; ///< The current pose.
2527
models::pose_t pose_order; ///< The target pose.
2628
uint16_t lidar_data[NUM_ANGLES][2]; ///< The Lidar data.

cogip/entities/robot.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ def __init__(self, robot_id: int, win: MainWindow, parent: Qt3DCore.QEntity | No
7878
self.update_pose_current_timer = QtCore.QTimer()
7979
self.update_pose_current_timer.timeout.connect(self.update_pose_current)
8080

81+
# Create a timer for consistent hit updates
82+
self.update_hit_timer = QtCore.QTimer()
83+
self.update_hit_timer.setTimerType(QtCore.Qt.TimerType.PreciseTimer)
84+
self.update_hit_timer.start(RobotEntity.update_pose_current_interval)
85+
8186
def setEnabled(self, isEnabled):
8287
if isEnabled:
8388
self.shared_memory = SharedMemory(f"cogip_{self.robot_id}")
@@ -148,6 +153,7 @@ def add_lidar_sensors(self):
148153
)
149154
sensor.shared_sensor_data = self.shared_lidar_data
150155
self.sensors.append(sensor)
156+
self.update_hit_timer.timeout.connect(sensor.ray_caster.trigger)
151157

152158
def add_tof_sensor(self):
153159
"""

0 commit comments

Comments
 (0)