Skip navigation

DIY Test Equipment

4 Posts authored by: balearicdynamics Top Member

Too many button clicks

Buttons and tactile switches are frequently used in many projects involving micro controllers; one of the most frequent issue is related to unwanted multiple transitions when the button is pressed once.

Tactile switches as well as push buttons are mechanical components subject to the problem of bouncing. When a button is connected to a digital GPIO input pin (i.e. an Arduino pin configured as INPUT) we ideally expect that when the button is pressed we get only one high signal; unfortunately this rarely happens. During the mechanical movement the physical material vibrates affecting the voltage and the transitions between the On/Off status are not so clear as we usually need. Micro controllers and FPGA are fast enough reading the microseconds oscillations when the button is pressed, resulting multiple transitions while apparently we are pressing the button only once.

 

Button debouncing

To solve this problems we should apply a button debouncing to reach the goal: pressing a button only one signal should be detected by the micro controller digital input. We can identify two possible approaches: software and hardware.

There are plenty of source examples on how to debounce a button via software; the software approach seems the easiest way but in my opinion this is one of the cases where a hardware solution may be more efficient and resource saving. Micro controllers have memory and resource limits so adding a debouncing routine maybe critical in many cases.

 

The hardware choice

As I had to add a button debouncer to a test project based on Arduino 101 I decided to make something as much general as possible, easy to adapt to almost any micro controller and possibly platform independent. I figured two possible approaches: RC (resistor-capacitor) method and IC method. The RC option is easier to realise but I am not so confident it can be applied to very different operating conditions (e.g. very different micro controllers types and clock speed). It is not so difficult to calculate the values of resistor and capacitor for a RC debouncing circuit but I see a limitation restricting the application range. The calculation of the RC circuit is  dependent on the voltage of the board used; this means that for different voltage boards (1.8V, 3.3V, 5V etc.) we should provide a different RC calculation.

The RC simple circuit shown in the image below can be calculated with the nice RC Debounce online calculator

Screen Shot 2017-08-11 at 23.58.14.png

The parameters involved in the calculation are:

 

  • Voltage
  • High logic level
  • Bounce time (ms)
  • Capacitor value
  • Resistor value

 

The other hardware alternative is adopting a debouncing IC.

There are many specific IC for mechanical contacts debouncing, but they are almost expansive and oriented to manage power buttons while we generally use a push button is to generate a logic signal. The LTC2951CTS8LTC2951CTS8 for example sounds good (not sure if the DIL version is available) with a base price of about 5$.

This is why I decided to move to a general-purpose debounce circuit based on the Vintage NE555. TI provides a wide range of 555 ICs including DIL packaging covering a range supply levels from 1.5V up to 16V; the most common is the DIL package NE555-PNE555-P in the range between 4.5V and 16V. Just what I need, sold at 1/10 (one tenth) of the specialised debouncing ICs average price!

 

The NE555 circuit

Screen Shot 2017-08-12 at 12.30.10.png

I designed the circuit based on the popular NE555 monostable configuration shown above and detailed in the below schematics:

LevelingArduino101DebouncingSchematics.PNG

