moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
ros_msg_typecasters.hpp
Go to the documentation of this file.
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2022, Peter David Fagan, Robert Haschke
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * The name of Robert Haschke may not be use to endorse or promote
18 * products derived from this software without specific prior
19 * written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34
35/* Author: Peter David Fagan, Robert Haschke */
36
37#pragma once
38
39#include <cstdint>
40#include <pybind11/pybind11.h>
41#include <rclcpp/rclcpp.hpp>
42#include <rclcpp/serialization.hpp>
43#include <rclcpp/duration.hpp>
44
45namespace py = pybind11;
46
47namespace moveit_py
48{
49namespace moveit_py_utils
50{
51PYBIND11_EXPORT pybind11::object createMessage(const std::string& ros_msg_name);
52PYBIND11_EXPORT bool convertible(const pybind11::handle& h, const std::string& ros_msg_name);
53} // namespace moveit_py_utils
54} // namespace moveit_py
55
56namespace pybind11
57{
58namespace detail
59{
60// Base class for type conversion (C++ <-> python) of ROS message types
61template <typename T>
63{
64 // C++ -> Python
65 // TODO: add error handling
66 static handle cast(const T& src, return_value_policy /* policy */, handle /* parent */)
67 {
68 // serialize src
69 rclcpp::Serialization<T> serializer;
70 rclcpp::SerializedMessage serialized_msg;
71 serializer.serialize_message(&src, &serialized_msg);
72 py::bytes bytes = py::bytes(reinterpret_cast<const char*>(serialized_msg.get_rcl_serialized_message().buffer),
73 serialized_msg.get_rcl_serialized_message().buffer_length);
74
75 // get Python object type
76 const std::string ros_msg_name = rosidl_generator_traits::name<T>();
77
78 // find delimiting '/' in ros_msg_name
79 std::size_t pos1 = ros_msg_name.find('/');
80 std::size_t pos2 = ros_msg_name.find('/', pos1 + 1);
81 py::module m = py::module::import((ros_msg_name.substr(0, pos1) + ".msg").c_str());
82
83 // retrieve type instance
84 py::object cls = m.attr(ros_msg_name.substr(pos2 + 1).c_str());
85
86 // deserialize into python object
87 py::module rclpy = py::module::import("rclpy.serialization");
88 py::object msg = rclpy.attr("deserialize_message")(bytes, cls);
89
90 return msg.release();
91 }
92
93 // Python -> C++
94 bool load(handle src, bool /*convert*/)
95 {
96 // check datatype of src
97 if (!moveit_py::moveit_py_utils::convertible(src, rosidl_generator_traits::name<T>()))
98 return false;
99
100 // serialize src into python buffer
101 py::module rclpy = py::module::import("rclpy.serialization");
102 py::bytes bytes = rclpy.attr("serialize_message")(src);
103
104 // deserialize into C++ object
105 rcl_serialized_message_t rcl_serialized_msg = rmw_get_zero_initialized_serialized_message();
106 char* serialized_buffer;
107 Py_ssize_t length;
108 if (PYBIND11_BYTES_AS_STRING_AND_SIZE(bytes.ptr(), &serialized_buffer, &length))
109 {
110 throw py::error_already_set();
111 }
112 if (length < 0)
113 {
114 throw py::error_already_set();
115 }
116 rcl_serialized_msg.buffer_capacity = length;
117 rcl_serialized_msg.buffer_length = length;
118 rcl_serialized_msg.buffer = reinterpret_cast<uint8_t*>(serialized_buffer);
119 rmw_ret_t rmw_ret =
120 rmw_deserialize(&rcl_serialized_msg, rosidl_typesupport_cpp::get_message_type_support_handle<T>(), &value);
121 if (RMW_RET_OK != rmw_ret)
122 {
123 throw std::runtime_error("failed to deserialize ROS message");
124 }
125 return true;
126 }
127
129};
130
131template <typename T>
132struct type_caster<T, enable_if_t<rosidl_generator_traits::is_message<T>::value>> : RosMsgTypeCaster<T>
133{
134};
135
136} // namespace detail
137} // namespace pybind11
PYBIND11_EXPORT bool convertible(const pybind11::handle &h, const std::string &ros_msg_name)
PYBIND11_EXPORT pybind11::object createMessage(const std::string &ros_msg_name)
static handle cast(const T &src, return_value_policy, handle)