Fix Family B angle decode + add LR-1FMI model
parse_family_b() dùng sai hệ số góc 0.25°/LSB; theo spec Olei chính hãng (Olei.LidarSensor/LidarDataBlock.GetAngleDegrees) AngleRaw là 0.01°/LSB. Sai 25× khiến điểm bị gán nhầm góc → một phòng bị bôi thành vòng tròn trên RViz. Đã verify với thiết bị thật OLELR-1FMI: sau khi sửa ra 2400 điểm/vòng, 0–359.9°, đúng hình học môi trường. - Đổi hệ số góc 0.25° → 0.01° trong parse_family_b(). - Bỏ qua block invalid (AngleRaw >= 0xFF00) theo spec. - Dò ranh giới vòng quay PER-POINT thay vì per-packet (một gói có thể chứa >1 vòng), tránh gộp nhiều vòng vào một scan. - Thêm model LR-1FMI (360°, 0.01°/LSB, ~2400 pts/rev) vào bảng model + kModelTable, đặt "1FMI" trước "1F" để khớp đúng chuỗi tên. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
80
include/lidarlib/config.hpp
Normal file
80
include/lidarlib/config.hpp
Normal file
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
#include "lidarlib/lidar.hpp"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace lidarlib {
|
||||
|
||||
// ─── Settings for one lidar ─────────────────────────────────────────────────
|
||||
// `name` is the unique key used to match entries across saves (rename = old
|
||||
// key removed, new key added) — useful if your GUI reconciles a running set of
|
||||
// lidars against an edited config list.
|
||||
struct LidarConfig {
|
||||
std::string name = "lidar";
|
||||
std::string ip = "0.0.0.0";
|
||||
uint16_t port = 2368;
|
||||
std::string model = "AUTO"; // must match an entry in model_names_for_brand(brand)
|
||||
bool inverted = false; // only applies to brand "OLEI" — SickDriver has no equivalent
|
||||
std::string brand = "OLEI"; // must match an entry in brand_names() — "OLEI" or "SICK"
|
||||
|
||||
friend bool operator==(const LidarConfig& a, const LidarConfig& b) {
|
||||
return a.name == b.name && a.ip == b.ip && a.port == b.port &&
|
||||
a.model == b.model && a.inverted == b.inverted && a.brand == b.brand;
|
||||
}
|
||||
friend bool operator!=(const LidarConfig& a, const LidarConfig& b) { return !(a == b); }
|
||||
};
|
||||
|
||||
// Any number of lidars — managed as a list so a consuming app/GUI can
|
||||
// add/remove entries freely instead of being locked to a fixed front/rear pair.
|
||||
struct Config {
|
||||
std::vector<LidarConfig> lidars = {
|
||||
{"front", "0.0.0.0", 2368, "AUTO", false},
|
||||
{"rear", "0.0.0.0", 2369, "AUTO", true},
|
||||
};
|
||||
};
|
||||
|
||||
// Known model name -> ModelConfig (matches the constants in lidar.hpp/sick_lidar.hpp).
|
||||
// Returns nullptr if name doesn't match any entry.
|
||||
const ModelConfig* model_by_name(const std::string& name);
|
||||
|
||||
// Names accepted by model_by_name(), for populating a UI dropdown.
|
||||
const std::vector<std::string>& model_names();
|
||||
|
||||
// Brand names accepted in LidarConfig::brand ("OLEI", "SICK"), for populating
|
||||
// a UI dropdown.
|
||||
const std::vector<std::string>& brand_names();
|
||||
|
||||
// Subset of model_names() valid for a given brand (e.g. "SICK" -> the
|
||||
// MODEL_SICK_* names) — empty if `brand` doesn't match any entry in
|
||||
// brand_names(). Used to filter the model dropdown once a brand is picked,
|
||||
// and to validate that LidarConfig::model actually belongs to its brand.
|
||||
const std::vector<std::string>& model_names_for_brand(const std::string& brand);
|
||||
|
||||
// Load config.json at `path`. If the file doesn't exist, returns defaults
|
||||
// (and does NOT create the file — caller decides whether to save it).
|
||||
Config load_config(const std::string& path);
|
||||
|
||||
// Overwrite `path` with `cfg` serialized as JSON.
|
||||
void save_config(const std::string& path, const Config& cfg);
|
||||
|
||||
// ─── THE single config function ─────────────────────────────────────────────
|
||||
// Build a ready-to-open lidar from one LidarConfig. This is the one entry point
|
||||
// a GUI/app needs: `brand` selects the transport — exactly "SICK" → TCP, any
|
||||
// other value (incl. "OLEI", empty, or an old config without the field) → OLEI
|
||||
// UDP. `model` is resolved *for that brand*: a name that is unknown OR belongs
|
||||
// to the other brand falls back to the brand's sensible default (MODEL_AUTO for
|
||||
// OLEI, MODEL_SICK_TIM571 for SICK), so a mis-paired brand+model can't silently
|
||||
// configure the wrong driver. `inverted` applies to OLEI only. Returns a unique
|
||||
// handle to the unified Lidar interface — call ->open() then
|
||||
// ->recv_scan(out, timeout_ms) to get ScanResult { LaserScan scan; ExtraInfo
|
||||
// info; }. Never returns nullptr.
|
||||
//
|
||||
// lidarlib::LidarConfig c{"front", "192.168.1.10", 2368, "AUTO", false, "OLEI"};
|
||||
// auto lidar = lidarlib::make_lidar(c);
|
||||
// lidar->open();
|
||||
// lidarlib::ScanResult r;
|
||||
// lidar->recv_scan(r, 1000); // r.scan = LaserScan, r.info = ExtraInfo
|
||||
std::unique_ptr<Lidar> make_lidar(const LidarConfig& cfg);
|
||||
|
||||
} // namespace lidarlib
|
||||
Reference in New Issue
Block a user