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+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 = "";
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("HC-05 AT Command Programmer V1.2");
Serial.print("For Arduino Rx use pin ");
Serial.println(SOFT_RX);
Serial.print("For Arduino Tx use pin ");
Serial.println(SOFT_TX);
Serial.println(" -- Command Reference ---");
Serial.println("To Read use '?', Like AT+PSWD?");
Serial.println("AT (simply checks connection)");
Serial.println("AT+VERSION (requests the firmware verison)");
Serial.println("AT+ROLE=x (0 =Slave role, 1 = Master role, 2 = Slave-Loop role default = 0)");
Serial.println("AT+NAME=xxxxx (to change name to xxxxx default=HC-05");
Serial.println("AT+PSWD=nnnn (to change password to 4 digit nnnn default = 1234");
Serial.println("AT+UART=nnnn,s,p (nnnn=Baud, s=stop bits (0=1, 1=2), p=parity (0=None, 1=Odd, 2=Even)");
Serial.println("AT+POLAR=a,b (a=PIO8 (LED), b=PIO9 for both 0=low turn on, 1 = high turn on.");
Serial.println("AT+ORGL (reset all parameters to defaults)");
Serial.println("AT+RESET (restarts the HC-05. Will not be in AT mode afterward unless button held");
}
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.
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.
I finished a PSoC 5 daughter card design for X-Controller-Controller project. 10 boards should arrive in about a week. This will clean up all the wiring from the breadboard testing I have been doing. My goal is to have a clean development platform for me and possibly others to work with.
Here is an image of the CYC8CKIT-059 development board. The CPU is a PSoC 5LP. The price is only about $10. It comes with a built in programmer, debugger, and USB/UART. This can be snapped off. To fit into the X-Controller, I snap off the programmer and mount it in another location. The connections are made on the PCB. I plan to use stackable headers so all of the pins are still easily accessible.
The TB6600 stepper drivers I have in the X-Controller have a “Torque” feature. You set the motor current with a reference voltage and the torque feature allows you to easily switch between that current and 1/3 third of it. This is typically used for an idle current reduction feature at the system level.
Why Idle Reduction?
Stepper motors have a lot of hold torque, but that torque quickly falls off with speed. Therefore you typically size a stepper motor and set the current for your maximum cut or rapid speed. This means your motors will have excess torque when idle and will tend to run hottest at idle. You basically the the current as high as possible until the motors get too hot. If you could reduce the current at idle, you would reduce the temperature and could set the current higher than normal when spinning.
This is great, but the machine will never be in idle during a long job. At least one of the motors should always be running. If you could figure out when each individual motor was idle, you handle each motor independently. That is not easy in firmware, but there are tricks to do it in hardware. You could tie the feature to the step pulse. Whenever the step pulse is active, the full torque could be active. That has two problems. The step pulse is extremely short, in the range of a few microseconds. The other is you might want the current high for a a short bit after the motor goes idle just to make sure the machine is stable in the new position.
The trick is to use the step pulse, but extend it to the desired duration. It should stay on through all the step pulses and extend the last pulse.
Discrete Hardware Solution
The X-Controller uses a discrete logic chip to do this. It uses a retriggerable monostable vibrator (74HC123D). The R/C circuit on the right of the schematic snippet sets the duration. It works great, but this adds a lot of parts and things are locked down and not easily adjustable. If you needed to override this function, you have to break out the soldering iron.
PSoC Solution
With PSoC, when you hear “discrete logic” you should know there is probably a good way to do it on the chip. In this case I designed a custom component using verilog.
The verilog code is quite simple. The best part is none of this is done on the CPU, so there is no impact on the motion control performance. What the video to see the details.
Paul Kaplan, originator of the Easel project, came up with another way to do the kinematics for the Line-us Clone. My method used intersecting circles. His method uses the Law of Cosines.
The Law of Cosines relates the lengths of the sides of a triangle to the cosine of one of its angles.
This can be used to find the angles of the servo arms.
(Click on the images if you want a larger view)
The Goal
The goal is to find the two angles, A1 and A2, of the servo arms
Known Values
Px is the desired X location of the pen
Py is the desired Y location of the pen
L1 is the length of the upper servo arm (50mm)
L2 is the length of the end of the Pen Arm (50mm)
Step 1
Find the distance “D” of the pen to hub using the Pythagorean Theroem and the angle T1 using arctangent.
Px2 + Py2 = D2
rewritten … D = Sqrt(Px2 + Py2)
T1 can be found using the arctangent or inverse tangent formula. Note: When programming use the atan2(x,y) function to preserve the quadtrant.
Find T3 using the Law of Cosines. We want the left one of the two T3 angles, but since the linkages form a parallelogram that same angle shows occurs in several places. We will use the right one and the dimensions associated with it.
Determine A1 and A2 from the angles we figured out.
A1 = T1 + T2
A2 = A1 + T3
Conclusion
I think I will switch the code to use this method. I think I can optimize it better in C code. The speed of the code is important. The faster it runs, the most times per second we can run it. The more often we run it, the smoother it will run.
The PSoC family is my go to line of processors for prototyping. It is like having a breadboard full of digital and analog circuits that you can wire up on the fly. I have been doing some stuff with hobby servos lately so I needed to figure out how to do it on the PSoC.
Hobby Servos
From Wikipedia
Image from Adafruit
Hobby servos set their rotation based on the length or a repeating pulse. The pulse should be 1ms to 2ms long and repeat every 20ms. One end of the rotation is at 1ms and the other is at 2ms.
The PSoC PWM Component
The PWM component is perfect for this job. The PWM component can be setup to have a period and an on time. The period should be 20ms and the on time would be between 1ms and 2ms. The component uses a clock and two counter values. The component will count on every clock pulse. It resets the counters after the period count has been reached and the CMP value determines how long the pulse is logic high.
The PWM output goes to the servo control line. Here is the configuration dialog box for the PWM component. The graph at the top is a good reference for what the output will look like.
The goal is to have a pretty decent resolution to set the 1ms to 2ms pulse. I chose a 2MHz clock. I picked the fastest clock that would still fit within the 16bit (65535) limit of the control. PSoC clocks are derived from system clocks, so you need to pick values easily divided down from them. The IDE helps with creation of these clocks. At 2Mhz the period (repeat rate) should be set to 40,000. The equation is the clock * period(in second) = period counts (2,000,000 counts/sec * 0.02 secs = 40,000 counts).
The CMP Value is how many counts the high pulse should last. The equation is the same. For 1ms the count would be (2,000,000 cnts/sec * 0.001secs = 2,000 counts) and for 2ms the counts would be 4,000. The range is 2,000 to 4,000 (2,000 count resolution). This is better than most hobby servos can do.
The Code
The IDE will generate a bunch of functions, a custom API, for each component used when the application is built. There are two PWM Component functions we need to use for this application .
PWM_Servo_Start() This will initialize the component and get it running. This is called once at the beginning of the program.
PWM_Servo_WriteCompare(val) This sets the CMP Value that will be used to set the pulse length.
I also wrote a function the can set the value by degrees.
void setServo(float degrees)
{ unsigned int val; // convert degrees to compare value // 2000 to 4000 = 0 to 180 // value is
val = (degrees / 180.0 * 2000.0) + 2000;
PWM_Servo_WriteCompare(val);
}
The Results
Here is a screen shot of my logic analyzer. The output was set for 1/2 rotation. The pulse is 1.51ms and the period is 20.14ms. That is close enough for me. It is likely the clock speed is different between the PSoC and and the analyzer.
Typically you will have to tune the to the actual servos used. Just tweak the endpoint values until you get the rotation you want.