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.

TWANG!

I have been a Patron of Robin Baumgarten for a while. He makes experimental hardware for games. His Line Wobbler one dimensional dungeon crawler is my favorite and I have always wanted to play it. It uses a door stop spring as the controller. An accelerometer in the knob allows it to work like a joystick and also detect the wobble used to attack the enemies.

Original Line Wobbler (Robin B.)

After seeing his playable Christmas tree version of the game, I had to make one for myself. I could not find any source files that he published, but I was able to find an open source clone called TWANG. The game is quite fun and surprisingly challenging.

Original Twang Version

Electronic Hardware

Here is a list of the electronics hardware used.

  • Arduino Mega.  The Mega is way overkill for the I/O requirements, but an UNO does not have enough memory.
  • MPU-6050 3 Axis Accel/Gyro Breakout Board. These are available for about $5 and have good library support for Arduino.
  • Small Speaker. I bought a pair of external PC speakers at Micro Center for $4 and pulled out some 2″ speakers. You need to use a 100 Ohm resistor on one of the wires.
  • RGB LED Strip: The default code is written for the APA102 type strips. The FastLED library used also supports the cheaper WS2812 (Neopixel) strips. I used a 144 LED 1 meter APA102 strip. The Clock and Data type strips can work faster and they typically have an overall brightness factor that gives them a more useful brightness range than Neopixels. The brightness of these strips is insane and you typically run them at about 1/2 brightness.
  • Life LEDs: You can use 3 individual LEDs to indicate the number of lives you have left. I decided to skip that. I preferred the simplicity of a signal display element. I added a game over animation to the game to make it more clear that you are dead, dead.

Printed Parts

I created my own 3D printed parts. I was having trouble with the TWANG Thingiverse files. They are OBJ files and the parts are grouped. Cura was not creating good prints. My speaker was not going to fit anyway.

  • Chassis: I made a heavy walled enclosure to give it a little weight and make it extra strong.
  • Cover: The cover is also very thick. The speaker mounts in a pocket and is attached with hot glue.
  • Spring Clamp. This holds the spring to the cover securely. I also added a little hot glue to prevent it from rotating.
  • Knob Base. This is very similar to the official TWANG version. It has a longer, threaded interface to grab the spring. This parts takes a lot of abuse.
  • Knob Top: Snaps on, but also gets a little hot glue.

The Firmware

The firmware is well written and pretty easy to follow. You need to download a lot of libraries. Some can be installed from the Arduino IDE and some must be downloaded manually. This is pretty well explained on the Github page.

Everything works on a 60 frames/second loop. This includes the display and the sound. I was able to tweak a few things easily and add a game over animation.

The levels are very easy to edit. You really don’t need to know how to program. I tweaked a few to make them easier for beginners.

Assembly

Build Spring Assembly

  • Solder wires to the accel module.
  • Slide the spring clamp over the spring.
  • Assemble the knob to the spring top.
  • Feed the wires through the knob base and spring.
  • Screw the module to the knob base.
  • Attach the knob top to the knob base.

 

 

Attach Spring to Cover (make sure spring stays vertical when attaching)

  • Adjust the metal spring base until the spring stands vertically.
  • Put a little bead of hot glue in recess on the cover
  • Feed the wires through and place the spring in the recess.
  •  Put a little hot glue around the spring where the clamp goes. Screw it down.

Attach Speaker to Cover

  • Blah
  • Attach some wires. Put a 100 Ohm, 1/4W inline on one of the wires.

Assemble Base

  • Install the Arduino Mega into the base with screws.
  • Connect all the wires per the graphic below. I wired the accel SCL/SDA at the left end, but you can also wire them to pins 20 & 21 at the right end.
  • Attach Cover

Usage

  • You need to power the LED strip with a separate 5V power supply. I used a 10A supply for my 144 LED strip.
  • You also need to power the Arduino. The easiest way is to do it via the USB port.  You could wire the power supply in the first step to the 5V on the Arduino, but be careful to never power from the power supply and the USB at the same time or something will likely break.
  • Note: I have been hooking up the LED power first. When I only power the Arduino, I see some flickering of LEDs.  That concerns me that it is drawing some power from the I/O pins.

Next Steps.

  • Make it Easier to Build: The wiring is a pain and probably not too durable. I used pins crimped into connectors that mated to the Arduino Mega. To make it easier I designed a little shield with screw clamps. It will also power the Arduino through a diode that will allow the USB to also be used. The speaker resistor is part of shield. It is also compatible with an Arduino UNO, so a pocket sized TWANG might be possible. That arrives next week. I will likely sell the extras on Tindie.
  • ESP32 Version: I would really like to try this. The sound and speed should be better and the ability to network with another player sounds cool. It is also smaller and cheaper.
  • Scoring System: Everyone want to compete.

Video

Here is a video of the Twang.

 



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

Coasty Source Files

A lot of people have asked about building their own Coasty Laser Cutter. It takes a lot of work to get the files ready for release. I will release the source files in stages as they are ready so people can get started. Watch this post for updates. Subscribing to this blog or following me on Twitter (@buildlog) is a good way to keep up.

When everything is ready, I’ll probably also post on Thingiverse.

3D Printed Parts

Here are the STL files for the 3D printed parts. The parts are generally pretty easy to print. They require no support and can be printed in low resolution. I print at 0.28mm layer height. You need to watch out for warping on the chassis and front door. If the chassis warps it will stress the PCB and could damage some parts. The door needs to be flat in order to close properly.

I printed my parts in generic PLA. They printed fine, but if you have some crappier PLA or if you don’t have a heated bed, you should probably print with a brim. I would suggest printing the chassis first. If you can print that, the other parts are easier. I have some PETG on order to test. That supposedly warps less that PLA.

The holes used for the 8mm rods are designed to be a press fit. If the rods are hard to install, try cleaning the holes up a little by hand with a 5/16 or 8mm drill. The drive shaft bearing is also a tight fit. Try using a vise or clamp to press it into the chassis.

Zip File containing the STL files.

Mechanical BOM

 

Part DescriptionQtySupplierSupplier P/N
3mm Smooth Pulley (16T equiv dia.) 6mm Wide1
Bearing 3mm x 10mm x 4mm2Generic623-2RS
BEARING 5mm 16mm 5mm1Generic625-2RS
Bearing Shaft 8mm2
Butoon Head Screw M3 x 302
Button Head Screw M3 x 121
Button Head Screw M5 x 201
Coasty Chassis13D Print
Coasty Controller Assy1Buildlog.netCoasty Controller
Coasty Drive Shaft13D Printed Part
Coasty Final Assembly1---
Coasty Laser Carriage13D Printed Part
Coasty Laser Carriage Assy1User Assembly
Coasty X Motor Cover13D Printed Part
Dual Fan Cover13D Printed Part
Flat Head Screw M3 x 64
GT2 Belt 6mm Wide cut to 385mm1GenericGT2 6mm
Hex Nut M33
Laser Module 3.5W 450nm1EleksmakerLA03-3500
Linear Shaft Bearing 8mm Dual2GenericLM8LUU
NEMA14 Stepper Motor2Generic
StepperOnLine
14HS13-0804S
Nylock Locking Nut M22
Nylon Locking Nut M33
Pan Head Screw M2 x 122
Silicon Oring #9052McMaster Carr1283N428
Socket Head Screw M3 x 820
Socket Head Screw M3 x 162
Socket Head Screw M3 x 203
Timing Pulley GT2 18T 6mm Wide 5mm Bore1
Wiring Cover13D Printed Part
Coasty Window149mm x 76mmJ Tech PhotonicsRating: OD+4 @ 445nm
Coasty Door13D Printed Part
Beam Stop (Metal Strip)170mm x 9mm x (0.5mm - 1.5mm)Fabricated

 

PCB Source Files

See this blog post

Firmware

Coming Soon

Build Instructions

Assembly Drawing


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

Coasty Controller Setup and Use Instructions

 

I have receive a lot of requests to sell Coasty laser cutters. It just is not practical for me to do this at this time, but the parts are easy to buy and/or print yourself. The only part that is difficult is the custom controller. I have about 10 extra ones and will sell them. If they go quickly I may buy more. They are here in my Tindie Shop.

What you get with the controller.

  • Fully assembled PCB
  • Arduino Nano programmed with Grbl and setup for the Coasty
  • An HC-05 Bluetooth module programmed with the proper settings baud rate.
  • (2) TI DRV8825 stepper motor drivers with heatsinks and the current set to a recommended value
  • (2) Fans with wires trimmed and connectorized.
  • A cable for the laser module
  • A door switch switch with proper length wires and connector.

These are the only electronic items you need to provide.

  • Laser Module: It is designed for the Eleksmaker 3.5W LA03-3500. Most other types probably won’t fit in the tight size of the Coasty or bolt properly to the PCB
  • 12V Power Supply: I recommend about 5A of current. They can be found on Amazon for less than $10. Make sure it has a standard barrel connector end.

Default Calibration

The controller will come setup with settings that work for me. You can fine tune the settings later, but these should get you started. Here are the settings you see if you send the $$ command to Grbl. The setting codes are listed here.

$0=10
$1=25
$2=0
$3=0
$4=0
$5=0
$6=0
$10=2
$11=0.010
$12=0.002
$13=0
$20=0
$21=0
$22=1
$23=3
$24=300.000
$25=2000.000
$26=250
$27=2.000
$30=1000
$31=0
$32=1
$100=88.889
$101=79.906
$102=250.000
$110=10000.000
$111=15000.000
$112=500.000
$120=750.000
$121=350.000
$122=50.000
$130=200.000
$131=200.000
$132=200.000

The homing switches locate the edge of the coaster and the left extent of the laser travel. This is not the X,Y zero of the work area on the coaster. That is set by the G54 work offset. The G28 and G30 locations are also set so they can be used as a coaster eject command. Here are the offsets you will see if you send the $# command.

[G54:-186.500,-245.000,0.000]
[G55:0.000,0.000,0.000]
[G56:0.000,0.000,0.000]
[G57:0.000,0.000,0.000]
[G58:0.000,0.000,0.000]
[G59:0.000,0.000,0.000]
[G28:-141.000,-138.000,0.000]
[G30:-141.000,-138.000,0.000]
[G92:0.000,0.000,0.000]
[TLO:0.000]
[PRB:0.000,0.000,0.000:0]

Note: If you want to reset the G54 to the value above send this command  G10 L2 P0 X-186.500 Y-245.000 Z0.000 For more information regarding work offsets see this video. You could also manually jog the machine to the exact position you want the 0,0, to be and send this command G10 L20 P0 X0 Y0 Z0

Testing

I will pre-test every controller, but there are many machine dependent things that need to be tested before safely operating the machine. You should only need to run these tests once.

  1. Watch this video completely before testing anything. You will get a general overview of the machine that will help you understand and successfully test it.
  2. Remove the Bluetooth Module. It will be easier to test with USB. Never use USB with the Bluetooth Module installed.
  3. Do not connect the external power supply until advised.
  4. Make sure the little power push button switch on the controller is in the off (out) position. This switch controls the laser and fans only. Other circuits remain on regardless of switch position.
  5. Connect a USB cable.
  6. Open a serial terminal connection at 115200. The terminal should be setup to send a carriage return at the end of each line. The Arduino IDE Serial Port Monitor is an easy terminal to use.
    1. It should reply with Grbl 1.1f [‘$’ for help] and  [MSG:’$H’|’$X’ to unlock] when connected
  7.  Send a question mark ?
    1. It should replay with some status like <Alarm|WPos:186.500… , but not have any switch status like Pn:…
  8. Send the $$ command.
    1. The values in the response should match the values listed in the calibration section above.
  9. Send the $# command
    1. The replied values should match the values listed in the calibration section.
  10. Connect power to the controller, but do not turn on the controller’s power switch. Be ready to pull the plug if anything goes wrong. The machine might make some motor noises as the motors engage for brief period.
  11. Open the door.
  12. Manually slide the laser carriage to the left to activate the X home switch.  While it is activating the switch send ? again.
    1. You should see Pn:X in the response.
  13.  Block the IR detector with a coaster and send ? again. Note: The IR detector requires external power and will always register as “on” when there is not external power.
    1. You should see Pn:Y in the response
  14. The next step is to test homing. There is a chance that it will home the wrong way, so be ready to disconnect power. You must pull the plug at the controller to fill power. Watch for the laser to move to the left and the coaster to move in.
  15. Send the $H command at the serial terminal.
    1. As soon as the motors start, watch for the laser to move to the left and you should feed in a coaster.
    2. If either go the wrong way, pull the plug.  See fixing direction errors below.
    3. The machine will only try homing for a few seconds. If you were unable to get it started in time, try $H again.
    4. If the coaster does not run smoothly you might need to sand the track a little.
  16. After a successful homing, send G1 X0 Y0 F400
    1. The machine should move so the laser is over the lower left corner of the coaster.
  17. Send G28 to eject the coaster. Remove it completely from the machine.
  18. Close the door and screw it shut.
  19. Turn on the laser with the push button. You should hear the fans turn on, but the laser should not fire.
  20. You will now test fire the laser. You only want to test fire it for a should period of time at low power.  Send the following commands. While the power will be low, do not leave it on for more than a second or 2.
    1. $X (this will make should the machine is not in alarm mode)
    2. G91 (this will allow you to move it in incremental mode)
    3. S10 (This will set the beam power to 1%. Full power is S1000)
    4. G1 X3 F400 (This will move the laser 3mm to the right. The primary purpose is to put the controller into g1 mode where we can turn on the laser)
    5. M3 (should turn on the laser. It will not be very bright.
    6. M5 (turn it off)
  21. Assuming all tests passed, the machine should be ready to use.

Fixing motor direction Errors

The easiest way to fix direction errors is to rotate the connector for the problem motor by 180°. The upper motor is for the X (the laser carriage) and the lower motor moves the coaster.

Rev 2.0 PCB Issues

  • There was one mistake on the PCB due to net naming issue. The 12V input did not get connected to the 12V to 5V DC power supply.  A small rework wire has been added on the back side of the PCB.

Source Files

Use Instructions

See this blog post … [Coming Soon]


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

Coasty Version 1.2

Here are some updates to Coasty – The Coaster Toaster,  the tiny laser cutter specifically designed to cut drink coasters.

New Traction Roller

I made the traction roller diameter a lot smaller and moved it behind the beam. A smaller roller has a lot of advantages. It allows the beam to be closer to the contact points of the rubber orings. This improves the usable work area, because you can get closer to the edge of the coaster. With a smaller diameter the coaster travels less per revolution. This increases the torque and resolution.

Smaller Chassis

The chassis is now about 16mm smaller in depth due to the smaller roller and new location. The depth of the machine is quite a bit smaller than the coaster.

Fan Guard and Carbon Filter

I added a fan cover on the back. This acts as a finger guard and also allows a few layers of carbon filter cloth to be used. Bulk carbon filter cloth for use in air purifiers can be purchased on Amazon very cheaply. It removes a good portion of the odor of the smoke.

Carbon Filter Cloth

Door Interlock Switch

There is now a switch that cuts all power to the laser when the door is opened. You can still run the machine to test the motors, homing etc, the the beam cannot turn on with the door open.

IR Coaster Detector

 

I was not happy with the coaster homing switch used on the first version. While it never failed, it did not appear to be very robust and it caused some drag on the coaster. I changed to a IR LED and photo diode. When the light from the LED hits the photo diode, it conducts to the +5V. When the coaster blocks the light, it is pulled down to ground. I used a pot on the pull down because it did not know what he exact value would be. It turns out the value needs to be about 40k. The only catch was the microcontroller input pin pull up resistor on the Nano could not not used because it is less than the 40k.  This required a slight hack to Grbl because Grbl is all or nothing on the pull ups for the limit switches.

I was not sure if ambient light changes might be a problem, like bright sunlight. The photo diode looks down and that appears to be good enough to avoid overhead light. I also have a mounting screw there in case I need to add a little shade/cover.

IR LED / Photo Diode Circuit

 

Bluetooth

I have been using Bluetooth on some other machines and really like it. Skipping USB cords and using a phone instead of a computer is great. I have found it to be very reliable. The real world bandwidth appears to be a little lower than 115200 USB. It has not been a problem, but I don’t do much gray scale engraving on this machine which needs higher bandwidth. Regardless, USB is still an option.

A standard HC-05 or HC-06 module plugs into a right angle connector.

Video

Here is a video of this version.


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

ESP32: Sending short pulses with the RMT

Well that was easy!  About an hour ago I wrapped up a blog post on creating stepper motor driver pulses with the ESP32 using timer interrupts. I added a to do list at the end to look into using the RMT peripheral to do this. It only took about an hour to figure out.

RMT stands for “remote control”. It was designed for things like an IR remote control where tight timing on GPIO is required. The peripheral has a lot of features that make it good for a lot of things. Some people have been using it for the notoriously tight timing of the NEO Pixels.

The documentation is pretty complete on the API, but there are very few examples and tutorials. Most that do exist are for complicated things and not too well commented. This Ebook by Neil Kolban has a good example that my code started from. Look for the section called “RMT – The Remote Peripheral”. Due to my limited knowledge of the RMT, I will only go over my implementation.

Basically you start with two structures…(also see code below)

rmt_config_t config;

This is used to setup the configuration. I set config.clk_div = 80 so that each unit of time in my setup is 1us.

rmt_item32_t items[1];

This is an array of items that represent the outputs transitions that you want. In my case I only want a transition to high for 3us and then transition to low with no duration . Here is the definition of that struct.

typedef struct {
    union {
        struct {
            uint32_t duration0 :15;
            uint32_t level0 :1;
            uint32_t duration1 :15;
            uint32_t level1 :1;
        };
        uint32_t val;
    };
} rmt_item32_t;

Here is my code. I had the pulse repeat with a 1us delay, so that is would be easy to catch some on my logic analyzer.

#include <driver/rmt>

#define STEP_PIN  GPIO_NUM_17

// Reference https://esp-idf.readthedocs.io/en/v1.0/api/rmt.html

rmt_config_t config;
rmt_item32_t items[1];



void setup() {
  // put your setup code here, to run once:
  config.rmt_mode = RMT_MODE_TX;
  config.channel = RMT_CHANNEL_0;
  config.gpio_num = STEP_PIN;
  config.mem_block_num = 1;
  config.tx_config.loop_en = 0;
  config.tx_config.carrier_en = 0;
  config.tx_config.idle_output_en = 1;
  config.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
  config.tx_config.carrier_level = RMT_CARRIER_LEVEL_HIGH;
  config.clk_div = 80; // 80MHx / 80 = 1MHz 0r 1uS per count

  rmt_config(&amp;config);
  rmt_driver_install(config.channel, 0, 0);  //  rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int rmt_intr_num)
  
  items[0].duration0 = 3;
  items[0].level0 = 1;
  items[0].duration1 = 0;
  items[0].level1 = 0;  

}

void loop() {
  // esp_err_t rmt_write_items(rmt_channel_t channel, rmt_item32_t *rmt_item, int item_num, bool wait_tx_done)
  rmt_write_items(config.channel, items, 1, 0);
  delay(1);
  
  
}

Here is a screen shot of the output on a logic analyzer. (Step/dir signals are swapped in the labels)

Conclusion

I think this will work great. This will will be very efficient and rum completely in the background. I will definitely try to move ahead with this method.


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&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.

Using The midTbot Controller

The midTbot Controller is a controller for midTbot pen drawing machines. It is sold on my Tindie store. When fully populated, it has the following features.

  • (2) Stepper Motor Drivers for the X and Y axes with microstepping selector jumpers
  • Servo Connector for Pen Lift
  • Arduino Nano Controller
  • 5V power supply
  • (2) Homing switches
  • Bluetooth connector for HC-05 or HC-06 module.
  • Aux power connector for easy access to 5V and 12V power.

Power Supply

You will need a 12V DC power supply with at least 3A of power. The DC plug should be a coaxial 5.5mm x 2.1mm type with center positive. This type of plug is the most common type and should be pretty easy to find.

Microcontroller.

You should use an Arduino Nano compatible controller. The controller bootloader will need to be changed to the smaller Arduino UNO bootloader in order to fit the firmware. I have instructions on how to do this here. If you would like to buy one already modified, I sell them on my Tindie store. Be sure to install the controller in the correct orientation. The USB connector should face the edge of the controller as noted on the silkscreen of the controller PCB.

Stepper Drivers

You will need 2 stepper driver modules. I recommend ones based on the Allegro A4988 controller or the TI DRV 8825 controller. The drivers often come with heatsinks. The current will typically be set low enough that heatsinks are not needed.

You will need to set the microstepping level. I recommend using 1/8 microstepping. That gives a good balance of accuracy, smoothness and speed. You set this using the jumper blocks. Each stepper driver type has its own configuration. Here are the jumper setting for A4988 and DRV8825

Microstep ResolutionA4988 JumpersDRV 8825 Jumpers
FullNoneNone
1/2MS1MS1
1/4MS2MS2
1/8MS1 + MS2MS1+MS2
1/16MS1+MS2+MS3MS3
1/32Not AvailableMS1+MS2+MS3

Note the MS1, MS2 & MS3 labels next to the jumpers.

The orientation of the drivers is very important. You will break the drivers and likely other parts if you insert them wrong. Most drivers have the pins labeled and the the controller PCB has the corner pins labeled. Be sure the labels match. Here are the correct orientations for the A4988 and DRV8825.

You should set the stepper driver output current to the level required by your stepper motors. The midTbot does not need a lot of power. If you set the power too high, the motor could get hot and damage the 3D printed part it mounts to. You set the current by adjusting a potentiometer and reading a voltage. The drivers need to be powered when you do this. You can install them and power the board to do this. Do not connect the motors when adjusting the potentiometer. Each driver will have a small hole with exposed metal. This is the measurement point. The metal adjustment screw of the potentiometer is also a place you can measure. The reference voltage to current formulea are here.

DRV8825 Current = VREF * 2   (Example 0.4V = 0.8A current)

A4988 is a little more complicated because there are different versions. See this page.

Stepper motors:

The controller is designed for NEMA14 motors. Be sure to get 4 wire motors. Just about any size should work, but I prefer to use smaller ones to keep the size and weight down. You will need to attach connectors to them.  Trim the wires to the correct length so they reach the board connectors when installed. Wires colors should be installed as shown.

The wiring legend on the board that shows where to plug in the motors might not be right. It depends on the way the motor manufacturer wired the coils and which stepper drivers you use. You may need to swap them or rotate the connectors 180° if your axes are moving the wrong way. Here is a photo of how mine are wired. Try this first. Note the wire colors and which motor goes to which connector.

Bluetooth

You can add an HC-05 or HC-06 Bluetooth module. They have different connectors, but just match the pin names on both sides. You will need to setup the module to have a baud rate of 115200, N,8,1. I have detail on how to do that here (HC-05, HC-06).

 

 


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 &lt;SoftwareSerial.h&gt;

#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.

Notes On Using The HC-06 Bluetooth Module

A couple weeks ago, on a whim, I added to add a Bluetooth module to my Amazon cart. I think I paid about $7 for it. I chose the HC-06, because it sounded better than the HC-05. I was wrong, but probably made the right choice. More on that later.

The module came with no documentation, but it was easy to find the default values via web searches.

  • Name: HC-06
  • Password: 1234
  • Baud: 9600

I powered up the module. A single red LED started blinking.

I searched for it with my PC. I saw a new device called HC-06. I was able to pair with the default password. The LED did not change. It continued to blink. I checked my settings and saw this.

I was pleasantly surprised because I thought there was going to be some deep Bluetooth programming involved. A virtual COM is perfect.  I tried opening COM12 using a Serial Terminal. It took a couple seconds, but the LED changed to constant red and the Serial Terminal was happily waiting for me to send stuff. Without anything connected to the TX and RX pins, sending stuff was not going to do anything. I was eager to test with Grbl so that meant changing to 115200 baud.

Changing the default values

You change values on the HC-06 using an AT command set. These are sent to the HC-06 on the RX and TX pins at the current baud rate. The HC-06 is in the mode to accept the commands when it is not paired and connected (blinking red LED).  You cannot use the AT commands over Bluetooth.

There are a lot of AT commands, but the ones we will use are here…

  • AT (it will simply respond “OK”. A good test to see if you are in AT command mode)
  • AT+NAMExxx (Example AT+NAMEFRED will set the name to FRED)
  • AT+PINnnnn (nnnn is a 4 digit password. Example AT+PIN1288 will set the password to 1288)
  • AT+BAUDn (where n is code number for the baud as follows. Example AT+BAUD8 will set the baud to 115200)
    • 1 = 1200
    • 2 = 2400
    • 3 = 4800
    • 4 = 9600
    • 5 = 19200
    • 6=38400
    • 7=57600
    • 8=115200
    • 9=230400
    • A=460800
    • B=921600
    • C=1382400

The commands are sent without a carriage return or line feed and must be sent within a second. If you are using a serial terminal, make sure it is not sending each character as you type it or you are probably not going to get the whole command out within the second. Most terminals have a mode to send the a whole line. The Arduino IDE Serial Monitor works this way. Make sure the terminal settings are correct.

Using an Arduino to setup the HC-06

We need some hardware to talk to the HC-06 using 3.3V TTL. An Arduino will easily do that. Here is a diagram and sketch to do this using the Arduino Serial Monitor.

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. This will use the hardware RX and TX pins. We also need a serial connection from the Arduino the HC-06. We will use a software serial port for this and can use any remaining pins to do this.

This is the hardware diagram. I show an UNO, but virtually any hardware (Nano, Mega, etc) will work. The HC-06 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-06, so we don’t need to shift that.

 

BTW: A lot of people don’t bother to shift the 5v down to 3.3V and it seems to not break anything, at least in the short term 🙂

Here is the sketch I use. By default the HC-06 is set to 9600 baud. If you change via the sketch, you will need to edit the line “hcSerial.begin(9600);” to current baud rate. This sketch strips out carriage returns and line feeds, so you can leave those on in the Serial Monitor.

#include <SoftwareSerial.h>
SoftwareSerial hcSerial(11, 12); // RX, TX

String fromPC = "";

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

  // print instructions
  Serial.println("HC-06 AT Command Programming");
  Serial.println(" -- Command Reference ---");
  Serial.println("AT (simply checks connection)");
  Serial.println("AT+VERSION (sends the firmware verison)");
  Serial.println("AT+NAMExxxxx (to change name to xxxxx");
  Serial.println("AT+PINnnnn (to change password to 4 digit nnnn");
  Serial.println("AT+BAUDn (to change to baud rate #1");
  Serial.println("  BAUD1 = 1200");
  Serial.println("  BAUD2 = 2400");
  Serial.println("  BAUD3 = 4800");
  Serial.println("  BAUD4 = 9600");
  Serial.println("  BAUD5 = 19200");
  Serial.println("  BAUD6 = 38400");
  Serial.println("  BAUD7 = 57600");
  Serial.println("  BAUD8 = 115200");
}

