Foreword

This project is an homage to my friend Lino Zangirolami from Italy (image above, credits Cristina Manfredini), a 71 y.o. crazy guy with an incredible experience in mechanics, CAD Machining and design: one of the most creative makers I ever know.

He is involved in the jewelry stones cutting business and some months ago he explained me a series of problems he always experience to control a special kind of semi-automated CNC, the cabbing machines, used in his job. These machines can replicate a 3D model, just like a pantograph can do with 3D designs. The problem is that the motion of these devices is almost primitive and imprecise. Without the need for a complex explanation, there is a rotation motion actuated by a big DC motor that gives some imprecisions to the machine making the entire device very heavy. The video below shows a cabbing machine in action.

As shown in the above video the stand supporting the master and copy stones (on the right side of the machine) rotates vertically to machine the bottom stone (copy) all around trying to make a copy of the upper stone (the master). The adopted electro-mechanical method is almost imprecise and the parameters like the vertical rotation speed are all set mechanically introducing a meaningful systematic error.

Discussing how to make this movement better and precise with the option to program the path, time-speed, and some other parameters, I designed the prototype presented in this project.

 

The problem analysis

Analyzing in-depth the possible solution, soon I discovered there were aspects of the electronic design making the project more complex than expected. In the meantime, I saw the possible solution was applicable in a lot of different environments so I decided to make the prototype study - a simulation of the final job - creating a general-purpose application for the stepper motors; modular, replicable and easy to customize to be applied in totally different contexts.

 

Facing some math

The first decision I took was using a robust stepper motor to grant the right stability an precise positioning along the curved path. The point is that the path is very uncommon respect what we are used to managing motion controlled by stepper motors; instead of managing distances, like what it is done by a 3D printer, in our case we should manage time: we need to complete the rotation semi-circular path during a predefined time. Just a few seconds of variation can be accepted and rotation should be very slow.

The image above shows the stepper motor I have used for this project. It is a 1.8 DEG per step, that means 200 steps every rotation. The average path the tool should rotate is around 90 DEG. Consider the following:

  • Angular rotation (easier to calculate than linear motion)
  • 90 DEG angle is our path
  • Time to travel: l minute (from 0 to 90 DEG)

Based on the above parameters, we deduce that

90 DEG = 1/4 of a full rotation
Resulting (theoretical) Motor speed = 0,25 RPM

At the speed of 1 RPM motor will run too fast!

A couple of gears reduction (in our case I have used a 42:75 steel gears) only solve partially the problem. Applying the reduction gear what we get is a 90 DEG rotation in about 200 steps. This is a too low limit and very difficult to control along the time. The scheme below shows the axis motion along distance respect the time needed.

To dramatically improve the steps performances without introducing a too complex gear mechanics, the solution has been completed with a motor driver supporting micro stepping.

Due to the industrial application of the target I have used a Moon's SR stepper controller. As a matter of fact, the same theory and development can be applied using cheaper components (stepper and motor controller) without any change to the design architecture.

 

Controls and Switches

The motion system should be programmed. Not so difficult, we just need to add some buttons. But things - again - become complex because the user interface has the following requisites:

  1. Many choice options should be easy to manage by the user
  2. Last settings should be saved to be persistent after power-down
  3. Users should interact also while a sequence is running
  4. Need an emergency stop button
  5. Need end-stop switches

To support the behavior as mentioned in the points above we should exclude any possible approach based on time delays but need an interrupt driven application. In detail, we should be able to manage at least three interrupts: one emergency button and two end-stop switches.

Fast prototyping the interface controller, the choice using an Arduino Mega 2560Arduino Mega 2560 revealed right.

256 Kb of flash is more than sufficient to write a complex software, and up to 4Kb available on EEPROM is what we need to store the user settings for persistence. We should add that the Mega2560 has 4 hardware interrupts available. Due to the available number of PINs, it was possible to connect the 16x2 alphanumeric LCD screen consuming six I/O ports without problems for better responsivity of the interface.

 

Prototype Design

Electronics

The circuit itself is not particularly complex but should work in not properly clean environments. For better stability, I have designed it as a Mega shield. The image below shows the schematics and the rendered PCB

The project has been developed with Altium CS

 

Simulation Building

As the simulation build should not support particular mechanic stress I decided to make a simple design, focusing the attention on replicating the critical points involved in the real world application. The image gallery below shows the 3D rendering of the design parts

 

 

{gallery} Prototype 3D Design

3D rendered prototype components spacially assembled

3D rendered prototype components spacially assembled

3D rendered prototype components spacially assembled

3D rendered prototype components spacially assembled

 

A simple box to host the Arduino Mega 2560 and the support for the motor with the rotating gauge to simulate the vertical rotating part of the real machine.

 

Assembling the prototype

The slideshow below shows the final prototype assembled on an MDF base. Note that the rotating gauge attached to the motor axis can move between the two end-stop switches to control the motion inside the mechanically preset angle (typically it is 90 DEG)

 

{gallery:width=800,height=600} My Gallery Title

IMAGE TITLE: THEN IMAGE DESCRIPTION

IMAGE TITLE: THEN IMAGE DESCRIPTION

IMAGE TITLE: THEN IMAGE DESCRIPTION

IMAGE TITLE: THEN IMAGE DESCRIPTION

IMAGE TITLE: THEN IMAGE DESCRIPTION

 

The Software

The software should provide three key components:

  • Interface
  • Motor control
  • Configurable parameters

 

Interface Design

