Skip to content

feat(nebula_hesai): add FTX140 support - #523

Draft
Autumn60 wants to merge 3 commits into
tier4:mainfrom
Autumn60:feat/hesai-ftx140-support
Draft

Autumn60 wants to merge 3 commits into
tier4:mainfrom
Autumn60:feat/hesai-ftx140-support

Conversation

@Autumn60

@Autumn60 Autumn60 commented Oct 28, 2026 •

Copy link
Copy Markdown

PR Type

  • New Feature

Related Links

Description

This PR adds support for the Hesai FTX140, a solid-state lidar using point cloud UDP protocol 7.3.

Note

This branch is stacked on the fault message PR and the AT128P PR, so until they are merged, it also contains their commits. Only the last commit, feat(nebula_hesai): add FTX140 support, belongs to this PR. I will rebase it onto main once the other two are merged.

Decoder

The FTX140 gets its own decoder, HesaiFtx140Decoder.

  • Packet layout: each packet contains one subzone of 6 rows × 16 columns of the sensor's 192 × 256 channel array.
  • Frames: frames are cut when the frame ID changes, not by azimuth.
  • Calibration (HesaiFtxCalibration): the sensor provides a fisheye camera model instead of per-pixel angles. The model consists of focal length, principal point, four radial distortion coefficients and a tilt of the image plane. The ray direction of each pixel is computed from this model on load.
    • The model and its constants follow FT::CorrectionV3::generate_pixel_vectors() of the Hesai LiDAR SDK 2.0, so points match the ones produced by Hesai's tools.
  • Supported packet variants:
    • Zoom mode: only the central 16 × 10 subzones are output.
    • Bottom-up row order.
  • Ignored packets: IMU and fault message packets arrive on the same port and are ignored (DecodeError::PACKET_IGNORED).
  • Return modes: only the single return modes First (sensor default), Last and Strongest are supported. Dual return modes are rejected in the configuration.

Hardware interface

  • Inventory: the FTX140 has the same 216-byte inventory layout as the AT128P, so HesaiInventory_AT128P is reused. Like the AT128P, it reports 0 as its product model, so it is handled like the AT128 (PTC only).

  • Status: HesaiLidarStatusFTX reads the lidar status. It has the AT128 layout, but the temperature fields are not reported because the sensor does not fill them.

  • Sensor setup (setup_sensor): the FTX140 has its own config info layout (HesaiConfig_FTX, 47 bytes without spin rate, sync angle or GPS port) and supports fewer setting commands, so it gets its own check_and_set_config(). It compares and, if needed, sets only:

    • Return mode: one of the supported single return modes. Unlike the other sensors, an invalid return mode does not fall back to a dual return mode.
    • Destination: IP and port. The GPS port is always sent as 0, as the FTX140 does not support it.
    • PTP config: automotive profile only, sent as 3 like on the OT128. The FTX140 expects the PTP status (enabled) before the profile, so the payload is {1, 3, domain, network, switch type}. The schema restricts ptp_profile to automotive accordingly.

    Spin rate, sync angle and lidar range do not exist on the FTX140 and are skipped. The command layouts follow the public FTX TCP API Reference (ARF04-en-260620).

Other changes

  • Parameter file, JSON schema and launch entries.
  • Calibration sample (FTX140.dat).
  • Documentation page and an entry in the supported sensors table.
  • Support in the offline extraction examples.

Review Procedure

  1. Build and run the unit tests:

    colcon build --packages-up-to nebula_hesai --cmake-args -DBUILD_TESTING=ON
    colcon test --packages-select nebula_hesai nebula_hesai_decoders nebula_hesai_hw_interfaces
    colcon test-result --verbose

    New tests:

    • test_hesai_ftx140: calibration against reference directions from the Hesai SDK, rejection of invalid calibration data, full frame decoding, zoom mode, bottom-up rows, FoV cropping, ignoring IMU and fault message packets, and the supported (single) return modes.
    • test_hesai_hw_interface: PTC commands of the FTX140, the config info layout, and the sensor setup. The mock sensor now records requests and can return custom responses, so the tests check the exact set commands: all three when the config differs, none when it matches.
  2. (Optional) With a sensor, launch the driver:

    ros2 launch nebula_hesai hesai_launch_all_hw.xml sensor_model:=FTX140

Test results

  • Unit tests: 178 tests in nebula_hesai, nebula_hesai_decoders and nebula_hesai_hw_interfaces pass (ROS 2 Jazzy, Agnocast disabled). This includes the tests of the two PRs this one depends on.
  • pre-commit: passes on all changed files.

Remarks

  • Hesai SDK derivation: the FTX140 calibration model is derived from the Hesai LiDAR SDK 2.0 (Modified BSD License). Attribution is in the comment of HesaiFtxCalibration. Please check whether this is acceptable for the license of this repository.

Pre-Review Checklist for the PR Author

PR Author should check the checkboxes below when creating the PR.

  • Assign PR to reviewer

Checklist for the PR Reviewer

Reviewers should check the checkboxes below before approval.

  • Commits are properly organized and messages are according to the guideline
  • (Optional) Unit tests have been written for new behavior
  • PR title describes the changes

Post-Review Checklist for the PR Author

PR Author should check the checkboxes below before merging.

  • All open points are addressed and tracked via issues or tickets

CI Checks

  • Build and test for PR: Required to pass before the merge.

Signed-off-by: Autumn60 <harada.akiro@gmail.com>
Signed-off-by: Autum60 <akiro.harada@tier4.jp>
…ponding tests

Signed-off-by: Autum60 <akiro.harada@tier4.jp>
Signed-off-by: Autum60 <akiro.harada@tier4.jp>
@codecov

codecov Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.16667% with 57 lines in your changes missing coverage. Please review.
✅ Project coverage is 46.80%. Comparing base (bdf127c) to head (7dbae36).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #523      +/-   ##
==========================================
+ Coverage   45.71%   46.80%   +1.09%     
==========================================
  Files         136      145       +9     
  Lines       10363    11057     +694     
  Branches     1282     1348      +66     
==========================================
+ Hits         4737     5175     +438     
- Misses       5624     5858     +234     
- Partials        2       24      +22     
Flag Coverage Δ
nebula 45.96% <84.16%> (?)
nebula_core_common 45.96% <84.16%> (?)
nebula_hesai 45.96% <84.16%> (?)
nebula_hesai_common 45.96% <84.16%> (?)
nebula_hesai_decoders 45.96% <84.16%> (?)
nebula_hesai_hw_interfaces 45.96% <84.16%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Autumn60 Autumn60 mentioned this pull request Oct 29, 2026
5 tasks
@Autumn60
Autumn60 marked this pull request as ready for review October 29, 2026 02:58
@Autumn60
Autumn60 marked this pull request as draft October 29, 2026 02:58
@Autumn60
Autumn60 requested a review from mojomex October 29, 2026 03:02
@Autumn60
Autumn60 marked this pull request as ready for review October 29, 2026 03:02
@Autumn60
Autumn60 marked this pull request as draft November 2, 2026 00:33

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant