LewanSoul Lobot LX-16A Serial Servo Review

I stumbled upon these LewanSoul LX-16A Servos the other day on Amazon while searching for standard digital servos. These servos are digital serial bus servos. That means they use a serial protocol on a bus rather than a PWM signal. I have used bus servos before, but the $12 price got my attention. That competes well with plain old PWM servos.

Serial bus servos have some real advantages over standard PWM servos.

  • Wiring: The wiring can be a lot simpler because you can put all your servos on a single 3 wire bus. Each servo has 2 connectors to make daisy chaining easier.
  • Higher resolution: The resolution is typically higher. It depends on the way they sense position. These use a high accuracy potentiometer and list 0.24° as the resolution.
  • You can set the speed: You can set a destination and speed for each move.
  • Set the range: You can limit the range of the servo. This is great if the using the full range would crash a joint on your machine.
  • Continuous turn mode: There is a speed adjustable continuous rotation mode on these, but absolute distance moves cannot be done.
  • Motor On/Off: Turn the motor off for manual movement.
  • Feedback: The communication is bi-directional so you can query a servo for…
    • Position: If you manually move a servo, you get its position. This is great for recording “poses” or setting range limits.
    • Temperature: You can read the current temperature of the motors.

Compared to Robotis

I have used the Robotis Dynamixel XL320 servos before but these are a lot stronger and the XL-320 has a weird, plastic rivet, mounting systems that I am not fond of.

Here is a size comparison with a XL-320.

Specs

Spec LX-16A XL-320
Max. Torque 17 kg-cm 4 kg-cm
Resolution 0.24° 0.29°
Range 240° and Continuous Rotation 300° and Continuous Rotation
Speed 62 RPM 114 RPM
Weight 52g 16.7g

Usage

To use the servos you need to use one of their controllers. The most basic controller just converts a USB or TTL serial signal to their protocol. The controller is small and low cost ($10). You can send commands via a USB (Com Port) or via the TTL pins.

Setup Program.

They have a setup program.  The program is Windows only and I had to run it in Administrator mode to get it to work. This makes setting up the servos easy, but you could write your own program if you don’t want to use theirs.

TTL Control

They also provide some Arduino Sketches. They worked fine and are a good place to grab some code if you are writing your own program.  The sketches use the Arduino hardware TX and RX pins. That conflicts with uploading, so you need to disconnect the controller every time you upload. I edited the sketch to use SoftwareSerial on some other pins and that made playing with the code a lot easier.

First Impressions

I found the servos very easy to use and they appear to be strong and responsive. I think they will be a good option for my on my machines.

Next Steps

I want to test these in a real machine. I thought I might try to make a slightly larger version of my Line-Us clone. That would be a good comparison of accuracy. I might try one day build on it tomorrow.  I can probably get a machine designed and built in a day, but the controller programming would need more time.

 

Pen/Laser Bot Controller

This a CNC controller I designed for small laser engravers and drawing machines. It is for sale on Tindie. It is designed for machines that are primarily 2 axis, but may use a servo for the Z axis.  The controller is designed for use with Grbl firmware running on on an Arduino Nano controller. It uses plug in modules (not included) for the micro controller and stepper drivers. This keeps costs down and gives the user more options. Everything is pinned out for the default configuration of Grbl. This is compatible with all of my recent projects.

Features

  • Power Connector: A standard barrel connector for motor power for the stepper drivers. Typically this will be 12V, but can be run up to 24V if your parts are compatible with higher voltages.
  • Controller: Arduino Nano Footprint.
  • 2 Stepper Drivers: Pololu Footprint
  • Servo Connector: The connector is the standard pinout for most servos.
  • 5V Power Supply: 1 Amp power supply to power the servo.
  • Laser Connectors: There are 2 connectors. One is power and ground for the laser. The other is for the PWM signal to fire the laser.
  • Aux Power Connectors: There is a connector with the primary motor power. This can be used for fans, relays, etc.
  • Limit Switch Connector: X and Y limit switches are available on the connector with convenient ground pins.
  • Control Switch Connector: Feed hold and start switches can be connected to this.
  • Raspberry Pi Interface: This is an optional interface to plug in a Raspberry Pi or any compatible controller that shares the  standard header connector.

Microcontroller

The footprint is designed for an Arduino Nano. These are available from many sources and can cost as little as less than $4. Be sure to install it in the correct orientation. The controller is typically powered by the USB cable, but will automatically switch to the 5V power supply is the USB is removed.

There are several other controllers that share the same footprint. They can be used, but you might need to change a few components if the voltage is not 5V. Make sure you plug it in correctly. While the pinout is the same it might need to be rotated 180 degrees. Contact me directly if you have questions regarding alternate controllers.

Use this view to confirm the orientation (note the pin labels on the Nano. Click to enlarge)

Stepper Drivers

This is designed to use Pololu compatible stepper drivers. The pinout is shown below. Insert them correctly or you could destroy them and possibly other items. There are dozens of compatible designs.  Pololu makes very good ones, but much cheaper version can be found on eBay and Amazon.

Servo Connection

Std Grbl does not support Servos

Limit and Control Switches

Laser Connection

Note: Lasers are very dangerous and no system is completely safe. The firmware is not fail safe and the laser could fire at any time power is available to it. Use safety glasses at all times power is applied. Enclose the laser with an interlock to remove power if covers or doors are open. Evaluate the entire circuit including this controller to determine if it provides the safety you need. If this controller is part of a laser you built, you are responsible for all aspects of safety.

The lower white connector is for the laser power. It is labeled VMot and Gnd. VMot is the voltage that is supplied on the barrel connector. Make sure you have the right power for your laser module.

The upper white connector is for the laser on/off control.  Pulse is the signal and there is a ground pin if you need it.

 

Raspberry Pi (Optional)

This can work as a HAT for a Raspberry Pi. It connects the hardware UART on the Pi to the Nano.

Solder in the supplied connector on the bottom of the board. It is not installed by default to allow more mounting flexibility if you don’t use a Raspberry Pi.

Setup the Raspberry pi to use the serial port. By default the port is used as a serial console. You need to stop that and free it up for your use. See this post for more information.

Do not use the USB while a power Pi is connected or the there will be two things trying to talk to the controller. This includes uploading firmware.

Note: Arduinos use a trick with a DTR control line in the USB-UART on the Arduino. This forces a reboot every time a connection is made. The Raspberry Pi cannot do this. Some senders are expecting Grbl to reboot when connected to and can be a little confused at startup. If you connect a serial terminal you will notice there is a no Grbl startup string at connection. Just type $I (with carriage return) to see the Grbl version info.

Open Source

 

 

A Polar Pre-Processor for the Pen Bot Written in Python

I got a little push back on the Cartesian to Polar gcode processor because it was a Windows, Visual Studio C# program. I rewrote it in Python, to make it more accessible to other operating systems.

I don’t do much Python programming, so I probably did some thing in a very non Python style, but here is is.

Usage: The program will accept 1 or two command line arguments. The first is the file you want to convert. The second the the output file name.  If you skip the second, it will just append “_polar” to the input file name.  For example box.gcode will be converted and output as box_polar.gcode.

PolarPreProcessor.zip (python file)

Before and After Example GCode

Here is the gcode for the logo if you want to test.

Visual Examples

To get a feel for what the translation looks like, here is what a simple square looks like in gcode before translation.

And here is is after translation

Here is what that python logo in the first image looks like in gcode after translation.

Video

Here is a video of it drawing the Python logo.

 

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

 

 

 

 

 

Polar Pen Machine Kinematics

When you have a round work piece like a drink coaster, it makes sense to have a round work area.  A round work area works best with a polar coordinate system. A polar coordinate system uses an angle and a distance from a center point to define a point in 2D.

The problem is that most drawing and CAM programs work in Cartesian (X,Y,Z) coordinate systems. My machine controller firmware, Grbl, also works in normal linear X,Y, and Z. The process of converting one system to another uses Kinematics.

 

The Firmware

The firmware is side is actually quite easy. I defined the X axis as the distance in mm from the center (the radius). The Y axis will control the angle. The Y axis is setup so that millimeters will equal degrees. If I tell the Y to move 360mm, it will actually rotate the work area by 360°.  I could have used radians, but my brain works a lot slower in radians.

The machine will only need to home on the X axis. It needs to know where the exact center of the work area is. The starting angle does not matter because the coaster is a circle.

The conversion from X, Y to polar is probably won’t fit in into the firmware, so the X, Y conversion is done in a preprocessor software program. The X,Y gcode is output from normal CAM programs, then run through a conversion program.

The Conversion Program

The program reads the X,Y gcode, converts any X or Y coordinates into polar coordinates and outputs a new gcode file. The sender simply sends the new files.  The math is actually quite simple.

Typical Gcode sends line data by giving the end points of lines. You simply draw from one point to the next, unfortunately this creates a few problems with a non linear machine.

The basic non-linearity problem

If we were trying to draw the green square centered on the work area, the generated gcode would basically send the corner points. Each corner point has an equal radius to the center. Therefore, the pen will never change radius when going to the next point. This will result in a circle. We want the green square, but we get the red circle.

We need to calculate each point along the way to stay on the desired path. The preprocessor divides the line into tiny segments. Each segment has the same problem, but at a scale you won’t be able to see.

The Spiral Problem

If we are drawing a shape that crosses the 0° angle we don’t want the angle to spin the wrong way. If a point is at 350° and the next point is 10° (crosses over 0) we don’t want it to spin backwards from 350° to 10°. We want it to go to 370°.  It happens anywhere the angle difference between 2 points is greater than 180°. The program will choose the shortest direction even if that means going above 360° or below 0° degrees.

The Feed Rate Problem

Feed rate, in CNC terms, is the speed of the tool across the material. The CAM software is setting the feed rate as if this were a Cartesian machine. On this machine, if you were drawing a circle, you would simply move 360 units in Y. Without compensating feed rate, the pen would move across the work piece faster for larger diameter circles. I want to do some sort of compensation to help with this. The coasters are very absorbent, so the  lines look thicker if the speed is slower. A consistent speed will help the quality of the work.

Since the lines are all very short, the easiest way to compensate for feed rate is to use the current radius. With a simple circle, Grbl thinks the machine moved 360mm. The real distance is easy to to calculate from the perimeter of that circle.

We can compare it to the 360mm (full circle) and apply the ratio to the desired feed rate from the CAM program.

polarFeedrate = cartesianFeedrate * 360 / (2 * pi * radius)

 

Video

Here is a video of it. The machine is rerunning a file to see the repeatability.

Next Steps.

I would like to automate the preprocessor.  I think a Raspberry pi, might be an easy way to do this.  It would sit between the sender and the controller.

 

 

 

Coasty Update

Here is a quick update on Coasty. Several people have asked if I am releasing the source files or selling a kit. I am adjusting the design to make that more viable.  The original version was made with parts I had laying about and not necessarily the best design choices for an open source project.

X Axis.

