Archive for the 'Programming' Category

DrawBot Badge – Preview

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.

 

 

 

 

 

 

 

Grbl_ESP32 with Bluetooth Serial Support

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.



 

 

 

TWANG Shield Rev. 2

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.

Where to Get One

They are currently for sale on Tindie.


If you want to be notified of future blog posts, please subscribe.

TWANG32 – An ESP32 Port of TWANG

 

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.

 

Game Audio for the ESP32

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.

ByteLengthDescription
04Always "RIFF"
44File size in Bytes
84Always "WAVE"
124Always "fmt " with a null
164Length of format
202Audio format (1=PCM)
222Number of channels
244Sample rate
284Byte Rate
322Block Align
342Bits per sample (8,16)
364Alaways "data"
404File size
44...Start of data

References

I found some good references to help me with this library.

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.

unsigned char PROGMEM pacman[33850] = {
  0x52, 0x49, 0x46, 0x46, 0x32, 0x84, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45,
  0x66, 0x6D, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
  0x40, 0x1F, 0x00, 0x00, 0x40, 0x1F, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00,
  0x64, 0x61, 0x74, 0x61, 0xC6, 0x83, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x7F,
  0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
  0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
  0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7E, 0x80, 0x7E, 0x80, 0x7E, 0x80,
  0x7E, 0x80, 0x7D, 0x84, 0xA2, 0x9F, 0xAF, 0xC0, 0xCE, 0xE1, 0xED, 0xF1,
  0xED, 0xE8, 0xDC, 0xCB, 0xB5, 0xA4, 0x95, 0x92, 0x91, 0x94, 0x9D, 0xB1,
  0xB6, 0xB5, 0xB9, 0xBB, 0x99, 0x7D, 0x66, 0x51, 0x64, 0x65, 0x5E, 0x74,
  0x9D, 0xAF, 0xC9, 0xC4, 0xB8, 0xC1, 0xBB, 0xA3, 0x89, 0x73, 0x54, 0x3B,
  0x2E, 0x30, 0x35, 0x42, 0x56, 0x70, 0x7F, 0x89, 0x8E, 0x8C, 0x86, 0x77,
  0x5E, 0x49, 0x3E, 0x34, 0x31, 0x42, 0x5A, 0x72, 0x91, 0xB1, 0xC2, 0xC1,
  ...... 

 

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.

Using the library

  • Download the zip file.
  • 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.

TWANG Play Testing

 

I took my TWANG Clone to ORD Camp, NERP and the Hardware Happy Hour Meetup over the past week. It got a ton of play time.  I received a lot of feedback to work on.

Observations and Feedback.

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.

TWANG Shield

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.

ESP32: Step Pulse Experiments with Timers

(Edit: Also check out my better “RMT” way to send the pulse)

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…

  1. Set direction
  2. Wait a bit (if it changed)
  3. Turn on the step pulse signal.
  4. Wait a bit
  5. 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 A4988TI DRV8825Toshiba TB6600
Direction Delay200ns650ns?
Step Pulse Delay1us1.9us2.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<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, &onStepperDriverTimer, true);// attach the interrupttimerAttachInterrupt(directionDelayTimer, &onDirectionDelayTimer, true);// attach the interrupt
 timerAttachInterrupt(stepPulseOffTimer, &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.

Using the HC-05 Bluetooth Module

In a previous post I showed how to use the HC-06 Bluetooth module. In this post we will be using the HC-05. They are very similar, but the HC-05 has more features. The ability to be a master is the main feature. A master can create a connection with other Bluetooth devices. In this post we will only being using it as a slave.

The basic module looks like this.

It is typically purchased soldered to carrier PCB with some additional electronics. The HC-05 typically has a 6 pin header, rather than the 4 pin HC-06 header. The two extra pins are state and enable (en). State gives the state of the Bluetooth connection and enable can power down the module by turning off the power regulator. I will not be using the enable. I will use the state to allow programming of the Arduino via Bluetooth.

 

Here is a schematic of the carrier board. Not all carrier boards are the same, though.

The parts on the carrier PCB are pretty basic

  • 3.3V Low Dropout Regulator, which allows you to power it from 3.6V to 6V.
  • An LED to show the mode.
    • Fast Blink = Waiting for Bluetooth connection3.6
    • Slow Blink = In AT command mode
    • Double Blink = Connected via Bluetooth
  • A button to enter AT Command Mode
  • A diode, probably for reverse voltage protection.
  • Various Pull Up/Down resistors and bypass capacitors.

Configuring the HC-05

Like the HC-06, the HC-05 has a AT command mode, but the commands are a little different. The HC-05 is put in the AT command mode by holding in the switch while applying power. It will do a slow blink when in AT mode. AT Mode accepts commands at 38400 baud , N,8,1 using the Rx and Tx pins. You should level shift the Tx out of your Arduino to 3.3V using a resistor divider. Commands are sent with line feed and carriage return appended to the end. Most serial monitors can do this for you including the Arduino Serial Monitor.

Any command that sets a parameter can also get it.

  • Set commands are in this format “AT+CMD=PARAM” like … AT+NAME=FRED to set the name to FRED. Some commands have multiple parameters that are separated by commas.
  • Get commands are in this format AT+CMD?” like AT+PSWD? to get the password. Weirdly, they all seem to work except AT+NAME?.

Here are the commands you needs for slave mode. Remember, each is followed by a line feed and carriage return.

  • AT (This is just a way to test the connection. It will respond “OK”)
  • AT+VERSION? (This returns firmware version info)
  • AT+ROLE=x (for x use 0 =Slave role, 1 = Master role, 2 = Slave-Loop role default = 0)
  • AT+NAME=xxxxx (to change name to xxxxx default=HC-05″)
  • AT+PSWD=nnnn (to change password to 4 digit nnnn default = 1234″)
  • AT+UART=nnnn,s,p (nnnn=Baud, s=stop bits (0=1, 1=2), p=parity (0=None, 1=Odd, 2=Even) Example AT+UART=115200,0,0
  • AT+POLAR=a,b (a=PIO8 (LED), b=PIO9 for both 0=low turn on, 1 = high turn on. (see below for how we use this)
  • AT+ORGL (reset all parameters to defaults)
  • AT+RESET (restarts the HC-05. Will not be in AT mode afterward unless button held”)

Using an Arduino to program the HC-05

We need some hardware to talk to the HC-05. An Arduino will easily do that. Here is a diagram and sketch to do this using an Arduino UNO.

This is the hardware diagram. I show an UNO, but virtually any hardware (Nano, Mega, etc) will work. The HC-05 is a 3.3V device so we need to level shift the Arduino 5V Tx signal down to 3.3V.  The diagram uses a resistor divider to do this. The Arduino should have no trouble reading the 3.3V Tx signal from the HC-05, so we don’t need to shift that.

The State connection through the capacitor is optional. This will force a reboot of the Arduino when a Bluetooth connection is made. More on that later.

BTW: A lot of people don’t bother to level shift and it appears to work fine, at least in the short term 🙂

The Arduino Sketch

Here is the sketch I use. We will be setting up 2 serial links. One link will be from the PC to the Arduino to send the commands from the keyboard over USB.  We also need a serial connection from the Arduino the HC-05. We will use a software serial port for this and can use any remaining pins to do this. HC-05 uses 38400 baud for AT commands, regardless of the what you set it to for Bluetooth operation.  I used 115200 for the PC to Arduino connection. Set the Serial monitor like this.

You can then type AT commands in the Sereial Monitor.

Here is the sketch…

#include <SoftwareSerial.h>

#define SOFT_RX 11
#define SOFT_TX 12

SoftwareSerial hcSerial(SOFT_RX, SOFT_TX); // RX, TX

String fromPC = &quot;&quot;;

void setup() { 
  Serial.begin(115200); // hardware serial for the USB-PC
  hcSerial.begin(38400);  // software serial Arduino to HC-06 (38400 is default)

  // print instructions
  Serial.println(&quot;HC-05 AT Command Programmer V1.2&quot;);

  Serial.print(&quot;For Arduino Rx use pin &quot;);
  Serial.println(SOFT_RX);
  
  Serial.print(&quot;For Arduino Tx use pin &quot;);
  Serial.println(SOFT_TX);  
  
  Serial.println(&quot; -- Command Reference ---&quot;);
  Serial.println(&quot;To Read use '?', Like AT+PSWD?&quot;);
  Serial.println(&quot;AT (simply checks connection)&quot;);
  Serial.println(&quot;AT+VERSION (requests the firmware verison)&quot;);
  Serial.println(&quot;AT+ROLE=x (0 =Slave role, 1 =  Master role, 2 = Slave-Loop role  default = 0)&quot;);
  Serial.println(&quot;AT+NAME=xxxxx (to change name to xxxxx default=HC-05&quot;);
  Serial.println(&quot;AT+PSWD=nnnn (to change password to 4 digit nnnn default = 1234&quot;);
  Serial.println(&quot;AT+UART=nnnn,s,p (nnnn=Baud, s=stop bits (0=1, 1=2), p=parity (0=None, 1=Odd, 2=Even)&quot;);
  Serial.println(&quot;AT+POLAR=a,b (a=PIO8 (LED), b=PIO9 for both 0=low turn on, 1 = high turn on.&quot;);  
  Serial.println(&quot;AT+ORGL (reset all parameters to defaults)&quot;);
  Serial.println(&quot;AT+RESET (restarts the HC-05. Will not be in AT mode afterward unless button held&quot;);
  
  
}

void loop() {
  // Read from HC-05
  if (hcSerial.available()) {
    while(hcSerial.available()) { // While there is more to be read, keep reading.
      Serial.print((char)hcSerial.read()); // send it to the PC
      }   
  }
  
  // Read from PC
  if (Serial.available()){
    delay(10); //     
    fromPC = (char)Serial.read();    
 
    
      hcSerial.print(fromPC); // show the HC-05 responce
      Serial.print(fromPC); // echo it back to the PC
    
  }
}

Arduino Programming over Bluetooth.

Arduinos are programmed over serial via a bootloader. A bootloader is program that runs for a few seconds whenever the Arduino is started. It looks for someone trying to program it. It runs in one part of the Arduino’s memory. If it does not detect an attempt to program the Arduino it switches to the part of memory where the last program (sketch) resides. If it does detect an attempt to program the Arduino, it reads the incoming program instructions over the serial port and writes them to that other part of memory where normal programs (sketches) reside. Once the upload is complete it switches to that program and runs it.

Therefore, in order to program the Arduino over a serial connection, you need to trigger a reboot. The Arduino USB creates a full RS232 connection. In addition to Rx and Tx is has other control lines like DTR (Data Terminal Ready). The Arduino uses the DTR signal to force a reset. To reset an Arduino you pull the reset line to ground. The DTR signal out of the USB chip is high when there is no connection and low (ground) when there is a connection.

If we directly connect DTR to the reset pin, the Arduino will be stuck in permanent reset mode whenever a serial connection is open. To correct that, a capacitor is inserted in the circuit. Capacitors block a continuous signal, but pass a quick transition. Therefore the the change from high to low will look like a quick pulse to ground at the reset pin. That pulse is exactly what is needed to reboot run the bootloader.

Here is what that circuit looks likes on an Arduino Nano schematic. The length of the pulse depend on the value of the capacitor and characteristics of the high to low transition.

The HC-05 state pin will work for this. In its normal mode it is high during a connection. We need that to be low (ground). Fortunately the HC-05 has the Polar command. That allows you to flip that logic. AT+POLAR=1,0 will do the trick. The first parameter is for the LED. We leave that at 1. The second parameter is the state and we switch that from the default of 1 to 0.

I found that the typical 0.1uF capacitor would not generate an adequate pulse to ground, so I bumped it up to 1.0uF. It occasionally does not work when uploading. I think a little less capacitance might be better. The Arduino uses the hardware serial connections for programming, so you use those pins. When programming the Arduino use the virtual serial port you got when pairing the Bluetooth. Do not use Bluetooth and the USB serial port at the same time. Both would be connected to the hardware Rx and Tx and conflict with each other and possibly cause damage.

 

Other Reset Features

You may not care about uploading code over Bluetooth, but some of your applications may expect that reboot on connect behavior. I have found this with some GCode senders. They open the serial port and expect to see the text Grbl spits out at startup. Without seeing this text, the program wrongly assumes there is a problem and closes the connection.

Video

Useful Links

 


If you want to be notified of future blog posts, please subscribe.

The Polar Coaster – A Drink Coaster Drawing Machine

I designed this machine to draw custom, round drink coasters. I already have a laser cutter for square coasters and I wanted to try something unique for round coaster.

The Base

The base of the machine has two stacked 5mm bearings in the center for the bed to rotate on. There are (3) 3mm bearings on the bed perimeter that provide support and keep it level. They have little shafts that snap into the base.

The Bed

The bed is  a 156 tooth GT2 pulley. It has little springy fingers that grip the coaster when it is on the bed. The bed connects to the motor pulley with a closed loop belt.

The Radial Arm.

This is a belt driven, cantilevered arm that uses 6mm shafts and linear bearings. The belt is a cut pieces with the ends clamped at the carriage. It has a slotted mounting hole that lets the arm rotate. The pen must be adjustable to get to the exact center of the coaster or the drawing will be distorted. There is a limit switch on the top.  This is the only axis that needs to be homed. To setup the machine you home it and jog the pen until it is exactly over the center of the bed. You then set the work zero for X (Gcode: “G10 L20 P0 X0”). This only needs to be done once. If you use different types of pens, the center should be rechecked.

The Z Axis

The Z axis uses a micro servo and a cam to control the height of the pen. The firmware is setup to only have (2) Z positions, pen up and pen down. It uses 3mm rods and tiny little 3mm linear bearings.  There is a compression spring on one of the rods that applies a little pressure to the pen, and allows the pen to float a little on uneven coasters.

The Controller

I used my Grbl HAT controller. It is a bit overkill for this project but works perfectly.  It is attached to a Raspberry Pi in this photo, but I have not been using the Pi in this project yet. I just connect directly via USB.

Kinematics and Pre-Processin

See this blog post on how it was done. The pre-processor is written in C#, but it is rather simple and you could probably read the source file and convert if you cannot deal with C# on Windows.

Firmware

I use a modified version of Grbl 1.1f.  Grbl does not support servos, so I needed to hack that in.  I used the PWM that is normally used for the spindle speed to control the servo. I turned off the variable speed spindle option and streamlined the spindle functions to the bare minimum I thought Grbl needed.  I adjusted the PWM parameters for use with a servo and added pen_up() and pen_down() functions. I tried to put as much of the custom code into one file spindle_control.c. I had to add a few lines in stepper.c to look at the current machine Z height and apply the correct pen up/down function.

CAM

You can use anything to generate the gcode that works with Grbl. The pen will go up when the Z is above zero and down when it is below zero. Therefore, you want the Z movement as short as possible to speed up the drawing and not have the pen dwell on the material and bleed.  I make the depth of cut 1mm and the z clearance 3mm.

CAD Files.

The design was done using PTC CREO 3.0.  A STEP version of the design is linked at the end of the post.

Performance

It does a great job. Here a recent coaster. This was done from a rasterized bitmap image found online (searched: circular Celtic braid).

Here is a Fat Tire beer themed coaster.

Coasters are made to be super absorbent, so larger tipped felt pens tend to bleed a little too much. I like to sketch with Micron pens and the thinner ones really work well on this machine.

Build You Own?

The build is not difficult, but covers a lot of areas. You should know how to work with STEP files and compile firmware.

The design is open source with no commercial restrictions, so feel free to use any part of my work. I found most of the parts on Amazon and eBay. I bought the belt from Stock Drive Products. The polar motor pulley is 36 tooth and the arm pulley is 20 tooth.  Cutting the shafts requires an abrasive cutoff wheel.

Please post any questions in the comments section and I will try to address them.

Links

 

I sell on Tindie