Recently I started to develop an Windows Universal App for IoT Core. The project behind it: I built a chicken house (yes, out of wood with my own hands, chop saw,… 😀 )
Back in the days when we lived at my in-laws farm, my brother in law used a mixer (yes a mixer, the kitchen-thingy you use to stir a dough) to shut the chicken house in the evening, so he hadn’t to go out in the evening and shut the hatch by hand.
Although this was very innovative, the mixer ran for about 15 minutes because that was the minimum the minimal timer switch of his „chicken house hatch closing“-system 🙂
Long story short: we had our bedroom window 5 meters away from the chicken house and it was… very annoying.
I wanted to do things differently, controll my mechanism via an PWA… after all I’m a software engineer… how hard can it be, right?
But first things first:
I bought an ULN2003 driver shield + stepper motor (yes this is an amazon affiliate link)
There are a couple of tutorials out there to run this stepper motor with an raspberry pi (e.g. here is a driver class https://github.com/ZhangGaoxing/windows-iot-demo/blob/master/src/ULN2003A/03_Source/ULN2003A_Demo/ULN2003A.cs )
but to make it short:
Don’t buy or use this stepper motor, unless you want to rotate a feather or something. The ULN2003 has an single output of 0.5A, which just isn’t enough for what I had in mind.
After some research I bought an NEMA 17 2 phase 4 wire stepper motor, something like this:
I wanted drive a fast linear rail with it (the faster it drives, the more torque it needs), so I bought an NEMA 17 taking a top of 3.0A. Since you can’t run such a stepper motor with the ULN2003 shield, you need something like a TB6600 or TB6560 driver shield (haven’t figured out the difference between those two yet, tbh…)
Since I didn’t find any code in c# out there to use this shield, I started to write it on my own, here you go:
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.Devices.Gpio;
namespace RedKakadooDeviceController.Driver
{
public class Tb6560Driver : IDisposable
{
private static GpioPin enaPin;
private static GpioPin pulPin;
private static GpioPin dirPin;
private static GpioPinValue turnLeft = GpioPinValue.High;
private static GpioPinValue turnRight = GpioPinValue.Low;
private static GpioPinValue Locked = GpioPinValue.Low;
private static GpioPinValue Released = GpioPinValue.High;
public Tb6560Driver(int ena, int pul, int dir)
{
Debug.WriteLine("Initializing TB6560 driver shield");
var gpioController = GpioController.GetDefault();
if (gpioController == null)
{
Debug.WriteLine("No device controller on device, aborting Intitialization");
return;
}
enaPin = gpioController.OpenPin(ena);
enaPin.SetDriveMode(GpioPinDriveMode.Output);
pulPin = gpioController.OpenPin(pul);
pulPin.SetDriveMode(GpioPinDriveMode.Output);
dirPin = gpioController.OpenPin(dir);
dirPin.SetDriveMode(GpioPinDriveMode.Output);
// release stepper motor
enaPin.Write(Released);
// intial turn direction right
dirPin.Write(turnRight);
Debug.WriteLine("Initialization successfull");
}
public async Task TurnAsync (int value, TurnDirection direction)
{
enaPin.Write(Locked);
if (direction == TurnDirection.Right)
{
dirPin.Write(turnRight);
}
else if (direction == TurnDirection.Left)
{
dirPin.Write(turnLeft);
}
else
{
Debug.WriteLine("Invalid direction");
return;
}
for (int i = 0; i < value; i++)
{
pulPin.Write(GpioPinValue.High);
await Task.Delay(1);
pulPin.Write(GpioPinValue.Low);
await Task.Delay(1);
}
enaPin.Write(Released);
}
public void Dispose()
{
// set Enable to high to release the stepper motor
// if Enable is on low, the stepper motor is blocked by the tb6560 driver shield
enaPin.Write(GpioPinValue.High);
enaPin.Dispose();
dirPin.Dispose();
pulPin.Dispose();
}
}
}
One thing to keep in mind: Windows IoT Core isn’t meant to be used for controlling stepper motors – at least I didn’t figure it out how. The minimum delay you can set on a task is 1ms and the 1ms isn’t constant.