Originally I used an TR8-8 ACME thread lead screw. It was mounted to the motor by drilling a hole in the lead screw and epoxying it to the motor shaft. This worked well, but you needed a lathe to drill the hole and a special low backlash nut. The axis was also a little loud with and all metal design.

I changed to use a GT2 open belt cut to length.  Belts and pulley are really easy to get and don’t cost too much.

Electronics

Need to shorten some wires after testing.

There were some issues with the EleksMaker electronics that I did not like. The laser circuit did not appear to have a pull down on the signal and it tended to fire if the Arduino was not pulling it low. This would happen during reboot and other scary times. The wiring was also quite a pain. There were no connectors for the limit switches so you had to directly solder to the Arduino Nano.

I changed to use a custom PCB that is the entire rear panel. This contains all of the circuits including the limit switches. Building a Coasty was a little like building a ship in a bottle. Now the bottle has no bottom and there are less parts inside.

Front Door.

The front door now has a window. This makes the machine more fun to watch and no glasses are required.

Next Steps.

I have one build and am testing it for a while. If all goes well, I will release the source files and consider a kit.

 

Using The Grbl HAT

Getting the Kit

The kit is available in my Tindie shop.

Getting the plug-in modules

The kit does not come with the stepper drivers or Arduino Nano modules. The point of the design was to keep costs low by using modules. At this time I cannot sell the modules anywhere close to what you find them for at other retailers. You must get them on your own.

  • Stepper drivers: I think the company that first set this form factor is Pololu. There is also an open source version call the StepStick. They typically use the A4988 driver chip from Allegro, but compatible modules with other chips are also available. You should search Pololu, Amazon, eBay or AliExpress for StepStick or A4988.  Make sure it has the pinout shown below (as viewed from top) and will work at 12V. You should be able to find them for around $3 each. It is best to get ones with heatsinks, so they can run at higher currents.


  • Arduino Nano: The Arduino Nano is a small version of the Arduino Uno.  It uses the same microcontroller chip as the Arduino Uno (ATMega328p). You will need a USB cable, so make sure you have one. Depending where you buy the Nano, it could have a mini or micro USB connector. You can often find them for less than $4.

Arduino Nano

  • Power Supply. You need a 12V-24V power supply that can output at least 5A. The connector should be a 5.5mm x 2.1mm barrel connector. The center pin should be the positive voltage.

Assembling the Kit

All of the surface mount parts ship already assembled. You only need to solder the through hole parts.  It typically takes only a few minutes to solder them. Here are some assembly tips.

  • I find it best to just tack one pin of each connector first. You can flip over the board and see if the connector is mounted straight. If not, you just heat the pin again and straighten the connector.
  • I like to assemble the parts shortest to tallest. You can insert the components, then flip the board. The weight of the board will keep the parts inserted.
  • Raspberry Pi Connector: The connector is mounted to the back side (not silkscreen side), so it is probably best to do it first, so you don’t forget the side.
  • Male Headers. Insert all the male headers on the top side. Place a small piece of cardboard on top of the connectors then flip over the PCB onto a table. Solder one pin per connector, inspect the straightness, then finish all soldering.
  • Female Headers: Repeat the last step with female headers.
  • Power connector. Solder this on the top side.

Install Grbl firmware on the Nano.

With the Nano not attached to the PCB install Grbl. You can get it here and there are instruction. Be sure to select Nano in the Arduino IDE Tools…Boards: menu

PCB Setup.

  • Determine the microstepping: Use the jumper blocks provided to set the microstepping level. You should look up the documentation on the driver chips to see how the settings work.
  • Install the Nano with the USB facing the edge of the board. See images.
  • Install the stepper drivers: Be sure to get the orientation right. Most will have the pins labeled. Match them up with the labels on the controller board.
  • Plug in your power supply.
  • Set the current: Most drivers will come with the current preset to a good value, but the pot on the driver can be used to fine tune that. You will need to use a meter and read the instructions where you got the driver.

I/O Connector

  • Limit and Probe Switches: The switches should all be setup as normally open and close to ground. A ground connection is provided for each switch to make wiring easier.
  • Control Switches (Start, Hold, Grbl Reset): These also should be normally open switches that close to ground. Grbl reset is a Grbl function to reset the planner, it is not a reset of the controller.
  • Spindle: This output is a TTL signal for a relay or speed controller. It cannot provide any power to run a motor or directly drive a relay.  That will break your Arduino Nano. Whether you use a relay or a variable speed spindle, I suggest Grbl be setup as a variable speed spindle (the default).
    • Variable Speed Spindle:
    • On/Off Spindle: Connect the output pin to the relay control circuit.  This can be used to control AC routers like a Dewalt 611.
  • Flood & Mist coolant: These should be connected to a relay control circuit. If you are using multiple relays, it is easiest to buy a multiple relay PCB like this one.

 

 

Stepper Connectors.

See the schematic to attach the servos, if you need (2) Y motors to turn in different directions just swap the (2) wires of one coil on one motor. You can also just rotate the connector of the motor you want to reverse by 180 degrees. If you want a different axis to use the 2 ganged motors you can change some setting in Grbl’s cpu_map.h file.  Here is the section of the file you change. The ganged drivers use pins 3 and 6.  Swap them with the axis you want.

// Define step pulse output pins. NOTE: All step bit pins must be on the same port.
#define STEP_DDR DDRD
#define STEP_PORT PORTD
#define X_STEP_BIT 2 // Uno Digital Pin 2
#define Y_STEP_BIT 3 // Uno Digital Pin 3
#define Z_STEP_BIT 4 // Uno Digital Pin 4
#define STEP_MASK ((1<<X_STEP_BIT)|(1<<Y_STEP_BIT)|(1<<Z_STEP_BIT)) // All step bits

// Define step direction output pins. NOTE: All direction pins must be on the same port.
#define DIRECTION_DDR DDRD
#define DIRECTION_PORT PORTD
#define X_DIRECTION_BIT 5 // Uno Digital Pin 5
#define Y_DIRECTION_BIT 6 // Uno Digital Pin 6
#define Z_DIRECTION_BIT 7 // Uno Digital Pin 7
#define DIRECTION_MASK ((1<<X_DIRECTION_BIT)|(1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT)) // All direction bits

 

Raspberry Pi.

This controller uses the TX and Rx on pins 14 and 15 of the Raspbery Pi header. These are typicall in use for a login shell. You will need to go in the raspi-confi program and stop the ligin shell and enable it for use by other programs.

Note: Arduinos use a trick with the USB to Serial adapter built into each one to reboot the CPU every time you connect. The Raspberry Pi cannot do that, because it has no access to the reboot pin . Grbl will not reboot each time you connect. This may confuse some senders. Also if you try to use the Arduino IDE to program the Nano via Raspberry Pi, it will not be able to trigger the bootloader. You will have to click the reset button on the Nano as the IDE is trying to upload the program. It is best to remove the Nano and program via USB.

Using a Servo.

Stock Grbl does not support servos, so the servo is wired to the Raspberry Pi header. The servo is using the 5V power from the Arduino or the Raspberry Pi, so you should only use micro servos to avoid drawing too much power and damaging something. You should use an external 5V power supply if you want to use a larger servo.

The servo is hooked up to PWM0 (Pin 12)

Using the Controller

You can use it via Raspberry Pi or standalone. If you use the Raspberry Pi, you should not connect the USB to the Arduino. That create a communications conflict and could damage something.

Documentation: (Current version 1.0):

The license is Creative Commons 4.0 Share Alike – Attribution.

Questions?

Please ask via the comments section. I’ll answer there and update this post as required.

 

 

 

 

 

 

Using Grbl’s Spindle PWM to Control a Servo

While I am waiting on some parts to arrive for a pen ‘bot, I started investigating ideas to control it. It will be using a hobby servo for pen up/down. Servos work great for things like this because they are easy to integrate and don’t need to be homed. They always know where they are in rotation.

I am probably going to use Grbl  and it outputs step and direction signals for motion.  A servo requires a PWM signal.  Since the spindle already uses PWM to set speed, this seems like a good place to start hacking. A PWM signal has a frequency and a duty cycle.  The frequency is how often the signal repeats and the duty cycle is how long the output signal is logic high (the rest of the time it is low). Servos want the signal to repeat every 20ms (50Hz). They want the duty cycle to be 1m long at one end of the rotation and 2ms at the other end.

  • 0 degree duty cycle = 1ms
  • 180 degree duty cycle 2ms
  • Frequency 50Hz (20ms)

PWM is a peripheral found on most micro controllers including Arduinos.  They use the timers built into CPU. You setup a few registers and the PWM runs independent of of the code. The spindle is using timer2.  All other timers are being used by other Grbl functions (on Unos), so they are not available. Timer2 is an 8 bit timer so it can only count up to 255.  To set the duty cycle you set a “compare” number that is 0-255. At the beginning of the cycle, the output will go high and the timer will begin counting.  When it reaches the compare value the output goes low. When it reaches 255, the cycle starts over again.

Issues

  • Resolution: Since the servo’s duty cycle range ( 1ms to 2ms ) is only a fraction of the frequency (1ms/20ms) , we only have 1/20 of the 256 counts at best. That is going to limit our resolution, but we only care about a rough pen up and pen down in this application.
  • Frequency: You don’t get to pick any frequency on Arduinos. You are limited to certain fractions of the CPU clock.  The allowable fractions are 1/1, 1/8, 1/64, 1/256 & 1/1024. We need to pick one that is close to getting us to 50Hz.

Setting the frequency.

The formula for the setting the frequency is..

Freq = F_CPU / (Prescaler * TimerResolution)    Eq #1

  • Freq: Our desired frequency of 50Hz
  • F_CPU: This is the frequency of the CPU. For most Arduino that is 16Mz
  • Prescaler: This is that fraction mentioned about.
  • TimerResolution: In our case this will be 256

This can be rewritten as this to find Prescaler…

Prescaler = F_CPU / (TimerResolution * Freq)  Eq #2

Prescaler = 16,000,000 / (256 * 50)

This yields 1250 as the desired prescaler. This is not an option so we pick the closest one of 1024.  If we plug that into Eq #1, we get 61Hz. That is close enough.

Determine the duty cycles.

We need to determine the compare values for each end of the servo rotation.  A unit of compare value is often called a “tick”. Each “tick” of the timer is…

Tick = 1 / (F_CPU / Prescaler) Eq3

Tick = 1 / (16,000,000 / 1024)

This yields a tick length of 0.000064 seconds. We then determine how many ticks are needed for each end of travel.

  • 0 degree = 0.001 / 0.000064. This yields 15.6 Ticks which needs to be rounded to 16
  • 180 degrees = 0.002 / 0.000064. This yields 31.25 Ticks which needs to be rounded to 31.

Setting The Resisters.

You need to deeply dive into the datasheets for these, but I’ll briefly explain them here.

