This project shows you how to build your own Magic Eight Ball using Project Lab's onboard motion sensor, so when shaking the board, it will give you an answer like the famous billiard ball on the ST7789 display.
Project Lab is the most functional IoT prototyping platform on the planet. No more breadboards, complicated wiring, or soldering. Project Lab was built from the ground up using the industry's most powerful, capable, and reliable sensors, components, and connectors.
Meadow.Foundation platform for quickly and easily building connected things using.NET on Meadow. Created by Wilderness Labs, it's completely open source and maintained by the Wilderness Labs community.
Before you dive in this project, ensure that your Meadow board and development environment is fully up to date. Check the Release Notes section to double check.
Step 1 - Create a Meadow Application projectCreate a new Meadow Application project in Visual Studio 2019 for Windows or macOS and name it MagicEightMeadow.
Step 2 - Add the required NuGet packagesFor this project, search and install the following NuGet packages:
Step 3 - Add project image assetsHead over the attachment section to download the image assets and add them to your project:
Important Note: When selecting each one, make sure to set the Build Action to Embedded resource.
Copy the following code below:
public class MeadowApp : App<F7CoreComputeV2>
{
IPixelBuffer questionBuffer;
IProjectLabHardware projectLab;
RgbPwmLed onboardLed;
MicroGraphics graphics;
bool isAnswering = false;
string GetQuestionFilename => "MagicEightMeadow.m8b_question.jpg";
public override Task Initialize()
{
Resolver.Log.Info("Initialize...");
projectLab = ProjectLab.Create();
Resolver.Log.Info($"Running on ProjectLab Hardware {projectLab.RevisionString}");
onboardLed = projectLab.RgbLed;
onboardLed.SetColor(Color.Red);
graphics = new MicroGraphics(projectLab.Display);
graphics.Clear(Color.FromHex("#00000C"));
questionBuffer = LoadJpeg(LoadResource(GetQuestionFilename));
var consumer = Bmi270.CreateObserver(
handler: result => MotionSensorHandler(result),
filter: result => MotionSensorFilter(result));
projectLab.MotionSensor.Subscribe(consumer);
onboardLed.SetColor(Color.Green);
return base.Initialize();
}
private async void MotionSensorHandler(IChangeResult<(Acceleration3D? a3D, AngularVelocity3D? v3D, Temperature? t)> e)
{
if (isAnswering)
return;
isAnswering = true;
onboardLed.SetColor(Color.Orange);
DisplayAnswer();
await Task.Delay(TimeSpan.FromSeconds(5));
DisplayQuestion();
onboardLed.SetColor(Color.Green);
isAnswering = false;
}
private bool MotionSensorFilter(IChangeResult<(Acceleration3D? a3D, AngularVelocity3D? v3D, Temperature? t)> e)
{
return e.New.v3D.Value.Y.DegreesPerSecond > 0.75;
}
void DisplayQuestion()
{
graphics.DrawBuffer((graphics.Width - questionBuffer.Width) / 2, 0, questionBuffer);
graphics.Show();
}
void DisplayAnswer()
{
var rand = new Random();
var buffer = LoadJpeg(LoadResource(GetAnswerFilename(rand.Next(1, 21))));
graphics.DrawBuffer((graphics.Width - questionBuffer.Width) / 2, 0, buffer);
graphics.Show();
}
string GetAnswerFilename(int answerNumber) => $"MagicEightMeadow.m8b_{answerNumber.ToString("00")}.jpg";
byte[] LoadResource(string fileName)
{
var assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(fileName))
{
using (var ms = new MemoryStream())
{
stream.CopyTo(ms);
return ms.ToArray();
}
}
}
IPixelBuffer LoadJpeg(byte[] jpgData)
{
var decoder = new JpegDecoder();
var jpg = decoder.DecodeJpeg(jpgData);
return new BufferRgb888(decoder.Width, decoder.Height, jpg);
}
public override Task Run()
{
Console.WriteLine("Run...");
DisplayQuestion();
projectLab.MotionSensor.StartUpdating(TimeSpan.FromSeconds(1));
return base.Run();
}
}
Initialize
- The application starts setting app the ProjectLab object, creates a graphic buffers to load the "Got a Question" image, and enables the onboard motion sensor and subscribes to a Observable pattern for all our sensors, where its composed of a handler and filter.MotionSensorHandler
- Event handler that turns the onboard LED to turn orange and show a random answer for a few seconds, and makes the LED turn back to green and loads the question image again.MotionSensorFilter
- Event handler used to control the motion sensitivity, and returns true to triggerMotionSensorHandler
.DisplayQuestion
- Loads and draw the "Got a Question?" Image.DisplayAnswer
- Loads and draws a random answer image.LoadResource
- Opens a image file to return its contents in a byte array.LoadJpeg
- Decodes the image byte array and loads it to aIPixelBuffer
.Run
- Method that runs right after Initialize, and callsDisplayQuestion(
and activates the motion sensor to start detecting movements every second.
Click the Run button in Visual Studio. It should look like to the following GIF:
This project is only the tip of the iceberg in terms of the extensive exciting things you can do with Meadow.Foundation.
- It comes with a huge peripheral driver library with drivers for the most common sensors and peripherals.
- The peripheral drivers encapsulate the core logic and expose a simple, clean, modern API.
- This project is backed by a growing community that is constantly working on building cool connected things and are always excited to help new-comers and discuss new projects.
Comments
Please log in or sign up to comment.