In this chapter, we’ll build a device library for a stepper motor driver. Stepper motors get used primarily in robotics projects, but it is not inconceivable they could be used in IOT projects.
There are many ways of driving a stepper motor, including simple drivers such as discrete transistors and H-bridges, which force you to do most of the work, and sophisticated drivers that do most of the work for you. In this book, we’ll look at the Watterott SilentStepStick (https://learn.watterott.com/silentstepstick/). It is a driver that I’ve used in some projects; its primary attraction is silent operation. I’d consider it around the middle of the “sophistication spectrum,” but it is still very easy to use.
Using multiple diozero base I/O devices, specifically GPIO output devices, to construct a single logical device
Finding, and ignoring, existing device libraries
Exploring the options and limitations of diozero
Understand the Device
Drives bipolar motors at up to 2A per coil, with voltages from 4.75V to 46V.
Can interpolate steps up to 256 microsteps per step.
StealthChop mode enables “extremely quiet” operation.
Enable, direction, and step signals control movement.
Seven configuration pins (CFG0–CFG6) control operation; one of them, CFG6, is the enable signal.
Maximum motor current can be controlled internally or externally.
Logic voltage can be 3.3V or 5V.
CFG0, CFG4, and CFG5 control “chopper” operation. All three default to the “recommended, most universal choice.” CFG4 and CFG5 have jumpers that allow change from the default.
CFG1 and CFG2 control the mode and microstep resolution of the driver. See the table on page 9 of TMC2100 datasheet or the table in Section 3 of the SilentStepStick datasheet for details.
CFG3 configures the means of setting the maximum motor current. It defaults to “float” for external control. It too has a jumper to allow change from the default.
A potentiometer on the breakout adjusts maximum motor current; both datasheets provide instructions on how to adjust the current.
In effect, the SilentStepStick establishes a reasonable default configuration that can be changed if you really need to do so. As a result, under the majority of circumstances, you only need to worry about CFG1 and CFG2.
Of course, the SilentStepStick is only interesting if you have a stepper motor attached. Stepper motors are fascinating beasts. See https://learn.adafruit.com/all-about-stepper-motors/what-is-a-stepper-motor for a useful introduction. Stepper motors come in many different sizes, require different voltages and currents, exhibit different step sizes, different torque, and so on. And of course, they are used for many different purposes.
That means it is impossible to determine a truly universal set of requirements for the device library or a universal configuration. Thus, I’ll simply identify a set of library and configuration requirements based on my past stepper projects.
I have a bipolar stepper motor for which the specifications are 12V, 0.4A, and 200 full steps/revolution (most stepper motors you’ll encounter are 200 steps/revolution). Further, I’ll require silent operation, but as fast as possible.
I am also going to make some simplifying, but rational, assumptions. First, the default values for CFG0, CFG3, CFG4, and CFG5 are acceptable. Second, the library does not set the configuration of CFG1 and CFG2; instead, it must be told the number of microsteps per step that result from the configuration. These assumptions save GPIO pins but might not be right for all projects.
Find a Device Library
To find a device library to use or port, I’ll follow the procedure outlined in Chapter 6. A look at the diozero device libraries shows no stepper motor drivers.
Searching for Java libraries produced nothing for the TMC2100. I did find hints of libraries for its more sophisticated cousins.
Search for Non-Java Libraries
Searching for Python libraries produced nothing for the TMC2100. Again, I found hints of libraries for its more sophisticated cousins.
The SilentStepStick product page has links to an “Arduino Library and Examples,” a “General Software Library,” and “Arduino Examples.” The first two do not offer support for the TMC2100 and so are no help. The last contains a very trivial example that is also not much help. Quite surprising, actually.
I found an Arduino sketch at https://electropeak.com/learn/interfacing-tmc2100-stepper-motor-driver-with-arduino/. The page contains an interesting summary of the SilentStepStick and TMC2100 datasheets as well as helpful hints. I expected to identify far more Arduino-based candidates.
You may have noticed the SilentStepStick product page says it is compatible with two other stepper motor controllers, the Watterott StepStick and the Pololu A4988 (www.pololu.com/product/1182). I’d claim the A4988 is partly compatible. It has only three configuration pins, which control the microsteps per step. Fortunately, the available resolutions match those of the SilentStepStick. Also, fortunately, Pololu provides an Arduino library for the A4988 (https://github.com/laurb9/StepperDriver/blob/master/src/A4988.cpp). The design is actually quite sophisticated in that it allows for “speed profiles,” so that the motor is accelerated from stopped up to nominal speed, run at nominal speed, then decelerated down to stopped.
And the Answer Is …
For better or worse, I will treat this as a “start from scratch” situation because of the anticipated simplicity. I will use the A4988 library for guidance, but ignore its sophisticated aspects, for two reasons. First, my expectations are low-speed and low-torque requirements. Second, I must leave something for you to do! More on the subject near the end of the chapter.
Device Library Design
Want to control the direction and speed of rotation.
Want to start and stop the rotation.
Anticipate only low speeds.
Want to enable and disable the driver. It is important to note that when enabled, the driver powers the motor, so the motor produces torque even when stopped. When disabled, the driver does not power the motor, so it does not produce torque; thus, the shaft and anything attached to it can move freely.
Do not want to control the microstepping configuration. Instead, will be told the configuration.
As hinted earlier, you must use the diozero GPIO digital output devices to control the SilentStepStick. Enable and direction controls are static and should use DigitalOutputDevice . The speed is determined by the step control; it could use a DigitalOutputDevice or a PwmOutputDevice. See Chapter 7 for more information on those diozero devices.
In theory, there could be multiple SilentStepSticks in a project, so there can be multiple instances of the library; in my last stepper project, I in fact used three SilentStepSticks. That means we must allow for multiple instances.
Raspberry Pi OS is not a real-time operating system and Java is not a real-time language. As a result, you cannot expect to produce truly accurate stepper motor speed control with the SilentStepStick since the Pi generates a step signal that is subject to the vagaries of the OS and Java. That said, you can produce truly accurate stepper motor position control because position depends only on the number of steps, which the Pi can accurately control.
Interface Design
Enable or disable the driver
Set the direction, either clockwise or counterclockwise
Set the speed of rotation
Run or stop
The GPIO pins for the enable, direction, and step pins
The microsteps per step, as determined by the SilentStepStick configuration pins CFG1 and CFG2
Device Library Development
As with any new diozero-based project, you must create a new NetBeans project, package, and class; configure the project for remote development on your Raspberry Pi; and configure the project to use diozero. See Chapter 7 for a summary of the steps. I’ll create a project called SSS (because SilentStepStick is too long), a package org.gaf.sss, and a class SilentStepStick. However, before creating the library, you should recognize the SilentStepStick presents a perfect opportunity to play. So that’s what we’ll do.
Play with the Device
Of course, before playing, you must construct the proper circuit for the SilentStepStick. That means connecting the motor, the motor power supply, and the logic power supply (3.3V from the Raspberry Pi). Page 3 of the SilentStepStick datasheet contains a nice circuit diagram you can use as a guide; page 6 contains some pictures I found useful for connecting the motor properly. You must also adjust the maximum motor current (see page 4 of the SilentStepStick datasheet and page 24 of the TMC2100 datasheet).
Since the configuration pins (including the enable pin) default to some reasonable value and direction does not matter, you can drive the motor using only the step pin driven by the Pi. Very nice!
An interesting question is how to drive the step pin. Earlier, I hypothesized using DigitalOutputDevice or PwmOutputDevice. The onOffLoop method of the former supports either a given number of cycles (steps) or an infinite number of cycles at a chosen frequency; good! The latter supports only an infinite number of cycles, though you can change the frequency; also good! Finally, if you read the documentation closely, you’ll find that with PwmOutputDevice, the desired frequency must be an integer; in contrast, with DigitalOutputDevice , you set the on and off periods in floating point, so, effectively, the frequency is in floating point. Thus, while either class works, DigitalOutputDevice offers more flexibility, so I’ll use it.
An important question is what frequency to use for the PWM signal that will drive the motor. You don’t want to go too fast or too slow. The motor has 200 steps per revolution. 1 RPM = 1/60 revolutions/second (RPS), so to produce 1 RPM, you must drive the motor at 200/60 = ~3.333 Hz. If the driver configuration you choose uses microstepping, you have to multiply that result by the number of microsteps per step. For example, if your configuration has 4 microsteps per step, to produce 1 RPM, you must drive the motor at (200/60) * 4 = ~13.333 Hz.
Since I’m after silent operation, I’m going to set CFG1=3.3V and CFG2=open, which turns on StealthChop at 4 microsteps/step. Now, 1 RPM is pretty slow, so let’s say the speed should be 4 RPM. Using the earlier formulas, that means a frequency of 4 * (200/60) * 4 = ~53.333 Hz, which produces a period of 18.75 milliseconds and a half period of 9.375 milliseconds.
Now, we’ll create a simple program to run the stepper motor. Listing 13-1 shows the program Step in package org.gaf.sss.test. The program is truly very simple; it has just three interesting statements. The first creates a DigitalOutputDevice instance that drives GPIO pin 17 which is connected to the SilentStepStick step pin; the second generates a 53.333 Hz step signal on GPIO pin 17; the third stops the step signal after 5 seconds.
Step
When you run Step , if everything is connected properly, the stepper motor shaft rotates at roughly 4 RPM for 5 seconds. You can put a piece of tape on the motor shaft to make the rotation easier to detect.
We’ve confirmed that the initial hardware and software configuration works. You can now begin to play/experiment with different configurations and different PWM frequencies to find a combination that works well for your project. You can also determine the motor direction for different states of the direction pin.
SilentStepStick Implementation
Now, we’ll develop SilentStepStick.1 In earlier chapters, we first developed a core. In the case of SilentStepStick, however, there is little difference between the core and the full library!
SilentStepStick constants and close method
Constructor Implementation
Listing 13-3 shows the SilentStepStick constructor . It implements the requirements discussed earlier. The only parameter not previously mentioned is stepsPerRev; it specifies the number of steps per revolution for the stepper motor being driven, necessary for calculating the frequency of the step signal.
SilentStepStick constructor and close method
Listing 13-3 also shows the completed close method. It ensures the driver is disabled and the step signal is off, so that the motor stops. The method also closes all the diozero device instances.
Listing 13-4 shows the implementation of the operative methods described earlier. The enable method is self-explanatory, as is the setDirection method .
After further reflection on the interface discussion earlier, it seemed appropriate to provide a single method that sets the direction, sets the speed, and turns on the step signal. Thus, the run method has parameters for direction and rotation speed. It uses the parameters to set the direction and determine the frequency of the step signal. The method turns on the step signal at the desired frequency by starting a DigitalOutputDevice infinite on/off loop. The step signal runs until it is turned off by calling the stop method .
SilentStepStick operative methods
The run method calls the getHalfPeriod method . The latter performs the calculations explained earlier to produce a step signal frequency from the speed parameter (in RPM). It then calculates the half period run uses to set up the DigitalOutputDevice on/off loop.
Finally, note the getStepCount method in Listing 13-4. It is not in the requirements or interface mentioned earlier. I realized after playing with Step (Listing 13-1) and thinking about the implications of the run method in Listing 13-4 that something like getStepCount would be quite useful in understanding stepper motor positioning in the context of a “run then stop” scenario. I requested the developer of diozero insert the necessary logic in DigitalOutputDevice.
Test SilentStepStick
Now, we’ll test SilentStepStick . A good first test is to reproduce the effect of the Step program in Listing 13-1. Listing 13-5 shows TestSSS1 that does so.
TestSSS1
Results of running TestSSS1
TestSSS2
Run TestSSS2, and if everything is wired properly, you should see the motor rotate clockwise for 5 seconds at 4 RPM and then counterclockwise for 5 seconds at 2 RPM. Success!
Result of running TestSSS2
What Next?
The implementation of SilentStepStick fulfills one benefit of stepper motors – speed control.2 The clever choice of DigitalOutputDevice allows us to also provide accurate position control! The reason is that with a stepping motor, accurate position control translates to moving an accurate number of steps, and DigitalOutputDevice can do that.
It does not allow termination of any stepping currently running. While a somewhat arbitrary decision, it does help maintain accurate positioning.
It exposes the ability of the DigitalOutputDevice to run an on/off loop in the foreground or background. The step count could be small enough that running in the foreground makes sense.
It exposes the ability of the DigitalOutputDevice to call the caller’s Action at the termination of the on/off loop. In most background situations, this is a good idea.
It must intercept the call by the DigitalOutputDevice to an Action in order to maintain internal state.
SilentStepStick stepCount method
An explanation of how stepCount works could be helpful. First, I’ll elaborate on the Action mechanism. stepCount always defines an internal “intercept” Action and provides that in the call to the onOffLoop method. Thus, when the on/off loop terminates, the DigitalOutputDevice always calls the intercept so it can do any internal housekeeping. If the caller provides a non-null stopAction, that Action gets called after the internal Action.
Runs until the count is complete
Calls the internal Action which sets the running flag false (and then calls the caller’s Action if it exists)
Returns to the stepCount method
The stepCount method then returns to the caller with the running flag false.
Runs until the count is complete
Calls the internal Action which sets the running flag false (and then calls the caller’s Action if it exists)
At this point, the SilentStepStick instance has the running flag false, and another stepper activity can be initiated.
TestSSS3
Results of running TestSSS3
Speed Profiles
I mentioned in the section on libraries the notion of “speed profiles” implemented in the Pololu A4988 library. Speed profiles can be extremely important in some stepper motor applications, especially where high speed or high torque are involved. The paper www.ti.com/lit/an/slyt482/slyt482.pdf?ts=1615587700571&ref_url=https%253A%252F%252Fwww.google.com%252F explains the concepts and issues.
At the time of writing, the answer is no. I base that on an examination of the implementation of DigitalOutputDevice.
- That said, with some changes suggested by the Arduino library mentioned earlier, the answer becomes yes, but. The “but” has several facets:
One form of the changes would impact the performance in ways that might not be palatable for some projects.
A second form of the changes would force a potentially unpleasant change in the interface of DigitalOutputDevice.
Using the revised DigitalOutputDevice would require ramping to be done in the foreground or use of Java concurrency constructs or perhaps diozero threading constructs to do it in the background.
I think in reality, the best choice would be to produce a peer or subclass of DigitalOutputDevice specifically targeting stepper motor speed profiles. Sadly, both are beyond the scope of the book. That said, if you really need speed profiles and you don’t want to create a “speed profile” class, you may be able to find a more sophisticated stepper motor driver that implements profiles, much as the RoboClaw controller does for DC motors (see Chapter 8).
Summary
Finding existing device libraries and mostly ignoring them
Creating a device library mostly from scratch
Using several diozero digital I/O devices to construct a single logical device
Playing with the device prior to implementing the library
Realizing that diozero cannot do everything
All good stuff!