Dashing Diademata(dashing

Dashing Diademata 是ROS 2的第四个版本。

支持的平台

Dashing Diademata主要支持以下平台:

一级平台:

  • Ubuntu 18.04(Bionic):amd64``和``arm64

  • Mac macOS 10.12 (Sierra)

  • Windows 10(Visual Studio 2019)

二级平台:

  • Ubuntu 18.04(Bionic):arm32

Tier 3 平台:

  • Debian Stretch(9):amd64arm64arm32

  • OpenEmbedded Thud(2.6)/ webOS OSE:arm32x86

有关RMW实现、编译器/解释器版本和系统依赖版本的更多信息,请参阅 REP 2000

这个ROS 2版本的新功能有:

我们想要强调一些功能和改进:

  • :doc:`组件 <../Tutorials/Intermediate/Composition>`现在是编写节点的推荐方式。它们可以独立使用,也可以在进程中进行组合,两种方式都可以完全支持``launch``文件。

  • 改进了:doc:`进程内通信 <../Tutorials/Demos/Intra-Process-Communication>`(仅限C++),无论是延迟还是最小化拷贝方面都有所改善。

  • Python客户端库已更新以匹配大部分C++等效库,并且解决了与内存使用和性能相关的一些重要错误和改进。

  • 参数现在是完全替代ROS 1中``dynamic_reconfigure``的选择,包括范围约束或只读。

  • 通过依赖(IDL 4.2的一个子集 <https://www.omg.org/spec/IDL/4.2>`__)来进行消息生成流程,现在可以使用 .idl 文件(除了 .msg / .srv / .action 文件)。这个变化还支持对普通字符串使用可选的UTF-8编码,以及对UTF-16编码的多字节字符串进行支持(参见 wide strings design article).

  • actionscomponents 相关的命令行工具。

  • 支持Deadline、Lifespan和Liveliness的服务质量设置。

  • MoveIt 2 alpha版本发布.

请查看GitHub上的 Dashing元票,其中包含了更多信息以及其他详细票据的参考。

自Crystal版本发布以来的变化。

声明参数

从Dashing开始,参数的行为发生了一些变化,同时还引入了一些新的API和废弃了其他的API。有关API变化的更多信息,请参阅下面的``rclcpp``和``rclpy``部分。

获取和设置未声明的参数

从Dashing开始,访问或设置参数之前需要先声明参数。

在Dashing之前,您可以调用``get_parameter(name)``,如果已经设置了值,您将得到一个值,否则将得到一个类型为``PARAMETER_NOT_SET``的参数。您也可以在任何时候调用``set_parameter(name, value)``,即使参数之前未设置。

自从Dashing版本以后,您需要先声明一个参数,然后才能获取或设置它。如果尝试获取或设置一个未声明的参数,您将会抛出异常,例如ParameterNotDeclaredException,或在某些情况下您将会以各种方式得到一个不成功的结果(请参阅具体函数以了解更多细节)。

然而,您可以通过在创建节点时使用 allow_undeclared_parameters 选项来获得旧的行为(大多数情况下,请参阅下一段的注释)。您可能希望暂时这样做,以避免现在进行代码更改,或者以满足一些不常见的用例。例如,"全局参数服务器" 或 "参数黑板" 可能希望允许外部节点在未声明参数的情况下在自身上设置新的参数,因此它可以使用 allow_undeclared_parameters 选项来实现该功能。然而,在大多数情况下,不建议使用此选项,因为它会使其他参数 API 对于参数名称拼写错误和 "在设置之前使用" 的逻辑错误等 bug 变得不太安全。

请注意,使用 allow_undeclared_parameters 选项将为 "get" 和 "set" 方法提供大部分旧行为,但它不会将与参数相关的所有行为更改恢复到 ROS Crystal 的状态。为此,您还需要将 automatically_declare_parameters_from_overrides 选项设置为 true,该选项在下面的 Parameter Configuration using a YAML File 中进行了描述。

使用 ParameterDescriptor 声明参数

在使用参数之前声明参数的另一个好处是可以同时声明参数描述符。

现在,当声明参数时,您可以同时包含自定义的 ParameterDescriptor、名称和默认值。ParameterDescriptorrcl_interfaces/msg/ParameterDescriptor 中定义为一条消息,其中包含诸如 description 这样的元数据和诸如 read_onlyinteger_range 这样的约束。这些约束可用于在设置参数时拒绝无效值,或者作为对外部工具的提示,告知给定参数的有效值是什么。read_only 约束将阻止参数在声明后更改其值,并防止其被撤销声明。

供参考,以下链接是撰写本文时的 ParameterDescriptor 消息的链接:

https://github.com/ros2/rcl_interfaces/blob/0aba5a142878c2077d7a03977087e7d74d40ee68/rcl_interfaces/msg/ParameterDescriptor.msg#L1

使用YAML文件进行参数配置

从Dashing版本开始,YAML配置文件中的参数(例如通过命令行参数``__params:=``传递给节点)仅用于在声明参数时覆盖参数的默认值。

在Dashing版本之前,通过YAML文件传递的任何参数都会隐式设置在节点上。

从Dashing版本开始,情况已经改变,因为需要声明参数才能在节点外部观察者(如``ros2 param list``)中显示参数。

可以通过在创建节点时使用``automatically_declare_parameters_from_overrides``选项来实现旧的行为。如果将此选项设置为``true``,则在构造节点时会自动声明输入YAML文件中的所有参数。这可以用于避免对现有代码进行重大更改或满足特定的用例。例如,"全局参数服务器"可能希望在启动时使用任意参数进行初始化,而事先无法声明这些参数。然而,大多数情况下,不建议使用此选项,因为它可能导致在YAML文件中设置参数,并假设节点会使用该参数,即使节点实际上并未使用该参数。

未来我们希望拥有一个检查器,如果您向节点传递了它不期望的参数,它将会提醒您。

YAML文件中的参数将继续影响在首次声明时的参数值。

ament_cmake

CMake函数``ament_index_has_resource``以前返回``TRUE``或``FALSE``。从`此版本开始 <https://github.com/ament/ament_cmake/pull/155>`_,如果找到资源,它将返回前缀路径,否则返回``FALSE``。

如果您在CMake条件中使用返回值,像这样:

ament_index_has_resource(var ...)
if(${var})

您需要更新条件以确保它将字符串值视为``TRUE``:

if(var)

rclcpp

``Node::get_node_names()``的行为变更

函数``NodeGraph::get_node_names()``,以及因此也是``Node::get_node_names()``,现在返回一个包含完全限定的节点名称(包括命名空间)的``std::vector<std::string>``,而不仅仅是节点名称。

更改了传递选项给节点的方式

``rclcpp::Node()``构造函数的扩展参数(除了名称和命名空间)已被替换为``rclcpp::NodeOptions``结构。有关该结构和选项的默认值的详细信息,请参阅`ros2/rclcpp#622 <https://github.com/ros2/rclcpp/pull/622/files>`__。

如果您正在使用类似以下方式的``rclcpp::Node()``的扩展参数:

auto context = rclcpp::contexts::default_context::get_global_default_context();
std::vector<std::string> args;
std::vector<rclcpp::Parameter> params = { rclcpp::Parameter("use_sim_time", true) };
auto node = std::make_shared<rclcpp::Node>("foo_node", "bar_namespace", context, args, params);

您需要更新为使用``NodeOptions``结构。

std::vector<std::string> args;
std::vector<rclcpp::Parameter> params = { rclcpp::Parameter("use_sim_time", true) };
rclcpp::NodeOptions node_options;
node_options.arguments(args);
node_options.parameter_overrides(params);
auto node = std::make_shared<rclcpp::Node>("foo_node", "bar_namespace", node_options);

创建发布者和订阅者的变化

在Dashing版本中,创建发布者和订阅者方面有一些变化:

  • 现在使用新的``rclcpp::QoS``类来传递QoS设置,并且API鼓励用户至少指定历史深度。

  • 选项现在作为对象传递,即``rclcpp::PublisherOptions``和``rclcpp::SubscriptionOptions``。

所有的变化都向后兼容(无需更改代码),但是一些旧的调用方式已被弃用。建议用户更新为新的签名。


在过去,创建发布者或订阅者时,可以不指定任何QoS设置(例如,对于发布者,只需提供主题名称),或者可以指定已设置了所有设置的“qos profile”数据结构(类型为``rmw_qos_profile_t``)。现在,您必须使用新的``rclcpp::QoS``对象来指定您的QoS,至少要为您的QoS指定历史设置。这鼓励用户在使用``KEEP_LAST``时指定历史深度,而不是将其默认为可能不合适的值。

在ROS 1中,这被称为``queue_size``,在C++和Python中都是必需的。我们正在更改ROS 2 API以恢复此要求。


此外,以前可以在创建发布者或订阅时传递的任何选项现在已封装在``rclcpp::PublisherOptions``和``rclcpp::SubscriptionOptions``类中。这使得签名更短,使用更方便,并且可以在不破坏API的情况下添加新的未来选项。


一些创建发布者和订阅者的签名现在已经过时,并添加了新的签名,以允许您使用新的``rclcpp::QoS``和发布者/订阅者选项类。

这些是新的推荐API:

template<
  typename MessageT,
  typename AllocatorT = std::allocator<void>,
  typename PublisherT = ::rclcpp::Publisher<MessageT, AllocatorT>>
std::shared_ptr<PublisherT>
create_publisher(
  const std::string & topic_name,
  const rclcpp::QoS & qos,
  const PublisherOptionsWithAllocator<AllocatorT> & options =
  PublisherOptionsWithAllocator<AllocatorT>()
);

template<
  typename MessageT,
  typename CallbackT,
  typename AllocatorT = std::allocator<void>,
  typename SubscriptionT = rclcpp::Subscription<
    typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, AllocatorT>>
std::shared_ptr<SubscriptionT>
create_subscription(
  const std::string & topic_name,
  const rclcpp::QoS & qos,
  CallbackT && callback,
  const SubscriptionOptionsWithAllocator<AllocatorT> & options =
  SubscriptionOptionsWithAllocator<AllocatorT>(),
  typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
    typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, AllocatorT
  >::SharedPtr
  msg_mem_strat = nullptr);

这些是已过时的API:

template<
  typename MessageT,
  typename AllocatorT = std::allocator<void>,
  typename PublisherT = ::rclcpp::Publisher<MessageT, AllocatorT>>
[[deprecated("use create_publisher(const std::string &, const rclcpp::QoS &, ...) instead")]]
std::shared_ptr<PublisherT>
create_publisher(
  const std::string & topic_name,
  size_t qos_history_depth,
  std::shared_ptr<AllocatorT> allocator);

template<
  typename MessageT,
  typename AllocatorT = std::allocator<void>,
  typename PublisherT = ::rclcpp::Publisher<MessageT, AllocatorT>>
[[deprecated("use create_publisher(const std::string &, const rclcpp::QoS &, ...) instead")]]
std::shared_ptr<PublisherT>
create_publisher(
  const std::string & topic_name,
  const rmw_qos_profile_t & qos_profile = rmw_qos_profile_default,
  std::shared_ptr<AllocatorT> allocator = nullptr);

template<
  typename MessageT,
  typename CallbackT,
  typename Alloc = std::allocator<void>,
  typename SubscriptionT = rclcpp::Subscription<
    typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, Alloc>>
[[deprecated(
  "use create_subscription(const std::string &, const rclcpp::QoS &, CallbackT, ...) instead"
)]]
std::shared_ptr<SubscriptionT>
create_subscription(
  const std::string & topic_name,
  CallbackT && callback,
  const rmw_qos_profile_t & qos_profile = rmw_qos_profile_default,
  rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr,
  bool ignore_local_publications = false,
  typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
    typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, Alloc>::SharedPtr
  msg_mem_strat = nullptr,
  std::shared_ptr<Alloc> allocator = nullptr);

template<
  typename MessageT,
  typename CallbackT,
  typename Alloc = std::allocator<void>,
  typename SubscriptionT = rclcpp::Subscription<
    typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, Alloc>>
[[deprecated(
  "use create_subscription(const std::string &, const rclcpp::QoS &, CallbackT, ...) instead"
)]]
std::shared_ptr<SubscriptionT>
create_subscription(
  const std::string & topic_name,
  CallbackT && callback,
  size_t qos_history_depth,
  rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr,
  bool ignore_local_publications = false,
  typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
    typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, Alloc>::SharedPtr
  msg_mem_strat = nullptr,
  std::shared_ptr<Alloc> allocator = nullptr);

传递QoS的更改最有可能影响用户。

一个出版商的典型更改如下所示:

- pub_ = create_publisher<std_msgs::msg::String>("chatter");
+ pub_ = create_publisher<std_msgs::msg::String>("chatter", 10);

对于订阅,如下所示:

- sub_ = create_subscription<std_msgs::msg::String>("chatter", callback);
+ sub_ = create_subscription<std_msgs::msg::String>("chatter", 10, callback);

如果您对使用的深度没有概念并且现在不关心(可能只是原型设计),那么我们建议使用 10,因为这是之前的默认值,应该保留现有行为。

有关如何选择适当的深度的更详细文档即将发布。

这是一个稍微复杂一些的更改示例,以避免使用新弃用的 API:

- // Creates a latched topic
- rmw_qos_profile_t qos = rmw_qos_profile_default;
- qos.depth = 1;
- qos.durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
-
  model_xml_.data = model_xml;
  node_handle->declare_parameter("robot_description", model_xml);
  description_pub_ = node_handle->create_publisher<std_msgs::msg::String>(
-   "robot_description", qos);
+   "robot_description",
+   // Transient local is similar to latching in ROS 1.
+   rclcpp::QoS(1).transient_local());

有关引入 QoS 更改的拉取请求(以及相关的拉取请求)的更多示例和详细信息,请参见:

由于参数声明更改而引起的变化

有关实际行为更改的详细信息,请参阅上述的`声明参数`_

``rclcpp::Node``的接口中新增了几个API调用:

  • 根据名称、可选默认值、可选描述符声明参数并返回实际设置的值的方法:

    const rclcpp::ParameterValue &
    rclcpp::Node::declare_parameter(
      const std::string & name,
      const rclcpp::ParameterValue & default_value = rclcpp::ParameterValue(),
      const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
      rcl_interfaces::msg::ParameterDescriptor());
    
    template<typename ParameterT>
    auto
    rclcpp::Node::declare_parameter(
      const std::string & name,
      const ParameterT & default_value,
      const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
      rcl_interfaces::msg::ParameterDescriptor());
    
    template<typename ParameterT>
    std::vector<ParameterT>
    rclcpp::Node::declare_parameters(
      const std::string & namespace_,
      const std::map<std::string, ParameterT> & parameters);
    
    template<typename ParameterT>
    std::vector<ParameterT>
    rclcpp::Node::declare_parameters(
      const std::string & namespace_,
      const std::map<
        std::string,
        std::pair<ParameterT, rcl_interfaces::msg::ParameterDescriptor>
      > & parameters);
    
  • 一个取消声明参数和检查参数是否已声明的方法:

    void
    rclcpp::Node::undeclare_parameter(const std::string & name);
    
    bool
    rclcpp::Node::has_parameter(const std::string & name) const;
    
  • 一些之前不存在的便捷方法:

    rcl_interfaces::msg::SetParametersResult
    rclcpp::Node::set_parameter(const rclcpp::Parameter & parameter);
    
    std::vector<rclcpp::Parameter>
    rclcpp::Node::get_parameters(const std::vector<std::string> & names) const;
    
    rcl_interfaces::msg::ParameterDescriptor
    rclcpp::Node::describe_parameter(const std::string & name) const;
    
  • 一种新的方法,用于设置每当参数将被更改时调用的回调函数,以便您有机会拒绝更改:

    using OnParametersSetCallbackType =
      rclcpp::node_interfaces::NodeParametersInterface::OnParametersSetCallbackType;
    
    OnParametersSetCallbackType
    rclcpp::Node::set_on_parameters_set_callback(
      OnParametersSetCallbackType callback);
    

还有几个已弃用的方法:

template<typename ParameterT>
[[deprecated("use declare_parameter() instead")]]
void
rclcpp::Node::set_parameter_if_not_set(
  const std::string & name,
  const ParameterT & value);

template<typename ParameterT>
[[deprecated("use declare_parameters() instead")]]
void
rclcpp::Node::set_parameters_if_not_set(
  const std::string & name,
  const std::map<std::string, ParameterT> & values);

template<typename ParameterT>
[[deprecated("use declare_parameter() and it's return value instead")]]
void
rclcpp::Node::get_parameter_or_set(
  const std::string & name,
  ParameterT & value,
  const ParameterT & alternative_value);

template<typename CallbackT>
[[deprecated("use set_on_parameters_set_callback() instead")]]
void
rclcpp::Node::register_param_change_callback(CallbackT && callback);

内存策略

接口``rclcpp::memory_strategy::MemoryStrategy``在各种方法签名中使用了``WeakNodeVector``的typedef。从Dashing开始,typedef已经被改为``WeakNodeList``,并且各种方法中的参数类型也随之改变。任何自定义的内存策略都需要更新以匹配修改后的接口。

相关的API更改可以在`ros2/rclcpp#741 <https://github.com/ros2/rclcpp/pull/741>`__中找到。

rclcpp_components

在Dashing中实现组合的正确方式是利用``rclcpp_components``包。

为了正确实现运行时组合,必须对节点进行以下更改:

节点必须有一个接受``rclcpp::NodeOptions``参数的构造函数:

class Listener: public rclcpp::Node {
  Listener(const rclcpp::NodeOptions & options)
  : Node("listener", options)
  {
  }
};

如果存在C++注册宏,需要更新为使用``rclcpp_components``的等效宏。如果不存在,则必须在一个翻译单元中添加注册宏。

// Insert at bottom of translation unit, e.g. listener.cpp
#include "rclcpp_components/register_node_macro.hpp"
// Use fully-qualifed name in registration
RCLCPP_COMPONENTS_REGISTER_NODE(composition::Listener);

如果存在CMake注册宏,需要进行更新。如果不存在,则必须将注册宏添加到项目的CMake中。

add_library(listener src/listener.cpp)
rclcpp_components_register_nodes(listener "composition::Listener")

有关组合的更多信息,请参阅`教程 <https://index.ros.org/doc/ros2/Tutorials/Composition/>`__。

rclpy

创建发布者、订阅者和QoS配置文件的更改

在Dashing之前,创建发布者或订阅时可以选择性地提供``QoSProfile``对象。为了鼓励用户为消息队列指定历史深度,现在我们**要求**在创建发布者或订阅时必须提供深度值或``QoSProfile``对象。

以前,创建发布者的方式如下:

node.create_publisher(Empty, 'chatter')
# Or using a keyword argument for QoSProfile
node.create_publisher(Empty, 'chatter', qos_profile=qos_profile_sensor_data)

在Dashing中,推荐使用以下 API,将深度值或``QoSProfile``对象作为第三个位置参数:

# Assume a history setting of KEEP_LAST with depth 10
node.create_publisher(Empty, 'chatter', 10)
# Or pass a QoSProfile object directly
node.create_publisher(Empty, 'chatter', qos_profile_sensor_data)

同样地,以前创建订阅的方式如下:

node.create_subscription(BasicTypes, 'chatter', lambda msg: print(msg))
# Or using a keyword argument for QoSProfile
node.create_subscription(BasicTypes, 'chatter', lambda msg: print(msg), qos_profile=qos_profile_sensor_data)

在Dashing中:

# Assume a history setting of KEEP_LAST with depth 10
node.create_subscription(BasicTypes, 'chatter', lambda msg: print(msg), 10)
# Or pass a QoSProfile object directly
node.create_subscription(BasicTypes, 'chatter', lambda msg: print(msg), qos_profile_sensor_data)

为了简化过渡,未使用新 API 的用户将看到废弃警告。

此外,我们还要求在构建``QoSProfile``对象时设置历史策略和/或深度。如果提供了``KEEP_LAST``的历史策略,则还需要提供一个深度参数。例如,以下调用是有效的:

QoSProfile(history=QoSHistoryPolicy.RMW_QOS_POLICY_HISTORY_KEEP_ALL)
QoSProfile(history=QoSHistoryPolicy.RMW_QOS_POLICY_HISTORY_KEEP_LAST, depth=10)
QoSProfile(depth=10)  # equivalent to the previous line

而以下调用将引发弃用警告:

QoSProfile()
QoSProfile(reliability=QoSReliabilityPolicy.RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT)
# KEEP_LAST but no depth
QoSProfile(history=QoSHistoryPolicy.RMW_QOS_POLICY_HISTORY_KEEP_LAST)

有关引入此更改的问题和拉取请求的详细信息,请参阅:

由于参数声明更改而引起的变化

有关实际行为变更的详细信息,请参阅上面的`声明参数`_。这些更改类似于``rclcpp``中的更改。

这些是 rclpy.node.Node 接口中的新 API 方法:

  • 通过给定名称、可选的默认值(由 rcl_interfaces.msg.ParameterValue 支持)和可选的描述符来声明参数,并返回实际设置的值:

    def declare_parameter(
        name: str,
        value: Any = None,
        descriptor: ParameterDescriptor = ParameterDescriptor()
    ) -> Parameter
    
    def declare_parameters(
      namespace: str,
      parameters: List[Union[
          Tuple[str],
          Tuple[str, Any],
          Tuple[str, Any, ParameterDescriptor],
      ]]
    ) -> List[Parameter]
    
  • 取消之前声明的参数并检查参数是否已经声明:

    def undeclare_parameter(name: str) -> None
    
    def has_parameter(name: str) -> bool
    
  • 获取和设置参数描述符:

    def describe_parameter(name: str) -> ParameterDescriptor
    
    def describe_parameters(names: List[str]) -> List[ParameterDescriptor]
    
    def set_descriptor(
        name: str,
        descriptor: ParameterDescriptor,
        alternative_value: Optional[ParameterValue] = None
    ) -> ParameterValue
    
  • 一个便利方法来获取可能尚未声明的参数:

    def get_parameter_or(name: str, alternative_value: Optional[Parameter] = None) -> Parameter
    

其他变化

现在``rclpy.parameter.Parameter``可以在没有显式设置类型的情况下猜测类型(只要它是由``rcl_interfaces.msg.ParameterValue``支持的类型之一)。例如,以下代码:

p = Parameter('myparam', Parameter.Type.DOUBLE, 2.41)

等效于以下代码:

p = Parameter('myparam', value=2.41)

这个更改不会破坏现有的API。

rosidl

在Crystal版本之前,每个消息生成器包都会使用``ament_cmake``扩展点``rosidl_generate_interfaces``注册自己,并传递一组``.msg``/.srv/.action``文件。从Dashing版本开始,消息生成流程基于.idl``文件。

任何消息生成器包都需要更改并使用新的扩展点``rosidl_generate_idl_interfaces``进行注册,该扩展点仅传递``.idl``文件。已经更新了用于常见支持语言C、C++和Python的消息生成器,以及用于内省、Fast RTPS、Connext和OpenSplice的类型支持包(请参阅`ros2/rosidl#334 <https://github.com/ros2/rosidl/pull/334/files>`__)。调用``rosidl_generate_interfaces()``的CMake代码可以直接传递``.idl``文件,也可以传递``.msg``/.srv/.action``文件,这些文件在传递给每个消息生成器之前将被内部转换为.idl``文件。

.msg / .srv / .action``文件的格式在未来不会进行改变。.msg`` / .srv / .action``文件与.idl``文件之间的映射在`这篇设计文章 <https://design.ros2.org/articles/legacy_interface_definition.html>`__中有描述。第二篇设计文章 <https://design.ros2.org/articles/idl_interface_definition.html>`__描述了`.idl``文件中支持的特性。为了利用任何新特性,现有接口需要进行转换(例如使用命令行工具``msg2idl`` / srv2idl / action2idl)。

为了区分具有不同命名空间的相同类型名称,内省结构现在包含一个命名空间字段,用于替换包名(参见`ros2/rosidl#335 <https://github.com/ros2/rosidl/pull/355/files>`_)。

.msg文件中的char映射

在`ROS 1 <https://wiki.ros.org/msg#Fields>`__中,char``已被废弃了很长时间,并且被映射为``uint8。在ROS 2中,直到Crystal版本,char``被映射为单个字符(C / C++中的``char,Python中长度为1的``str``),以提供更自然的映射。从Dashing版本开始,恢复了ROS 1的语义,char``再次映射为``uint8

rosidl_generator_cpp

为消息、服务和动作生成的C++数据结构为每个字段提供了设置方法。在Crystal版本之前,每个设置方法返回数据结构本身的指针,以实现命名参数惯用法。从Dashing版本开始,这些设置方法改为`返回引用 <https://github.com/ros2/rosidl/pull/353>`__,因为这似乎是更常见的签名,而且它澄清了返回值不能为``nullptr``的事实。

rosidl_generator_py

直到 Crystal 版本,消息中的数组(固定大小)或序列(动态大小,可选上限)字段在 Python 中以``list``的形式存储。从 Dashing 版本开始,数值数组/序列的 Python 类型已经发生了变化:

  • 数值数组以``numpy.ndarray``的形式存储(dtype 被选择以匹配数值类型)

  • 数值序列以``array.array``的形式存储(typename 被选择以匹配数值类型)

与以前一样,非数值类型的数组/序列仍然在 Python 中表示为``list``。

这个改变带来了一些好处:

  • 新的数据结构确保数组/序列中的每个项目都符合数值类型的值范围限制。

  • 数值可以更高效地存储在内存中,避免了每个项目的 Python 对象开销。

  • 这两种数据结构的内存布局允许在单个操作中读取和写入数组/序列的所有项目,这使得与 Python 之间的转换显著更快/更高效。

启动

launch_testing 包已经赶上了 Bouncy Bolson 中对 launch 包的重新设计。已将遗留的 Python API 移动到 launch.legacy 子模块中,并因此将其弃用并移除。

请参考 launch示例文档 了解如何使用其新 API。

参考 demos tests 了解如何使用新的``launch_testing`` API。

rmw

自从 Crystal Clemmys 发布以来的更改:

  • rmw 中的新 API,rmw_context_t 的 fini 函数:

  • 修改了 rmw,现在将 rmw_context_t 传递给 rmw_create_wait_set:

  • 在``rmw``中新增的用于预分配发布和订阅消息空间的API:

  • 修改了``rmw``,现在分别向``rmw_publish``和``rmw_take``传递``rmw_publisher_allocation_t``或``rmw_subscription_allocation_t``。注意,此参数可以是``NULL``或``nullptr``,保持了现有的 Crystal 行为。

  • rmw_get_*_names_and_types* 函数返回的类型名称应具有完全限定的命名空间。例如,返回的类型名称应为 rcl_interface/msg/Parameterrcl_interfaces/srv/GetParameters,而不是 rcl_interfaces/Parameterrcl_interfaces/GetParameters

actions

  • rclcpp_action::Client 签名的更改:

    rclcpp_action::Client::async_send_goal 的签名已更改。现在用户可以使用新的 SendGoalOptions 结构可选择性地提供回调函数来处理 目标响应结果。当动作服务器接受或拒绝目标时,将调用目标响应回调函数,并在接收到目标的结果时调用结果回调函数。还在 rclcpp_action::Client::async_cancel_goalrclcpp_action::Client::async_get_result 中添加了可选回调函数。

  • 目标转换名称的更改:

    目标状态转换的名称已进行了重构以反映设计文档。这会影响 rcl_actionrclcpp_actionrclpy。以下是事件名称的更改列表 (旧名称 -> 新名称):

    • GOAL_EVENT_CANCEL -> GOAL_EVENT_CANCEL_GOAL

    • GOAL_EVENT_SET_SUCCEEDED -> GOAL_EVENT_SUCCEED

    • GOAL_EVENT_SET_ABORTED -> GOAL_EVENT_ABORT

    • GOAL_EVENT_SET_CANCELED -> GOAL_EVENT_CANCELED

  • CancelGoal.srv 的更改:

    CancelGoal 服务的响应消息中添加了一个 return_code 字段。这是为了更好地传达服务调用失败的原因。有关详细信息,请参见 拉取请求 和相关问题。

rviz

  • 插件应该使用完全限定的类型名称,否则将记录警告。例如,在 这个示例 中,使用类型 sensor_msgs/msg/Image,而不是 sensor_msgs/Image。有关更多详细信息,请参见 引入此更改的 PR

已知问题

  • [ros2/rclcpp#715] 在独立的ROS 2节点和组合的ROS 2节点之间加载参数YAML文件的方式存在不一致。目前可用的解决方法在一个`问题评论中 <https://github.com/ros2/rclcpp/issues/715#issuecomment-497392626>`_ 中有说明。

  • [ros2/rclpy#360] 在使用OpenSplice时,rclpy节点在Windows上忽略 ctrl-c 命令。

  • [ros2/rosidl_typesupport_opensplice#30] 使用OpenSplice时,在服务或动作定义中将消息嵌套在相同名称的消息中存在错误。

  • [ros2/rclcpp#781]on_set_parameter_callback 中调用 get_parameter/list_parameter 会在Dashing版本中造成死锁。这在Eloquent版本中已经修复,但由于ABI的变动,未被反向移植到Dashing。

  • [ros2/rclcpp#912] 当在一个 std::unique_ptr 发布者和一个单独的 std::unique_ptr 订阅者之间进行进程内通信时(发布的 std::unique_ptr 内部被升级为 std::shared_ptr),会强制执行消息的复制操作。

  • [ros2/rosbag2#125] 不会记录具有不可靠QOS的主题。

  • [ros2/rclcpp#715] 可组合节点无法通过重映射接收参数。可以使用 [此评论] 中描述的方法向可组合节点提供参数。

  • [ros2/rclcpp#893] rclcpp::Context 由于与 rclcpp::GraphListener 存在引用循环而无法销毁。这导致内存泄漏。由于破坏ABI的风险,修复尚未进行回溯。

发布前的时间线

发布前的一些关键节点:

4月8日(alpha版本)

核心软件包的首次发布可用。从现在开始可以进行测试(某些功能可能尚未完全实现)。

星期四。5月2日

核心包的API冻结

星期一。5月6日(beta版)

可用的核心包更新版本。对最新功能进行额外测试。

星期四。5月16日

功能冻结。在此之后,只能发布修复错误的版本。新包可以独立发布。

周一,5月20日(发行候选版)

可用的核心软件包更新版本。

周三,5月29日

冻结rosdistro。在`rosdistro`仓库中,不会合并任何关于Dashing的PR(在发布公告之后重新开放)。