Skip to content

parameter_dict_from_yaml_file loads doubles as strings when str() uses exponent notation (e.g. 0.00001, 5e-06, 1e+20) #1672

Description

@Lots-ninety-nine

Bug report

Required Info:

  • Operating System: Ubuntu 24.04 (osrf/ros:rolling-desktop)
  • Installation type: binaries
  • Version or commit hash: rolling (the offending line is still present on the rolling branch, rclpy/parameter.py:565)
  • DDS implementation: rmw_fastrtps_cpp
  • Client library (if applicable): rclpy

Description

parameter_dict_from_yaml_file (used by ros2 param load) loads floating-point parameters as strings whenever the value's Python str() representation uses exponent notation, e.g. 0.00001, 5e-06, 1.0e+20. Plain decimals such as 3.14 are unaffected. This also affects double arrays.

Steps to reproduce issue

repro.yaml:

/parameter_blackboard:
  ros__parameters:
    a_small: 0.00001
    b_sci: 5e-06
    c_large: 1.0e+20
    d_normal: 3.14
    e_arr: [1.0e-5, 2.0e-5]
ros2 run demo_nodes_cpp parameter_blackboard &
ros2 param load /parameter_blackboard repro.yaml
for p in a_small b_sci c_large d_normal e_arr; do ros2 param get /parameter_blackboard $p; done

Expected behavior

a_small, b_sci, c_large are doubles and e_arr is a double array — matching what the C++ params-file loader (--params-file) and ros2 param set already produce for the same values.

Actual behavior

a_small   -> String value is: 1e-05
b_sci     -> String value is: 5e-06
c_large   -> String value is: 1e+20
d_normal  -> Double value is: 3.14
e_arr     -> String values are: ['1e-05', '2e-05']

Root cause

In _unpack_parameter_dict (rclpy/parameter.py):

parameter.value = get_parameter_value(str(param_value))

yaml.safe_load parses the file and already types these values correctly as floats. _unpack_parameter_dict then converts each value back to a string with str() and re-parses it through get_parameter_valueyaml.safe_load. For magnitudes where str(float) yields exponent notation without a decimal point (1e-05, 5e-06, 1e+20), PyYAML's YAML 1.1 implicit resolver does not treat the result as a float (it requires a .), so it returns a str and the parameter is created with type STRING.

The float → str() → YAML round-trip discards the type that yaml.safe_load already determined. Building the ParameterValue from the already-parsed Python value, instead of re-parsing str(param_value), avoids the lossy round-trip.

This is the same underlying problem reported in ros2/ros2cli#834, but the fix is local to rclpy. Happy to open a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions