Refactor lidar library: rename olei_config to lidar_config, add nanoscan example and shared byte helpers

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-03 09:27:43 +07:00
parent 59880871b0
commit 323715eab0
16 changed files with 621 additions and 814 deletions

View File

@@ -6,27 +6,29 @@
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.
// Settings for one lidar. `name` is the unique key across saves.
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"
std::string model = "AUTO";
bool inverted = false; // OLEI only
std::string brand = "OLEI"; // "OLEI" or "SICK"
// Output angle window (deg): scan angles are remapped onto
// [angle_min_deg, angle_max_deg] without dropping points.
// Defaults (±360) = off.
float angle_min_deg = -360.f;
float angle_max_deg = 360.f;
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;
a.model == b.model && a.inverted == b.inverted && a.brand == b.brand &&
a.angle_min_deg == b.angle_min_deg && a.angle_max_deg == b.angle_max_deg;
}
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},
@@ -34,47 +36,25 @@ struct Config {
};
};
// Known model name -> ModelConfig (matches the constants in lidar.hpp/sick_lidar.hpp).
// Returns nullptr if name doesn't match any entry.
// nullptr if `name` doesn't match any known model.
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.
// Subset of model_names() valid for `brand`; empty if unknown.
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).
// Returns defaults if the file doesn't exist (without creating 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
// Build a ready-to-open lidar from one LidarConfig — the only entry point an
// app needs. brand "SICK" → SICK driver (model "SICK-nanoScan3" → UDP
// NanoScanDriver, others → TCP SickDriver); anything else → OLEI UDP.
// Unknown/cross-brand model falls back to the brand default. Never nullptr.
std::unique_ptr<Lidar> make_lidar(const LidarConfig& cfg);
} // namespace lidarlib