TCCR2A = (1<<COM2A1) | ((1<<WGM20) | (1<<WGM21));
TCCR2B = (1<<CS22) | (1 <<CS21) | (1<<CS20);
OCR2A = 31;


  • First line: TCCR2A (Timer/Counter Control Register A for Timer 2).   WGM20 & WGM21 (Waveform Generation Modes) are setting the mode to Fast PWM.  The COM2A1 bit tells the CPU to clear the compare value when reached.
  • Second line: TCCR2B (Timer/Counter Control Register B for Timer 2) This sets the Clock Select bits to the value needed for a 1024 prescaler .
  • Third Line: Sets OCR2A (Output Compare Register A for Timer 2) to 31, which is the 180 degree value determined above.

Note: Grbl uses some aliases for the register names to make the code a little easier to read and more universal between Uno/Mega, so keep that in mind when reading the actual code.

Testing:

I loaded the firmware and hooked the output to my Saleae Logic 4 logic analyzer.

Here is the output at at the 0 degree rotation 1.087ms @ 61.07Hz

Here is the output at 180 degree rotation. 2.047 @ 61.07Hz

The Firmware.

I put everything into the a spindle_control.c file. Just replace it with the one Grbl comes with. Note: This is designed for Grbl 1.1f

 


/*
  spindle_control.c - spindle control methods
  Part of Grbl

  PEN_SERVO update by Bart Dring 8/2017
  Copyright (c) 2012-2017 Sungeun K. Jeon for Gnea Research LLC
  Copyright (c) 2009-2011 Simen Svale Skogsrud

  Grbl is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  Grbl is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with Grbl.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "grbl.h"

/*
Pen Servo: 

For a pen bot I want to use the spindle PWM to control a servo
When the spindle is on, the servo moves the pen down
When it is off the pen moves up

The spindle output is using a PWM, but we need to adjust that 

We only need a rough 

Use 1024 prescaler to get. ... 16,000,000 Mhz  / 1024 = 15625 Hz
It is an 8 bit timer so 15625 / 256 = 61 Hz. This is pretty close the the 50Hz recommended for servos
Each tick = 0.000064sec 
One end of servo is 0.001 sec (0.001 / 0.000064 = 15.6 ticks)
The other end is 0.002 sec (0.002 / 0.000064 = 31 ticks)


*/

#define PEN_SERVO
// these are full travel values. If you want to move less than full travel adjust these values
// If your servo is going the wrong way, swap them.
#define PEN_SERVO_DOWN     16      
#define PEN_SERVO_UP       31        

#ifdef VARIABLE_SPINDLE
  static float pwm_gradient; // Precalulated value to speed up rpm to PWM conversions.
#endif


void spindle_init()
{
  #ifdef VARIABLE_SPINDLE

    SPINDLE_PWM_DDR |= (1<<SPINDLE_PWM_BIT); // Configure as PWM output pin.
	
	#ifndef PEN_SERVO 
  
		// Configure variable spindle PWM and enable pin, if requried. On the Uno, PWM and enable are
		// combined unless configured otherwise.
		
		SPINDLE_TCCRA_REGISTER = SPINDLE_TCCRA_INIT_MASK; // Configure PWM output compare timer
		SPINDLE_TCCRB_REGISTER = SPINDLE_TCCRB_INIT_MASK;
    
	#else
		#ifdef CPU_MAP_ATMEGA2560
      	
		// not supported yet
		
	  #else
		
        SPINDLE_TCCRA_REGISTER = (1<<COM2A1) | ((1<<WGM20) | (1<<WGM21));
		TCCR2B = (1<<CS22) | (1 <<CS21) | (1<<CS20);
	    
	  #endif
	#endif
	
	
	
	#ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
      SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin.
    #else
      SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT); // Configure as output pin.
    #endif

    pwm_gradient = SPINDLE_PWM_RANGE/(settings.rpm_max-settings.rpm_min);

  #else

    // Configure no variable spindle and only enable pin.
    SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin.
    SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT); // Configure as output pin.

  #endif

  spindle_stop();
}


uint8_t spindle_get_state()
{
	#ifdef VARIABLE_SPINDLE
    #ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
		  // No spindle direction output pin. 
			#ifdef INVERT_SPINDLE_ENABLE_PIN
			  if (bit_isfalse(SPINDLE_ENABLE_PORT,(1<<SPINDLE_ENABLE_BIT))) { return(SPINDLE_STATE_CW); }
	    #else
	 			if (bit_istrue(SPINDLE_ENABLE_PORT,(1<<SPINDLE_ENABLE_BIT))) { return(SPINDLE_STATE_CW); }
	    #endif
    #else
      if (SPINDLE_TCCRA_REGISTER & (1<<SPINDLE_COMB_BIT)) { // Check if PWM is enabled.
        if (SPINDLE_DIRECTION_PORT & (1<<SPINDLE_DIRECTION_BIT)) { return(SPINDLE_STATE_CCW); }
        else { return(SPINDLE_STATE_CW); }
      }
    #endif
	#else
		#ifdef INVERT_SPINDLE_ENABLE_PIN
		  if (bit_isfalse(SPINDLE_ENABLE_PORT,(1<<SPINDLE_ENABLE_BIT))) { 
		#else
		  if (bit_istrue(SPINDLE_ENABLE_PORT,(1<<SPINDLE_ENABLE_BIT))) {
		#endif
      if (SPINDLE_DIRECTION_PORT & (1<<SPINDLE_DIRECTION_BIT)) { return(SPINDLE_STATE_CCW); }
      else { return(SPINDLE_STATE_CW); }
    }
	#endif
	return(SPINDLE_STATE_DISABLE);
}


// Disables the spindle and sets PWM output to zero when PWM variable spindle speed is enabled.
// Called by various main program and ISR routines. Keep routine small, fast, and efficient.
// Called by spindle_init(), spindle_set_speed(), spindle_set_state(), and mc_reset().
void spindle_stop()
{
	
  #ifndef PEN_SERVO	
	
	  #ifdef VARIABLE_SPINDLE
		SPINDLE_TCCRA_REGISTER &= ~(1<<SPINDLE_COMB_BIT); // Disable PWM. Output voltage is zero.
		#ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
		  #ifdef INVERT_SPINDLE_ENABLE_PIN
			SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);  // Set pin to high
		  #else
			SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT); // Set pin to low
		  #endif
		#endif
	  #else
		#ifdef INVERT_SPINDLE_ENABLE_PIN
		  SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);  // Set pin to high
		#else
		  SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT); // Set pin to low
		#endif
	  #endif
  
  #else	  
    SPINDLE_OCR_REGISTER = PEN_SERVO_UP;     
  #endif
  
}


