Secondary Control - Clockwork Application Code
Application control for the clockwork component is fundamentally about:
- Controlling the stepper motors to position the clock hands
- Communication to receive application instructions
Application control for the clockwork mechanism was created using Arduino toolchains and workflows - the Arduino IDE with C/C++ programming and libraries.
Research
In selecting approaches for stepper motor control, I considered different potential options. For communication, I selected BLE based on my earlier Fab Academy assignment experience.
My Earlier Fab Academy Projects
As part of Mechanical Design, Machine Design week, we worked with 28BYJ-48 stepper motors for a basic 3D printed drawing machine. The initial exploration used the Arduino Stepper library, which was a consideration.
For communication, I had previously worked with Bluetooth® Low Energy (BLE) in Embedded Networking & Communications, which was a consideration.
Prior Projects
For stepper motor control, I reviewed prior projects that had used stepper motors, to consider options. There were two primary options - direct motor control and use of the AccelStepper library.
| Project | Stepper Control Approach |
|---|---|
| Modern Weasley Clock | Direct Coded Control |
| Where'sLy Clock Project | AccelStepper Library |
| Magic-Clock | AccelStepper Library |
Reference
In working with the 28BYJ-48 stepper motors, I found the reference of Control 28BYJ-48 Stepper Motor with ULN2003 Driver & Arduino to be very helpful. This covered use of both the Arduino Stepper library and the AccelStepper library.
Selection
Based on my research, for controlling stepper motors, the main choice was between the Arduino Stepper library and the AccelStepper library. I had used the Arduino Stepper library as part of previous Fab Academy assignments and as the enabling library for the clockwork testing code. The AccelStepper library, however, had a key advantage in being able to control multiple motors simultaneously.
In conducted some basic control testing with each library. The AccelStepper library seems to have some internal overhead and is not able to match the fastest revolutions per minute available with the Arduino Stepper library for the 28BYJ-48 motors. But the AccelStepper library provided reasonable speed for the clock hand application and it enabled multiple motor control. So, I decided to move forward with the AccelStepper library.
For communication, I had a good previous experince with the Arduino Bluetooth® Low Energy (BLE) in Embedded Networking & Communications, so I moved foward with BLE communication.
Locus Pocus - Secondary Clockwork Control Design
For the Locus Pocus project, I selected the AccelStepper library for motor control and the ArduinoBLE library for Bluetooth® Low Energy communication.
In developing Locus Pocus, I used previous approaches as points of reference, but I created all of the clockwork control code myself.
I adopted an object-oriented approach, breaking clock functionality down into:
- Clock Motor - containing motor detail for specific motor types
- Clock Hand - responsible for motor control to drive the hands
- Clock Face - responsible for managing available face positions
- Clock - bringing together and managing component functionality
Application control for the clockwork mechanism was created using Arduino toolchains and workflows - the Arduino IDE with C/C++ programming and libraries.
Clock Motor
While fairly straightforward, I separated out a clock motor type to act as a container for key motor characteristics. Currently this is only the number of steps for the motor, but could be used to refine motor use, or use different types of motors.
| ClockMotor.h | |
|---|---|
Clock Hand
The clock hand class encapsulates functionality for the clock hands. Effectively, this is about motor control for turning the clock hands. It inherits from the AccelStepper class provided by the library, so is a stepper motor controller wrapped with additional, clock-specific functions for moving to specific positions.
The main functionality is:
- moveTo() - move to a specific stepper position in terms of steps
- moveToDegree() - move to a degree position on a 360 degree circle - this considers the top of the circle to be 0
- calibrate() - supports manual calibration for this hand - will make 2 complete revolutions - if data is entered, it marks that point as the new home (zero point)
Clock Face
The clock face class encapsulates functionality for managing the defined positions on a clock face.
The main functionality is:
- getPosition() - given a string naming a hand position, return the degree position (on a 360 degree circle, where 0 is at the top) or -1 if there is no such named hand position on this face
- getPositionRandom() - returns a random position from the clock face
Clock
The clock class encapsulates functionality for the clock as a whole. It is constructed with a specific clock face and set of clock hands.
Clock commands are given in a "target:action" format, where the target represents the name associated with a hand (or the "clock" itself), and the action represents the goal for the named hand/clock. Typically the action is the name of a clock face position. For example, "h1:home" would indicate that the hand named "h1" should move to the "home" position on the clock face.
The main functionality is:
- set() - given a single command string, split it into target / action and call the 2-string version
- set() - given a target string and action string, check whether it is for the clock itself (if so, move to taking a clock action), or for one of the hands (if so, pass the action to the named hand)
- tick() - needs to be called every loop() of the main application, passthrough for underlying motor control of the AccelStepper library
- manage() - dispatches to functions for named clock actions
- calibrate() - calibrates each hand in turn
- facelift() - moves the hands to a horizontal position to enable changing the clock face
- randomize() - moves each hand to a random position on the clock face
| Clock.cpp | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | |
Main Application
The main application sets up the clock and communication functions. It loops to check for input from the serial monitor, and calls the functions needed to drive the ArduinoBLE and AccelStepper library functionality.
- The SafeStringReader library is used to enable non-blocking reads from the serial monitor input.
- BLE communication sets up a service (with UUID) and writeable control characteristic (with UUID) to receive clock commands over BLE communication
| clockdriver.ino | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | |