Initial commit

This commit is contained in:
2026-07-13 09:25:40 +07:00
parent c08ff54676
commit bccfb156d7
1938 changed files with 641646 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
using RobotNet10.Shared.Enum;
using RobotNet10.Shared.Numbers;
namespace RobotNet10.Shared.Detection;
/// <summary>
/// Request to search for a specific marker
/// </summary>
public struct MarkerEntry
{
/// <summary>
/// Marker ID from database
/// </summary>
public string MarkerId { get; set; }
public MarkerType Type { get; set; }
/// <summary>
/// Search priority (1 = highest, 2 = second highest, etc.)
/// Lower number = higher priority
/// </summary>
public int Priority { get; set; }
public string DeviceId { get; set; }
public string Code { get; set; }
/// <summary>
/// Optional: Override detection parameters for this session
/// If null, use default parameters from marker definition
/// Tọa độ trong marker frame
/// </summary>
public Vector2[] ReferencePoints { get; set; }
}

View File

@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace RobotNet10.Shared.Detection;
/// <summary>
/// Configuration for a detection session
/// Defines search area and which markers to look for
/// </summary>
public struct MarkersSearchRequest
{
/// <summary>
/// Tọa độ dự đoán global X
/// </summary>
public double X { get; set; }
/// <summary>
/// Tọa độ dự đóan global Y
/// </summary>
public double Y { get; set; }
/// <summary>
/// Hướng dự đoán global
/// </summary>
public double Yaw { get; set; }
/// <summary>
/// Width (local X-axis, meters) kích thước tìm kiếm theo chiều rộng khi chưa xoay Yaw
/// </summary>
public double Width { get; set; }
/// <summary>
/// Length (local Y-axis, meters) kích thước tìm kiếm theo chiều dài khi chưa xoay Yaw
/// </summary>
public double Length { get; set; }
/// <summary>
/// List of markers to search for with their priorities
/// </summary>
public MarkerEntry[] MarkerSearchRequests { get; set; }
}

View File

@@ -0,0 +1,25 @@
namespace RobotNet10.Shared.Enum;
/// <summary>
/// Marker type enumeration
/// </summary>
public enum MarkerType
{
None = 0,
/// <summary>
/// QR Code marker (detected by camera)
/// </summary>
QRCode,
/// <summary>
/// ArUco marker (detected by camera)
/// </summary>
ArUco,
/// <summary>
/// Shape reflective marker - 2,3,4 reflective posts (detected by LiDAR)
/// </summary>
ShapeReflective,
}

View File

