Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Person sensor #10

Merged
merged 5 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions Source/CompositeDevices.sln
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Relays.ElectromagneticRelay
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectronmagneticRelayModule_Sample", "Relays.ElectromagneticRelayModule\Samples\ElectronmagneticRelayModule_Sample\ElectronmagneticRelayModule_Sample.csproj", "{815E8496-8359-4D35-83EB-A1120D3AA404}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sensors", "Sensors", "{78203E26-CBDE-48BC-B8CF-617F8A863D65}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Motion", "Motion", "{7A284A89-FBA4-4E57-9357-B0F3AE9AE429}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UsefulSensors", "UsefulSensors", "{B9A8627E-0A83-4FEB-B3CF-7772109C3F44}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PersonSensor", "PersonSensor", "{4A6B7EF6-7730-4570-A72F-6E4506227668}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sensors.Motion.UsefulSensors.PersonSensor", "Sensors.Motion.UsefulSensors.PersonSensor\Driver\Sensors.Motion.UsefulSensors.PersonSensor.csproj", "{773E12FF-A4F0-4835-9BAA-34454DB42E6B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sample", "Sample", "{1B4743D8-E3B7-4466-9A66-266B91AB3676}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PersonSensor_Sample", "Sensors.Motion.UsefulSensors.PersonSensor\Samples\PersonSensor_Sample\PersonSensor_Sample.csproj", "{6046728F-EFF4-4B77-8C15-7CB87B145395}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -93,6 +107,18 @@ Global
{815E8496-8359-4D35-83EB-A1120D3AA404}.Release|Any CPU.ActiveCfg = Release|Any CPU
{815E8496-8359-4D35-83EB-A1120D3AA404}.Release|Any CPU.Build.0 = Release|Any CPU
{815E8496-8359-4D35-83EB-A1120D3AA404}.Release|Any CPU.Deploy.0 = Release|Any CPU
{773E12FF-A4F0-4835-9BAA-34454DB42E6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{773E12FF-A4F0-4835-9BAA-34454DB42E6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{773E12FF-A4F0-4835-9BAA-34454DB42E6B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{773E12FF-A4F0-4835-9BAA-34454DB42E6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{773E12FF-A4F0-4835-9BAA-34454DB42E6B}.Release|Any CPU.Build.0 = Release|Any CPU
{773E12FF-A4F0-4835-9BAA-34454DB42E6B}.Release|Any CPU.Deploy.0 = Release|Any CPU
{6046728F-EFF4-4B77-8C15-7CB87B145395}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6046728F-EFF4-4B77-8C15-7CB87B145395}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6046728F-EFF4-4B77-8C15-7CB87B145395}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{6046728F-EFF4-4B77-8C15-7CB87B145395}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6046728F-EFF4-4B77-8C15-7CB87B145395}.Release|Any CPU.Build.0 = Release|Any CPU
{6046728F-EFF4-4B77-8C15-7CB87B145395}.Release|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -110,6 +136,12 @@ Global
{BC092D17-F8D5-4BEA-ABE4-E98B44A04DA6} = {AE474B14-7388-421B-BB92-8700CD54BC57}
{29CF3228-7907-4FD6-88E3-DB91023B6281} = {AE474B14-7388-421B-BB92-8700CD54BC57}
{815E8496-8359-4D35-83EB-A1120D3AA404} = {BC092D17-F8D5-4BEA-ABE4-E98B44A04DA6}
{7A284A89-FBA4-4E57-9357-B0F3AE9AE429} = {78203E26-CBDE-48BC-B8CF-617F8A863D65}
{B9A8627E-0A83-4FEB-B3CF-7772109C3F44} = {7A284A89-FBA4-4E57-9357-B0F3AE9AE429}
{4A6B7EF6-7730-4570-A72F-6E4506227668} = {B9A8627E-0A83-4FEB-B3CF-7772109C3F44}
{773E12FF-A4F0-4835-9BAA-34454DB42E6B} = {4A6B7EF6-7730-4570-A72F-6E4506227668}
{1B4743D8-E3B7-4466-9A66-266B91AB3676} = {4A6B7EF6-7730-4570-A72F-6E4506227668}
{6046728F-EFF4-4B77-8C15-7CB87B145395} = {1B4743D8-E3B7-4466-9A66-266B91AB3676}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BF2FC8CE-57C6-468C-B82D-D8204E6D9360}
Expand Down
411 changes: 411 additions & 0 deletions Source/Sensors.Motion.UsefulSensors.PersonSensor/Datasheet/Readme.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
namespace Meadow.Foundation.Sensors;

public partial class PersonSensor
{
/// <summary>
/// Represents information about a detected face.
/// </summary>
public struct PersonFace
{
/// <summary>
/// Confidence level for the detected face.
/// </summary>
public byte BoxConfidence { get; set; }

/// <summary>
/// X coordinate of the left side of the detected face.
/// </summary>
public byte BoxLeft { get; set; }

/// <summary>
/// Y coordinate of the top edge of the detected face.
/// </summary>
public byte BoxTop { get; set; }

/// <summary>
/// X coordinate of the right side of the detected face.
/// </summary>
public byte BoxRight { get; set; }

/// <summary>
/// Y coordinate of the bottom edge of the detected face.
/// </summary>
public byte BoxBottom { get; set; }

/// <summary>
/// Confidence level for the assigned ID of the detected face.
/// </summary>
public sbyte IdConfidence { get; set; }

/// <summary>
/// Numerical ID assigned to the detected face.
/// </summary>
public sbyte Id { get; set; }

/// <summary>
/// Indicates whether the person is facing the camera (1) or not (0).
/// </summary>
public byte IsFacing { get; set; }
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
using Meadow.Hardware;
using System;
using System.Linq;

namespace Meadow.Foundation.Sensors;

/// <summary>
/// Represents a Useful Sensor's Person Sensor
/// </summary>
public partial class PersonSensor : II2cPeripheral
{
/// <inheritdoc/>
public byte DefaultI2cAddress => 0x62;

/// <summary>
/// The maximun number of faces the sensor can recognize
/// </summary>
public int MAX_FACE_COUNT => 4;

/// <summary>
/// The max number of specific face IDs the sensor can track
/// </summary>
public int MAX_IDS_COUNT => 7;

private readonly int HEADER_LENGTH = 4;
private readonly int DATA_LENGTH = 40;
private readonly byte[] readBuffer;
private readonly II2cCommunications i2cComms;


/// <summary>
/// Initializes a new instance of the ElectroMagneticRelayModule device
/// </summary>
/// <param name="i2cBus">The I2C bus the peripheral is connected to</param>
/// <param name="address">The bus address of the peripheral</param>
public PersonSensor(II2cBus i2cBus, byte address = 0x62)
{
i2cComms = new I2cCommunications(i2cBus, address, DATA_LENGTH);
readBuffer = new byte[DATA_LENGTH];
}

/// <summary>
/// Sets the capture mode of the sensor
/// </summary>
/// <param name="enable">Continuous if true</param>
public void SetContinuousMode(bool enable)
{
i2cComms.WriteRegister((byte)Commands.MODE, (byte)(enable ? 0x0 : 0x1));
}

/// <summary>
/// Sets the Person Sensor to single-shot mode for inference.
/// </summary>
public void SetSingleShotMode()
{
i2cComms.WriteRegister((byte)Commands.SINGLE_SHOT, 0x1);
}

/// <summary>
/// Sets the debug mode for the Person Sensor.
/// </summary>
/// <param name="enable">True to enable debug mode, False to disable.</param>
public void SetDebugMode(bool enable)
{
i2cComms.WriteRegister((byte)Commands.DEBUG_MODE, (byte)(enable ? 0x1 : 0x0));
}

/// <summary>
/// Enables or disables the ID model for the Person Sensor.
/// </summary>
/// <param name="enable">True to enable the ID model, False to disable.
/// With this flag set to False, only bounding boxes are captured.</param>
public void SetEnableId(bool enable)
{
i2cComms.WriteRegister((byte)Commands.ENABLE_ID, (byte)(enable ? 0x1 : 0x0));
}

/// <summary>
/// Sets whether to persist recognized IDs even when unpowered for the Person Sensor.
/// </summary>
/// <param name="enable">True to store recognized IDs even when unpowered, False otherwise.</param>
public void SetPersistIds(bool enable)
{
i2cComms.WriteRegister((byte)Commands.PERSIST_IDS, (byte)(enable ? 0x1 : 0x0));
}

/// <summary>
/// Initiates wiping recognized IDs from storage for the Person Sensor.
/// </summary>
public void SetEraseIds()
{
i2cComms.WriteRegister((byte)Commands.ERASE_IDS, 0x1);
}

/// <summary>
/// Initiates calibration for the next identified frame as a specific person ID (0 to 7) for the Person Sensor.
/// </summary>
/// <param name="id">The person ID to calibrate.</param>
/// <exception cref="Exception">Thrown if the specified ID exceeds the maximum number of IDs.</exception>
public void SetCalibrateId(byte id)
{
if (id > MAX_IDS_COUNT)
{
throw new Exception($"ID ({id}) exceeds the maximum number of IDs ({MAX_IDS_COUNT})");
}

i2cComms.WriteRegister((byte)Commands.CALIBRATE_ID, id);
}

/// <summary>
/// Gets the structured sensor data.
/// </summary>
/// <returns>The structured sensor data.</returns>
public PersonSensorResults GetSensorData()
{
i2cComms.Read(readBuffer);
return ParseSensorResults(readBuffer);
}

/// <summary>
/// Parses the sensor results from the provided byte array.
/// </summary>
/// <param name="data">The byte array containing sensor data.</param>
/// <returns>The structured sensor data.</returns>
public PersonSensorResults ParseSensorResults(byte[] data)
{
PersonSensorResults results = new();
results.Header = data.Take(HEADER_LENGTH).ToArray();

results.NumberOfFaces = (sbyte)data[HEADER_LENGTH];

if (results.NumberOfFaces < 0)
{
throw new Exception($"Number of faces detected ({results.NumberOfFaces}) is less than zero");
}

if (results.NumberOfFaces > MAX_FACE_COUNT)
{
throw new Exception($"Number of faces detected ({results.NumberOfFaces}) exceeds the maximum number of faces ({MAX_FACE_COUNT})");
}

results.FaceData = new PersonFace[MAX_FACE_COUNT];

for (int i = 0; i < MAX_FACE_COUNT; ++i)
{
var faceStartIndex = i * 8 + HEADER_LENGTH + 1;
results.FaceData[i] = new PersonFace
{
BoxConfidence = data[faceStartIndex],
BoxLeft = data[faceStartIndex + 1],
BoxTop = data[faceStartIndex + 2],
BoxRight = data[faceStartIndex + 3],
BoxBottom = data[faceStartIndex + 4],
IdConfidence = (sbyte)data[faceStartIndex + 5],
Id = (sbyte)data[faceStartIndex + 6],
IsFacing = data[faceStartIndex + 7]
};
}

results.CheckSum = BitConverter.ToUInt16(data.Skip(38).Take(2).ToArray(), 0);
return results;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
namespace Meadow.Foundation.Sensors
{
public partial class PersonSensor
{
/// <summary>
/// Enumeration of configuration commands for the Person Sensor.
/// </summary>
enum Commands : byte
{
/// <summary>
/// Mode configuration command. Default: 0x01 (continuous).
/// </summary>
MODE = 0x01,
/// <summary>
/// Enable/Disable ID model configuration command. Default: 0x00 (False).
/// With this flag set to False, only capture bounding boxes.
/// </summary>
ENABLE_ID = 0x02,
/// <summary>
/// Single-shot inference configuration command. Default: 0x00.
/// Trigger a single-shot inference. Only works if the sensor is in standby mode.
/// </summary>
SINGLE_SHOT = 0x03,
/// <summary>
/// Calibrate the next identified frame as person N, from 0 to 7.
/// If two frames pass with no person, this label is discarded. Default: 0x00.
/// </summary>
CALIBRATE_ID = 0x04,
/// <summary>
/// Store any recognized IDs even when unpowered configuration command. Default: 0x01 (True).
/// </summary>
PERSIST_IDS = 0x05,
/// <summary>
/// Wipe any recognized IDs from storage configuration command. Default: 0x00.
/// </summary>
ERASE_IDS = 0x06,
/// <summary>
/// Debug mode configuration command. Default: 0x01 (True).
/// Whether to enable the LED indicator on the sensor.
/// </summary>
DEBUG_MODE = 0x07,
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using static Meadow.Foundation.Sensors.PersonSensor;

namespace Meadow.Foundation.Sensors;

/// <summary>
/// Represents the structured results returned from the person sensor.
/// </summary>
public class PersonSensorResults
{
/// <summary>
/// Header information of the data packet.
/// </summary>
public byte[] Header { get; set; } = default!;

/// <summary>
/// Number of faces detected.
/// </summary>
public sbyte NumberOfFaces { get; set; }

/// <summary>
/// Information about detected faces.
/// </summary>
public PersonFace[] FaceData { get; set; } = new PersonFace[4];

/// <summary>
/// Checksum value of the data packet.
/// </summary>
public ushort CheckSum { get; set; }
}
Loading
Loading