Foreword
This project has been originally developed as part of the RoadTest of the Infineon TLE94112EL Arduino compatible shield. On occasion of the Element14 Birthday and he Arduino Birthday, I am repurposing the making here. At the actual date, the DC brushless motor controller by Infineon remain IMHO one of the best motor shields developed for the Arduino and Arduino compatible platforms. I hope that the project details and full software availability will be a good inspiration for other members. While the text of this project remains the same with some small aesthetic changes, now the building if totally open, with some updated to the GitHub repository including the 3D printable STL files.
The GitHub technical site, sources and documentation can be found here: https://alicemirror.github.io/3DPrinterFilamentDispenserAndMonitor/
Note: Aiming to make this project 100% open and fully available for the community I have removed it from the online market on Tindie. If you like it, just download, hack and Do It Yourself!
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 Arduino or the Infineon 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:
- Insert the shield on top of the Arduino or the Infineon XMC110 Arduino compatible board
- Connect the motor wires to the Out1 and Out2 screwed connectors of the shield
- 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.
- Check (in mode auto) if the extruder needs more filament
- If the motor is running check for hardware errors (returned by the TLE94112LE)
- 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:
- Send a command to the FilamentWeight class (weight commands) or to the MotorControl class (motor commands)
- Executes a calculation to update weight values or update one of the internal parameters
- 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
Top Comments