#ifdef VARIABLE_SPINDLE
  // Sets spindle speed PWM output and enable pin, if configured. Called by spindle_set_state()
  // and stepper ISR. Keep routine small and efficient.
  void spindle_set_speed(uint8_t pwm_value)
  {
	
    #ifdef PEN_SERVO
		if (pwm_value == SPINDLE_PWM_OFF_VALUE) 
			spindle_stop();
		else // not off
			SPINDLE_OCR_REGISTER = PEN_SERVO_DOWN;
    #else	
	  
	  
		SPINDLE_OCR_REGISTER = pwm_value; // Set PWM output level.
		#ifdef SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED
		  if (pwm_value == SPINDLE_PWM_OFF_VALUE) {
			spindle_stop();
		  } else {
			SPINDLE_TCCRA_REGISTER |= (1<<SPINDLE_COMB_BIT); // Ensure PWM output is enabled.
			#ifdef INVERT_SPINDLE_ENABLE_PIN
			  SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT);
			#else
			  SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);
			#endif
		  }
		#else
		  if (pwm_value == SPINDLE_PWM_OFF_VALUE) {
			SPINDLE_TCCRA_REGISTER &= ~(1<<SPINDLE_COMB_BIT); // Disable PWM. Output voltage is zero.
		  } else {
			SPINDLE_TCCRA_REGISTER |= (1<<SPINDLE_COMB_BIT); // Ensure PWM output is enabled. } #endif #endif } #ifdef ENABLE_PIECEWISE_LINEAR_SPINDLE // Called by spindle_set_state() and step segment generator. Keep routine small and efficient. uint8_t spindle_compute_pwm_value(float rpm) // 328p PWM register is 8-bit. { uint8_t pwm_value; rpm *= (0.010*sys.spindle_speed_ovr); // Scale by spindle speed override value. // Calculate PWM register value based on rpm max/min settings and programmed rpm. if ((settings.rpm_min >= settings.rpm_max) || (rpm >= RPM_MAX)) {
        rpm = RPM_MAX;
        pwm_value = SPINDLE_PWM_MAX_VALUE;
      } else if (rpm <= RPM_MIN) { if (rpm == 0.0) { // S0 disables spindle pwm_value = SPINDLE_PWM_OFF_VALUE; } else { rpm = RPM_MIN; pwm_value = SPINDLE_PWM_MIN_VALUE; } } else { // Compute intermediate PWM value with linear spindle speed model via piecewise linear fit model. #if (N_PIECES > 3)
          if (rpm > RPM_POINT34) {
            pwm_value = floor(RPM_LINE_A4*rpm - RPM_LINE_B4);
          } else 
        #endif
        #if (N_PIECES > 2)
          if (rpm > RPM_POINT23) {
            pwm_value = floor(RPM_LINE_A3*rpm - RPM_LINE_B3);
          } else 
        #endif
        #if (N_PIECES > 1)
          if (rpm > RPM_POINT12) {
            pwm_value = floor(RPM_LINE_A2*rpm - RPM_LINE_B2);
          } else 
        #endif
        {
          pwm_value = floor(RPM_LINE_A1*rpm - RPM_LINE_B1);
        }
      }
      sys.spindle_speed = rpm;
      return(pwm_value);
    }
    
  #else 
  
    // Called by spindle_set_state() and step segment generator. Keep routine small and efficient.
    uint8_t spindle_compute_pwm_value(float rpm) // 328p PWM register is 8-bit.
    {
      uint8_t pwm_value;
      rpm *= (0.010*sys.spindle_speed_ovr); // Scale by spindle speed override value.
      // Calculate PWM register value based on rpm max/min settings and programmed rpm.
      if ((settings.rpm_min >= settings.rpm_max) || (rpm >= settings.rpm_max)) {
        // No PWM range possible. Set simple on/off spindle control pin state.
        sys.spindle_speed = settings.rpm_max;
        pwm_value = SPINDLE_PWM_MAX_VALUE;
      } else if (rpm <= settings.rpm_min) {
        if (rpm == 0.0) { // S0 disables spindle
          sys.spindle_speed = 0.0;
          pwm_value = SPINDLE_PWM_OFF_VALUE;
        } else { // Set minimum PWM output
          sys.spindle_speed = settings.rpm_min;
          pwm_value = SPINDLE_PWM_MIN_VALUE;
        }
      } else { 
        // Compute intermediate PWM value with linear spindle speed model.
        // NOTE: A nonlinear model could be installed here, if required, but keep it VERY light-weight.
        sys.spindle_speed = rpm;
        pwm_value = floor((rpm-settings.rpm_min)*pwm_gradient) + SPINDLE_PWM_MIN_VALUE;
      }
      return(pwm_value);
    }
    
  #endif