To make the UI easy to use also with a small-sized alphanumeric display I have created a two-buttons multilevel tree. After I have experienced the difficult managing some 3D printers interfaces, where the menu tree is controlled by an encoder I have opted for a multi-functional three buttons controller. To avoid irritating long button-press sequences, I have also added a potentiometer when the parameters of some functions should be changed between a wide range of numeric values. The scheme below (left) shows the menu tree while the right image shows how it has been created.

The Left - RIght LEDs monitor the end-stop switches status. The Alert section stop immediately the job and free the stepper motor.

 

The Software Headers

The core of the menu behavior is defined in the header file parameters.h

 

// Options default values
#define DEFAULTCYCLES 1       ///< Number of cycles by default
#define DEFAULTSPEED 1        ///< Default motion speed in minutes per cycle
#define DEFAULTOPTION 1       ///< Default startup option shown
#define MAXOPTIONS 6          ///< Max number of options (corresponding to emergency button)

#define LCD_OPTION1 1         ///< Menu option #1
#define LCD_OPTION2 2         ///< Menu option #2
#define LCD_OPTION3 3         ///< Menu option #3
#define LCD_OPTION4 4         ///< Menu option #4
#define LCD_OPTION5 5         ///< Menu option #5
#define LCD_OPTION6 6         ///< Menu option #6

#define COMMAND_NOCOMMAND 0   ///< No command button pressed
#define COMMAND_LEFT 1        ///< Left command button ID
#define COMMAND_RIGHT 2       ///< Right command button ID

#define MIN_TIME 1            ///< Minimum one-cycle duration (minutes)
#define MAX_TIME 6            ///< Maximum one-cycle duration (minutes)
#define MIN_CYCLES 1          ///< Minimum number of cycles
#define MAX_CYCLES 50         ///< Maximum number of cycles
#define MIN_ANALOG 0          ///< Minimum analog reading
#define MAX_ANALOG 1023       ///< Maximum analog reading (depends on the analog resolution)

#define APP_SET_TIME 1        ///< Application status: Set time per cycle
#define APP_SET_CYCLES 2      ///< Application status: Set number of cycles

 

The current status of the application is continuously updated (via interrupts) in the structure defined below

 

/**
 * State of the environment options
 */
struct options {
  volatile int optionsLevel;       ///< Current option level
  volatile boolean optionChanged;  ///< The option button has been pressed and should be processed
  boolean motorOn;        ///< Motor running status
  boolean isRotating;     ///< Motor rotation status
  volatile int motorDir;           ///< Current motor direction of rotation
  volatile boolean emergency;      ///< Emergency status
  volatile boolean rightLimit;     ///< Detected the right endstop switch
  volatile boolean leftLimit;      ///< Detected the left endstop switch
  boolean calibration;             ///< Flag set after the zero point has be found
  int appStatus;          ///< Status of the application
  int numSteps;           ///< Max number of steps between limiters
  int baseSpeed;          ///< Motor RPM for 1 minute cycle
};

 

parameters.h header then defines also the structure where we store the parameters saved in the Arduino Mega EEPROM

 

#define EEPROM_ADDRESS 0X00  ///< EEPROM address to read/write the configuration variables
/**
 * Configuration parameters, saved as single object to the EEPROM
 */
struct configObject {
  int cycleTime;          ///< Motor speed expressed in seconds per cycle
  int numCycles;          ///< Number of cycles
};

 

The header file displaystrings.h defines all the strings used by the program. Changing the language definition it is possible to translate the program into other languages.

 

// Language settings
#undef ENGLISH "EN"
#define ITALIAN "IT"
#undef SPANISH "ES"

 

The header file settings.h defines all the parameters and constants related to the motor control

 

The Main Application (Lino.ino)

As mentioned above, this application runs interrupt-driven.

The Setup() method, runs once when the Arduino Mega is powered-on initializes the parameters, get the last settings from the EEPROM then, last, enable the four interrupt vectors that control the application behavior

 

// Enable the interrupt vectors
  attachInterrupt(IRQ_SETTING_BUTTON, switchOption, LOW);
  attachInterrupt(IRQ_LEFT_LIMITER, switchLeft, CHANGE);
  attachInterrupt(IRQ_RIGHT_LIMITER, switchRight, CHANGE);
  attachInterrupt(IRQ_EMERGENCY_BUTTON, emergency, CHANGE);

 

All the application methods are a callback, so the resulting loop() main function is very short. In my hopinion, this approach makes also the source easier to understand.

 

/**
 * Main loop
 */
void loop(){
  if(initSys) {
    // Initialize the path and position
    sysStatus.calibration = false;
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print(OPTION1B_11);
    lcd.setCursor(0,1);
    lcd.print(OPTION1B_12);
    countSteps();
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print(OPTION1C_11);
    lcd.setCursor(0,1);
    lcd.print(OPTION1C_12);
    delay(COMMAND_DELAY); // Show the message then continue
    lcdShowOption();
    initSys = false;
  }
  // Check if the option status has changed and update the display
  if(sysStatus.optionChanged) {
    lcd.clear();
    sysStatus.optionChanged = false;
    delay(BUTTON_DELAY);
    attachInterrupt(IRQ_SETTING_BUTTON, switchOption, LOW); // re-enable the interrupts
    lcdShowOption();
    }
    // If we are in emergency status, the setting button is not reset until
    // the emergency status is disabled
    if(sysStatus.emergency == false) {
      // Check for command buttons. Command buttons can't be executed
      // when the system is in emergency state
      doCommand(checkCommandButtons());
    }
    else {
      setEmergency();
    }
  } // loop

 

The full source and the STL files are available in the GitHub repository: https://alicemirror.github.io/Lino/

The video below shows the prototype in action.