void loop() {
  // Read from HC-06
  if (hcSerial.available()) {
    while(hcSerial.available()) { // While there is more to be read, keep reading.
      Serial.print((char)hcSerial.read());
      }   
  }
  
  // Read from PC
  if (Serial.available()){
    delay(10); //     
    fromPC = (char)Serial.read();    
 
    if (fromPC == "r" || fromPC == "n") {  // don't send carriage returns to HC-06          
      Serial.println();  // echo it back to the PC
    }
    else {
      hcSerial.print(fromPC); // show the HC-06 responce
      Serial.print(fromPC); // echo it back to the PC
    }
  }
}

Using the HC-06 as a virtual serial port

If you want to use it for Grbl, you will need to change it to 115200 baud with “AT+BAUD8”. You can now connect it to your controller Tx and Rx pins. Tx on the HC-06 would go to Rx on the controller.

You then need to pair the HC-06 with the PC using the normal Bluetooth features. It will create 2 virtual COM ports. You need to select the “outgoing” port.   No all programs that use normal COM port can use these ports. When you connect in the program the blinking red light will turn steady red when connected. It take a second or 2.

The Reboot Issue.

Normally Arduinos reboot when you connect. This is due to a trick with the DTR signal. The HC-06 cannot do this trick, so a Bluetooth connection does not reboot the Arduino. This should not be a problem, but some firmwares, like Grbl, send some identifying information at boot. Some senders look for this. They open the COM port and wait for that information. If they don’t see it, they think something is wrong and give an error.

Some senders don’t care and some senders have been using another trick. If they don’t see the information they send a $I command to ask for it.  Ideally all sender will adopt this over time if they want to play with Grbl over Bluetooth and Wi-fi.

The HC-05

There is another device called the HC-05. It is actually more advanced than the HC-06. It can be a master or a slave device. This makes setup a little more complicated, so it was good that I chose the HC-06.  The one thing I want to try is there might be a way to fix the boot issue. The HC-05 might be able to send a connected signal to force that reboot.

 


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