#endif


// Immediately sets spindle running state with direction and spindle rpm via PWM, if enabled.
// Called by g-code parser spindle_sync(), parking retract and restore, g-code program end,
// sleep, and spindle stop override.
#ifdef VARIABLE_SPINDLE
  void spindle_set_state(uint8_t state, float rpm)
#else
  void _spindle_set_state(uint8_t state)
#endif
{
  if (sys.abort) { return; } // Block during abort.
  if (state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm.
  
    #ifdef VARIABLE_SPINDLE
      sys.spindle_speed = 0.0;
    #endif
    spindle_stop();
  
  } else {
  
    #ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN
      if (state == SPINDLE_ENABLE_CW) {
        SPINDLE_DIRECTION_PORT &= ~(1<<SPINDLE_DIRECTION_BIT);
      } else {
        SPINDLE_DIRECTION_PORT |= (1<<SPINDLE_DIRECTION_BIT);
      }
    #endif
  
    #ifdef VARIABLE_SPINDLE
      // NOTE: Assumes all calls to this function is when Grbl is not moving or must remain off.
      if (settings.flags & BITFLAG_LASER_MODE) { 
        if (state == SPINDLE_ENABLE_CCW) { rpm = 0.0; } // TODO: May need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE);
      }
      spindle_set_speed(spindle_compute_pwm_value(rpm));
    #endif
    #if (defined(USE_SPINDLE_DIR_AS_ENABLE_PIN) && 
        !defined(SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED)) || !defined(VARIABLE_SPINDLE)
      // NOTE: Without variable spindle, the enable bit should just turn on or off, regardless
      // if the spindle speed value is zero, as its ignored anyhow.
      #ifdef INVERT_SPINDLE_ENABLE_PIN
        SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT);
      #else
        SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);
      #endif    
    #endif
  
  }
  
  sys.report_ovr_counter = 0; // Set to report change immediately
}


// G-code parser entry-point for setting spindle state. Forces a planner buffer sync and bails 
// if an abort or check-mode is active.
#ifdef VARIABLE_SPINDLE
  void spindle_sync(uint8_t state, float rpm)
  {
    if (sys.state == STATE_CHECK_MODE) { return; }
    protocol_buffer_synchronize(); // Empty planner buffer to ensure spindle is set when programmed.
    spindle_set_state(state,rpm);
  }
#else
  void _spindle_sync(uint8_t state)
  {
    if (sys.state == STATE_CHECK_MODE) { return; }
    protocol_buffer_synchronize(); // Empty planner buffer to ensure spindle is set when programmed.
    _spindle_set_state(state);
  }
#endif

A Grbl Raspberry Pi Hat

I have been making small scale CNC machines lately. I wanted a very small Grbl based CNC controller. I used the Eleksmaker Mana SE for the Coasty Laser. The big drawback was no access to the pins used for limit and control switches. I did like the modular approach.  The Stepstick style drivers are easy to find at less the $2 each and Arduino Nano clones can be found for less than $4.  There is no way I could even get the components for that price at the scale I am working at.

Edit: Now a few are available on Tindie.

(my hand tacked limit switch wires)

Raspberry Pi Real time Issues.

Raspberry Pi is great, but it cannot handle the real time requirements of CNC. Beagle Bone uses coprocessors (PRU) to get around this and there are some dual core devices like the UDOO NEO that have a second core that can be used for CNC. That got me thinking, why not just add the second processor myself. If I added an Arduino 328 processor connected by the hardware UART on the Pi, I would have an easy fix without any firmware development.

It’s a Raspberry Pi HAT…or not.

After taking Chris Gammell’s KiCAD lesson I wanted to make a Raspberry Pi HAT, but I typically don’t use a Raspberry Pi. I realized that the Nano could talk to either the USB or the Pi. The female header going to the Pi is out of the way and well protected from shorts if it is not used. You can therefore use it on the Pi or stand alone.

5V Power.

The 5V logic power can come from the USB connection or the Pi. There is a diode OR isolating the 2 sources. There is no on board step down supply, so this cannot be used if it is not connected to USB or a Pi.

Processor.

The processor uses a standard Arduino Nano. This is a mini version of the Uno, but it actually exposes more of the I/O pins (A6 and A7).

 

3 Axis Drivers (+1 slaved)

The firmware is standard Grbl, so it is limited to 3 axes. I had room for 4 drivers, so there are 2 for Y. If you needed 2 on a different axis, you could simply edit the config file for Grbl. These use standard Stepstick / Pololu footprints. There are jumpers to select the microstepping value.

I/O

I added a big header for all of the I/O. All of the typically used signals have their own grounds to make wiring easier. A6, A7 and +5V are also on the header.

Servo

I added this at the last minute, just for experimenting. It is hooked to the Raspberry Pi PWM0 pin. If you wanted Grbl to use a servo for pen up type applications, you should hook the servo up to one of the Nano GPIO pins.

Using the Raspberry Pi serial port.

The standard GPIO header has UART Tx and Rx on pins 8 and 10.

This serial port is /dev/ttys0.  It is typically used for a serial console. You will need to disable this to use the serial port.  To disable type…

sudo raspi-config

To get the configuration screen. Select Advanced Options.

Select Serial.

Disable the serial login shell.

There are several ways to use the serial port with a basic terminal session. The most basic is ….

screen devttys0 115200

If you want a more interactive GUI, use …

cutecom.  You will probably need to install it

sudo apt-get install cutecom

 

 