In this specific case using the two 10uF capacitors connected in parallel to the discharge pin and the 10K resistor for charging we get a timing of about 220 ms. It is a reasonable value to debounce a tactile switch connected to a digital input pin of an Arduino board; changing the values of the capacitors and the resistor we can increase or reduce the charge time resulting a different timing to the output pin (debounced signal.

 

Wiring the circuit

Using the NE555-P IC the circuit can be powered by the Arduino itself; the images below show the circuit placed as part of the Arduino 101 project where a push button is needed. The small board can also host the designated button making a compact object independent by the platform (an external power source can also be used) involving only the debounced signal connected to the desired GPIO micro controller pin.

IMG_20170801_094225.jpg IMG_20170806_201844.jpg

IMG_20170806_201900.jpg IMG_20170806_201907.jpg

IMG_20170806_202753_008.jpg IMG_20170806_202753_014.jpg

The resulting PCB is about 30x35 mm; I have provided a tactile switch button surface mounted on the opposite side of the components to make easier assembling the module in any project.

LevelingArduino101DebouncingSchematics3D01.PNG LevelingArduino101DebouncingSchematics3D02.PNG

The button in action

The video below shows the debouncer module at work powered by the Arduino 101 and a couple of screenshots showing the stability of the signal

 

 

Capture.PNG Capture3.PNG

 

IMG_20170722_080932.jpg

Introduction

I am one of the road testers for the Infineon DC Motor Shield w/ TLE94112EL for Arduino and this project shows the testing platform I developed to test the features of the board shield, but it is also useful to test the DC motors performance, as well as other motor controller boards for Arduino.

According to me, carrying out a testing on the road of this platform based on the Infineon TLE94112TLE94112 IC requires a versatile and flexible platform to make possible all the tests without building a lot of unreliable breadboarded stuff with loose wires. Moreover, in order to widen the range of possible tests making the platform reusable in the future you need to add only few extra components.

 

A full test of the TLE94112LE shield for Arduino based on this platform will be published in the Road Test section.

IMG_20170529_162044.jpg

 

The Project

Planning the Design

The idea of making an interactive testing platform evolved as I progressed analyzing in depth the shield features on several Arduino compatible platforms: Arduino UNO R3Arduino UNO R3, Chipkit PIChipkit PI and the Infineon XMC1100 BootInfineon XMC1100 Boot. All these platforms were reliable with no t special issues by the TLE94112 shield; for the final development I opted for the Infineon board due the better ARM MCU, which is faster and with more available flash and RAM memory (ARM Cortex M0 32 bit, 16Kb high-speed RAM, 64Kb Flash memory) I should admit that the better performance of this board compared to the Arduino UNO kept as reference.

IMG_20170519_095746.jpg IMG_20170519_095806.jpg

Testing motors

To create a reference for the test platform I chosen 6 brushed geared micro-motors with electrical characteristics included in the acceptable ranges of the TLE94112LE IC assembled together on an Aluminium square bar.

IMG_20170628_232738.jpg IMG_20170628_233349.jpg IMG_20170629_000615.jpg

To that aim, I used cheap motors from Pimoroni with the following characteristics:

 

Free-run current @ 6V: 60mA (max 120mA) - in some conditions can generate an overcurrent that is useful to test the error registers of the TLE94112

Stall torque @6V: 2.5Kg/cm

Stall current @6V: 900mA (TLE94112LE max current per half-bridge is just 0.9A)

Gear ratio: 298:1

BrushedMotorTest.jpg

A small 3D printed object has been designed to make visible the rotation of the motors.

 

Control I/O

Using a terminal to control the shield seemed immediately the right choice as the available control options open a wide scenario of many motion possibilities. The problem arose when I saw that some status information and configuration updates need continuous and immediate feedback. To solve this problem, an LCD display has been added to the testing board.

IMG_20170529_215359.jpg

 

DC/DC Regulator

To provide the right power supply to the TL94112 a separate power line has been set through a DC/DC power regulator.

IMG_20170719_210202.jpg

Design in practice

The working version of the design evolved around the features of the board I have experienced during the first phase of the hardware testing growing its complexity. The images below show the most meaningful steps.

 

{gallery} Platform design evolution

IMG_20170529_212524.jpg

IMG_20170719_210151_BURST002.jpg

IMG_20170701_110839.jpg

IMG_20170719_210210.jpg

IMG_20170720_231205.jpg

The Testing Platform

The last element added to the testing platform is a 50K potentiometer connected to the analog port 0. That will be used by the software when you need to read dynamic values (e.g. the manual duty cycle). The diagram below shows the components connection.

Screen Shot 2017-07-26 at 17.02.13.png

The Software

The hard part was developing the software, that required a lot of revisions, 37 pushes on the GitHub repository, but nowat last it is available as Open Source under the LGPL 3.0 license: https://github.com/alicemirror/TLE94112LE

 

 

Software Design

The software is divided into functional blocks as listed below

  • Main Sketch: initialize and setup the system. The main loop controls the TLE94112 through the Arduino library (via SPI protocol on PINs 8 and 10), the analog input and the parser, the messaging via the serial terminal and the LCD display.
  • Commands: definition of all the serial commands response messages and all related to the parsing.
  • MotorControl: the class interfacing the (thanks to) Infineon TLE94112 Arduino library with the high-level methods used by the serial commands

We'll see them in detail in the next chapters.

 

1. Main Sketch

I tried to reduce as much as possible the definition of global variables and constants in the main sketch. The only pre-processor definitions in the TLE94112LE.ino are limited to the global flags driving thebehaviorr of the program in the mainLoop() and the symbolic constants definitions strictly related to the application logic to avoid confusion and better readability and making the MotorControl class fully reusable in other projects.

 

//! Max analog reading range with a 50K potentiometer
#define MAX_ANALOG_RANGE 1024
//! Min analog reading range with a 50K potentiometer
#define MIN_ANALOG_RANGE 0

//! Duty cycle analog read should be ignore (bypass the analog reading)
#define ANALOG_DCNONE 0
//! Duty cycle analog read should be assgined to DC min
#define ANALOG_DCMIN 1
//! Duty cycle analog read should be assgined to DC mAX
#define ANALOG_DCMAX 2
//! Duty cycle analog read should be assgined to DC manual reading
#define ANALOG_DCMAN 3

 

A special note about the preprocessor directive _SERIAL_ECHO:

 

#define _SERIAL_ECHO - all commands are echoed to the serial terminal as shown in the example below

Serial output

setting  all

Direction  ccw

setting  none

setting  m1+

PWM:  80

setting  dc80

set  accel

setting  dc100

#undef _SERIAL_ECHO - only wrong commands are notified on the serial terminal

Serial output

wrong command  'mindc'

Main loop() structure

The main loop control the logic of the application. It is organised in three functional blocks checked sequentially every cycle depending on the status of the top flags and the data availability on the serial port (Tx/Rx, Pin 0 and 1)

 

Motors running status block

This block is checked only if the system status is running (start command). Every loop cycle when the motors are running it is checked for the presence of some error on the TLE94112LE registers and eventually errors are notified on the serial terminal

  // Check if at least one motor is running to test the error status
  // Note: It is possible to isolate the error status, if any,
  // for any motor. Here we make a simplification and check over
  // the motor without filtering
  isRunStatus = false;
  for(j = 0; j < MAX_MOTORS; j++) {
    if(motor.internalStatus[j].isRunning) {
      isRunStatus = true;
      j = MAX_MOTORS; // Force exit from loop
    } // check for running motors
  } // motors loop
  // If at least one motor is running check for diagnostic
  if(isRunStatus) {
    if(motor.tleCheckDiagnostic()) {
      //! Show the error star
      lcdShowError();
      motor.tleDiagnostic();
      lcdClearError();
    }
  }

 

Serial parsing block

If there are data available on the serial, the parser function parseCommand(String) is launched to check the command (or return a command error).

Serial commands are received as String terminated by CR=LF characters to be supported by any terminal or common serial connection. The last two terminating characters are removed before the string parsing.

All the commands and parser related strings are defined in the header file commads.h

 

Analog reading block

There are three conditions that enable the reading of analog values:

  • ANALOG_DCMIN User is setting manually via the potentiometer the minimum duty cycle value for one of the three PWM channels
  • ANALOG_DCMAX User is setting manually via the potentiometer the maximum duty cycle value for one of the three PWM channels
  • ANALOG_DCMAN User can change manually via the potentiometer the current duty cycle value for the PWM channel(s) enabled for manual duty cycle

 

Other functions in the main sketch

The main sketch also includes the functions to control the optional LED (on pin 12) and the LCD layout control functions.

 

LCD layout

For obvious size reasons the LCD shows several layouts depending on the conditions using a layout with abbreviations; whenever possible, more readable strings have been used. The shortened symbols used by the LCD are listed below:

  • M1, M2, M3, ... M6 Set the corresponding motor
  • M* Set all the motors with the same parameter
  • PWM[1] 80Hz, PWM[2]100Hz, PWM[3] 200Hz Set one of the three PWM channels (assigned to a fixed frequency)
  • CW/CCW Clockwise/Counterclockwise direction of the selected motor(s)
  • FreeWh+/FreeWh- FreeWheeling active enabled/disabled for the selected motor(s)
  • DCMin Minimum duty cycle value for the selected PWM channel(s)
  • DCMax Maximum duty cycle value for the selected PWM channel(s)
  • ena/dis Selected motor(s) set as enabled or disabled
  • Ramp Set acceleration and deceleration for the selected PWM channel(s)
  • Inst. Set instant starting for the selected PWM channel(s)

 

The gallery below shows and example of several LCD layouts

 

{gallery} LCD Layout examples

IMG_20170725_083326_1.jpg

IMG_20170725_083810.jpg

IMG_20170725_084142.jpg

IMG_20170725_084152.jpg

IMG_20170725_084431_1.jpg

IMG_20170725_084218_1.jpg

IMG_20170725_084546.jpg

IMG_20170725_084557.jpg

IMG_20170725_084649_1.jpg

 

2. MotorControl Class

The MotorControl C++ class is pat of the software, uses the TLE94112 Arduino Library by Infineon and is built around the files motorcontrol.cpp, motorcontrol.h and motor.h (extra preprocessor definitions). The class itself is structured through two level methods.

For the complete methods of the class and full documentation refer to the software available on the GitHub repository

 

MotorControl - Hardware control methods

The hardware control method interfaces directly the features of the hardware shield exposed by the TLE94112 Arduino library.

 

MotorControl:: tleCheckDiagnostic(void)

MotorControl::tleDiagnostic(int motor)

MotorControl::tleDiagnostic()

Check the diagnostic status and send the corresponding error message to the serial terminal (if any)

 

MotorControl::motorConfigHBCCW(int motor)

MotorControl::motorConfigHBCW(int motor)

and others similar to configure half bridges direction and the other parameters, the PWM channel, duty cycle etc.

 

MotorControl - High level methods

The hight level methods interfaces the commands calling recursively after filtering potential errors, This avoid internal problems or unexpected behaviours or hardware damages.

Every parser command call one of the high level commands of this class.

 

3. Commands Description and Syntax

Excluding the potentiometer on the board all the controls are sent via terminal through a USB-to-serial connection. When the system is in running mode it can accept configuration commands that will be effective after a stop and start call.

If errors occur while the system is running these are shown in detail on the serial terminal and are notified on the LCD screen

The available commands are listed below:

Direction control

  • cw : clockwise rotation
  • ccw : counterclockwise rotation
  • accel : enable the acceleration when motor start
  • noaccel : disable the acceleration when motor start

Action commands

  • start : start all motors
  • stop : stop all motors
  • reset : reset the system to the default

Duty cycle settings to PWM channels

  • dcmanual : Set the duty cycle value depending on the pot
  • dcauto : Set the duty cycle current limits
  • dcmin : Set the min duty cycle value via pot
  • dcmax : Set the max duty cycle value via pot
  • dcinfo : Shows the duty cycle range for the selected PWM channel

PWM channel selection for duty cycle settings

  • dc80 : Set the duty cycle to the PWM channel 80Hz
  • dc100 : Set the duty cycle to the PWM channel 100Hz
  • dc200 : Set the duty cycle to the PWM channel 200Hz
  • dcPWM : Set the duty cycle to all the PWM channels

Motor select for settings

  • all : Select and enable all motors
  • none : Disble all motors
  • m1 : select motor 1
  • m2 : select motor 2
  • m3 : select motor 3
  • m4 : select motor 4
  • m5 : select motor 5
  • m6 : select motor 6

Motor enable

  • m1+ : enable motor 1
  • m2+ : enable motor 2
  • m3+ : enable motor 3
  • m4+ : enable motor 4
  • m5+ : enable motor 5
  • m6+ : enable motor 6

PWM Frequency selector

  • 80 : PWM 80 Hz
  • 100 : PWM 100 Hz
  • 200 : PWM 200 Hz

Freewheeling mode motor(s) setting

  • fwactive : Fereewheeling active
  • fwpassive : Freewheeling passive

Show all motors configuration

  • conf : Dump the current settings

 

For the last updates and revisions please follow the TLE94112LE on GitHub

(special thanks to antoricagno for text review)

Introduction

I am one of the road testers for the Infineon DC Motor Shield w/ TLE94112EL for Arduino and this project is the second part of the road test blogging. This is the motorised evolution of the 3d printer filament roll holder and monitor for Arduino and it is also the second Arduino project I publish in this area.

In the first part I presented the building of the 3D printed structure to manage the load sensor while printing and the motor control of the filament spool with a geared brushed motor. Now we see the electronic part based on ArduinoArduino or the Infineon XMC1100 BootInfineon XMC1100 Boot compatible with Arduino and the TLE94122LE Arduino shield .

 

Hardware setup

 

The video above shows the system at work. Thanks to the completeness of the TLE94112LE Arduino shield the electronic assembly is extremely easy; this is one of the aspects I most appreciated of this Infineon board as well as the possibility to manage many motors together. The setting can be done just in three steps:

 

  1. Insert the shield on top of the Arduino or the Infineon XMC110 Arduino compatible board
  2. Connect the motor wires to the Out1 and Out2 screwed connectors of the shield
  3. Connect the power and signals from the HX711 AD weight sensor amplifier to the Arduino pins. In this case I have used pins 2 and 3 but all the free pins can be used

 

Note: pins 8 and 10 are reserved by the TLE94113LE shield for the SPI connection

That's all.

 

Controlling the system through the serial port

There is a precise reason - imposed by the number of available pins on the Arduino UNO family boards - I chose to control the system via the USB to serial connection and a serial terminal: The TLE94112LE shield can manage up to 6 brushed motors (or more in cascade configuration) and every motor in this setup can control a different filament roll independently. As every motorised unit is based on a weight sensor to control six different filament dispensers we should be able to read data from six weight sensors. Every load cell "consumes" two pins, pin 0 and 1 are reserved (Tx/Rx) for the serial and pins 8 and 10 are reserved for the SPI channel connecting the TLE94112LE shield.

 

System status

The control software works through four different states, defined in filament.h:

 

#define SYS_READY "Ready"       // System ready
#define SYS_RUN "Running"       // Filament in use
#define SYS_LOAD "Load"         // Roll loaded
#define SYS_STARTED "Started"   // Application started

// Status codes
#define STAT_NONE 0
#define STAT_READY 1
#define STAT_LOAD 2
#define STAT_RUN 3

 

Status : Started

This status occurs after a hardware reset or when the system is powered on. The power-on (and setup() call when the sketch starts) initialises the internal default values and should be started with no extra weight on the platform as part of the initialisation sequence is the acquisition of the absolute tare to reach the physical zero weight.

 

Status : Ready

The ready state occurs after a soft reset (sent from the serial terminal). It is similar to the physical resect but no tare is calculated; the reset command can be launched also when the system is running.

 

Status : Load

The load status occurs when the load command is sent by the terminal. This means that the filament roll has been loaded and the dynamic tare has been calculated. The exact filament weight is obtained by the kind of roll setup subtracting the weight of the motor unit and the empty roll.

 

Status : Running

This status enable the automatic weight calculation and the automatic filament dispenser.

 

Terminal messages

The current version of the software returns human readable messages to the terminal depending on the commands. The string messages are defined in two header files: commands.h (command related messages and responses) and filament.h (strings used by the parser to create compound messages).

 

In commands.h

// Execution notification
#define CMD_EXEC "executing "
#define CMD_NOCMD "unknown "
#define CMD_SET "setting "
#define CMD_MODE "set mode to "
#define CMD_UNITS "set units to "
#define CMD_STATUS "set status to "
#define CMD_WEIGHT "Weight "
#define CMD_WRONGCMD "wrong value "
#define CMD_EXTRUDERPULL "WARNING!!!"

 

In filament.h

#define MSG_USED "used: "
#define MSG_REMAINING "remain: "

#define SYS_READY "Ready"       // System ready
#define SYS_RUN "Running"       // Filament in use
#define SYS_LOAD "Load"         // Roll loaded
#define SYS_STARTED "Started"   // Application started

#define DIAMETER175 "1.75 mm"
#define DIAMETER300 "3.00 mm"

// Units
#define UNITS_GR "gr"
#define UNITS_CM "cm"
#define UNITS_MT "m"
#define UNITS_KG "Kg"
#define FILAMENT_ROLL "Roll"

#define PLA_MAT "PLA"
#define ABS_MAT "ABS"

 

Commands

Two different files are involved in the command management: commands.h including all the commands and related parameters and filament.h including all the constants and definitions used by the weighting system and by the parser. While the internal calculations are done automatically by software I have implemented a series of commands to set the behaviour of the system and manually control some parameters.

Command keywords are case sensitive and should just be send from the terminal. If a command is not appropriate for the current status of it is not recognised a wrong command message is returned else the command is executed.

 

Status commands

Change the current status of the system and the behaviour is adapted as well

// Status change
#define S_RESET "reset"        // Reset the system with the current filament setup
#define S_LOAD "load"          // Filament roll has been loaded
#define S_RUN "run"            // Print job is running
#define S_DEFAULT "default"    // Reset the system with the default settings

 

Filament commands

Using separate commands it is possible to setup the filament and roll characteristics based on the most common weight and sizes today available on the market

// Filament setup
#define SET_PLA "PLA"
#define SET_ABS "ABS"
#define SET_175 "1.75"
#define SET_300 "3.00"
#define SET_1KG "1kg"
#define SET_2KG "2kg"

 

Units commands

These are a couple of commands to set the visualisation of the measure units in grams or centimetres. As a matter of fact it is possible to eliminate this commands and always represent data in both units.

// Units setting
#define SET_WEIGHT "gr"
#define SET_CENTIMETERS "cm"

 

Information commands

Shows group of information depending on the system status

// Information commands
#define SHOW_INFO "info"          // Shows roll current info (weight, material, diameter, remaining percentage)
#define SHOW_STATUS "stat"        // Shows weight status values (used material)
#define SHOW_DUMP "conf"          // Dump the current settings
#define SHOW_WEIGHT "weight"      // Show the current read weight (last absolute weight value read from the sensor)

 

Motor commands

Control the motor for filament feed or pull.

If the preprocessor _USE_MOTOR_ is undefined in filament.h header all the motor functions and commands are ignored. This is to grant the compatibility of the program with the non-motorised version of the system without maintaining separate sources.

// Motor control
#ifdef _USE_MOTOR
#define MOTOR_FEED "feed"       // Feed a length unit
#define MOTOR_PULL "pull"       // Pull back a lenght unit
#define MOTOR_STOP "stop"       // Pull back a lenght unit
#define MOTOR_FEED_CONT "feedc"    // Feed continuopusly
#define MOTOR_PULL_CONT "pullc"    // Pull back continuously
#endif

 

All motor commands follow an acceleration/deceleration path. The two commands feed and pull executes a short sequence as defined in motor.h by the constant FEED_EXTRUDER_DELAY while feedc and pullc commands runs indefinitely until a stop command is not received.

 

Running mode commands

The running status accept two modes; mode man just read periodically the weight and the motor moves until a motor control command is not sent. Mode auto instead executes two feed commands when the extruder needs more filament.

The principle is based on the weight readings, contextualised to this particular environment. We expect that the filament consumption is relatively slow, 3D printers are almost slow and the normal weight oscillations depends on the environment vibration (better if you don't put the entire stuff on the 3D printer ) When the extruder pulls the filament instead the weight difference dramatically increase (50 gr or more) in very few time, typically between two o three readings. This information is filtered by the software that "deduct" that new filament is needed.

To avoid wrong readings weight variations while the motor is running are ignored at all.

// Running mode
#define MODE_AUTO "auto"        // Run in automatic mode
#define MODE_MANUAL "man"    // Run in manual mode

 

Application logic

The application logic is distributed in the .ino main (the Arduino sketch) along three functions: setup(), loop() and parseCommand(commandString) The sketch uses two separate classes: FilamentWeight class to manage all the filament calculations and sensor reading via the HX711 IC and MotorControl class interfacing the low level methods of the TLE94112LE Arduino shield.

 

setup()

Launched once when at power-on or after a hardware reset initalises the instances of the classes, setup the hardware and the terminal communication.

// ==============================================
// Initialisation
// ==============================================
void setup() {
  // Serial is initialised at high speed. If your Arduino boards
  // loose characters or show unwanted/unexpected behavior
  // try with a lower communication speed
  Serial.begin(38400);

  // Print the initialisation message
  Serial.println(APP_TITLE);

  // Initialize the weight class
  scale.begin();
#ifdef _USE_MOTOR
  // initialize the motor class
  motor.begin();  
  modeAuto = false;
#endif
}

 

loop()

The main loop function just manage three different conditions. While there are two classes for weight sensor and motors relatively complex, there is the advantage that the resulting sketch is really easy to understand and manage.

  1. Check (in mode auto) if the extruder needs more filament
  2. If the motor is running check for hardware errors (returned by the TLE94112LE)
  3. If there are serial data available parse the command
// ==============================================
// Main loop
// ==============================================
/** 
 * The main loop role is executing the service functions; display update, 
 * calculations, button checking
 * The scale reading is done at a specific frequence and is interrupt-driven
 */
void loop() {
  scale.readScale();
  
#ifdef _USE_MOTOR
  // Check for the extruder request
  if( (scale.statID == STAT_RUN) && (scale.currentStatus.filamentNeededFromExtruder == true) ) {
    if(modeAuto) {
      motor.feedExtruder(FEED_EXTRUDER_DELAY);
      motor.tleDiagnostic();
    }
  }
#endif

  // Check if the motor is running to test the errors status
  if(motor.internalStatus.isRunning) {
    if(motor.tleCheckDiagnostic()) {
      motor.tleDiagnostic();
    }
  }

  if(Serial.available() > 0){
    parseCommand(Serial.readString());
  } // serial available
}

//! Send a single line message to the serial
void serialMessage(String title, String description) {
    Serial.print(title);
    Serial.print(" ");
    Serial.println(description);
}

 

parserCommand(commandString)

The parsing function check for the strings coming from the serial and when a command is recognised it is immediately processed. Every command act as a state machine impacting on some parameter of the system; following this logic all the commands are reduced to three sequential actions:

 

  1. Send a command to the FilamentWeight class (weight commands) or to the MotorControl class (motor commands)
  2. Executes a calculation to update weight values or update one of the internal parameters
  3. Show on the terminal and information output when the execution complete

 

Below the full parsing listing; commands have been grouped by type as shown in the Commands section above.

 // =========================================================
  // Parameters settings
  // =========================================================

  // Set PLA material and recalculate the material characteristics
  // Flag is set to display an update nesxt loop cycle
  if(commandString.equals(SET_PLA)) {
    scale.materialID = PLA;
    scale.calcMaterialCharacteristics();
    scale.showInfo();
  }
  // Set ABS material and recalculate the material characteristics
  // Flag is set to display an update nesxt loop cycle
  else if(commandString.equals(SET_ABS)) {
    scale.materialID = ABS;
    scale.calcMaterialCharacteristics();
    scale.showInfo();
  }
  // Set 1.75 mm filament diameter and recalculate the material characteristics
  // Flag is set to display an update nesxt loop cycle
  else if(commandString.equals(SET_175)) {
    scale.diameterID = DIAM_175;
    scale.calcMaterialCharacteristics();
    scale.showInfo();
  }
  // Set 3.00 mm filament diameter and recalculate the material characteristics
  // Flag is set to display an update nesxt loop cycle
  else if(commandString.equals(SET_300)) {
    scale.diameterID = DIAM_300;
    scale.calcMaterialCharacteristics();
    scale.showInfo();
  }
  // Set 1kg filament spool and recalculate the material characteristics
  // Flag is set to display an update next loop cycle
  else if(commandString.equals(SET_1KG)) {
    scale.wID = ROLL1KG;
    scale.calcMaterialCharacteristics();
    scale.showInfo();
  }
  // Set 2kg filament spool and recalculate the material characteristics
  // Flag is set to display an update nesxt loop cycle
  else if(commandString.equals(SET_2KG)) {
    scale.wID = ROLL2KG;
    scale.calcMaterialCharacteristics();
    scale.showInfo();
  }
  // Set units in grams
  else if(commandString.equals(SET_WEIGHT)) {
    serialMessage(CMD_UNITS, commandString);
    scale.filamentUnits = _GR;
  }
  // Set units in cm
  else if(commandString.equals(SET_CENTIMETERS)) {
    serialMessage(CMD_UNITS, commandString);
    scale.filamentUnits = _CM;
  }

  // =========================================================
  // Change current functional status
  // =========================================================
  // Send a reset command and restore the parameters to the defaults
  // The tare is not recalculated to avoid wrong measure (if the spool
  // is already on the scale platform
  // This command had mandatory executi9on and ignore the previous state
  // The flag is set to show an update nextg loop cycle
  else if(commandString.equals(S_RESET)) {
    scale.reset();
    scale.stat = SYS_READY;
    scale.statID = STAT_READY;
//    scale.flashLED();
    scale.showInfo();
  }
  // Send a load command status setting
  // Should be executed after the filament roll has been set 
  // and placed on the scale base or after a reset command
  // The flag is set to show an update nextg loop cycle
  else if(commandString.equals(S_LOAD)) {
    scale.stat = SYS_LOAD;
    scale.statID = STAT_LOAD;
    scale.initialWeight = 0;
    scale.readScale();
    scale.showLoad();
  }
  // Send a run command status setting
  // Should be sent when a print job is started
  else if(commandString.equals(S_RUN)) {
    scale.stat = SYS_RUN;
    scale.statID = STAT_RUN;
    scale.initialWeight = scale.lastRead - scale.rollTare;
    scale.prevRead = scale.lastRead;
    scale.lastConsumedGrams = 0;
    scale.showStat();
  }
  // Send a default command status setting
  // Should be used to reset the system to the default values 
  // of the material without changing any setting in the weight
  // tare and calculations but the current status is not changed.
  // Use this commmand to reset the material to the internal conditions
  else if(commandString.equals(S_DEFAULT)) {
    scale.setDefaults();
    scale.showInfo();
  }  

  // =========================================================
  // Informative commands
  // =========================================================
  else if(commandString.equals(SHOW_INFO)) {
    scale.showInfo();
  }
  else if(commandString.equals(SHOW_STATUS)) {
    scale.showLoad();
    scale.showStat();
  }
  else if(commandString.equals(SHOW_DUMP)) {
    scale.showConfig();
  }
  else if(commandString.equals(SHOW_WEIGHT)) {
    Serial.print(CMD_WEIGHT);
    Serial.print(scale.getWeight());
    Serial.println(UNITS_GR);
  }

  // =========================================================
  // Motor control
  // =========================================================
#ifdef _USE_MOTOR
  else if(commandString.equals(MOTOR_FEED)) {
    serialMessage(CMD_EXEC, commandString);
    motor.feedExtruder(FEED_EXTRUDER_DELAY);
    motor.tleDiagnostic();
  }
  else if(commandString.equals(MOTOR_PULL)) {
    serialMessage(CMD_EXEC, commandString);
    motor.filamentLoad(FEED_EXTRUDER_DELAY);
    motor.tleDiagnostic();
  }
  else if(commandString.equals(MOTOR_STOP)) {
    serialMessage(CMD_EXEC, commandString);
    motor.motorBrake();
    motor.tleDiagnostic();
  }
  else if(commandString.equals(MOTOR_FEED_CONT)) {
    serialMessage(CMD_EXEC, commandString);
    motor.filamentContFeed();
  }
  else if(commandString.equals(MOTOR_PULL_CONT)) {
    serialMessage(CMD_EXEC, commandString);
    motor.filamentContLoad();
  }
#endif

  // =========================================================
  // Change behaviour mode
  // =========================================================
  else if(commandString.equals(MODE_AUTO)) {
    serialMessage(CMD_MODE, commandString);
    modeAuto = true;
  }
  else if(commandString.equals(MODE_MANUAL)) {
    serialMessage(CMD_MODE, commandString);
    modeAuto = false;
  }
  else
    serialMessage(CMD_WRONGCMD, commandString);
 }

 

The last updated version of the software is available under the LGPL 3.0 open source license on GitHub: https://github.com/alicemirror/3DPrinterFilamentDispenserAndMonitor

 

Read also the first part: 3D Printer Filament Automatic Dispenser for Arduino - #1 Design and Hardware

Introduction

I am one of the road testers for the Infineon DC Motor Shield w/ TLE94112EL for Arduino and this project is the first part of the road test blogging. This is the motorised evolution of the 3d printer filament roll holder and monitor for Arduino and it is also the second Arduino project I publish in this area.

I have made and used for months the filament roll support based on the mechanics illustrated in the mentioned project but some filament issues have not yet been solved by this tool.

When it is used by 3D printers filament - usually almost robust - is pulled by the extruder while the roll is placed nearby free to rotate. I have observed meaningful differences in the material behaviour depending on the usage level, based on 1Kg filament rolls. A new filament spool flows almost well but the force applied by the extruder should be relatively relevant. The extruder motor (a Nema17 stepper motor) is not damaged but the two gears of the extruder collect particles of the plastic material due the applied force; this requires extruder maintenance after a while to avoid clogging of the filament in the hot end. These particles tends to detach and mix with the clean filament while it is feeding the hot end nozzle increasing clogging problems and a general more frequent nozzle wear; this occurs more frequently with 0.3 mm diameter nozzles.

When the filament roll is half used and more its spirals become smaller and in some environmental conditions the filament tend to break too frequently.

Long print jobs become less reliable; for example I can't leave the printer working alone for an entire night without controlling it. Thus the idea to make a controlled filament feeder figured a precise series of issues to solve.

 

  • Make the automated engine almost simple and easy to reproduce
  • Reduce as much as possible the number of non-3D printable components to make it
  • Reduce as much as possible the stress applied to the extruder while printing
  • Use a low cost and easy to program micro controller board
  • Use the weight load sensor to keep under control che filament consumption and filament feeding
  • Manage the environmental noise interfering with the filament weight measures

 

Also using a single 3D printer we frequently manage more filament rolls (different colors) not all at the same level depending on the print job we are doing. Using an Arduino and the TLE94112EL shield motor controller may result the most reliable and cheaper solution: the board can control up to 6 different brushed motors with simple commands. This Infineon board has its own half bridge motor controller including three different frequencies PWM channels: 80, 100 and 200 Hz. In practice this means running motors sending commands from Arduino keeping the MCU free to other tasks while motors are running.

 

IMG_20170616_173135.jpg

Choosing the design approach

Respect to the mechanical components the design approach should comply some essential requisites. The most important is the possibility to make corrections and upgrades to the mechanical prototype if testings does not reach the expected results. We should also consider the applied forces to every part: it is not a good practice designing the entire complex component (but possible) to avoid issues some frequent issues:

 

  • Different parts of the same structure requires different levels of robustness
  • Too long single-printing time
  • Difficulty positioning the 3D printed object requiring as less as possible support material
  • Difficulty refining the entire object
  • If something goes wrong in a part the entire object should be reprinted and a lot of material will be trashed with a single-object approach
  • Difficult adapting the same design to different versions of the model

 

Making the right choice in the 3D design means saving a lot of prototyping and production time, a considerable quantity of filament and creating an adaptable structure. To say this in one word: 3D parametric model

An adaptable design means also a model reusable building; the same structure can be reused with a different kind of motor, different bearings etc. Thanks to a modular design it was possible approaching a solution for this project after a first prototype with a different and not reliable motion transmission solution..

 

Introducing the TLE94112LE Arduino shield

TLE94112EL_shield.jpg

One of the limits I have experienced with other motor control shields for Arduino (but not only) is that they uses the features of the same micro controller (i.e. PWM and other GPIO pins); this means that your board becomes dedicated to these tasks while only few other resources (MPU and GPIO) are available for other uses. To stay on the same topic of this project many 3D printer controllers based on Arduino clones experience this kind of limits. Having the possibility to put my hands on the TLE94122LE Arduino shield for road testing, the most evident advantage of the IC the board is based on is just its completeness. Arduino board communicates with the board via the SPI protocol using just only two pins (or three if you stack two different TLE94112 shields on the same Arduino). Every command you send to the shield is processed autonomously by the IC without consuming MPU resources. Another remarkable feature of the Infineon board is the possibility to control up to six brushed motors with three programmable PWM channels. This means that Arduino can setup one or more motors, start then continue working on other tasks. This shield revealed perfect to support up to six different filament rolls at the same time that is just one of the main goals of this project.

Considering the possibility to manage six different filament spools with a single Arduino + shield the micro controller cost impact of every single filament controller less than 5 Euro.

 

3D Printer Filament Dispenser.png

Functional design and components

As shown in the image above this project is not extremely complex to assemble starting from the kit; HX711 do his job very well (a well working Arduino library is available on GitHub) sending to Arduino the load cell readings. By the other side the TLE94112LE shield (with its own library too, thanks to the Infineon developers) manages all the motor part.

 

The MCU

Arduino UNO R3.jpg XMC1100_Boot-Kit.jpg

This project has been developed in several steps making (and discarding) early prototypes using Arduino UNO R3 and Infineon XMC1100 Boot KitXMC1100 Boot Kit Arduino compatibile. By a hardware point of view there was no difference at all but I should say that the higher processor speed and more available memory of the XMC1100 made the difference in the general performances: the systems - that works perfectly with Arduino - show better responsiveness and performances when running on the Infineon board. One of the advantages using the XMC1100 board is the availability of more internal resources (memory and MCU speed).

 

Weight sensor

After doing some experiments in several directions I saw it was possible to control the entire system - monitoring and automatic feeding - with a single sensor; with some experience managing data in the right way a load cell able to dynamically measure the filament spool weight variations can provide all the information we need.

IMG_20170612_144450.jpg IMG_20170613_143006.jpg

I  used an inexpensive load cell in the range 0-5 Kg (less than 4 Euro) sold together with a small breakout board of the HX711 AD Amplifier, an IC adapt to manage the load cells sensors. There was not interfacing problems as the Arduino library is available on GitHub (HX711).

 

Motion hardware

Spool rotation is obtained by a couple of 2:1 demultiplied gears moved by a 280 rpm brushed motor. The motor is a McLennan instrument DC geared motor McLennan instrument DC geared motor 90:1 with a rated current of 50 mA and a max no-load current of 20 mA (see the attached datasheet). This brushed geared motor fits the specifications of the TLE94112LE DC motor controller shield.

IMG_20170629_105331.jpg

Obviously also similar characteristics geared motors can be used as well.

 

Filament spool driver

The spool driver is the base where the filament spool rotates free. The weight sensor is the mid support of the two-layers base so the system is able to detect the weight variations in the various conditions.

IMG_20170701_140929.jpg IMG_20170613_143006.jpg

To avoid as much as possible the friction during rotation I have used four bearings while on the bottom part of the base the HX711 breakout board is fixed with a couple of screws.

Only six wires should be connected to the Arduino shield:

 

  • 5V and GND (from Arduino) power line for the HX711 IC
  • Two signal lines from the HX711 IC (to Arduino I/O pins 4 and 5)
  • Two power lines from the brushed motor connected to out 1 & 2 of the shield (TLE94112LE power lines)

 

Mechanics and motion design

Mechanic design needed two different prototypes. Before seeing in depth the steps I followed there is a short foreword we should say about 3D printing and mechanic design.

When we need 3D printing to build - no matter how complex - moving parts and in general mechanical elements we should always consider that there will be some forces, static of dynamics, that will be applied to the prototype while it is working. Knowing before what are the kind of forces applied to our 3D printed structure it is essential to decide important parameters:

 

  • 3D printing orientation: always reduce as much as possible the extra-material used to create supports while printing, large surfaces grant better adhesion so it is good to place them to the bottom on the printing bed
  • Layer thickness: a too thick layer (i.e. 4 mm) makes printing fast but we loose definition. I always use 2 mm layers that are a good compromise between final quality and printing speed
  • Solid fill density: excluding the first experiments I have done with my first 3D printer, it is very rare I fill objects more than 75% and I strongly suggest never to fill objects less than 15-20% to avoid very crap results.

 

But the first step that can dramatically change the quality and robustness of the resulting 3D printed piece is the CAD design. Designing single objects like cases, puppets, gadgets CAD choices is not influencing too much the final result but when we have many moving parts I consider a must designing compound objects for at least two reasons:

 

  1. Depending on the role of every part it is possible to decide separately the better fill density
  2. The compound object - just like in this case - can be easily modified and upgraded without impacting the entire structure and reducing the number of elements to reprint

3D Parts.jpg 3D Top.jpg

The two images above shows all the parts to be printed from the first prototype design. You can see the two green pulley used to manage the movement; the first idea was using a tooth belt for the transmission but when the prototype was built the solution revealed almost bad. The gallery below illustrated several rendering of the mechanics design before I started 3D printing the parts.

 

{gallery} Model rendering

Assembled 02.jpg

Asssembled 01.jpg

Exploeded 01.jpg

Exploeded 02.jpg

IMAGE TITLE: THEN IMAGE DESCRIPTION

Exploeded 03.jpg

Exploeded 04.jpg

Exploded 07.jpg

Exploded 06.jpg

Exploded  05.jpg

Assembled 06.jpg

Assembled 04.jpg

Final 01.jpg

Final 02.jpg

 

After 3D printing then assembling the first prototype the tooth belt transmission was not working well. The tension of the belt required a more robust support than the structure I designed. The rest of the parts instead was working perfectly. As the complete structure was built with different parts it was sufficient to replace the two tooth pulleys with a couple of gears; I had to reprint only these two replacements and the issue was solved.

The video below shows the final solution and the making of refining and assembling the first prototype

 

In the second part we see the commands and software logic: 3D Printer Filament Automatic Dispenser for Arduino - #2 Connection and Software