The field service manual is quite helpful, but the pin numbers of the connectors are not labeled and there are no part number.
Between the manual and some measurements with my meter, I think I have it figured out.
Power Supply.
I do not have the original external (wall wart) power supply. You can tell it is AC from the schematic. I did some research and found out it is 9VAC. That goes through (2) 5V volt linear regulators (with a huge heatsink). One powers the stepper motors and all the logic. The other powers the pen up/down solenoid.
Basically, I should be able to power everything with a robust 5VDC power supply. I’ll probably use this style.
The function switches are normally open, momentary switches that close to ground.
Here is the pinout of that cable.
Pin #
Description
Wire color
1
Grn
Black
2
Pen Change Sw
Blue
3
Paper Feed Sw
Pink
4
pen Change Sw
Yellow
5
Power (in)
Red
6
Power (out)
Red
Pen Solenoid
Then pen moves to and away from the paper using a solenoid. The schematic is amazingly complex here, but basically the voltage flows one way through it for pen up and the for pen down. It is a 5V coil with a resistance of 5.2 Ohm.
Stepper motors
There are (2) stepper motors. One is for the paper feed and the other moves the pen carriage. These motors are 5 wire unipolar motors. These are typically used by connecting the common to voltage+ and the other wires to transistors. If sequenced on one at a time, you get 4 independent coils.
The coil resistance of the paper feed stepper coils is 50 Ohm and the carriage is 60 Ohm.
Pen Change, Homing switch
There is a reed switch activated by a magnet in the pen carriage.
Printer Mechanism Cable
There is a 13 pin cable that connects everything in the plotter mechanism to the controller PCB. This uses a Molex connector p/n 511911300. The mate on the PCB is Molex p/n 22041131. The pinout is here.
I recently decided to update the Polar Coaster project. The primary reason was to update the controller to use Grbl_ESP32 firmware. I also thought I could make it smaller, lighter and remove a little cost.
Controller
The old controller was not custom made and just sort of tacked onto the back. This increased the size and didn’t look very good. It had a Bluetooth module, but you still had to stream the gcode. You could use an Android app, but that was still a little awkward.
Firmware
The controller runs Grbl_ESP32. This was recently updated to include pen machine features. This allows precise control and calibration of the pen servo. You can control the speed, timing and endpoints of the servo travel.
WebUI
The controller has a web server that serves a web app. This allows complete control of the machine. Web browser based control is ideal, because it is compatible with anything that can use a browser. We hope to add additional web apps for generating gcode from images and SVGs.
SD Card
This is a great feature. If you have files on the SD card, they can easily be plotted. The WebUI lets you upload files and then click play.
Stepper motors
Both versions use NEMA 14 motors. The original version used 34mm deep motors. I used these because I had some. They are overkill, because there is very little load on the motors. I bought some 20mm deep motors for the new version. These are even a little overkill. I am only running about 0.3A of current into each one. There are not too many options for standard stepper motors that are smaller and lower cost than these.
Gear Driven Rotational Axis
I decided to change from a belt driven rational axis to a gear driven one. Loop belts are a pain, because you have to order them from expensive places like SDP-SI and if you want to tweak anything, you might need to order a different size. I decided to use helix gears this time. These are 15° gears with a modulus of 1. They print and work great with my printer, even on a coarse layer height. The motor is mounted on slots and it is easy to get virtually no backlash. The helix keeps them quiet.
Rotational Platter
The platter rotates around a central bearing. This pulls (3) smaller bearings, that act like wheels, into contact with the PCB. This causes the platter to stay very flat, without wobble. I created a copper ring, plated with solder on the PCB to make it extra smooth and wear resistant. It also looks really cool and shiny on the PCB!
Buttons
Since there was a little room left on he board, I added three buttons. I have not added anything to the firmware yet. I think one will definitely be a homing button. I am not sure what to use the others for. I thought it might be handy to have a repeat button to repeat the last plot without having to fire up the phone app.
Battery Power
I made a battery case in the base of the machine to hold an RC style LiPo battery. I am using a 3 cell (11.1V) 2200 mah battery. The idle current on the machine with the WiFi running is about 80ma. When plotting it peaks at about 800ma. I think I should get about 2 hours of continuous plotting.
Future
Put kinematics into the firmware. currently files need to be pre-processed with the python script.
If you want to be notified of future blog posts, please subscribe.
I showed off an early version of my DrawBot Badge at the Hardware Happy Hour last night. Some tweeted pictures generated a lot of questions, so I thought I would write a quick post about it.
I have been following the #badgelife thing for a few years and felt that the mechanical and CNC world needed to be represented. The goal was to create something small, safe, fun and something anyone could learn to use. A drawing machine seemed the perfect fit.
Drawing Surface
I decided to use 3″ square Post-It notes. The main feature is that they are self stick, so I don’t need any clamps or tape. It is also cool that you can stick them to things when the drawing is done. They are cheap and easy to find. I like the kind that have the majority of the back (full stick) covered in adhesive. This means you can use a small stack of them and peel them off as they are done.
Drawing Mechanism
I tried to make the drawing mechanism as tiny as possible. The size is about 30mm x 70mm. It uses (3) of the smallest readily available class of hobby servos call micro servos. You can buy these from AliExpress for as low $1-$2 in low quantities. The choice of the arm configurations was primarily based on tightly packing the the motors, but I also wanted something new and interesting.
The pen lift is simply a cam on one of the motors. The entire mechanism rotates on two 3mm bearings. In my experience with drawing machines, gravity is the best way to engage the pen to the work. The mechanism needed to work hanging from a lanyard or sitting on a table.
Electronics
There is only one electronic item right now. It is an ESP32 dev module. There are also (3) connectors for the servos and (1) for voltage monitoring. The entire back of the badge is a PCB. I made the board full size to enclose the back and the pen lift cam need to push on something. I have big plans for the rest of the area though. The ESP32 provides the Bluetooth and Wifi needed for the remote control.
Firmware
It is running my ESP32 port of Grbl with a little hacking for the servos. The ESP32 uses an RTOS, so I just created a low priority, repeating task (20Hz). The task checks the position of a virtual CNC machine, does some kinematic math and updates the servos. The software supports streaming drawing data (gcode) via serial port, bluetooth, SD card or wifi. I am using the bluetooth option to send via my phone. I will publish the firmware soon.
Crazy Math (Kinematics)
The math is actually not too hard. You know the desired pen location, the axes of the servos and the lengths of the linkages. There are two ways to do the math. The first way is using the law of cosines and the Pythagorean theorem.
The second method uses intersecting circles. Each linkage can sweep a circle from a axis point and radius. Any two linkage’s circles will intersect at two points. It is easy to pick one of the points as more desirable. While it is less deterministic, due to the two points thing, it appears to run about 40% faster on the ESP32.
The Z is very simple. Any Z value less than 0 is pen down and everything else is pen up.
Drawing Quality
The quality is basically “Adorably Wiggly”. I am using the cheapest analog servos. That means I might get about 200 x 200 resolution at best at the servo hubs. If you mapped that grid to the paper it would be a warped grid with dense and sparse areas of the grid due to the non-linear nature of the mechanism. Digital servos with very low deadbands (~1us) it would probably do a lot better, but I am not sure that is worth it. It would only be a little less wiggly. They cost about 4x what analog servos do (still pretty cheap).
There is a calibration feature. Each servo is a little different and it is difficult to precisely mount the arms at the right angle. The calibration adjusts the zero angle and pwm/degree of rotation.
Next Steps
This project is part of a talk proposal for Hackaday SuperCon 2018. If that gets accepted, the badge will become a full featured CNC controller capable of running a router, laser cutters, high res plotter, etc, as well as the Drawbot badge. Only the DrawBot will be populated. The rest will be modular like this board.
I may also make a simple version that is only the draw bot. The BOM cost is currently about $10-$12 (without 3D printed parts)
Regardless of what happens all source files will be publish sometime in October.
Follow me on Twitter (@buildlog) or subscribe to this blog if you want to follow the project.
If you want to be notified of future blog posts, please subscribe.
Bluetooth Serial has now been added to the master branch of Grbl_ESP32. Bluetooth Serial means the Bluetooth connection looks like a serial port when you pair with the device. This is ideal because it allows all existing gcode senders that support serial ports to use Bluetooth.
This was added using the Bluetooth Serial library that is part of the espressif/arduino-esp32 development environment. This library is relatively new and has a few issues, but I was able to work around them.
Sending Characters: The reporting done by Grbl sends characters a character at a time. This means dozens of calls to the library are needed for each response. This caused characters to be dropped. The solution is to send a full string in a single call using .print(), rather than sending individual characters using .write(). Grbl was written using the character at a time method to highly optimize the reporting. The raw speed of the ESP32 does not require that optimization and the resulting code is much more readable.
No Password: The library does not support the use of a password for the pairing. This is a big drawback, and needs to be considered before you enable Bluetooth. Apparently this was due to an upstream component that has now been fixed. Hopefully it means the library will be updated soon.
Why and when to use it.
The cost, size and wireless features of the ESP32 are the primary reason I ported Grbl to the ESP32. I make a lot of tiny CNC machines. A laptop is likely to be many times the size of the CNC machine. I wanted to control the machines via a phone or small tablet. I have found the connection to be very reliable, even for jobs lasting more than an hour. The phone can even be in the “off” state in your pocket and it will still stream reliably. The battery drain is accelerated, but not significantly (like listening to audio via Bluetooth) You do need to stay within range of the machine, although Grbl Controller (Android) appears to be able to resume a job.
Using Bluetooth.
It is optional. You enable the feature at compile time. That allows you to save some code space (not really an issue now). Once the feature is enabled, you can still turn it on or off via a serial port command. All Bluetooth traffic is echo’d to the serial port. This allows you to monitor the communications. You can also use the Serial port at any time, but it is not a good idea to do that while running a job. Here are the steps to set it up.
Make sure #define ENABLE_BLUETOOTH is not commented out in config.h.
Use a serial port terminal to set the Bluetooth name using $I=NAME, where NAME is the Bluetooth name you want. I don’t know all the naming rules, so keep it short and simple. There is no capability to use a password yet. Grbl converts all input to capital letters, so lowercase will cannot be used.
Reboot the ESP32 to turn on Bluetooth with that name. Grbl will send Starting Bluetooth:ESP32BT as the first item when booting to let you know Bluetooth is on. ESP32BT is the Bluetooth name I used in this case. Grbl will now respond on either Bluetooth or Serial data. All Bluetooth sends are echo’d on the Serial port if you want to watch the data.
You can now pair a phone or PC with Grbl_ESP32.
Caution: Do not pair while running a job. The ESP32 will likely interrupt and/or watchdog issues while the stepper timer is running and the pairing process is running.
Next Steps
Other modes: A phone also makes an awesome display and control panel. Maybe the PC is the primary sender and the phone acts as a pendant.
SD card. SD card is next on the roadmap. This pairs well with bluetooth, because the phone could select and start an SD card job.
If you want to be notified of future blog posts, please subscribe.
I recently ran out of the original TWANG shields. I took the opportunity to make a few changes.
Audio Jack
The internal speaker is powered by the Arduino I/O pins. This limits it to the low voltage and current that those pins can provide. In normal environments that sound has plenty of volume. I have used it at some very loud events where that sound level is not loud enough.
This version adds a standard 3mm (1/8 in.) audio jack. You can connect this to a powered, external speaker.
Power Capacitor
Some old LED strips like the WS2812 are very sensitive to voltage spikes that might come from lower quality power supplies at turn on. They recommend adding a large capacitor to reduce voltage spikes. A larger 1000uF capacitor has been added to the PCB, so you do not need to install it externally.
Life LEDs
The TWANG firmware supports the use of remaining life LEDs. The firmware normally shows the remaining life LEDs on the LED strip. This has the advantage of making it easy to change the lives per level without having to change your hardware. On version 1, there was a place to install (3) life LEDs, but the LEDs were never installed. This version removes that feature.
I ported the TWANG game over to ESP32. I wanted to do this for several reasons.
Cost: The ESP32 is generally lower cost than the Arduino Mega
Speed: The ESP32 has a dual core 80MHz processor vs. the 16MHz Arduino Mega
Memory: The ESP32 has much more RAM and program space to allow more features, levels and audio files.
Physical Size: A Mega is very big. This creates a large enclosure that takes a while to print. The smaller enclosure is also more portable.
DAC Pins: The audio capabilities on the Mega are very crude and basically limited to square wave tones. A DAC can output digital audio. Currently I am just using a similar square wave tone to the Mega, but it works much better for adjusting the volume.
Wireless: The ESP32 has Wifi and Bluetooth. This will allow easier (smartphone) interfacing for options (brightness, volume) and level pack uploads. I also want to consider dual player battle type games with linked controllers.
The Audio
The original TWANG bit banged audio directly from I/O to a speaker. This was super simple, but the volume at max was not loud enough for noisy environments. The ESP32 I/O is a lower voltage (3.3v) and less current, so something needed to be done. I prototyped with a PAM8403 based amplifier (~$4 on Amazon). This worked great, so I added that I.C. to my shield. The volume is controlled by the amplitude of the DAC.
The Shield
I made a shield to simply the wiring and provide a stable way to mount the ESP32. I used a NodeMCU 32S development board for the ESP32. Under the ESP32 is a the audio circuitry. I should have some extra boards to sell on Tindie soon. I will publish the source files soon.
The Firmware
The code is on Github. The port was relatively easy, but I had to rewrite a few libraries. They were designed so the main “setup” and “loop” parts did not change much. Currently the serial port based setup from the Mega version was not ported. This probably won’t be used. A wireless version is in the works.
Enclosure
The new enclosure is smaller. It prints quicker and is easier to fit in my backpack. The size is still big enough to hold comfortably while playing. The files will be uploaded to Thingiverse within the week.
Next Steps
Wireless control: I want a simple way to read the game statistics (average score, levels played, boos kills, etc) and tweak simple settings like audio volume and brightness. I think the easiest way is to make it a wifi access point with a simple web server. This eliminates having to write any client side apps and any smartphone or computer can hope on easily.
Levels: Make some way to edit or upload levels via wifi.
Multiplayer: I should be able to link multiple controllers. If I can think of a good dual player game idea, I might try to add that.
Python: It might be a fun challenge to write the game in Micro Python. This might open up the development to more people.
If you want to be notified of future blog posts, please subscribe.
I have been working on some games for the ESP32 and needed some decent quality audio with a minimum number of additional components. I was bouncing between using the DAC and using the I2S bus. The DAC requires less external parts, so I went that way. I ended up creating a very simple library for use in he Arduino IDE. (Note: This only works with ESP32)
DACs
The ESP32 has (2) internal 8 bit DACs. DACs are Digital to Analog Converters. You give them an 8 bit value and they output an analog voltage. The voltage range of the 0-255 8-bit value is roughly Gnd to 3.3V on the ESP32. If you digitize an audio file, you can then play it back through the DAC. The DAC can’t directly drive a basic speaker, but you can connect it to an amplifier or amplified external speakers. The 8-bit quality is not great, but more than good enough for simple games.
The sound data comes from wave (.wav) files. This uses the 8 bit, unsigned, uncompressed format. Wave files can be saved with any sampling rate you want. To get a decent sound you need to sample the analog files at thousands of times per second. I have found that 4000 Hz is about the minimum for anything musical or spoken. 8000 sounds pretty good for most stuff. For reference, CDs are sampled a 44100 Hz (also 16-bit not 8-bit). This means there is a lot of data even for short duration audio. The typical ESP32 board has 2 to 4MB. At an 8000Hz sampling rate that gives you 125 seconds per MB. That is plenty for what I am working on, so I decided to store the data on the ESP32. If that is not good enough, you could use an SD card.
Here is a reference of the wave format. Only a few of the values are used.
Byte
Length
Description
0
4
Always "RIFF"
4
4
File size in Bytes
8
4
Always "WAVE"
12
4
Always "fmt " with a null
16
4
Length of format
20
2
Audio format (1=PCM)
22
2
Number of channels
24
4
Sample rate
28
4
Byte Rate
32
2
Block Align
34
2
Bits per sample (8,16)
36
4
Alaways "data"
40
4
File size
44
...
Start of data
References
I found some good references to help me with this library.
IoT Sharing: This was a great reference for understanding the basics, but it uses an SD card to save the data.
Xtronical: This was very helpful and my code is very close to this.
I started with the Xtronical XT_DAC_Audio library, but found it got be very unstable when I added it to my game. It often crashed when seemingly unrelated code was added. I think the problem was due to trying to use floating point math in the interrupt. As soon as I took that out, it got very stable. They make reference to the issue in the code and suggest it could get fixed via compiler updates.
How it works
The wave data is stored in large char arrays. An interrupt reads the data and feeds that to the DAC. Using an interrupt allows the audio to play “in the background” while the game is running. The Xtronical library uses a fixed interrupt rate of 50kHz. It does some floating math in the interrupt to adjust to the actual sample rate of the wav file. I decided to change the interrupt rate to the actual sample rate of the wav data.
Here is a snippet of what wave data array looks like.
The sample rate is stored in the header of the wav data. When you play the file, it sets the interrupt rate to match the sample rate, so no math is required. You can use a mix of sample rates in the waves you use. It will adjust as needed before it is played back. It allows 2000Hz to 50000Hz sample rates. If you try to go outside that range it will use 2000 Hz. You will easily know there is a problem if you hear that.
Game Related Features
I added some features that might be needed when using with a game.
Check to see if the audio player is currently playing anything.
Interrupt The Current Wave – If something happens like an explosion you need to immediately switch to that sound. This is an option when you send a command to play a wave.
Change the Frequency – I had some sounds that needed to change based on game speed. There is an option speed up r slow down the play back speed by a multiplier to give.
Install the library using the Sketch…Include Library…Add .ZIP Library menus.
It will also add an example. Open that using the File…Examples…Game_Audio menus.
Create a character array of the wav data. See this video from XTronical for how to do that.
Give the XTronical video a thumbs up and a nice comment 🙂
Create a Game_Audio_Class object. The first parameter is the DAC pin number you want to use. It should be 25, 26. The second parameter is the timer number to use. Example: Game_Audio_Class GameAudio(25,0);
Create a Game_Audio_Wav_Class object. The only parameter is name of the char array of you wave data. Example: Game_Audio_Wav_Class pmDeath(pacmanDeath);
Here is the demo that installs with the library
#include "SoundData.h";
#include "Game_Audio.h";
Game_Audio_Class GameAudio(25,0);
Game_Audio_Wav_Class pmDeath(pacmanDeath); // pacman dyingsound
Game_Audio_Wav_Class pmWav(pacman); // pacman theme
void setup() {
Serial.begin(115200);
Serial.println("Begin...");
}
void loop() {
// ------------- Play 2 wavs one after the other ----------------
Serial.print("Pacman Theme Sample Rate (Hz):");
Serial.println(pmWav.getSampleRate());
Serial.print("Duration (secs):");
Serial.println(pmWav.getDuration());
GameAudio.PlayWav(&pmWav, false, 1.0);
// wait until done
while(GameAudio.IsPlaying()){
}
delay(200);
GameAudio.PlayWav(&pmDeath, false, 1.0);
// wait until done
while(GameAudio.IsPlaying())
{
}
// -------- Play a wav then interrupt it after 600ms ------------
GameAudio.PlayWav(&pmWav, false, 1.0);
delay(600); // this is less than the duration of the last wav
// this wav will not play because the other is playing and interruptCurrent is false
GameAudio.PlayWav(&pmWav, false, 1.0);
// this will interrupt the playing file
GameAudio.PlayWav(&pmDeath, true, 1.0);
// --------- Play a wav with increacing sample rate (speeds up playback)
for (int i=0; i<10; i += 2)
{
while(GameAudio.IsPlaying()){// wait for wav to complete
}
GameAudio.PlayWav(&pmWav, false, (1.0) + (float)i / 10.0);
}
while (true) { // stop here program is done...but anything still playing will complete
}
}
Video
Next Steps
I’ll am working on some games, so new features might be added.
I’ll probably add the option to use I2S audio rather than the DAC.
I might add the option to pull files from an SD card.
If you want to be notified of future blog posts, please subscribe.
It’s difficult to beat. Only one person got all the way to the boss level and defeated it. Amazingly, it was Elan Lee. He loved the game and gave me some good ideas to work on.
Most people got killed in the second to last level. It has a lot of enemies and a conveyor that keeps pushing you back to the bottom. There is also a sneaky enemy spawner at the bottom that gets a lot of people. It is a great level, so I don’t want to remove it. I have added a few more levels before it to practice before that.
The Lava Pools. The lava pools confused some people. I changed the pools to look more red, flickering and scary when they are on and less scary when off. To me it looks more obvious now what to do.
The Sound. I love the chip tune style sound out of the Arduino, but it needs to be way louder. In a large crowd, you cannot hear it at all. I think it needs an amplifier or an option for an external speaker.
Boss Level: By design, the exit at the top of the boss level does not appear until all bosses are dead. People did not understand this and tried to exit out the top early, because the boss respawns below you after the first “kill”. That caused the players to try to leave the game without ending the level. If you exited the top in this mode, the player disappeared without a way back. This is very annoying if you get all the way to this last level. I fixed the code so you can’t goes past the second to last LED when the boss is still alive.
New Features: I asked several people for new ideas. I got some to work on, but already added one. The attack width is now adjustable. It will default to the old width, but you can change it per level.
More levels. A typical game lasts about about 1-2 minutes. I think a few more medium difficulty levels would help.
Scoring System: It would be cool to know how you did compared to others. It could display the score as a bar on the strip, with the max possible being the full length. You could then mark your level somehow by the strip. (Postit note flag, dry erase pen, etc)
Next Steps
Release all the source files.
Firmware: I have been hacking the code quite a bit. I’ll release my changes after some clean up and testing.
STL files: I have been using odd sized speakers harvested from some cheap external speakers. When looking looking to buy some, it seems like 40mm diameter is a good standard size that is cheap and available. As soon as I get some and test them, I will release the files for this size.
Sell on Tindie. My shield makes wiring super easy, but is definitely not required. I think I’ll sell everything, except for the Mega and LED strip. I’ll also just sell the assembled PCB by itself.
New Hardware:
Raspberry Pi Zero W: I have looked into several hardware options and this seems to be a good candidate. I think it will be a simple way to get good audio and connectivity. I have the accelerometer and LED strip working so far. The audio will be an I2S amp chip that will be put on a shield. The (2) drawbacks are boot time (20-30 second) and you are probably limited to APA102C (dotstar) type LED strips. Edit: I got a good portion of the code on the Pi running. It runs fine, but I don’t like the requirement for a slow and controlled shutdown of the Pi. It would require a button and some sort of visual feedback.
TWANG Pi Zero Prototype
If you want to be notified of future blog posts, please subscribe.
While the my TWANG clone has been running great, I wanted to clean up the wiring, so I made a shield to plug into the Arduino. I previously used header connectors plugging into the Arduino. The connectors go to three different places and come from all over the Arduino , so there were a lot of connectors including some single pin ones. I was worried they might pop out or fail. I also had to externally power the LED strip and supply power via USB to the Arduino.
The shield takes care of all of this and groups all of the external connections by function on easy to connect and clearly labeled terminal blocks. Here are the features I have…
Single 5V Power Connector: This connector powers the LED strip via a very heavy trace on the PCB. It also powers the Arduino. The Arduino is powered through a Schottke diode. If you plug in the USB, the Arduino switches to be powered by the USB. This allows you to program and hack the firmware while the LED strip is powered.
Terminal Block Connections: The wires are grouped by peripheral (Accel, Speaker, LED Strip) and clearly labeled.
LED Strip Connections: This powers and controls the LED strip. I have tested it with 4 wire (APA102, Dotstar) and 3 wire (Neopixel) strips.
Speaker Connection: There is an integral 100 Ohm resistor that is required when you directly power the a speaker from an Arduino. The terminal block also has 5V and Gnd in case you want to add a simple amplifier. BTW: Driving the speaker directly from the Arduino is plenty loud in my opinion.
Shield Size: The shield will work on both an Arduino Mega sized board or an Arduino UNO sized board. The TWANG firmware requires the extra memory of the Mega, but a tiny, reduced feature, UNO version could probably be made.
Life LEDs: There are provisions for 3 LEDs that are typically used to show remaining lives. I have not been using those. I prefer to use the LED strip to show remaining lives. I like working with the restriction of a 1D LED strip display.
Prototype Assembly Notes: I did not have all of the correct parts for the build. I did not have a 100 Ohm SMD part, so I tacked on a through hole part. I did not have the right terminal blocks, so I cut one and only used 3 positions for the speaker. The correct parts will arrive soon.
Here are some more images.
Future Changes
I will probably get rid of the life LEDs.
I will add a large capacitor for sensitive LEDs, like Neopixels. Right now I just connect the cap to the terminal block.
I will probably sell the rest of this batch on my Tindie store in a week or two. I will probably sell assembled boards and full assemblies (less LED strip and Mega)
I will release of the documentation under an CC4.0-A-SA license.
If you want to be notified of future blog posts, please subscribe.
I have been playing with the ESP32 microcontroller to see how well it would perform as a small scale CNC controller. The low cost and high performance as well as the built in Wifi and Bluetooth make it very attractive.
One of the challenges is step pulse timing. Most stepper drivers work with a direction signal and step signal. The step signals are a short pulse for each step. If they are too short, the driver will not detect them. If they are too long, it limits the rate at which you can send them.
You first set the direction signal high or low depending on the direction you want the motors to spin. You then send the step pulse. The direction signal has to be stable for a short period of time before the step signal is sent. The process is…
Set direction
Wait a bit (if it changed)
Turn on the step pulse signal.
Wait a bit
Turn off the step pulse signal.
The timing is critical and varies by motor driver. Here is a typical spec.
Here are the specs for a few of the stepper drivers I regularly use.
Allegro A4988
TI DRV8825
Toshiba TB6600
Direction Delay
200ns
650ns
?
Step Pulse Delay
1us
1.9us
2.2us
Test Firmware
Typically the firmware motion planner determines when to take a step, then sets an interrupt to occur at that time in the future. This allows the firmware to do other things like interacting with the user and planning future moves while it is waiting for the interrupt.
To simulate a stream of pulses, I created a timer interrupt that would case steps to occur at a constant 5kHz rate. That is onStepperDriverTimer() in the code.
In that interrupt service routine I first set the direction pin. Normally you only need to set it when the direction changes, but it will be easier to see this on a logic analyzer if I change it every time for this test. I then need to wait a little time before setting the step pulse pin. I could use another interrupt to do this, but the time is so short at about 750ns, that it is better to just waste a few cycles. In the CNC software I will only need to do this when the direction changes. That will be at the few beginning of the acceleration when the step rate is the slowest. I do this delay with a few NOP()s. The are “no operations”.
I then setup the the interrupt to end the pulse. That is onStepPulseOffTimer() in the code. I set the step pin after this because those instructions take clock cycles too. I can use those as part of my delay.
When that interrupt occurs, I turn off the step pulse signal. I also turn off the direction in this example. I am only doing it here so I can see that change on the logic analyzer. Normal CNC frmware would just leave it alone because there are typically thousands of steps before the direction is likely to change.
I wrote a program to simulate some CNC firmware so I could play with step pulse timing.
// create the hardware timers */
hw_timer_t * stepperDriverTimer = NULL; // The main stepper driver timer
hw_timer_t * stepPulseOffTimer = NULL; // This turns the step pulse off after xx uSeconds
// define the gpio pins
#define STEP_PIN 17
#define DIR_PIN 16
// the step pulse interrupt service routine.
void IRAM_ATTR onStepperDriverTimer()
{
// if ... the direction changed from last time (not in this demo)
digitalWrite(DIR_PIN, HIGH); // in actual CNC firmware this will go high or low
for(uint8_t i=0; i&lt;10; i++)
{
NOP(); // do nothing for one cycle
}
// end if
// setup the pulse off timer
timerWrite(stepPulseOffTimer, 0);
timerAlarmWrite(stepPulseOffTimer, 22, false); // the alarm point is found by looking at logic analyzer
timerAlarmEnable(stepPulseOffTimer);
digitalWrite(STEP_PIN, HIGH); // put it after the timer setup to include the timeto do that
}
//
void IRAM_ATTR onStepPulseOffTimer()
{
digitalWrite(STEP_PIN, LOW); // end step pulse
digitalWrite(DIR_PIN, LOW); // only here for dem program CNC firmware would leave this until direction change
}
void setup() {
pinMode(DIR_PIN, OUTPUT);
pinMode(STEP_PIN, OUTPUT);
stepperDriverTimer = timerBegin(0, 4, true); // 80Mhz / 4 = 20Mhz// setup stepper timer interrupt ... this will simulate a flow of steps
stepPulseOffTimer = timerBegin(1, 1, true); //
// attach the interrupts
timerAttachInterrupt(stepperDriverTimer, &amp;onStepperDriverTimer, true);// attach the interrupttimerAttachInterrupt(directionDelayTimer, &amp;onDirectionDelayTimer, true);// attach the interrupt
timerAttachInterrupt(stepPulseOffTimer, &amp;onStepPulseOffTimer, true);// attach the interrupt
// setup the time for the
timerAlarmWrite(stepperDriverTimer, 4000, true); // 20Mhz / 4000 = 5kHz rate ... this is the only one that auto repeats
timerAlarmEnable(stepperDriverTimer);
}
void loop() {
// no loop code required.:
}
Results
Here is a picture of my setup.
This is screen shot of what the logic analyzer captured. The upper line is the step signal and the lower line is the direction signal. The direction signal comes on first and then the step pulse signal comes on 0.75us later. The step pulse then lasts for about 2.5us before turning off.
Next Steps
I’ll go forward this method to see how well it works in actual CNC firmware.
I have been programming in the Arduino-ESP32 environment. This is an easy way to learn about the peripherals and do some quick tests. I may switch to the ESP-IDF in the future.
I would like to investigate the RMT features of the ESP32. It is designed for Remote Controls, but I have heard it is quite flexible and might help with pulse generation.
If you want to be notified of future blog posts, please subscribe.