Next Steps

  • I want to experiment with running full featured sender programs like BCNC on the Pi.
  • I will release the source and might sell some on Tindie if there is some demand. Unfortunately I did the layout in Diptrace, but I can release the Gerbers too.

Documentation (more coming soon after complete testing)

 

 

 

 

 

Coasty the Coaster Toaster

Overview

This is a just a silly little project that can only do one thing. It laser etches or cuts drink coasters.

I was interested in learning Grbl’s new laser features, so I bought a small laser module. We have a monthly-ish Hardware Happy Hour meetup in Chicago. We drink beer and show off our projects. My typical projects are big motion control/CNC stuff, so for the first few meetups, I could not bring anything. I challenged myself to design something interesting for each meetup. Here are my criteria…

  • Must fit in a commuter sized backpack.
  • Must be battery or USB powered.
  • Can only scare the bar staff a little.
  • Learn something new.

Parts

Most of my design choices were based on materials I had left over from other projects. The parts I needed to buy for this project were these…

  1. ($99) 3.5 watt / 2.5 watt continuous laser module with power supply
  2. ($26) Small 2 axis motion controller.
  3. ($9) A backlash resistant leadscrew nut. (small size/diameter was important)
  4. (($10 for 50) O-Rings for the drive wheels.

 

Enclosure

The enclosure is 3D printed in 2 parts. The chassis is quite complex, but prints easily without support. It should fit on most printers. It takes about 12 hours on my Taz 6. The second part is a simple hinged door.

X-Axis

The required width was hard too reduce too much.  You are stuck with the width of the coaster and the width of the laser module.  The beam is in the center of the module, so you need room for the rest of the laser module to fit within the width as it travels to the edges.

I tried the design with the motors inside the box with belts. Getting the motor pulley, the idler pulley and a belt attachment method into that minimum width was not working out well. I decided to use a Tr8-8 lead screw instead with the motor outside the case. A tr8-8 is pretty common and easy to buy. It is 8mm diameter it is 2 mm pitch with 4 starts (independent threads) so this will cause a travel of 8mm per turn.

The linear bearing uses (2) 8mm rods and 2 double wide ball bearings. The leadscrew attachment was a bit of a hack. I drilled a hole down the center of one end and epoxied it to the inserted motor shaft.

Y-Axis

The Y axis uses feed rollers to move the coaster.  This allowed me to make the machine smaller in depth than the coaster. A 1″ O.D. x 1/8″ rubber oring is driven by a large axel. The coaster runs over some small bearings where it is pinched by the o-ring. The coaster slides over a large platform.  This allows it to drag along cutouts pieces pretty well.

Z-Axis

The nice thing about limiting it to printing coasters is that you only need to deal with 2 axes. The focus length never changes. No Z provisions required.

Home Switches

Each axis has a home switch.  The Y home switch is triggered by the top coaster as it slides in.  The X home switch is triggered by an adjustable screw on the X carriage.

Electronics

I used a super cheap 2 axis CNC controller called the EleksMaker Mana SE. It uses 2 stepstick stepper drivers and a Arduino Nano. Both of those items were included in the price. It is designed to run Grbl for simple pen plotters, egg bots and lasers. It can control the laser via PWM and also has a servo connector. The board is not open source, so it was a little tricky to figure some things out. I’ll do some future posts about all the details.

I also added 2 fans. The laser generates a bit of smoke while cutting the coasters.  The fans wisk it out the back.

I need to measure the current better, but the values below are a good estimate.  The controller has a switch on the 12V that turns almost everything off, but the Arduino will stay on while plugged into USB.  I typically turn off the 12V after each job. I want to make sure the laser never fires accidentally between jobs.

  1. 2 amps peak when cutting at full power
  2. 0.3 amps when idle.

Software

I tried several things, but ultimately settled on Laser Grbl.  It is open source and quite simple. It is written in C#, so it is windows only. I was able to easily recompile it and try a few tweaks.

A full cut through job like the “Coasty COASTY” coaster takes about 4-5 minutes. I run at about 250mm/min for those. For bar use I think it is quicker just to do outline engraves.  I run at about 1000-1200 mm/min for those and they typically take less than a minute. Full solid engraves are pretty smoky and take a long time.

Safety

I have no idea if this is safe, so I supervise its use pretty closely.  The chassis and cover block direct viewing of the beam unless you really try to peer into some holes at sharp angles.  The vents on the door angle so you can’t see through them. There is always the chance the coaster could catch fire, but that is not a lot of fuel. The cover is not interlocked, but it does bolt shut. Most DIY lasers like this are just run in the open.

Future

Here are some things I am thinking about.

  • Add another row of drive wheels on the other side of the laser.  This should increase the work area if the coaster transfers from one set to the other to get to the top and bottom edges. I would also like to reduce the diameter of them to make the machine a little smaller in depth.
  • Cover the electronics.  The electronics are a little vulnerable to damage and not quite ready to be tossed into a backpack.
  • Add a filter to reduce the smoke smell.  I bought a big sheet of carbon filter material. I would like to test it’s effectiveness.
  • I would like to try some new ideas for a belt driven X axis.  It would run faster and quieter. I think I could put the motor on the side like the Y motor. Currently drilling out the center of the TR8-8 leadscrew is requires a lathe.
  • When cutting through something the laser energy has to be blocked by something.  Right now there is a thin metal strip under the coaster where the beam goes. I would like to try moving the strip to the bottom of the device further away from the focal point.  The beam would eventually cut a thin  line through the enclosure until it hits the metal. The thinnest interruption in the base in best for dealing with cutout pieces. The beam will have some distance to diverge before bouncing off the metal.