@@ -0,0 +1,39 @@
using RobotNet10.Shared.Numbers;
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// Accel message (geometry_msgs/Accel)
/// Expresses acceleration in free space broken into its linear and angular parts
/// </summary>
public struct Accel
{
/// <summary>
/// Linear acceleration (Vector3)
/// </summary>
public Vector3 Linear { get; set; }
/// <summary>
/// Angular acceleration (Vector3)
/// </summary>
public Vector3 Angular { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public Accel()
{
Linear = new Vector3();
Angular = new Vector3();
}
/// <summary>
/// Constructor with parameters
/// </summary>
public Accel(Vector3 linear, Vector3 angular)
{
Linear = linear;
Angular = angular;
}
}

View File

@@ -0,0 +1,37 @@
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// AccelStamped message (geometry_msgs/AccelStamped)
/// An Accel with reference coordinate frame and timestamp
/// </summary>
public struct AccelStamped
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Acceleration
/// </summary>
public Accel Accel { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public AccelStamped()
{
Header = new Header();
Accel = new Accel();
}
/// <summary>
/// Constructor with parameters
/// </summary>
public AccelStamped(Header header, Accel accel)
{
Header = header;
Accel = accel;
}
}

View File

@@ -0,0 +1,49 @@
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// AccelWithCovariance message (geometry_msgs/AccelWithCovariance)
/// An Accel with associated covariance matrix
/// </summary>
public struct AccelWithCovariance
{
/// <summary>
/// Acceleration
/// </summary>
public Accel Accel { get; set; }
/// <summary>
/// Covariance matrix (row-major order)
/// The orientation parameters use a fixed-axis representation.
/// In order, the parameters are:
/// (ax, ay, az, wx, wy, wz)
/// </summary>
public double[] Covariance { get; set; }
/// <summary>
/// Size of covariance matrix (6x6 = 36 elements)
/// </summary>
public const int CovarianceSize = 36;
/// <summary>
/// Default constructor
/// </summary>
public AccelWithCovariance()
{
Accel = new Accel();
Covariance = new double[CovarianceSize];
}
/// <summary>
/// Constructor with parameters
/// </summary>
public AccelWithCovariance(Accel accel, double[] covariance)
{
Accel = accel;
if (covariance == null || covariance.Length != CovarianceSize)
{
throw new ArgumentException($"Covariance array must have {CovarianceSize} elements", nameof(covariance));
}
Covariance = covariance;
}
}

View File

@@ -0,0 +1,37 @@
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// AccelWithCovarianceStamped message (geometry_msgs/AccelWithCovarianceStamped)
/// An AccelWithCovariance with reference coordinate frame and timestamp
/// </summary>
public struct AccelWithCovarianceStamped
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Acceleration with covariance
/// </summary>
public AccelWithCovariance Accel { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public AccelWithCovarianceStamped()
{
Header = new Header();
Accel = new AccelWithCovariance();
}
/// <summary>
/// Constructor with parameters
/// </summary>
public AccelWithCovarianceStamped(Header header, AccelWithCovariance accel)
{
Header = header;
Accel = accel;
}
}

View File

@@ -0,0 +1,18 @@
using RobotNet10.Shared.Numbers;
namespace RobotNet10.Shared.Geometry;
public static class GeometryExtensions
{
extension(Quaternion q)
{
public double ToYawRadian()
{
var sinYaw = 2.0 * (q.W * q.Z + q.X * q.Y);
var cosYaw = 1.0 - 2.0 * (q.Y * q.Y + q.Z * q.Z);
return Math.Atan2(sinYaw, cosYaw);
}
public double ToYawDegrees() => q.ToYawRadian() * 180 / Math.PI;
}
}

View File

@@ -0,0 +1,44 @@
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// Point message (geometry_msgs/Point)
/// Represents a point in free space with x, y, z coordinates
/// </summary>
public struct Point
{
/// <summary>
/// X coordinate
/// </summary>
public double X { get; set; }
/// <summary>
/// Y coordinate
/// </summary>
public double Y { get; set; }
/// <summary>
/// Z coordinate
/// </summary>
public double Z { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public Point()
{
X = 0.0;
Y = 0.0;
Z = 0.0;
}
/// <summary>
/// Constructor with parameters
/// </summary>
public Point(double x, double y, double z)
{
X = x;
Y = y;
Z = z;
}
}

View File

@@ -0,0 +1,39 @@
using RobotNet10.Shared.Numbers;
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// PointStamped message (geometry_msgs/PointStamped)
/// A Point with reference coordinate frame and timestamp
/// </summary>
public struct PointStamped
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Point
/// </summary>
public Vector3 Point { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public PointStamped()
{
Header = new Header();
Point = new Vector3();
}
/// <summary>
/// Constructor with parameters
/// </summary>
public PointStamped(Header header, Vector3 point)
{
Header = header;
Point = point;
}
}

View File

@@ -0,0 +1,32 @@
using RobotNet10.Shared.Numbers;
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// Polygon message (geometry_msgs/Polygon)
/// A specification of a polygon where the first and last points are assumed to be connected
/// </summary>
public struct Polygon
{
/// <summary>
/// Array of points defining the polygon
/// </summary>
public Vector3[] Points { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public Polygon()
{
Points = [];
}
/// <summary>
/// Constructor with parameters
/// </summary>
public Polygon(Vector3[] points)
{
Points = points;
}
}

View File

@@ -0,0 +1,37 @@
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// PolygonStamped message (geometry_msgs/PolygonStamped)
/// A Polygon with reference coordinate frame and timestamp
/// </summary>
public struct PolygonStamped
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Polygon
/// </summary>
public Polygon Polygon { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public PolygonStamped()
{
Header = new Header();
Polygon = new Polygon();
}
/// <summary>
/// Constructor with parameters
/// </summary>
public PolygonStamped(Header header, Polygon polygon)
{
Header = header;
Polygon = polygon;
}
}

View File

@@ -0,0 +1,37 @@
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// Pose message (geometry_msgs/Pose)
/// Represents a pose in free space, composed of position and orientation
/// </summary>
public struct Pose
{
/// <summary>
/// Position (Point)
/// </summary>
public Point Position { get; set; }
/// <summary>
/// Orientation (Quaternion)
/// </summary>
public Quaternion Orientation { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public Pose()
{
Position = new Point();
Orientation = new Quaternion();
}
/// <summary>
/// Constructor with parameters
/// </summary>
public Pose(Point position, Quaternion orientation)
{
Position = position;
Orientation = orientation;
}
}

View File

@@ -0,0 +1,37 @@
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// PoseStamped message (geometry_msgs/PoseStamped)
/// A Pose with reference coordinate frame and timestamp
/// </summary>
public struct PoseStamped
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Pose
/// </summary>
public Pose Pose { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public PoseStamped()
{
Header = new Header();
Pose = new Pose();
}
/// <summary>
/// Constructor with parameters
/// </summary>
public PoseStamped(Header header, Pose pose)
{
Header = header;
Pose = pose;
}
}

View File

@@ -0,0 +1,49 @@
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// PoseWithCovariance message (geometry_msgs/PoseWithCovariance)
/// A Pose with associated covariance matrix
/// </summary>
public struct PoseWithCovariance
{
/// <summary>
/// Pose
/// </summary>
public Pose Pose { get; set; }
/// <summary>
/// Covariance matrix (row-major order)
/// The orientation parameters use a fixed-axis representation.
/// In order, the parameters are:
/// (x, y, z, rotation about X axis, rotation about Y axis, rotation about Z axis)
/// </summary>
public double[] Covariance { get; set; }
/// <summary>
/// Size of covariance matrix (6x6 = 36 elements)
/// </summary>
public const int CovarianceSize = 36;
/// <summary>
/// Default constructor
/// </summary>
public PoseWithCovariance()
{
Pose = new Pose();
Covariance = new double[CovarianceSize];
}
/// <summary>
/// Constructor with parameters
/// </summary>
public PoseWithCovariance(Pose pose, double[] covariance)
{
Pose = pose;
if (covariance == null || covariance.Length != CovarianceSize)
{
throw new ArgumentException($"Covariance array must have {CovarianceSize} elements", nameof(covariance));
}
Covariance = covariance;
}
}

View File

@@ -0,0 +1,37 @@
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// PoseWithCovarianceStamped message (geometry_msgs/PoseWithCovarianceStamped)
/// A PoseWithCovariance with reference coordinate frame and timestamp
/// </summary>
public struct PoseWithCovarianceStamped
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Pose with covariance
/// </summary>
public PoseWithCovariance Pose { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public PoseWithCovarianceStamped()
{
Header = new Header();
Pose = new PoseWithCovariance();
}
/// <summary>
/// Constructor with parameters
/// </summary>
public PoseWithCovarianceStamped(Header header, PoseWithCovariance pose)
{
Header = header;
Pose = pose;
}
}

View File

@@ -0,0 +1,51 @@
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// Quaternion message (geometry_msgs/Quaternion)
/// Represents a rotation in free space in quaternion form
/// </summary>
public struct Quaternion
{
/// <summary>
/// X component
/// </summary>
public double X { get; set; }
/// <summary>
/// Y component
/// </summary>
public double Y { get; set; }
/// <summary>
/// Z component
/// </summary>
public double Z { get; set; }
/// <summary>
/// W component (scalar part)
/// </summary>
public double W { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public Quaternion()
{
X = 0.0;
Y = 0.0;
Z = 0.0;
W = 1.0; // Identity quaternion
}
/// <summary>
/// Constructor with parameters
/// </summary>
public Quaternion(double x, double y, double z, double w)
{
X = x;
Y = y;
Z = z;
W = w;
}
}

View File

@@ -0,0 +1,39 @@
using RobotNet10.Shared.Numbers;
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// QuaternionStamped message (geometry_msgs/QuaternionStamped)
/// A Quaternion with reference coordinate frame and timestamp
/// </summary>
public struct QuaternionStamped
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Quaternion
/// </summary>
public Quaternion Quaternion { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public QuaternionStamped()
{
Header = new Header();
Quaternion = new Quaternion();
}
/// <summary>
/// Constructor with parameters
/// </summary>
public QuaternionStamped(Header header, Quaternion quaternion)
{
Header = header;
Quaternion = quaternion;
}
}

View File

@@ -0,0 +1,39 @@
using RobotNet10.Shared.Numbers;
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// Transform message (geometry_msgs/Transform)
/// Represents a transform between two coordinate frames in free space
/// </summary>
public struct Transform
{
/// <summary>
/// Translation (Vector3)
/// </summary>
public Vector3 Translation { get; set; }
/// <summary>
/// Rotation (Quaternion)
/// </summary>
public Quaternion Rotation { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public Transform()
{
Translation = new Vector3();
Rotation = new Quaternion();
}
/// <summary>
/// Constructor with parameters
/// </summary>
public Transform(Vector3 translation, Quaternion rotation)
{
Translation = translation;
Rotation = rotation;
}
}

View File

@@ -0,0 +1,44 @@
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// TransformStamped message (geometry_msgs/TransformStamped)
/// A Transform with reference coordinate frame and timestamp
/// </summary>
public struct TransformStamped
{
/// <summary>
/// Header with timestamp and frame ID (child_frame_id is stored in frame_id)
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Child frame ID (the frame being transformed to)
/// </summary>
public string ChildFrameId { get; set; }
/// <summary>
/// Transform
/// </summary>
public Transform Transform { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public TransformStamped()
{
Header = new Header();
ChildFrameId = string.Empty;
Transform = new Transform();
}
/// <summary>
/// Constructor with parameters
/// </summary>
public TransformStamped(Header header, string childFrameId, Transform transform)
{
Header = header;
ChildFrameId = childFrameId;
Transform = transform;
}
}

View File

@@ -0,0 +1,39 @@
using RobotNet10.Shared.Numbers;
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// Twist message (geometry_msgs/Twist)
/// Expresses velocity in free space broken into its linear and angular parts
/// </summary>
public struct Twist
{
/// <summary>
/// Linear velocity (Vector3)
/// </summary>
public Vector3 Linear { get; set; }
/// <summary>
/// Angular velocity (Vector3)
/// </summary>
public Vector3 Angular { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public Twist()
{
Linear = new Vector3();
Angular = new Vector3();
}
/// <summary>
/// Constructor with parameters
/// </summary>
public Twist(Vector3 linear, Vector3 angular)
{
Linear = linear;
Angular = angular;
}
}

View File

@@ -0,0 +1,37 @@
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// TwistStamped message (geometry_msgs/TwistStamped)
/// A Twist with reference coordinate frame and timestamp
/// </summary>
public struct TwistStamped
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Twist
/// </summary>
public Twist Twist { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public TwistStamped()
{
Header = new Header();
Twist = new Twist();
}
/// <summary>
/// Constructor with parameters
/// </summary>
public TwistStamped(Header header, Twist twist)
{
Header = header;
Twist = twist;
}
}

View File

@@ -0,0 +1,49 @@
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// TwistWithCovariance message (geometry_msgs/TwistWithCovariance)
/// A Twist with associated covariance matrix
/// </summary>
public struct TwistWithCovariance
{
/// <summary>
/// Twist
/// </summary>
public Twist Twist { get; set; }
/// <summary>
/// Covariance matrix (row-major order)
/// The orientation parameters use a fixed-axis representation.
/// In order, the parameters are:
/// (vx, vy, vz, wx, wy, wz)
/// </summary>
public double[] Covariance { get; set; }
/// <summary>
/// Size of covariance matrix (6x6 = 36 elements)
/// </summary>
public const int CovarianceSize = 36;
/// <summary>
/// Default constructor
/// </summary>
public TwistWithCovariance()
{
Twist = new Twist();
Covariance = new double[CovarianceSize];
}
/// <summary>
/// Constructor with parameters
/// </summary>
public TwistWithCovariance(Twist twist, double[] covariance)
{
Twist = twist;
if (covariance == null || covariance.Length != CovarianceSize)
{
throw new ArgumentException($"Covariance array must have {CovarianceSize} elements", nameof(covariance));
}
Covariance = covariance;
}
}

View File

@@ -0,0 +1,37 @@
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// TwistWithCovarianceStamped message (geometry_msgs/TwistWithCovarianceStamped)
/// A TwistWithCovariance with reference coordinate frame and timestamp
/// </summary>
public struct TwistWithCovarianceStamped
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Twist with covariance
/// </summary>
public TwistWithCovariance Twist { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public TwistWithCovarianceStamped()
{
Header = new Header();
Twist = new TwistWithCovariance();
}
/// <summary>
/// Constructor with parameters
/// </summary>
public TwistWithCovarianceStamped(Header header, TwistWithCovariance twist)
{
Header = header;
Twist = twist;
}
}

View File

@@ -0,0 +1,44 @@
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// Vector3 message (geometry_msgs/Vector3)
/// Represents a vector in free space
/// </summary>
public struct Vector3
{
/// <summary>
/// X component
/// </summary>
public double X { get; set; }
/// <summary>
/// Y component
/// </summary>
public double Y { get; set; }
/// <summary>
/// Z component
/// </summary>
public double Z { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public Vector3()
{
X = 0.0;
Y = 0.0;
Z = 0.0;
}
/// <summary>
/// Constructor with parameters
/// </summary>
public Vector3(double x, double y, double z)
{
X = x;
Y = y;
Z = z;
}
}

View File

@@ -0,0 +1,39 @@
using RobotNet10.Shared.Numbers;
namespace RobotNet10.Shared.Geometry;
/// <summary>
/// Vector3Stamped message (geometry_msgs/Vector3Stamped)
/// A Vector3 with reference coordinate frame and timestamp
/// </summary>
public struct Vector3Stamped
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Vector3
/// </summary>
public Vector3 Vector { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public Vector3Stamped()
{
Header = new Header();
Vector = new Vector3();
}
/// <summary>
/// Constructor with parameters
/// </summary>
public Vector3Stamped(Header header, Vector3 vector)
{
Header = header;
Vector = vector;
}
}

View File

@@ -0,0 +1,43 @@
namespace RobotNet10.Shared;
/// <summary>
/// Standard ROS Header message (similar to std_msgs/Header)
/// </summary>
public struct Header
{
/// <summary>
/// Sequence number: consecutively increasing ID
/// </summary>
public uint Seq { get; set; }
/// <summary>
/// Timestamp: time when data was acquired
/// </summary>
public DateTime Stamp { get; set; }
/// <summary>
/// Frame ID: frame this data is associated with
/// </summary>
public string FrameId { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public Header()
{
Seq = 0;
Stamp = DateTime.MinValue;
FrameId = string.Empty;
}
/// <summary>
/// Constructor with parameters
/// </summary>
public Header(uint seq, DateTime stamp, string frameId)
{
Seq = seq;
Stamp = stamp;
FrameId = frameId;
}
}

View File

@@ -0,0 +1,153 @@
using RobotNet10.Shared.Geometry;
namespace RobotNet10.Shared.Localization;
/// <summary>
/// Occupancy grid for representing map as a 2D grid of cells
/// Compatible with ROS navigation_msgs/OccupancyGrid
/// </summary>
public class OccupancyGrid
{
/// <summary>
/// Resolution of the grid (meters per pixel)
/// </summary>
public double Resolution { get; set; }
/// <summary>
/// Width of the grid (number of cells)
/// </summary>
public int Width { get; set; }
/// <summary>
/// Height of the grid (number of cells)
/// </summary>
public int Height { get; set; }
/// <summary>
/// Origin of the grid in map frame (bottom-left corner)
/// </summary>
public Pose Origin { get; set; }
/// <summary>
/// Grid data: -1 = Unknown, 0-100 = Probability of occupancy (0 = free, 100 = occupied)
/// Stored in row-major order (index = y * width + x)
/// </summary>
public sbyte[] Data { get; set; }
/// <summary>
/// Creates a new empty occupancy grid
/// </summary>
public OccupancyGrid()
{
Resolution = 0.05;
Width = 0;
Height = 0;
Origin = new Pose();
Data = [];
}
/// <summary>
/// Creates a new occupancy grid with specified dimensions
/// </summary>
public OccupancyGrid(double resolution, int width, int height, Pose origin)
{
Resolution = resolution;
Width = width;
Height = height;
Origin = origin;
Data = new sbyte[width * height];
// Initialize all cells as unknown (-1)
Array.Fill(Data, (sbyte)-1);
}
/// <summary>
/// Gets the occupancy value at the specified cell coordinates
/// </summary>
/// <param name="x">X coordinate (0 to Width-1)</param>
/// <param name="y">Y coordinate (0 to Height-1)</param>
/// <returns>-1 = Unknown, 0-100 = Occupancy probability</returns>
public sbyte GetCell(int x, int y)
{
if (x < 0 || x >= Width || y < 0 || y >= Height)
{
return -1; // Out of bounds = unknown
}
return Data[y * Width + x];
}
/// <summary>
/// Sets the occupancy value at the specified cell coordinates
/// </summary>
/// <param name="x">X coordinate (0 to Width-1)</param>
/// <param name="y">Y coordinate (0 to Height-1)</param>
/// <param name="value">-1 = Unknown, 0-100 = Occupancy probability</param>
public void SetCell(int x, int y, sbyte value)
{
if (x < 0 || x >= Width || y < 0 || y >= Height)
{
return; // Out of bounds, ignore
}
Data[y * Width + x] = value;
}
/// <summary>
/// Converts world coordinates (meters) to grid cell coordinates
/// </summary>
/// <param name="worldX">X coordinate in meters</param>
/// <param name="worldY">Y coordinate in meters</param>
/// <returns>Cell coordinates (x, y)</returns>
public (int x, int y) WorldToGrid(double worldX, double worldY)
{
// Convert world coordinates relative to origin
var relativeX = worldX - Origin.Position.X;
var relativeY = worldY - Origin.Position.Y;
// Convert to grid coordinates
var gridX = (int)Math.Floor(relativeX / Resolution);
var gridY = (int)Math.Floor(relativeY / Resolution);
return (gridX, gridY);
}
/// <summary>
/// Converts grid cell coordinates to world coordinates (meters)
/// </summary>
/// <param name="gridX">X coordinate in grid cells</param>
/// <param name="gridY">Y coordinate in grid cells</param>
/// <returns>World coordinates (x, y) in meters</returns>
public (double x, double y) GridToWorld(int gridX, int gridY)
{
var worldX = Origin.Position.X + (gridX * Resolution);
var worldY = Origin.Position.Y + (gridY * Resolution);
return (worldX, worldY);
}
/// <summary>
/// Gets the bounds of the grid in world coordinates
/// </summary>
public BoundingBox GetBounds()
{
var (minX, minY) = GridToWorld(0, 0);
var (maxX, maxY) = GridToWorld(Width, Height);
return new BoundingBox
{
MinX = Math.Min(minX, maxX),
MinY = Math.Min(minY, maxY),
MaxX = Math.Max(minX, maxX),
MaxY = Math.Max(minY, maxY)
};
}
}
/// <summary>
/// Bounding box for representing map bounds
/// </summary>
public class BoundingBox
{
public double MinX { get; set; }
public double MinY { get; set; }
public double MaxX { get; set; }
public double MaxY { get; set; }
}

View File

@@ -0,0 +1,5 @@
namespace RobotNet10.Shared;
public record MessageResult(bool IsSuccess, string Message = "");
public record MessageResult<T>(bool IsSuccess, T? Data = default, string Message = "");

View File

@@ -0,0 +1,204 @@
using System.Runtime.CompilerServices;
namespace RobotNet10.Shared.Numbers;
/// <summary>
/// Custom 3x2 matrix struct for 2D affine transformations.
/// Replacement for System.Numerics.Matrix3x2 which doesn't serialize properly.
/// </summary>
public struct Matrix3x2 : IEquatable<Matrix3x2>
{
/// <summary>
/// Value at row 1, column 1
/// </summary>
public double M11 { get; set; }
/// <summary>
/// Value at row 1, column 2
/// </summary>
public double M12 { get; set; }
/// <summary>
/// Value at row 2, column 1
/// </summary>
public double M21 { get; set; }
/// <summary>
/// Value at row 2, column 2
/// </summary>
public double M22 { get; set; }
/// <summary>
/// Value at row 3, column 1 (translation X)
/// </summary>
public double M31 { get; set; }
/// <summary>
/// Value at row 3, column 2 (translation Y)
/// </summary>
public double M32 { get; set; }
/// <summary>
/// Creates a new Matrix3x2
/// </summary>
public Matrix3x2(double m11, double m12, double m21, double m22, double m31, double m32)
{
M11 = m11;
M12 = m12;
M21 = m21;
M22 = m22;
M31 = m31;
M32 = m32;
}
#region Static Properties
/// <summary>
/// Returns the identity matrix
/// </summary>
public static Matrix3x2 Identity => new(1, 0, 0, 1, 0, 0);
#endregion
#region Static Methods
/// <summary>
/// Creates a rotation matrix
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Matrix3x2 CreateRotation(double radians)
{
double cos = Math.Cos(radians);
double sin = Math.Sin(radians);
return new Matrix3x2(cos, sin, -sin, cos, 0, 0);
}
/// <summary>
/// Creates a translation matrix
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Matrix3x2 CreateTranslation(double x, double y)
{
return new Matrix3x2(1, 0, 0, 1, x, y);
}
/// <summary>
/// Creates a translation matrix from a Vector2
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Matrix3x2 CreateTranslation(Vector2 position)
{
return new Matrix3x2(1, 0, 0, 1, position.X, position.Y);
}
/// <summary>
/// Creates a scale matrix
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Matrix3x2 CreateScale(double scale)
{
return new Matrix3x2(scale, 0, 0, scale, 0, 0);
}
/// <summary>
/// Creates a scale matrix
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Matrix3x2 CreateScale(double scaleX, double scaleY)
{
return new Matrix3x2(scaleX, 0, 0, scaleY, 0, 0);
}
/// <summary>
/// Multiplies two matrices
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Matrix3x2 Multiply(Matrix3x2 value1, Matrix3x2 value2)
{
return value1 * value2;
}
#endregion
#region Operators
/// <summary>
/// Multiplies two matrices
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Matrix3x2 operator *(Matrix3x2 value1, Matrix3x2 value2)
{
return new Matrix3x2(
value1.M11 * value2.M11 + value1.M12 * value2.M21,
value1.M11 * value2.M12 + value1.M12 * value2.M22,
value1.M21 * value2.M11 + value1.M22 * value2.M21,
value1.M21 * value2.M12 + value1.M22 * value2.M22,
value1.M31 * value2.M11 + value1.M32 * value2.M21 + value2.M31,
value1.M31 * value2.M12 + value1.M32 * value2.M22 + value2.M32
);
}
/// <summary>
/// Checks if two matrices are equal
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Matrix3x2 left, Matrix3x2 right)
{
return left.M11 == right.M11 && left.M12 == right.M12 &&
left.M21 == right.M21 && left.M22 == right.M22 &&
left.M31 == right.M31 && left.M32 == right.M32;
}
/// <summary>
/// Checks if two matrices are not equal
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Matrix3x2 left, Matrix3x2 right)
{
return !(left == right);
}
#endregion
#region Equality
/// <summary>
/// Checks if this matrix equals another matrix
/// </summary>
public readonly bool Equals(Matrix3x2 other)
{
return M11 == other.M11 && M12 == other.M12 &&
M21 == other.M21 && M22 == other.M22 &&
M31 == other.M31 && M32 == other.M32;
}
/// <summary>
/// Checks if this matrix equals an object
/// </summary>
public override readonly bool Equals(object? obj)
{
return obj is Matrix3x2 matrix && Equals(matrix);
}
/// <summary>
/// Gets the hash code for this matrix
/// </summary>
public override readonly int GetHashCode()
{
return HashCode.Combine(M11, M12, M21, M22, M31, M32);
}
#endregion
#region String
/// <summary>
/// Returns a string representation of this matrix
/// </summary>
public override readonly string ToString()
{
return $"{{ {{M11:{M11} M12:{M12}}} {{M21:{M21} M22:{M22}}} {{M31:{M31} M32:{M32}}} }}";
}
#endregion
}

View File

@@ -0,0 +1,605 @@
using System.Runtime.CompilerServices;
namespace RobotNet10.Shared.Numbers;
/// <summary>
/// Custom quaternion struct that supports JSON serialization.
/// Replacement for System.Numerics.Quaternion which doesn't serialize properly.
/// Represents rotation in 3D space using the formula: q = w + xi + yj + zk
/// </summary>
public struct Quaternion : IEquatable<Quaternion>
{
/// <summary>
/// X component of the vector part
/// </summary>
public double X { get; set; }
/// <summary>
/// Y component of the vector part
/// </summary>
public double Y { get; set; }
/// <summary>
/// Z component of the vector part
/// </summary>
public double Z { get; set; }
/// <summary>
/// W component (scalar/real part)
/// </summary>
public double W { get; set; }
/// <summary>
/// Creates a new Quaternion
/// </summary>
public Quaternion(double x, double y, double z, double w)
{
X = x;
Y = y;
Z = z;
W = w;
}
/// <summary>
/// Creates a quaternion from a vector and scalar parts
/// </summary>
public Quaternion(Vector3 vectorPart, double scalarPart)
{
X = vectorPart.X;
Y = vectorPart.Y;
Z = vectorPart.Z;
W = scalarPart;
}
#region Static Properties
/// <summary>
/// Returns the identity quaternion (no rotation)
/// </summary>
public static Quaternion Identity => new(0, 0, 0, 1);
public static Quaternion FromYawRadian(double yaw)
{
var halfYaw = yaw / 2.0;
return new Quaternion(0, 0, Math.Sin(halfYaw), Math.Cos(halfYaw));
}
#endregion
#region Properties
/// <summary>
/// Returns the length (magnitude) of the quaternion
/// </summary>
public readonly double Length()
{
return Math.Sqrt(X * X + Y * Y + Z * Z + W * W);
}
/// <summary>
/// Returns the squared length of the quaternion (faster than Length)
/// </summary>
public readonly double LengthSquared()
{
return X * X + Y * Y + Z * Z + W * W;
}
/// <summary>
/// Returns true if this is a unit quaternion
/// </summary>
public readonly bool IsIdentity
{
get
{
return X == 0 && Y == 0 && Z == 0 && W == 1;
}
}
#endregion
#region Methods
/// <summary>
/// Returns a normalized copy of this quaternion (unit length)
/// </summary>
public readonly Quaternion Normalize()
{
double length = Length();
if (length < double.Epsilon)
return Identity;
double invLength = 1.0 / length;
return new Quaternion(X * invLength, Y * invLength, Z * invLength, W * invLength);
}
/// <summary>
/// Normalizes this quaternion in place
/// </summary>
public void NormalizeInPlace()
{
double length = Length();
if (length < double.Epsilon)
{
X = Y = Z = 0;
W = 1;
return;
}
double invLength = 1.0 / length;
X *= invLength;
Y *= invLength;
Z *= invLength;
W *= invLength;
}
/// <summary>
/// Returns the conjugate of this quaternion (negated vector part)
/// For unit quaternions, conjugate equals inverse
/// </summary>
public readonly Quaternion Conjugate()
{
return new Quaternion(-X, -Y, -Z, W);
}
/// <summary>
/// Returns the inverse of this quaternion
/// </summary>
public readonly Quaternion Inverse()
{
double lengthSq = LengthSquared();
if (lengthSq < double.Epsilon)
return Identity;
double invLengthSq = 1.0 / lengthSq;
return new Quaternion(-X * invLengthSq, -Y * invLengthSq, -Z * invLengthSq, W * invLengthSq);
}
#endregion
#region Static Methods
/// <summary>
/// Calculates the dot product of two quaternions
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Dot(Quaternion quaternion1, Quaternion quaternion2)
{
return quaternion1.X * quaternion2.X +
quaternion1.Y * quaternion2.Y +
quaternion1.Z * quaternion2.Z +
quaternion1.W * quaternion2.W;
}
/// <summary>
/// Returns the conjugate of a quaternion (static version)
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Quaternion Conjugate(Quaternion value)
{
return value.Conjugate();
}
/// <summary>
/// Returns the inverse of a quaternion (static version)
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Quaternion Inverse(Quaternion value)
{
return value.Inverse();
}
/// <summary>
/// Returns a normalized copy of a quaternion (static version)
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Quaternion Normalize(Quaternion value)
{
return value.Normalize();
}
/// <summary>
/// Multiplies two quaternions (static version)
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Quaternion Multiply(Quaternion value1, Quaternion value2)
{
return value1 * value2;
}
/// <summary>
/// Performs spherical linear interpolation between two quaternions
/// </summary>
public static Quaternion Slerp(Quaternion quaternion1, Quaternion quaternion2, double amount)
{
double cosOmega = Dot(quaternion1, quaternion2);
bool flip = false;
if (cosOmega < 0.0)
{
flip = true;
cosOmega = -cosOmega;
}
double s1, s2;
if (cosOmega > (1.0 - 1e-6))
{
// Too close, do straight linear interpolation
s1 = 1.0 - amount;
s2 = flip ? -amount : amount;
}
else
{
double omega = Math.Acos(cosOmega);
double invSinOmega = 1.0 / Math.Sin(omega);
s1 = Math.Sin((1.0 - amount) * omega) * invSinOmega;
s2 = flip
? -Math.Sin(amount * omega) * invSinOmega
: Math.Sin(amount * omega) * invSinOmega;
}
return new Quaternion(
s1 * quaternion1.X + s2 * quaternion2.X,
s1 * quaternion1.Y + s2 * quaternion2.Y,
s1 * quaternion1.Z + s2 * quaternion2.Z,
s1 * quaternion1.W + s2 * quaternion2.W
);
}
/// <summary>
/// Performs linear interpolation between two quaternions
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Quaternion Lerp(Quaternion quaternion1, Quaternion quaternion2, double amount)
{
double t = amount;
double t1 = 1.0 - t;
Quaternion result;
double dot = Dot(quaternion1, quaternion2);
if (dot >= 0.0)
{
result = new Quaternion(
t1 * quaternion1.X + t * quaternion2.X,
t1 * quaternion1.Y + t * quaternion2.Y,
t1 * quaternion1.Z + t * quaternion2.Z,
t1 * quaternion1.W + t * quaternion2.W
);
}
else
{
result = new Quaternion(
t1 * quaternion1.X - t * quaternion2.X,
t1 * quaternion1.Y - t * quaternion2.Y,
t1 * quaternion1.Z - t * quaternion2.Z,
t1 * quaternion1.W - t * quaternion2.W
);
}
return result.Normalize();
}
/// <summary>
/// Concatenates two quaternions (applies rotation1 followed by rotation2)
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Quaternion Concatenate(Quaternion value1, Quaternion value2)
{
// This is equivalent to value2 * value1
double q1x = value2.X;
double q1y = value2.Y;
double q1z = value2.Z;
double q1w = value2.W;
double q2x = value1.X;
double q2y = value1.Y;
double q2z = value1.Z;
double q2w = value1.W;
// Cross product
double cx = q1y * q2z - q1z * q2y;
double cy = q1z * q2x - q1x * q2z;
double cz = q1x * q2y - q1y * q2x;
double dot = q1x * q2x + q1y * q2y + q1z * q2z;
return new Quaternion(
q1x * q2w + q2x * q1w + cx,
q1y * q2w + q2y * q1w + cy,
q1z * q2w + q2z * q1w + cz,
q1w * q2w - dot
);
}
/// <summary>
/// Creates a quaternion from an axis and angle
/// </summary>
public static Quaternion CreateFromAxisAngle(Vector3 axis, double angle)
{
double halfAngle = angle * 0.5;
double s = Math.Sin(halfAngle);
double c = Math.Cos(halfAngle);
return new Quaternion(
axis.X * s,
axis.Y * s,
axis.Z * s,
c
);
}
/// <summary>
/// Creates a quaternion from yaw, pitch, and roll angles (in radians)
/// </summary>
public static Quaternion CreateFromYawPitchRoll(double yaw, double pitch, double roll)
{
double halfRoll = roll * 0.5;
double halfPitch = pitch * 0.5;
double halfYaw = yaw * 0.5;
double sinRoll = Math.Sin(halfRoll);
double cosRoll = Math.Cos(halfRoll);
double sinPitch = Math.Sin(halfPitch);
double cosPitch = Math.Cos(halfPitch);
double sinYaw = Math.Sin(halfYaw);
double cosYaw = Math.Cos(halfYaw);
return new Quaternion(
cosYaw * sinPitch * cosRoll + sinYaw * cosPitch * sinRoll,
sinYaw * cosPitch * cosRoll - cosYaw * sinPitch * sinRoll,
cosYaw * cosPitch * sinRoll - sinYaw * sinPitch * cosRoll,
cosYaw * cosPitch * cosRoll + sinYaw * sinPitch * sinRoll
);
}
/// <summary>
/// Creates a quaternion from a rotation matrix
/// </summary>
public static Quaternion CreateFromRotationMatrix(double[,] matrix)
{
if (matrix.GetLength(0) < 3 || matrix.GetLength(1) < 3)
return Identity;
double trace = matrix[0, 0] + matrix[1, 1] + matrix[2, 2];
Quaternion q = default;
if (trace > 0.0)
{
double s = Math.Sqrt(trace + 1.0);
q.W = s * 0.5;
s = 0.5 / s;
q.X = (matrix[2, 1] - matrix[1, 2]) * s;
q.Y = (matrix[0, 2] - matrix[2, 0]) * s;
q.Z = (matrix[1, 0] - matrix[0, 1]) * s;
}
else
{
if (matrix[0, 0] >= matrix[1, 1] && matrix[0, 0] >= matrix[2, 2])
{
double s = Math.Sqrt(1.0 + matrix[0, 0] - matrix[1, 1] - matrix[2, 2]);
double invS = 0.5 / s;
q.X = 0.5 * s;
q.Y = (matrix[1, 0] + matrix[0, 1]) * invS;
q.Z = (matrix[2, 0] + matrix[0, 2]) * invS;
q.W = (matrix[2, 1] - matrix[1, 2]) * invS;
}
else if (matrix[1, 1] > matrix[2, 2])
{
double s = Math.Sqrt(1.0 + matrix[1, 1] - matrix[0, 0] - matrix[2, 2]);
double invS = 0.5 / s;
q.X = (matrix[0, 1] + matrix[1, 0]) * invS;
q.Y = 0.5 * s;
q.Z = (matrix[1, 2] + matrix[2, 1]) * invS;
q.W = (matrix[0, 2] - matrix[2, 0]) * invS;
}
else
{
double s = Math.Sqrt(1.0 + matrix[2, 2] - matrix[0, 0] - matrix[1, 1]);
double invS = 0.5 / s;
q.X = (matrix[0, 2] + matrix[2, 0]) * invS;
q.Y = (matrix[1, 2] + matrix[2, 1]) * invS;
q.Z = 0.5 * s;
q.W = (matrix[1, 0] - matrix[0, 1]) * invS;
}
}
return q;
}
#endregion
#region Operators
/// <summary>
/// Adds two quaternions component-wise (rarely used - prefer multiplication for combining rotations)
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Quaternion operator +(Quaternion value1, Quaternion value2)
{
return new Quaternion(
value1.X + value2.X,
value1.Y + value2.Y,
value1.Z + value2.Z,
value1.W + value2.W
);
}
/// <summary>
/// Subtracts two quaternions component-wise (rarely used)
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Quaternion operator -(Quaternion value1, Quaternion value2)
{
return new Quaternion(
value1.X - value2.X,
value1.Y - value2.Y,
value1.Z - value2.Z,
value1.W - value2.W
);
}
/// <summary>
/// Negates a quaternion
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Quaternion operator -(Quaternion value)
{
return new Quaternion(-value.X, -value.Y, -value.Z, -value.W);
}
/// <summary>
/// Multiplies two quaternions (combines rotations: first apply value2, then value1)
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Quaternion operator *(Quaternion value1, Quaternion value2)
{
double q1x = value1.X;
double q1y = value1.Y;
double q1z = value1.Z;
double q1w = value1.W;
double q2x = value2.X;
double q2y = value2.Y;
double q2z = value2.Z;
double q2w = value2.W;
// Cross product
double cx = q1y * q2z - q1z * q2y;
double cy = q1z * q2x - q1x * q2z;
double cz = q1x * q2y - q1y * q2x;
double dot = q1x * q2x + q1y * q2y + q1z * q2z;
return new Quaternion(
q1x * q2w + q2x * q1w + cx,
q1y * q2w + q2y * q1w + cy,
q1z * q2w + q2z * q1w + cz,
q1w * q2w - dot
);
}
/// <summary>
/// Multiplies a quaternion by a scalar
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Quaternion operator *(Quaternion value1, double value2)
{
return new Quaternion(
value1.X * value2,
value1.Y * value2,
value1.Z * value2,
value1.W * value2
);
}
/// <summary>
/// Divides a quaternion by a scalar
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Quaternion operator /(Quaternion value1, double value2)
{
double invValue = 1.0 / value2;
return new Quaternion(
value1.X * invValue,
value1.Y * invValue,
value1.Z * invValue,
value1.W * invValue
);
}
/// <summary>
/// Checks if two quaternions are equal
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Quaternion value1, Quaternion value2)
{
return value1.X == value2.X &&
value1.Y == value2.Y &&
value1.Z == value2.Z &&
value1.W == value2.W;
}
/// <summary>
/// Checks if two quaternions are not equal
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Quaternion value1, Quaternion value2)
{
return value1.X != value2.X ||
value1.Y != value2.Y ||
value1.Z != value2.Z ||
value1.W != value2.W;
}
/// <summary>
/// Implicit conversion from System.Numerics.Quaternion
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Quaternion(System.Numerics.Quaternion value)
{
return new Quaternion(value.X, value.Y, value.Z, value.W);
}
/// <summary>
/// Implicit conversion to System.Numerics.Quaternion
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator System.Numerics.Quaternion(Quaternion value)
{
return new Quaternion((float)value.X, (float)value.Y, (float)value.Z, (float)value.W);
}
#endregion
#region Equality
/// <summary>
/// Checks if this quaternion equals another quaternion
/// </summary>
public readonly bool Equals(Quaternion other)
{
return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
}
/// <summary>
/// Checks if this quaternion equals an object
/// </summary>
public override readonly bool Equals(object? obj)
{
return obj is Quaternion quaternion && Equals(quaternion);
}
/// <summary>
/// Gets the hash code for this quaternion
/// </summary>
public override readonly int GetHashCode()
{
return HashCode.Combine(X, Y, Z, W);
}
#endregion
#region String
/// <summary>
/// Returns a string representation of this quaternion
/// </summary>
public override readonly string ToString()
{
return $"{{X:{X} Y:{Y} Z:{Z} W:{W}}}";
}
/// <summary>
/// Returns a formatted string representation of this quaternion
/// </summary>
public readonly string ToString(string format)
{
return $"{{X:{X.ToString(format)} Y:{Y.ToString(format)} Z:{Z.ToString(format)} W:{W.ToString(format)}}}";
}
#endregion
}

View File

@@ -0,0 +1,384 @@
using System.Runtime.CompilerServices;
namespace RobotNet10.Shared.Numbers;
/// <summary>
/// Custom 2D vector struct that supports JSON serialization.
/// Replacement for System.Numerics.Vector2 which doesn't serialize properly.
/// </summary>
public struct Vector2 : IEquatable<Vector2>
{
/// <summary>
/// X component
/// </summary>
public double X { get; set; }
/// <summary>
/// Y component
/// </summary>
public double Y { get; set; }
/// <summary>
/// Creates a new Vector2
/// </summary>
public Vector2(double x, double y)
{
X = x;
Y = y;
}
/// <summary>
/// Creates a Vector2 with both components set to the same value
/// </summary>
public Vector2(double value)
{
X = Y = value;
}
#region Static Properties
/// <summary>
/// Returns a Vector2 with both components set to zero
/// </summary>
public static Vector2 Zero => new(0, 0);
/// <summary>
/// Returns a Vector2 with both components set to one
/// </summary>
public static Vector2 One => new(1, 1);
/// <summary>
/// Returns the unit vector for the X axis (1, 0)
/// </summary>
public static Vector2 UnitX => new(1, 0);
/// <summary>
/// Returns the unit vector for the Y axis (0, 1)
/// </summary>
public static Vector2 UnitY => new(0, 1);
#endregion
#region Properties
/// <summary>
/// Returns the length (magnitude) of the vector
/// </summary>
public readonly double Length()
{
return Math.Sqrt(X * X + Y * Y);
}
/// <summary>
/// Returns the squared length of the vector (faster than Length)
/// </summary>
public readonly double LengthSquared()
{
return X * X + Y * Y;
}
#endregion
#region Methods
/// <summary>
/// Returns a normalized copy of this vector (unit length)
/// </summary>
public readonly Vector2 Normalize()
{
double length = Length();
if (length < double.Epsilon)
return Zero;
double invLength = 1.0 / length;
return new Vector2(X * invLength, Y * invLength);
}
/// <summary>
/// Normalizes this vector in place
/// </summary>
public void NormalizeInPlace()
{
double length = Length();
if (length < double.Epsilon)
{
X = Y = 0;
return;
}
double invLength = 1.0 / length;
X *= invLength;
Y *= invLength;
}
#endregion
#region Static Methods
/// <summary>
/// Calculates the dot product of two vectors
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Dot(Vector2 left, Vector2 right)
{
return left.X * right.X + left.Y * right.Y;
}
/// <summary>
/// Returns a normalized copy of a vector (static version)
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Normalize(Vector2 value)
{
return value.Normalize();
}
/// <summary>
/// Returns the distance between two vectors
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Distance(Vector2 value1, Vector2 value2)
{
double dx = value1.X - value2.X;
double dy = value1.Y - value2.Y;
return Math.Sqrt(dx * dx + dy * dy);
}
/// <summary>
/// Returns the squared distance between two vectors (faster than Distance)
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DistanceSquared(Vector2 value1, Vector2 value2)
{
double dx = value1.X - value2.X;
double dy = value1.Y - value2.Y;
return dx * dx + dy * dy;
}
/// <summary>
/// Performs linear interpolation between two vectors
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Lerp(Vector2 value1, Vector2 value2, double amount)
{
return new Vector2(
value1.X + (value2.X - value1.X) * amount,
value1.Y + (value2.Y - value1.Y) * amount
);
}
/// <summary>
/// Returns a vector with the minimum components of two vectors
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Min(Vector2 value1, Vector2 value2)
{
return new Vector2(
Math.Min(value1.X, value2.X),
Math.Min(value1.Y, value2.Y)
);
}
/// <summary>
/// Returns a vector with the maximum components of two vectors
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Max(Vector2 value1, Vector2 value2)
{
return new Vector2(
Math.Max(value1.X, value2.X),
Math.Max(value1.Y, value2.Y)
);
}
/// <summary>
/// Returns a vector whose components are the absolute values of the input vector
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Abs(Vector2 value)
{
return new Vector2(
Math.Abs(value.X),
Math.Abs(value.Y)
);
}
/// <summary>
/// Clamps a vector to the specified minimum and maximum values
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Clamp(Vector2 value, Vector2 min, Vector2 max)
{
return new Vector2(
Math.Clamp(value.X, min.X, max.X),
Math.Clamp(value.Y, min.Y, max.Y)
);
}
/// <summary>
/// Reflects a vector off a surface with the specified normal
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Reflect(Vector2 vector, Vector2 normal)
{
double dot = Dot(vector, normal);
return vector - 2.0 * dot * normal;
}
/// <summary>
/// Transforms a Vector2 by a Matrix3x2
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Transform(Vector2 position, Matrix3x2 matrix)
{
return new Vector2(
position.X * matrix.M11 + position.Y * matrix.M21 + matrix.M31,
position.X * matrix.M12 + position.Y * matrix.M22 + matrix.M32
);
}
#endregion
#region Operators
/// <summary>
/// Adds two vectors
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator +(Vector2 left, Vector2 right)
{
return new Vector2(left.X + right.X, left.Y + right.Y);
}
/// <summary>
/// Subtracts two vectors
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator -(Vector2 left, Vector2 right)
{
return new Vector2(left.X - right.X, left.Y - right.Y);
}
/// <summary>
/// Negates a vector
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator -(Vector2 value)
{
return new Vector2(-value.X, -value.Y);
}
/// <summary>
/// Multiplies two vectors component-wise
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator *(Vector2 left, Vector2 right)
{
return new Vector2(left.X * right.X, left.Y * right.Y);
}
/// <summary>
/// Multiplies a vector by a scalar
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator *(Vector2 left, double right)
{
return new Vector2(left.X * right, left.Y * right);
}
/// <summary>
/// Multiplies a scalar by a vector
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator *(double left, Vector2 right)
{
return new Vector2(left * right.X, left * right.Y);
}
/// <summary>
/// Divides two vectors component-wise
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator /(Vector2 left, Vector2 right)
{
return new Vector2(left.X / right.X, left.Y / right.Y);
}
/// <summary>
/// Divides a vector by a scalar
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator /(Vector2 left, double right)
{
double invRight = 1.0 / right;
return new Vector2(left.X * invRight, left.Y * invRight);
}
/// <summary>
/// Checks if two vectors are equal
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Vector2 left, Vector2 right)
{
return left.X == right.X && left.Y == right.Y;
}
/// <summary>
/// Checks if two vectors are not equal
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Vector2 left, Vector2 right)
{
return left.X != right.X || left.Y != right.Y;
}
#endregion
#region Equality
/// <summary>
/// Checks if this vector equals another vector
/// </summary>
public readonly bool Equals(Vector2 other)
{
return X == other.X && Y == other.Y;
}
/// <summary>
/// Checks if this vector equals an object
/// </summary>
public override readonly bool Equals(object? obj)
{
return obj is Vector2 vector && Equals(vector);
}
/// <summary>
/// Gets the hash code for this vector
/// </summary>
public override readonly int GetHashCode()
{
return HashCode.Combine(X, Y);
}
#endregion
#region String
/// <summary>
/// Returns a string representation of this vector
/// </summary>
public override readonly string ToString()
{
return $"<{X}, {Y}>";
}
/// <summary>
/// Returns a formatted string representation of this vector
/// </summary>
public readonly string ToString(string format)
{
return $"<{X.ToString(format)}, {Y.ToString(format)}>";
}
#endregion
}

View File

@@ -0,0 +1,452 @@
using System.Runtime.CompilerServices;
namespace RobotNet10.Shared.Numbers;
/// <summary>
/// Custom 3D vector struct that supports JSON serialization.
/// Replacement for System.Numerics.Vector3 which doesn't serialize properly.
/// </summary>
public struct Vector3 : IEquatable<Vector3>
{
/// <summary>
/// X component
/// </summary>
public double X { get; set; }
/// <summary>
/// Y component
/// </summary>
public double Y { get; set; }
/// <summary>
/// Z component
/// </summary>
public double Z { get; set; }
/// <summary>
/// Creates a new Vector3
/// </summary>
public Vector3(double x, double y, double z)
{
X = x;
Y = y;
Z = z;
}
/// <summary>
/// Creates a Vector3 with all components set to the same value
/// </summary>
public Vector3(double value)
{
X = Y = Z = value;
}
#region Static Properties
/// <summary>
/// Returns a Vector3 with all components set to zero
/// </summary>
public static Vector3 Zero => new(0, 0, 0);
/// <summary>
/// Returns a Vector3 with all components set to one
/// </summary>
public static Vector3 One => new(1, 1, 1);
/// <summary>
/// Returns the unit vector for the X axis (1, 0, 0)
/// </summary>
public static Vector3 UnitX => new(1, 0, 0);
/// <summary>
/// Returns the unit vector for the Y axis (0, 1, 0)
/// </summary>
public static Vector3 UnitY => new(0, 1, 0);
/// <summary>
/// Returns the unit vector for the Z axis (0, 0, 1)
/// </summary>
public static Vector3 UnitZ => new(0, 0, 1);
#endregion
#region Properties
/// <summary>
/// Returns the length (magnitude) of the vector
/// </summary>
public readonly double Length()
{
return Math.Sqrt(X * X + Y * Y + Z * Z);
}
/// <summary>
/// Returns the squared length of the vector (faster than Length)
/// </summary>
public readonly double LengthSquared()
{
return X * X + Y * Y + Z * Z;
}
#endregion
#region Methods
/// <summary>
/// Returns a normalized copy of this vector (unit length)
/// </summary>
public readonly Vector3 Normalize()
{
double length = Length();
if (length < double.Epsilon)
return Zero;
double invLength = 1.0 / length;
return new Vector3(X * invLength, Y * invLength, Z * invLength);
}
/// <summary>
/// Normalizes this vector in place
/// </summary>
public void NormalizeInPlace()
{
double length = Length();
if (length < double.Epsilon)
{
X = Y = Z = 0;
return;
}
double invLength = 1.0 / length;
X *= invLength;
Y *= invLength;
Z *= invLength;
}
#endregion
#region Static Methods
/// <summary>
/// Calculates the dot product of two vectors
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Dot(Vector3 left, Vector3 right)
{
return left.X * right.X + left.Y * right.Y + left.Z * right.Z;
}
/// <summary>
/// Calculates the cross product of two vectors
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Cross(Vector3 left, Vector3 right)
{
return new Vector3(
left.Y * right.Z - left.Z * right.Y,
left.Z * right.X - left.X * right.Z,
left.X * right.Y - left.Y * right.X
);
}
/// <summary>
/// Returns a normalized copy of a vector (static version)
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Normalize(Vector3 value)
{
return value.Normalize();
}
/// <summary>
/// Returns the distance between two vectors
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Distance(Vector3 value1, Vector3 value2)
{
double dx = value1.X - value2.X;
double dy = value1.Y - value2.Y;
double dz = value1.Z - value2.Z;
return Math.Sqrt(dx * dx + dy * dy + dz * dz);
}
/// <summary>
/// Returns the squared distance between two vectors (faster than Distance)
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DistanceSquared(Vector3 value1, Vector3 value2)
{
double dx = value1.X - value2.X;
double dy = value1.Y - value2.Y;
double dz = value1.Z - value2.Z;
return dx * dx + dy * dy + dz * dz;
}
/// <summary>
/// Performs linear interpolation between two vectors
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Lerp(Vector3 value1, Vector3 value2, double amount)
{
return new Vector3(
value1.X + (value2.X - value1.X) * amount,
value1.Y + (value2.Y - value1.Y) * amount,
value1.Z + (value2.Z - value1.Z) * amount
);
}
/// <summary>
/// Returns a vector with the minimum components of two vectors
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Min(Vector3 value1, Vector3 value2)
{
return new Vector3(
Math.Min(value1.X, value2.X),
Math.Min(value1.Y, value2.Y),
Math.Min(value1.Z, value2.Z)
);
}
/// <summary>
/// Returns a vector with the maximum components of two vectors
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Max(Vector3 value1, Vector3 value2)
{
return new Vector3(
Math.Max(value1.X, value2.X),
Math.Max(value1.Y, value2.Y),
Math.Max(value1.Z, value2.Z)
);
}
/// <summary>
/// Returns a vector whose components are the absolute values of the input vector
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Abs(Vector3 value)
{
return new Vector3(
Math.Abs(value.X),
Math.Abs(value.Y),
Math.Abs(value.Z)
);
}
/// <summary>
/// Clamps a vector to the specified minimum and maximum values
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Clamp(Vector3 value, Vector3 min, Vector3 max)
{
return new Vector3(
Math.Clamp(value.X, min.X, max.X),
Math.Clamp(value.Y, min.Y, max.Y),
Math.Clamp(value.Z, min.Z, max.Z)
);
}
/// <summary>
/// Reflects a vector off a surface with the specified normal
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Reflect(Vector3 vector, Vector3 normal)
{
double dot = Dot(vector, normal);
return vector - 2.0 * dot * normal;
}
/// <summary>
/// Transforms a Vector3 by a Quaternion rotation
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Transform(Vector3 value, Quaternion rotation)
{
// This is the formula: q * v * q^-1 where v is treated as a quaternion with w=0
// Optimized version without creating intermediate quaternions
double x2 = rotation.X + rotation.X;
double y2 = rotation.Y + rotation.Y;
double z2 = rotation.Z + rotation.Z;
double wx2 = rotation.W * x2;
double wy2 = rotation.W * y2;
double wz2 = rotation.W * z2;
double xx2 = rotation.X * x2;
double xy2 = rotation.X * y2;
double xz2 = rotation.X * z2;
double yy2 = rotation.Y * y2;
double yz2 = rotation.Y * z2;
double zz2 = rotation.Z * z2;
return new Vector3(
value.X * (1.0 - yy2 - zz2) + value.Y * (xy2 - wz2) + value.Z * (xz2 + wy2),
value.X * (xy2 + wz2) + value.Y * (1.0 - xx2 - zz2) + value.Z * (yz2 - wx2),
value.X * (xz2 - wy2) + value.Y * (yz2 + wx2) + value.Z * (1.0 - xx2 - yy2)
);
}
#endregion
#region Operators
/// <summary>
/// Adds two vectors
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator +(Vector3 left, Vector3 right)
{
return new Vector3(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
}
/// <summary>
/// Subtracts two vectors
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator -(Vector3 left, Vector3 right)
{
return new Vector3(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
}
/// <summary>
/// Negates a vector
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator -(Vector3 value)
{
return new Vector3(-value.X, -value.Y, -value.Z);
}
/// <summary>
/// Multiplies two vectors component-wise
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator *(Vector3 left, Vector3 right)
{
return new Vector3(left.X * right.X, left.Y * right.Y, left.Z * right.Z);
}
/// <summary>
/// Multiplies a vector by a scalar
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator *(Vector3 left, double right)
{
return new Vector3(left.X * right, left.Y * right, left.Z * right);
}
/// <summary>
/// Multiplies a scalar by a vector
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator *(double left, Vector3 right)
{
return new Vector3(left * right.X, left * right.Y, left * right.Z);
}
/// <summary>
/// Divides two vectors component-wise
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator /(Vector3 left, Vector3 right)
{
return new Vector3(left.X / right.X, left.Y / right.Y, left.Z / right.Z);
}
/// <summary>
/// Divides a vector by a scalar
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator /(Vector3 left, double right)
{
double invRight = 1.0 / right;
return new Vector3(left.X * invRight, left.Y * invRight, left.Z * invRight);
}
/// <summary>
/// Checks if two vectors are equal
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Vector3 left, Vector3 right)
{
return left.X == right.X && left.Y == right.Y && left.Z == right.Z;
}
/// <summary>
/// Checks if two vectors are not equal
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Vector3 left, Vector3 right)
{
return left.X != right.X || left.Y != right.Y || left.Z != right.Z;
}
/// <summary>
/// Implicit conversion from System.Numerics.Vector3
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Vector3(System.Numerics.Vector3 value)
{
return new Vector3(value.X, value.Y, value.Z);
}
/// <summary>
/// Implicit conversion to System.Numerics.Vector3
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator System.Numerics.Vector3(Vector3 value)
{
return new Vector3((float)value.X, (float)value.Y, (float)value.Z);
}
#endregion
#region Equality
/// <summary>
/// Checks if this vector equals another vector
/// </summary>
public readonly bool Equals(Vector3 other)
{
return X == other.X && Y == other.Y && Z == other.Z;
}
/// <summary>
/// Checks if this vector equals an object
/// </summary>
public override readonly bool Equals(object? obj)
{
return obj is Vector3 vector && Equals(vector);
}
/// <summary>
/// Gets the hash code for this vector
/// </summary>
public override readonly int GetHashCode()
{
return HashCode.Combine(X, Y, Z);
}
#endregion
#region String
/// <summary>
/// Returns a string representation of this vector
/// </summary>
public override readonly string ToString()
{
return $"<{X}, {Y}, {Z}>";
}
/// <summary>
/// Returns a formatted string representation of this vector
/// </summary>
public readonly string ToString(string format)
{
return $"<{X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)}>";
}
#endregion
}

View File

@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,3 @@
namespace RobotNet10.Shared;
public record SearchRequest(int Page, int Size, string TxtSearch);

View File

@@ -0,0 +1,4 @@
namespace RobotNet10.Shared;
public record SearchResult<T>(int Total, int Page, int Size, T[] Items);

View File

@@ -0,0 +1,139 @@
namespace RobotNet10.Shared.Sensor;
/// <summary>
/// BatteryState message (sensor_msgs/BatteryState)
/// Describes the state of a battery
/// </summary>
public struct BatteryState
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Voltage in Volts (Mandatory)
/// </summary>
public double Voltage { get; set; }
/// <summary>
/// Current in Amperes (If not available: NaN)
/// </summary>
public double Current { get; set; }
/// <summary>
/// Charge in Ah (If not available: NaN)
/// </summary>
public double Charge { get; set; }
/// <summary>
/// Capacity in Ah (last full capacity) (If not available: NaN)
/// </summary>
public double Capacity { get; set; }
/// <summary>
/// Design capacity in Ah (If not available: NaN)
/// </summary>
public double DesignCapacity { get; set; }
/// <summary>
/// Percentage (0-100) (If not available: NaN)
/// </summary>
public double Percentage { get; set; }
/// <summary>
/// Power supply status constants
/// </summary>
public const byte PowerSupplyStatusUnknown = 0;
public const byte PowerSupplyStatusCharging = 1;
public const byte PowerSupplyStatusDischarging = 2;
public const byte PowerSupplyStatusNotCharging = 3;
public const byte PowerSupplyStatusFull = 4;
/// <summary>
/// Power supply status (PowerSupplyStatus constants)
/// </summary>
public byte PowerSupplyStatus { get; set; }
/// <summary>
/// Power supply health constants
/// </summary>
public const byte PowerSupplyHealthUnknown = 0;
public const byte PowerSupplyHealthGood = 1;
public const byte PowerSupplyHealthOverheat = 2;
public const byte PowerSupplyHealthDead = 3;
public const byte PowerSupplyHealthOvervoltage = 4;
public const byte PowerSupplyHealthUnspecifiedFailure = 5;
public const byte PowerSupplyHealthCold = 6;
/// <summary>
/// Power supply health (PowerSupplyHealth constants)
/// </summary>
public byte PowerSupplyHealth { get; set; }
/// <summary>
/// Power supply technology (chemistry) constants
/// </summary>
public const byte PowerSupplyTechnologyUnknown = 0;
public const byte PowerSupplyTechnologyNiMh = 1;
public const byte PowerSupplyTechnologyLion = 2;
public const byte PowerSupplyTechnologyLipo = 3;
public const byte PowerSupplyTechnologyLife = 4;
public const byte PowerSupplyTechnologyNiCd = 5;
public const byte PowerSupplyTechnologyLiMn = 6;
/// <summary>
/// Power supply technology (PowerSupplyTechnology constants)
/// </summary>
public byte PowerSupplyTechnology { get; set; }
/// <summary>
/// True if the battery is present
/// </summary>
public bool Present { get; set; }
/// <summary>
/// An array of individual cell voltages. Each individual cell voltage should be > 0.0.
/// If not available: empty array
/// </summary>
public double[] CellVoltage { get; set; }
/// <summary>
/// An array of individual cell temperatures. Each individual cell temperature should be > 0.0.
/// If not available: empty array
/// </summary>
public double[] CellTemperature { get; set; }
/// <summary>
/// The location into which the battery is inserted. (slot number or plug)
/// </summary>
public string Location { get; set; }
/// <summary>
/// The serial number of the battery pack.
/// </summary>
public string SerialNumber { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public BatteryState()
{
Header = new Header();
Voltage = 0.0;
Current = double.NaN;
Charge = double.NaN;
Capacity = double.NaN;
DesignCapacity = double.NaN;
Percentage = double.NaN;
PowerSupplyStatus = PowerSupplyStatusUnknown;
PowerSupplyHealth = PowerSupplyHealthUnknown;
PowerSupplyTechnology = PowerSupplyTechnologyUnknown;
Present = false;
CellVoltage = [];
CellTemperature = [];
Location = string.Empty;
SerialNumber = string.Empty;
}
}

View File

@@ -0,0 +1,153 @@
namespace RobotNet10.Shared.Sensor;
/// <summary>
/// CameraInfo message (sensor_msgs/CameraInfo)
/// This message defines meta information for a camera
/// </summary>
public struct CameraInfo
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Image height (rows)
/// </summary>
public uint Height { get; set; }
/// <summary>
/// Image width (columns)
/// </summary>
public uint Width { get; set; }
/// <summary>
/// Distortion model constants
/// </summary>
public const string DistortionModelPlumbBob = "plumb_bob";
public const string DistortionModelRationalPolynomial = "rational_polynomial";
/// <summary>
/// The distortion model used
/// </summary>
public string DistortionModel { get; set; }
/// <summary>
/// Intrinsic camera matrix for the raw (distorted) images.
/// [fx 0 cx]
/// K = [ 0 fy cy]
/// [ 0 0 1]
/// Projects 3D points in the camera coordinate frame to 2D pixel
/// coordinates using the focal lengths (fx, fy) and principal point
/// (cx, cy).
/// </summary>
public double[] K { get; set; }
/// <summary>
/// Size of intrinsic camera matrix (3x3 = 9 elements)
/// </summary>
public const int KSize = 9;
/// <summary>
/// Rectification matrix (stereo cameras only)
/// A rotation matrix aligning the camera coordinate system to the ideal
/// stereo image plane so that epipolar lines in both stereo images are
/// parallel.
/// </summary>
public double[] R { get; set; }
/// <summary>
/// Size of rectification matrix (3x3 = 9 elements)
/// </summary>
public const int RSize = 9;
/// <summary>
/// Projection/camera matrix
/// [fx' 0 cx' Tx]
/// P = [ 0 fy' cy' Ty]
/// [ 0 0 1 0]
/// By convention, this matrix specifies the intrinsic (camera) matrix
/// of the processed (rectified) image. That is, the left 3x3 portion
/// is the normal camera intrinsic matrix for the rectified image.
/// </summary>
public double[] P { get; set; }
/// <summary>
/// Size of projection matrix (3x4 = 12 elements)
/// </summary>
public const int PSize = 12;
/// <summary>
/// The distortion parameters, size depending on the distortion model.
/// For "plumb_bob", the 5 parameters are: (k1, k2, t1, t2, k3).
/// </summary>
public double[] D { get; set; }
/// <summary>
/// Region of interest (subwindow of full camera resolution)
/// </summary>
public RegionOfInterest Roi { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public CameraInfo()
{
Header = new Header();
Height = 0;
Width = 0;
DistortionModel = DistortionModelPlumbBob;
K = new double[KSize];
R = new double[RSize];
P = new double[PSize];
D = [];
Roi = new RegionOfInterest();
}
}
/// <summary>
/// RegionOfInterest message (sensor_msgs/RegionOfInterest)
/// This message is used to specify a region of interest within an image
/// </summary>
public struct RegionOfInterest
{
/// <summary>
/// Leftmost pixel of the ROI
/// </summary>
public uint XOffset { get; set; }
/// <summary>
/// Topmost pixel of the ROI
/// </summary>
public uint YOffset { get; set; }
/// <summary>
/// Height of ROI
/// </summary>
public uint Height { get; set; }
/// <summary>
/// Width of ROI
/// </summary>
public uint Width { get; set; }
/// <summary>
/// True if a distinct rectified ROI should be calculated from the "raw"
/// ROI in this message. Typically this should be False on the "raw" image
/// and True on the "rectified" image.
/// </summary>
public bool DoRectify { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public RegionOfInterest()
{
XOffset = 0;
YOffset = 0;
Height = 0;
Width = 0;
DoRectify = false;
}
}

View File

@@ -0,0 +1,35 @@
namespace RobotNet10.Shared.Sensor;
/// <summary>
/// CompressedImage message (sensor_msgs/CompressedImage)
/// This message contains a compressed image
/// </summary>
public struct CompressedImage
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Specifies the format of the data
/// Acceptable values: jpeg, png, tiff
/// </summary>
public string Format { get; set; }
/// <summary>
/// Compressed image buffer
/// </summary>
public byte[] Data { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public CompressedImage()
{
Header = new Header();
Format = string.Empty;
Data = Array.Empty<byte>();
}
}

View File

@@ -0,0 +1,34 @@
namespace RobotNet10.Shared.Sensor;
/// <summary>
/// FluidPressure message (sensor_msgs/FluidPressure)
/// Single pressure reading
/// </summary>
public struct FluidPressure
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Absolute pressure reading in Pascals
/// </summary>
public double FluidPressureValue { get; set; }
/// <summary>
/// Variance of the pressure reading
/// </summary>
public double Variance { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public FluidPressure()
{
Header = new Header();
FluidPressureValue = 0.0;
Variance = 0.0;
}
}

View File

@@ -0,0 +1,34 @@
namespace RobotNet10.Shared.Sensor;
/// <summary>
/// Illuminance message (sensor_msgs/Illuminance)
/// Single photometric illuminance measurement
/// </summary>
public struct Illuminance
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Illuminance reading in Lux
/// </summary>
public double IlluminanceValue { get; set; }
/// <summary>
/// Variance of the illuminance reading
/// </summary>
public double Variance { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public Illuminance()
{
Header = new Header();
IlluminanceValue = 0.0;
Variance = 0.0;
}
}

View File

@@ -0,0 +1,58 @@
namespace RobotNet10.Shared.Sensor;
/// <summary>
/// Image message (sensor_msgs/Image)
/// This message contains an uncompressed image
/// </summary>
public struct Image
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Image height (rows)
/// </summary>
public uint Height { get; set; }
/// <summary>
/// Image width (columns)
/// </summary>
public uint Width { get; set; }
/// <summary>
/// Encoding of pixels -- channel meaning, ordering, size
/// </summary>
public string Encoding { get; set; }
/// <summary>
/// Is this data bigendian?
/// </summary>
public byte IsBigendian { get; set; }
/// <summary>
/// Full row length in bytes
/// </summary>
public uint Step { get; set; }
/// <summary>
/// Actual matrix data, size is (step * rows)
/// </summary>
public byte[] Data { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public Image()
{
Header = new Header();
Height = 0;
Width = 0;
Encoding = string.Empty;
IsBigendian = 0;
Step = 0;
Data = [];
}
}

View File

@@ -0,0 +1,128 @@
using RobotNet10.Shared.Geometry;
namespace RobotNet10.Shared.Sensor;
/// <summary>
/// Imu message (sensor_msgs/Imu)
/// Contains data from an IMU (Inertial Measurement Unit)
///
/// Accelerations should be in m/s^2 (not g's), and rotational velocity should be in rad/sec
///
/// If the covariance of the measurement is known, it should be filled in (if all you know is the
/// variance of each measurement, e.g. from the datasheet, just put those along the diagonal)
/// A covariance matrix of all zeros will be interpreted as "covariance unknown", and to use the
/// data a covariance will have to be assumed or gotten from some other source
///
/// If you have no estimate for one of the data elements (e.g. your IMU doesn't produce an orientation
/// estimate), please set element 0 of the associated covariance matrix to -1
/// If you are interpreting this message, please check for a value of -1 in the first element of each
/// covariance matrix, and ignore the associated estimate.
/// </summary>
public struct Imu
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Orientation quaternion (geometry_msgs/Quaternion)
/// </summary>
public Quaternion Orientation { get; set; }
/// <summary>
/// Orientation covariance matrix (row-major about x, y, z axes)
/// Size: 9 (3x3 matrix)
/// </summary>
public double[] OrientationCovariance { get; set; }
/// <summary>
/// Size of orientation covariance matrix (3x3 = 9 elements)
/// </summary>
public const int OrientationCovarianceSize = 9;
/// <summary>
/// Angular velocity (geometry_msgs/Vector3)
/// </summary>
public Vector3 AngularVelocity { get; set; }
/// <summary>
/// Angular velocity covariance matrix (row-major about x, y, z axes)
/// Size: 9 (3x3 matrix)
/// </summary>
public double[] AngularVelocityCovariance { get; set; }
/// <summary>
/// Size of angular velocity covariance matrix (3x3 = 9 elements)
/// </summary>
public const int AngularVelocityCovarianceSize = 9;
/// <summary>
/// Linear acceleration (geometry_msgs/Vector3)
/// </summary>
public Vector3 LinearAcceleration { get; set; }
/// <summary>
/// Linear acceleration covariance matrix (row-major about x, y, z axes)
/// Size: 9 (3x3 matrix)
/// </summary>
public double[] LinearAccelerationCovariance { get; set; }
/// <summary>
/// Size of linear acceleration covariance matrix (3x3 = 9 elements)
/// </summary>
public const int LinearAccelerationCovarianceSize = 9;
/// <summary>
/// Default constructor
/// </summary>
public Imu()
{
Header = new Header();
Orientation = new Quaternion();
OrientationCovariance = new double[OrientationCovarianceSize];
AngularVelocity = new Vector3();
AngularVelocityCovariance = new double[AngularVelocityCovarianceSize];
LinearAcceleration = new Vector3();
LinearAccelerationCovariance = new double[LinearAccelerationCovarianceSize];
}
/// <summary>
/// Constructor with parameters
/// </summary>
public Imu(
Header header,
Quaternion orientation,
double[] orientationCovariance,
Vector3 angularVelocity,
double[] angularVelocityCovariance,
Vector3 linearAcceleration,
double[] linearAccelerationCovariance)
{
Header = header;
Orientation = orientation;
if (orientationCovariance == null || orientationCovariance.Length != OrientationCovarianceSize)
{
throw new ArgumentException($"Orientation covariance array must have {OrientationCovarianceSize} elements", nameof(orientationCovariance));
}
OrientationCovariance = orientationCovariance;
AngularVelocity = angularVelocity;
if (angularVelocityCovariance == null || angularVelocityCovariance.Length != AngularVelocityCovarianceSize)
{
throw new ArgumentException($"Angular velocity covariance array must have {AngularVelocityCovarianceSize} elements", nameof(angularVelocityCovariance));
}
AngularVelocityCovariance = angularVelocityCovariance;
LinearAcceleration = linearAcceleration;
if (linearAccelerationCovariance == null || linearAccelerationCovariance.Length != LinearAccelerationCovarianceSize)
{
throw new ArgumentException($"Linear acceleration covariance array must have {LinearAccelerationCovarianceSize} elements", nameof(linearAccelerationCovariance));
}
LinearAccelerationCovariance = linearAccelerationCovariance;
}
}

View File

@@ -0,0 +1,46 @@
namespace RobotNet10.Shared.Sensor;
/// <summary>
/// JointState message (sensor_msgs/JointState)
/// This message holds data to describe the state of a set of torque controlled joints
/// </summary>
public struct JointState
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// The joint names
/// </summary>
public string[] Name { get; set; }
/// <summary>
/// The joint positions (rad)
/// </summary>
public double[] Position { get; set; }
/// <summary>
/// The joint velocities (rad/s)
/// </summary>
public double[] Velocity { get; set; }
/// <summary>
/// The joint efforts (Nm)
/// </summary>
public double[] Effort { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public JointState()
{
Header = new Header();
Name = Array.Empty<string>();
Position = Array.Empty<double>();
Velocity = Array.Empty<double>();
Effort = Array.Empty<double>();
}
}

View File

@@ -0,0 +1,95 @@
namespace RobotNet10.Shared.Sensor;
/// <summary>
/// Joy message (sensor_msgs/Joy)
/// Reports the state of a joystick's axes and buttons
/// </summary>
public struct Joy
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// The axes measurements from a joystick
/// </summary>
public double[] Axes { get; set; }
/// <summary>
/// The buttons measurements from a joystick
/// </summary>
public int[] Buttons { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public Joy()
{
Header = new Header();
Axes = [];
Buttons = [];
}
}
/// <summary>
/// JoyFeedback message (sensor_msgs/JoyFeedback)
/// Reports the state of a joystick's axes and buttons
/// </summary>
public struct JoyFeedback
{
/// <summary>
/// Type constants
/// </summary>
public const byte TypeLed = 0;
public const byte TypeRumble = 1;
public const byte TypeBuzzer = 2;
/// <summary>
/// Type of feedback (Type constants)
/// </summary>
public byte Type { get; set; }
/// <summary>
/// This will hold an id number for each type of each feedback.
/// Example, the first led would be id=0, the second would be id=1
/// </summary>
public byte Id { get; set; }
/// <summary>
/// Intensity of the feedback, from 0.0 to 1.0, inclusive. If device is
/// actually binary, driver should treat 0<=x<0.5 as off, 0.5<=x<=1.0 as on.
/// </summary>
public double Intensity { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public JoyFeedback()
{
Type = TypeLed;
Id = 0;
Intensity = 0.0;
}
}
/// <summary>
/// JoyFeedbackArray message (sensor_msgs/JoyFeedbackArray)
/// Array of JoyFeedback
/// </summary>
public struct JoyFeedbackArray
{
/// <summary>
/// Array of feedback
/// </summary>
public JoyFeedback[] Array { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public JoyFeedbackArray()
{
Array = System.Array.Empty<JoyFeedback>();
}
}

View File

@@ -0,0 +1,80 @@
namespace RobotNet10.Shared.Sensor;
/// <summary>
/// LaserScan message (sensor_msgs/LaserScan)
/// Single scan from a planar laser range-finder
/// </summary>
public struct LaserScan
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Start angle of the scan (rad)
/// </summary>
public double AngleMin { get; set; }
/// <summary>
/// End angle of the scan (rad)
/// </summary>
public double AngleMax { get; set; }
/// <summary>
/// Angular distance between measurements (rad)
/// </summary>
public double AngleIncrement { get; set; }
/// <summary>
/// Time between measurements (seconds) - if your scanner
/// is moving, this will be used in interpolating position
/// of 3d points
/// </summary>
public double TimeIncrement { get; set; }
/// <summary>
/// Time between scans (seconds)
/// </summary>
public double ScanTime { get; set; }
/// <summary>
/// Minimum range value (m)
/// </summary>
public double RangeMin { get; set; }
/// <summary>
/// Maximum range value (m)
/// </summary>
public double RangeMax { get; set; }
/// <summary>
/// Range data (m)
/// (Note: values < range_min or > range_max should be discarded)
/// </summary>
public double[] Ranges { get; set; }
/// <summary>
/// Intensity data (device-specific units)
/// If your device does not provide intensities, please leave the array empty
/// </summary>
public double[] Intensities { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public LaserScan()
{
Header = new Header();
AngleMin = 0.0;
AngleMax = 0.0;
AngleIncrement = 0.0;
TimeIncrement = 0.0;
ScanTime = 0.0;
RangeMin = 0.0;
RangeMax = 0.0;
Ranges = [];
Intensities = [];
}
}

View File

@@ -0,0 +1,58 @@
using RobotNet10.Shared.Geometry;
using RobotNet10.Shared.Numbers;
namespace RobotNet10.Shared.Sensor;
/// <summary>
/// MagneticField message (sensor_msgs/MagneticField)
/// Measurement of the Magnetic Field vector at a specific location
/// </summary>
public struct MagneticField
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Magnetic field vector in Tesla
/// </summary>
public RobotNet10.Shared.Numbers.Vector3 MagneticFieldVector { get; set; }
/// <summary>
/// Covariance matrix (row-major about x, y, z axes)
/// Size: 9 (3x3 matrix)
/// </summary>
public double[] MagneticFieldCovariance { get; set; }
/// <summary>
/// Size of magnetic field covariance matrix (3x3 = 9 elements)
/// </summary>
public const int MagneticFieldCovarianceSize = 9;
/// <summary>
/// Default constructor
/// </summary>
public MagneticField()
{
Header = new Header();
MagneticFieldVector = new RobotNet10.Shared.Numbers.Vector3();
MagneticFieldCovariance = new double[MagneticFieldCovarianceSize];
}
/// <summary>
/// Constructor with parameters
/// </summary>
public MagneticField(Header header, RobotNet10.Shared.Numbers.Vector3 magneticFieldVector, double[] magneticFieldCovariance)
{
Header = header;
MagneticFieldVector = magneticFieldVector;
if (magneticFieldCovariance == null || magneticFieldCovariance.Length != MagneticFieldCovarianceSize)
{
throw new ArgumentException($"Magnetic field covariance array must have {MagneticFieldCovarianceSize} elements", nameof(magneticFieldCovariance));
}
MagneticFieldCovariance = magneticFieldCovariance;
}
}

View File

@@ -0,0 +1,136 @@
namespace RobotNet10.Shared.Sensor;
/// <summary>
/// NavSatFix message (sensor_msgs/NavSatFix)
/// Navigation Satellite fix for any Global Navigation Satellite System
/// </summary>
public struct NavSatFix
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Navigation Satellite fix status constants
/// </summary>
public const short StatusNoFix = -1;
public const short StatusFix = 0;
public const short StatusSbasFix = 1;
public const short StatusGbasFix = 2;
/// <summary>
/// Navigation Satellite fix status (Status constants)
/// </summary>
public short Status { get; set; }
/// <summary>
/// Service constants
/// </summary>
public const ushort ServiceGps = 1;
public const ushort ServiceGlonass = 2;
public const ushort ServiceCompass = 4;
public const ushort ServiceGalileo = 8;
/// <summary>
/// Service which is being used (Service constants)
/// </summary>
public ushort Service { get; set; }
/// <summary>
/// Latitude in degrees
/// </summary>
public double Latitude { get; set; }
/// <summary>
/// Longitude in degrees
/// </summary>
public double Longitude { get; set; }
/// <summary>
/// Altitude in meters
/// </summary>
public double Altitude { get; set; }
/// <summary>
/// Position covariance matrix (row-major about x, y, z axes)
/// Size: 9 (3x3 matrix)
/// </summary>
public double[] PositionCovariance { get; set; }
/// <summary>
/// Size of position covariance matrix (3x3 = 9 elements)
/// </summary>
public const int PositionCovarianceSize = 9;
/// <summary>
/// Position covariance type constants
/// </summary>
public const byte CovarianceTypeUnknown = 0;
public const byte CovarianceTypeApproximated = 1;
public const byte CovarianceTypeDiagonalKnown = 2;
public const byte CovarianceTypeKnown = 3;
/// <summary>
/// Position covariance type (CovarianceType constants)
/// </summary>
public byte PositionCovarianceType { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public NavSatFix()
{
Header = new Header();
Status = StatusNoFix;
Service = 0;
Latitude = 0.0;
Longitude = 0.0;
Altitude = 0.0;
PositionCovariance = new double[PositionCovarianceSize];
PositionCovarianceType = CovarianceTypeUnknown;
}
}
/// <summary>
/// NavSatStatus message (sensor_msgs/NavSatStatus)
/// Navigation Satellite fix status for any Global Navigation Satellite System
/// </summary>
public struct NavSatStatus
{
/// <summary>
/// Status constants
/// </summary>
public const sbyte StatusNoFix = -1;
public const sbyte StatusFix = 0;
public const sbyte StatusSbasFix = 1;
public const sbyte StatusGbasFix = 2;
/// <summary>
/// Status (Status constants)
/// </summary>
public sbyte Status { get; set; }
/// <summary>
/// Service constants
/// </summary>
public const ushort ServiceGps = 1;
public const ushort ServiceGlonass = 2;
public const ushort ServiceCompass = 4;
public const ushort ServiceGalileo = 8;
/// <summary>
/// Service which is being used (Service constants)
/// </summary>
public ushort Service { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public NavSatStatus()
{
Status = StatusNoFix;
Service = 0;
}
}

View File

@@ -0,0 +1,56 @@
using RobotNet10.Shared;
using RobotNet10.Shared.Geometry;
namespace RobotNet10.Shared.Sensor;
/// <summary>
/// Odometry message (nav_msgs/Odometry)
/// This represents an estimate of a position and velocity in free space.
/// The pose in this message should be specified in the coordinate frame given by header.frame_id.
/// The twist in this message should be specified in the coordinate frame given by the child_frame_id.
/// </summary>
public struct Odometry
{
/// <summary>
/// Header with timestamp and frame ID (parent frame, typically "odom")
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Child frame ID (typically "base_link" or "base_footprint")
/// </summary>
public string ChildFrameId { get; set; }
/// <summary>
/// Pose with covariance (PoseWithCovariance)
/// </summary>
public PoseWithCovariance Pose { get; set; }
/// <summary>
/// Twist with covariance (TwistWithCovariance)
/// </summary>
public TwistWithCovariance Twist { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public Odometry()
{
Header = new Header();
ChildFrameId = string.Empty;
Pose = new PoseWithCovariance();
Twist = new TwistWithCovariance();
}
/// <summary>
/// Constructor with parameters
/// </summary>
public Odometry(Header header, string childFrameId, PoseWithCovariance pose, TwistWithCovariance twist)
{
Header = header;
ChildFrameId = childFrameId;
Pose = pose;
Twist = twist;
}
}

View File

@@ -0,0 +1,132 @@
namespace RobotNet10.Shared.Sensor;
/// <summary>
/// PointCloud2 message (sensor_msgs/PointCloud2)
/// This message holds a collection of N-dimensional points, which may
/// contain additional information such as normals, intensity, etc. The
/// point data is stored as a binary blob, its layout described by the
/// contents of the "fields" array.
/// </summary>
public struct PointCloud2
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Height of the cloud
/// </summary>
public uint Height { get; set; }
/// <summary>
/// Width of the cloud
/// </summary>
public uint Width { get; set; }
/// <summary>
/// Describes the channels and their layout in the binary data blob
/// </summary>
public PointField[] Fields { get; set; }
/// <summary>
/// Is this data bigendian?
/// </summary>
public bool IsBigendian { get; set; }
/// <summary>
/// Length of a point in bytes
/// </summary>
public uint PointStep { get; set; }
/// <summary>
/// Length of a row in bytes
/// </summary>
public uint RowStep { get; set; }
/// <summary>
/// Actual point data, size is (row_step*height)
/// </summary>
public byte[] Data { get; set; }
/// <summary>
/// True if there are no invalid points
/// </summary>
public bool IsDense { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public PointCloud2()
{
Header = new Header();
Height = 0;
Width = 0;
Fields = Array.Empty<PointField>();
IsBigendian = false;
PointStep = 0;
RowStep = 0;
Data = Array.Empty<byte>();
IsDense = false;
}
}
/// <summary>
/// PointField message (sensor_msgs/PointField)
/// This message holds the description of one point entry in the PointCloud2 message format
/// </summary>
public struct PointField
{
/// <summary>
/// Point field name constants
/// </summary>
public const string NameX = "x";
public const string NameY = "y";
public const string NameZ = "z";
public const string NameRgb = "rgb";
public const string NameIntensity = "intensity";
/// <summary>
/// Name of field
/// </summary>
public string Name { get; set; }
/// <summary>
/// Offset from start of point struct
/// </summary>
public uint Offset { get; set; }
/// <summary>
/// Datatype enumeration constants
/// </summary>
public const byte Int8 = 1;
public const byte Uint8 = 2;
public const byte Int16 = 3;
public const byte Uint16 = 4;
public const byte Int32 = 5;
public const byte Uint32 = 6;
public const byte Float32 = 7;
public const byte Float64 = 8;
/// <summary>
/// Datatype enumeration (Datatype constants)
/// </summary>
public byte Datatype { get; set; }
/// <summary>
/// How many elements in field
/// </summary>
public uint Count { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public PointField()
{
Name = string.Empty;
Offset = 0;
Datatype = 0;
Count = 0;
}
}

View File

@@ -0,0 +1,60 @@
namespace RobotNet10.Shared.Sensor;
/// <summary>
/// Range message (sensor_msgs/Range)
/// Single range reading from an active ranger that emits energy and reports
/// one range reading that is valid along an arc at the distance measured.
/// </summary>
public struct Range
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Radiation type constants
/// </summary>
public const byte RadiationTypeUltrasound = 0;
public const byte RadiationTypeInfrared = 1;
/// <summary>
/// The type of radiation used by the sensor (RadiationType constants)
/// </summary>
public byte RadiationType { get; set; }
/// <summary>
/// The size of the arc that the distance reading is valid for (rad)
/// </summary>
public double FieldOfView { get; set; }
/// <summary>
/// Minimum range value (m)
/// </summary>
public double MinRange { get; set; }
/// <summary>
/// Maximum range value (m)
/// </summary>
public double MaxRange { get; set; }
/// <summary>
/// Range data (m)
/// (Note: values < range_min or > range_max should be discarded)
/// </summary>
public double RangeValue { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public Range()
{
Header = new Header();
RadiationType = RadiationTypeUltrasound;
FieldOfView = 0.0;
MinRange = 0.0;
MaxRange = 0.0;
RangeValue = 0.0;
}
}

View File

@@ -0,0 +1,34 @@
namespace RobotNet10.Shared.Sensor;
/// <summary>
/// RelativeHumidity message (sensor_msgs/RelativeHumidity)
/// Single reading from a relative humidity sensor
/// </summary>
public struct RelativeHumidity
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Relative humidity reading (0-1)
/// </summary>
public double RelativeHumidityValue { get; set; }
/// <summary>
/// Variance of the relative humidity reading
/// </summary>
public double Variance { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public RelativeHumidity()
{
Header = new Header();
RelativeHumidityValue = 0.0;
Variance = 0.0;
}
}

View File

@@ -0,0 +1,34 @@
namespace RobotNet10.Shared.Sensor;
/// <summary>
/// Temperature message (sensor_msgs/Temperature)
/// Single temperature reading
/// </summary>
public struct Temperature
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Temperature reading in Celsius
/// </summary>
public double TemperatureValue { get; set; }
/// <summary>
/// Variance of the temperature reading
/// </summary>
public double Variance { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public Temperature()
{
Header = new Header();
TemperatureValue = 0.0;
Variance = 0.0;
}
}

View File

@@ -0,0 +1,34 @@
namespace RobotNet10.Shared.Sensor;
/// <summary>
/// TimeReference message (sensor_msgs/TimeReference)
/// Measurement from an external time source not actively synchronized with the system clock
/// </summary>
public struct TimeReference
{
/// <summary>
/// Header with timestamp and frame ID
/// </summary>
public Header Header { get; set; }
/// <summary>
/// Measurement from an external time source not actively synchronized with the system clock
/// </summary>
public DateTime TimeRef { get; set; }
/// <summary>
/// The source of the time reference
/// </summary>
public string Source { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public TimeReference()
{
Header = new Header();
TimeRef = DateTime.MinValue;
Source = string.Empty;
}
}