Machine weeks



Hero Shot

Here are two examples of drawings made by our machine.

Drawing a face:

DrawRes1

Drawing mountains:

DrawRes2

Introduction

Launching Session

machine week launch
Launch of the machine week : our six Fab Academy students discussing the plan and strategy for the two coming weeks. First time they are all together in the Lab (Bogdan joined us from Bucharest for this week).

General Idea

The general idea is to take the concept of the Urumbu machine and improve it in our own way. We want to develop the Urumbu ULB machine, whose main functions are 2D movement (2D axis systems) and a modular tool head. In the first iteration of the project, the 2-axis system will be taken over entirely from the Urumbu 2022 machine, while the modular function of the tool head will be considered. The software side also needs to be thought through, as nothing in particular has been documented on this subject.

If all goes well in terms of planning, a second iteration can be envisaged in which the 2-axis system is redesigned to reduce to the strict minimum the number of unmanufacturable parts to be purchased. Additional tool heads can also be considered.

Tasks Definition & Repartition

There are mainly 2 functions to be developed, each of which can be divided into three themes: mechanical development, electronic development, and software development.

The two functions are the 2-axis system, and the modular tool head.

The distribution of topics was worked out together, with each person taking responsibility for a part of the project. This is described in the table below.

Function... DevelopmentWho
2D Axis SystemMechanicalTeo & Charlotte
ElectronicBogdan & Alex
SoftwareSiméon
Modular Tool HeadMechanicalLuis
ElectronicAlex
SoftwareSiméon

Our idea is to start with this distribution, and then eventually redistribute people as tasks progress.

Work Organisation

To organize our work, we decided to use the Trello management tool to see how other team members were progressing. Trello lets you define tasks and the people in charge of them, as well as comment on them. Temporally, you can also define a calendar and assign tasks or progress to it.

Another communication tool is of course the documentation on the FabLab ULB gitlab. Documenting as soon as we can allows others to see the progress we’ve made, and perhaps the difficulties we may encounter.

Finally, we’ve decided to organize a meeting every morning at 10am to discuss the previous day’s progress, the day’s objectives and so on. This scrum meeting system enables us to keep abreast of progress and difficulties, and to offer to help, etc. It’s also a horizontal organization, which we like.

Of course, when it comes to communication, we also have a messaging channel so we can easily communicate with each other.

2D Axis - Mechanical Development

Introduction & Basic Principles

The 2-axis system consists of a frame placed parallel to the work surface. This frame will house a rail that can be moved in the Y direction by means of two modules, referred to here as Y-plates. This will be able to move along the rail to perform movements in the X direction. The combination of the movement of the raille on the frame and the end effector on the rail allows movement in XY (2 dimensions).

Stepper motors will be attached to the frame, and a pulley system will pull the end-effector in the desired direction. The corners of the frame will house the two motors, as well as two pulleys system. The railing will also house a pulley system on either side of it.

The principle of movement is illustrated below. It is a coreXY movement system.

coreXY system

Parts Manufacturing

Our instructor Axel bought aluminium T-slotted framing rails that will be the main components of the machine’s frame. The other mechanical components were either cut using the laser cutter or 3D printed using files available on the UrumbotXY Fall 2022 gitlab. Some files have been modified after some tests, it will be developped below.

Laser cutter

The parts on which the weels and motors are fixed have been cut in plexiglass sheet of 3mm, and then superposed to obtain a resulting thickness of 6mm in order to fit with the screws size.

lasercutter-parts cuttingparts

Before cutting the parts, a characterization of the power/speed of the laser cutter has been made on the plexiglass sheet to know what parameters were the best for a fast and clean cut. Speed: 30% (= 690mm/min), Power: 80%.

3D printing

With the Prusa 3D printer, we printed the pulleys, the adjuster and the spacers for the end effector plate.

print-parts1 cutprint-parts2tingparts

The adjusters have a hole slightly shifted from the center in which the screw is inserted. This offset makes it possible to adjust the space between the wheel and the rail, to reduce the gap between the rail and the wheel without causing too much friction.

adjuster

Purchased Parts

It was necessary to purchase parts such as racks, screws, bolts, wheels and ball bearings. The bill of materials can be consulted here.

Assembly

Assembly here involves making the frame on which the center rail will run. The corners of the frame will house the two motor modules and the two pulley modules. The center rail will house the two Y-Plate modules, as well as the end effector to which the modular tool head system will be attached.

Modules Assembly

Assembly of the different modules that will be fixed on the frame.

1) Y-plates

The Y plates are the modules that will be fixed to the central rail and roll on the frame to create the Y movement. In the picture below, the three wheels that will roll/slide on the frame can be seen in the lower section. Three wheels are necessary to ensure sufficient stability and avoid any unwanted movements. On the top part of the picture, the two pulleys that form the pulley system of this Y-plate can be seen. They are used to bring the threads to the end effector. The yellow part is the asymmetric adjuster used to adjust the tightness of the wheels to the frame rail.

This assembly must be carried out twice, once on each side of the central rail. Washers are used to space the pulleys slightly from the plate. A bolt is added on the wheel side to space the wheel sufficiently from the plate.

y-plates

2) Motors fixation and pulley

The motor modules house the motors. They are fixed in two corners of the frame. Two special pulleys have been 3D printed to wind the wire and accumulate it in the motor. The pulleys not fixed to the motors are also positioned so as to align the pulleys with the frame. This module also has to be made twice.

motor-pulleys-side
motor-pulleys-top

3) Corners pulley fixation

Two pulley system modules must be assembled for the two remaining corners of the frame. There is one pulley per row. Two pulley modules need to be made, this time in mirror image to ensure symmetry across the frame. The two pulleys are at different heights to prevent the two rows from touching.

corners-pulleys-side
corners-pulleys-top

4) End-effector plate

Finally, the end-effector will be mounted on the plate shown below. The tread will also be fixed on this plate. It is composed of 3 wheels, arranged similarly as the ones on the Y-plates.

effector-plate-side
effector-plate-top

Frame Assembly

Assembly of the frame includes not only the frame itself, but also the attachment of the various modules to it and the central rail.

Step 1 : U-shaped Frame

We start by mounting three sides of the frame. It’s easier to leave one side empty so that you can slide in the grid that will be made next. We’ll then need to complete the assembly by closing the frame.

Right-angled pieces are used here to bind the railles together. In addition, special inserts are fitted inside the channels, as can be seen in the images below. Two inserts are required per module, and a further 4 inserts are added on the side to assemble the machine stands.

An important detail when fitting the frame rails is to leave a gap between the side bars and the centre bar. This is because the central rail that will slide along the frame must not rub against the frame.

frame-step1
frame-step1-side

Step 2 : Adding Motor Modules

The two motor modules are added to the frame using suitable inserts and screws. Note that the two modules are in the same direction. This is necessary so that the thread is aligned with the upper pulleys.

frame-step2

frame-step2-side
frame-step2-motor

Step 3 : Central Rail Assembly

Now it’s time to fit the centre rail. Using 4 inserts, we attach the two Y plate modules. The rail can then be slid over the two frame rails left open.

frame-step3

Step 4 : Closing the Frame

Now that the centre rail is inserted into the frame, the frame can be closed using the fourth bar of the frame. Once again, two right-angled pieces are used, taking care to leave a gap between this upper central bar and the two side bars. There are also 4 inserts on the side to fix the stands of the machine, as on the other side.

frame-step4

Step 5 : Adding Pulley Modules & Stands

We can now fix the pulley system modules to the top of the frame using four inserts. The machine stands can also be added.

frame-step5

Step 6 : Adding End Effector

The end effector plate is fixed on the central frame by removing one wheel to slide the two other on the rail and putting back the third wheel.

effector-plate-onframe

When the first part is fixed on the frame, the rest of the end-effector plate can be assembled, in particular the part on which the thread will bed fixed.

thread-plate-top
thread-plate-bottom

thread-plate-onframe

Step 7 : Adding Thread System

There are 2 threads to fix: they both start from the end-effector plate and end there as well. The thread first goes in the pulley of the y-plate, then goes in the two 2 motor pulleys, by starting by the bottom.

thread1
thread2

Then the thread is wrapped around the pulleys, before going to the corner pulley.

thread3
thread-onframe

Final Result : Structure With Threads

final-structure-with-thread

Testing

We did a first test before attaching the end-effector plate with the thread, to be sure that there was not too much friction between the wheels and the rails.

After adding the thread we tested the structure again.

On the video below, we can see that when the end-effector is doing a diagonal, only one of the 2 motors is turning. The, when the end-effector is going vertically, the 2 motors are rotating.

2D Axis Improvements

Improvement Thread Crossing

In the initial version of the structure, the threads cross at one point, causing friction between them with each movement of the motors. To prevent the threads from breaking due to the friction between them, we added an extra pulley, as shown in the picture below. To do so, we just modified the dxf file of an existing plate to attach the pulley on it.

thread-crossing
thread-crossing

new-plate-thread

Z Axis - Mechanical Development

As an improvement of the machine, we decided to add a third axis to the structure. To keep the modular idea of the machine, the Z axis can be added as an option, by mounting an additional structure on the existing 2D structure of the machine. In this case, the end effector is thus attached to the Z axis to allow his movement, and the working bed is fixed in the 2D structure instead of the end effector. The only limiting factor is the working area that is reduced in the XY plane, but it can be solved by doing a bigger structure in the first place.

The designed is based on the solution explored in the urumbu project, aand can be found here. Some changes have been made in the Z-axis, and will be developped below.

Parts Manufacturing

Laser cutter

We cut the same parts as before for the end-effector module, and for the motor. We also changed the design of the motor plate design and adapted it too fix 2 pulleys on it.

Zaxis-parts

3D printing

We printed 3 bearing pulleys and one more to be attached to the motor, one plate for the wire attachment, one adjuster and 3 spacers.

Purchased Parts

We used the remaining parts of the first kit that we bought.

Assembly

As mentioned above, the idea is to add an additional structure without changing the basic 2-axis structure. The first step is to assemble the frame, which will be attached to the base structure, and then the Z-axis, which will be attached to the frame.

Frame Assembly

Step 1 : Adding Side Structures

We start by assembling the structure using the extruded rails we’ve purchased. Given that they’re 50 cm long, we decided to cut some of them in 2 to get our structure 25 cm above the 2-axis frame. We start by making two sides as shown below on either side of the base frame.

Zaxis-Frame-1

Step 2 : Adding Middle Rail

The center rail is then added in a fairly basic way. This rail will be fixed, so the position will have to be adapted according to the tool to be used later.

Zaxis-Frame-2

Axis Assembly

Step 1 : Fixing the motor and pulleys on the Z axis

The motor is attached on one side of the Z axis, with one bearing pulley and one motor pulley. On the other side, 2 pulleys are attached.

Zaxis-step1

Step 2 : Fixing the end-effector module on the Z-axis

The same end-effector module as the one for the 2D axis have been assembled and then fixed on the Z axis.

Zaxis-EndEffector-Module
Zaxis-step2

Step 3 : Adding the thread system

Now that the various modules are attached to our Z axis, we need to add the thread that will move the end-effector.

Zaxis-thread
Zaxis-thread

Step 3 : Adding the Z axis on the structure

Last step is to attach the Z axis on the structure ! The final result is shown below.

Zaxis-step4

Final Result : 3D Structure

The fixed Z axis allows vertical movement of a tool. The XY axes are used to move the work plane that holds the raw material.

Final-3Dstructure

Testing

Below, a short video showing the movement of the two end-effectors: the one on the Z axis, and the one on the XY plane.

2D Axis - Electronic Development

The Motors!

To carry out the movement of the axes, the type of motor could have been selected, but step motors are the ones selected par excellence for CNC developments, due to their ease of use, their good precision and their widespread applications on the web. Stepper motors use a cogged wheel and electromagnets to rotate the wheel one ‘step’ at a time.
Each HIGH pulse sent energizes the coil, attracting the teeth closest to the cogged wheel and driving the motor one step forward.

Stepper-Motor-Working-Animation

Photo by lastminuteengineers

Our system, unlike other CNC developments based on the very popular Ramps shields, aims to be completely modular, so each Axis will have its own microcontroller with its corresponding independent USB output. Therefore, we believe that it will be much easier to incorporate new modules and continue their development in the near future.

yes

To use and control which motor, a power interface is necessary, an electronic device that translates the logic values produced by the microcontroller into high voltage and current values necessary to drive the motor. In the market there are simpler and more complex solutions depending on the demands of the project, in our case we choose the Driver par excellence for this type of projects.

all-drivers

For single-stepper-motor applications, a driver like the L298N is fine, but if you want to construct your own CNC machine or 3D printer, you’ll need a dedicated stepper motor driver like the A4988. Due to the simplicity of the step motor control and the variety of stepping modes provided by the A4988 driver, it is an ideal solution for building applications that require precise and reliable stepper motor control, such as the movement control of beds, heads, and assemblies in various CNC plotting, milling, and 3D printer designs. The fact that it only requires two pins to control the speed and direction of the bipolar stepper motors like the NEMA is pretty neat, too.

A4988

With nothing more to define, create a small PCB for each motor, to do this use the Kicad PCB design software, already worked on in previous weeks and which has turned out to be very useful.

esquema
pcb
pcb_motors
pcb_on

To test the PCB, use the following code fragment without libraries to check its operation, what it does is turn it for 2 seconds to one side and then 2 seconds to the other…“easy and for the all family.”

const int dirPin = 25;
const int stepPin = 26;
const int stepsPerRevolution = 200;

void setup()
{
	// Declare pins as Outputs
	pinMode(stepPin, OUTPUT);
	pinMode(dirPin, OUTPUT);
  Serial.begin(9600);
}
void loop()
{
	// Set motor direction clockwise
	digitalWrite(dirPin, HIGH);

	// Spin motor slowly
	for(int x = 0; x < stepsPerRevolution; x++)
	{
		digitalWrite(stepPin, HIGH);
		delayMicroseconds(2000);
		digitalWrite(stepPin, LOW);
		delayMicroseconds(2000);
	}
	delay(1000); // Wait a second
	
	// Set motor direction counterclockwise
	digitalWrite(dirPin, LOW);

	// Spin motor quickly
	for(int x = 0; x < stepsPerRevolution; x++)
	{
		digitalWrite(stepPin, HIGH);
		delayMicroseconds(1000);
		digitalWrite(stepPin, LOW);
		delayMicroseconds(1000);
	}
	delay(1000); // Wait a second
}

2D Axis - Software Development

In this segment, our goal is to develop a numerical controller that, based on a specific file input, will generate motion control. Given that we’re working with a pen plotter scenario, the input will typically be an SVG file.

We have two alternatives for this task:

  1. Transform the SVG into G-code and utilize an intermediate motion controller, such as an Arduino Mega equipped with GRBL.
  2. Employ our laptop as the motion controller, allowing us to write the code in a higher-level language like Python.

We opt for the second approach, which aligns with Urumbu’s philosophy of a “controllerless” design that virtualizes low-level controls in high-level parallel software. The Urumbu codebase already includes a motion controller capable of parsing G-code from XY files. However, we aim to enhance this functionality to directly support SVG files. This is because converting to G-code is not only unnecessary but also results in loss of information. Indeed, the benefit of gcode is to create a intermediate representation of the path to be interpreted by the motion controller but as we get rid of the motion controller we don’t need that intermediate representation. Finally, the current SVG parser in the Urumbu code only supports linear move commands (G0, G1).

However, we cannot directly extract control signal for the stepper motors from the SVG.

From SVG to polylines

The SVG file format uses mathematical primitives to represent shapes. These primitives include lines, curves (cubic and quadratic Bézier), arcs, and more complex shapes like polygons and paths. Each of these primitives is defined by a set of parameters. For example, a line is defined by two points (start and end), a cubic Bézier curve is defined by four points (start, end, and two control points), and so on.

To convert these primitives into a path that a machine can follow, we need to discretize them into a series of small, straight line segments (Polylines). This process is called tessellation. For example, a Bézier curve can be tessellated into a series of straight lines by repeatedly subdividing it at the midpoint.

Fortunately, there’s an excellent Python software that can handle this task: Axidraw. Axidraw is an open-source initiative that offers both software and hardware solutions for pen plotters.

Axidraw is available as an extension for Inkscape, as well as a Python API. Here’s how you can install it

python -m pip install https://cdn.evilmadscientist.com/dl/ad/public/AxiDraw_API.zip

The primary challenge we encountered was that Axidraw requires a connection to the motor board via serial for most of its functions, and it won’t proceed without this connection. Initially, we considered modifying the hardware connection layer of Axidraw to fit the Urumbu architecture. However, due to time constraints and the fact that our plotter’s electronic components were only completed a day before the deadline, this wasn’t feasible.

We worked our way around that by using the estimate_time.py example script that does not need serial connection and we work our way up to find the few lines of code that enable to convert a svg input to a set of polyline path.

The final script is pretty short :

from pyaxidraw import axidraw
ad = axidraw.AxiDraw()             # Create class instance
ad.plot_setup(filename)    # Parse the input file
ad.options.preview  = True
ad.plot_run()
layers = ad.digest.layers
for layer in ad.digest.layers:
        for path in layer.paths:
            for subpath in path.subpaths:
                #do job

The layers are the different layer of the original svg. Then, the pathes are a set of polylines that you can traverse without raising the pen. Finally, the subpath are all the linear segment that form that polyline. In the above example, the layer is the ensemble of both the rectangle and the triangle, each shape is a different path, and each edge in a subpath.

Final-3Dstructure

Here we can see how a super small circle is converted to polyline by axidrax : Final-3Dstructure

In the following section we will have a look at how we can use that hierarchy to create motion control.

From polylines to motion control

In this section, we conceptualize a motion control command as a step, direction order at a specific time, t. This concept aligns with our final decision to use the Pololu stepper driver on our motor board. The ‘step’ can be either true, indicating that the motor takes a step, or false, signifying that the motor remains idle. The ‘direction’ can be either forward or backward. If we apply this to both motors, it implies that at each control step, the end effector can execute one of the movements illustrated below:

Final-3Dstructure

Conventional motion controllers like Axidraw’s or GRBL’s generate trajectories with smooth acceleration and deceleration profiles to minimize vibrations and maximize speed (ramping up and down speed). However, to simplify our task, we’ve chosen to adhere to the simpler constant velocity control approach utilized in the original Urumbu code.

The code snippet below illustrates the primary steps involved in the plotting process. Initially, the SVG file is parsed using the parse_svg function as previously described. For each continuous polyline (subpath), the servo is initially lifted, moved to the first coordinates, and then lowered. Subsequently, a line action is added to the queue for each subsequent point on the polyline. This process is repeated for each subpath. Once the parsing is complete, the action queue is filled and we transition to the module manager.

The module manager instantiates the various motors and servos and initiates the main loop for consuming actions. When a LineAction is encountered, it sets the starting position of the line to the start position defined in the LineAction. It then calculates the target position along the line.

The tick_motor function is responsible for advancing the motor forward or backward if the x or y distance exceeds half a step distance. The m.steps value represents the current step index of the motor (for instance, if the motor has taken 200 steps forward and 100 steps backward since the start of the plot, the index is 100). By computing the integer rounding of pos_motors[j] * m.steps_per_unit, we determine the nearest step index we should be at to be as close as possible to the actual position on the line at time t. If this value matches the current step index, we don’t tick; if it’s larger, we tick forward; if it’s smaller, we tick backward.

If a servo action is encontered, the servo is lowered or lift accordingly.


def parse_svg(filename, action_queue, default_feedrate,  servo_up_action=None, servo_down_action=None):
    # ...
    for layer in ad.digest.layers:
        for path in layer.paths:
            for subpath in path.subpaths:
                for i, (x, y) in enumerate(path):
                    if i == 0:
                        action_queue.put(servo_up_action)
                        action_queue.put(Line([x, y], feedrate))
                        action_queue.put(servo_down_action)
                    else:
                        action_queue.put(Line([x, y], feedrate))

class Stepper(Module):
    # ...

    def step(self, forward):
        self.steps += 1 if forward else -1
        if self.reverse:
            forward = not forward
        if not self.preview:
            self.write(b"f" if forward else b"r")
    # ...

class Line(PathAction):
    def __init__(self, pos_end, feedrate):
        self.pos_start = np.zeros_like(pos_end)
        self.pos_end = np.array(pos_end)
        self.duration = -1
        self.feedrate = feedrate

    def init(self, pos_start):
        self.pos_start = np.array(pos_start)
        mask_nan = np.isnan(self.pos_end)
        self.pos_end[mask_nan] = self.pos_start[mask_nan]
        self.duration = np.linalg.norm(self.pos_end - self.pos_start) / self.feedrate

    def __call__(self, t):
        if t > self.duration:
            # end move
            return None
        u = t / self.duration
        return self.pos_start * (1 - u) + self.pos_end * u

def modules_manager(action_queue, modules_config, pos_transformer=None, preview=False):
    # ..

    n_axis = len(modules_axis)
    pos = np.zeros((n_axis,))
    pos_motors = np.zeros((n_axis,))
    def tick_motor():
            if pos_transformer is None:
                pos_motors[:] = pos[:]
            else:
                pos_transformer(pos, pos_motors)
            for j in range(n_axis):
                m = modules_axis[j] #m is a Stepper object
                s = int(pos_motors[j] * m.steps_per_unit)
                if m.steps < s:
                    m.step(True)
                elif m.steps > s:
                    m.step(False)
            # ...

    while True:
        if not action_queue.empty():
            # ...
            for sub_action in action:
                if isinstance(sub_action, PathAction):
                    # time in s, ~us resolution
                    sub_action.init(pos)

                    while True:
                        t = time.perf_counter()

                        # path is a time function
                        pos_new = sub_action(t - t0)

                        if pos_new is None:
                            # done
                            break
                        tick_motor()
                elif isinstance(sub_action, ServoAction):
                    #Move servo up or down

Preview functionnality

We added a preview functionality to the code :

Firmware

This will depends on the motor driver

Stepper

#define DIR 26
#define STEP 27
#define MS1 0
#define MS2 7
#define MS3 6

void setup() {
  Serial.begin(0);
  digitalWrite(STEP,LOW);
  pinMode(STEP,OUTPUT);
  digitalWrite(DIR,LOW);
  pinMode(DIR,OUTPUT);
  pinMode(BUTTON, INPUT_PULLUP);
   // 1/16 step
  pinMode(MS1, OUTPUT);
  digitalWrite(MS1, HIGH);
  pinMode(MS2, OUTPUT);
  digitalWrite(MS2, HIGH);
  pinMode(MS3, OUTPUT);
  digitalWrite(MS3, HIGH);
}

void loop() {
   if (Serial.available()) {
      char c = Serial.read();
      if (c == 'f') {
         digitalWrite(DIR,HIGH);
         digitalWrite(STEP,HIGH);
         delayMicroseconds(2);
         digitalWrite(STEP,LOW);
         }
      else if (c == 'r') {
         digitalWrite(DIR,LOW);
         digitalWrite(STEP,HIGH);
         delayMicroseconds(2);
         digitalWrite(STEP,LOW);
         }
      }
   }

Servo

void setup() {
   Serial.begin(0);
   digitalWrite(SERVO,LOW);
   pinMode(SERVO,OUTPUT);
   }

void loop() {
   uint16_t duration;
   if (Serial.available()) {
      Serial.readBytes((char *)&duration,2);
      if (duration == 65535L) {
         // special command, reply with button value
         int btn = digitalRead(BUTTON);
         Serial.write(btn ? '1' : '0');
         }
      else {
         digitalWrite(SERVO,HIGH);
         delayMicroseconds(duration);
         digitalWrite(SERVO,LOW);
         }
      }
   }

The impact of microstepping

Possible enhancements

Modular Tool Head - Mechanical Development

The goal of this section is to design and make an effector that will hold a drawing instrument in place. A ballpoint pen will be used for testing purposes, but any other instrument can be used as a replacement. This effector can accommodate a servomotor in addition to the drawing instrument, enabling it to move vertically (referred to as the Z-axis hereafter), as well as the PCB. The PCB was specifically designed and manufactured in our laboratory for this purpose.

The design of the effector

The effector was designed based on one of the variants of the 4xiDraw drawing machine, which can be found in the following Thingiverse link.

Below are the shown parts used: 4xiDraw

Only two designs were modified. The first modification was made to the motor base, to which a new base was added to mate with the base of the previous Urumbu effector. The second modification was made to the Z-axis motion system to accommodate the designed plate. Both modifications can be seen in the figure below.

4xiDraw_Modified

The final design and assemble is show below:

Effector01 Effector02 Effector03

Modular Tool Head - Electronic Development

Servos are motors that allow you to precisely control physical movement because they generally move to a position rather than continuously rotating. Servos contain a small DC motor connected to the output shaft through gears. The output shaft drives a servo horn and is also linked to a potentiometer (pot). Due to this simplicity, the servos can be controlled without the need for drivers, just with a PWM PIN.

Servo-Motor-Working-Timing-Diagram

Photo by lastminuteengineers

In addition to the movement in this module, we wanted to include the possibility of self-leveling for when the head was changed, to correct small unevenness in the work table or for future developments, finally, after evaluating different options we opted for the VL6180 sensor.

vl6180

Once again for the design of the PCB we will use Kicad (which the truth is that you have already taken a liking to it)

esquema_efector
pcb_efector
efector_1
efector_2

Finally, to check the sensor, I used the native Arduino library but I did not get good results, so I used an example from a third-party library called SparkFun_ToF_Range_Finder-VL6180_Arduino_Library-master.


/******************************************************************************
 * SparkFun_VL6180X_demo.ino
 * Example Sketch for VL6180x time of flight range finder.
 * Casey Kuhns @ SparkFun Electronics
 * 10/29/2014
 * https://github.com/sparkfun/SparkFun_ToF_Range_Finder-VL6180_Arduino_Library
 *
 * The VL6180x by ST micro is a time of flight range finder that
 * uses pulsed IR light to determine distances from object at close
 * range.  The average range of a sensor is between 0-200mm
 *
 * Resources:
 * This library uses the Arduino Wire.h to complete I2C transactions.
 *
 * Development environment specifics:
 * 	IDE: Arduino 1.0.5
 * 	Hardware Platform: Arduino Pro 3.3V/8MHz
 * 	VL6180x Breakout Version: 1.0
 *  **Updated for Arduino 1.6.4 5/2015**

 *
 * This code is beerware. If you see me (or any other SparkFun employee) at the
 * local pub, and you've found our code helpful, please buy us a round!
 *
 * Distributed as-is; no warranty is given.
 ******************************************************************************/

#include <Wire.h>

#include <SparkFun_VL6180X.h>

/*const float GAIN_1    = 1.01;  // Actual ALS Gain of 1.01
const float GAIN_1_25 = 1.28;  // Actual ALS Gain of 1.28
const float GAIN_1_67 = 1.72;  // Actual ALS Gain of 1.72
const float GAIN_2_5  = 2.6;   // Actual ALS Gain of 2.60
const float GAIN_5    = 5.21;  // Actual ALS Gain of 5.21
const float GAIN_10   = 10.32; // Actual ALS Gain of 10.32
const float GAIN_20   = 20;    // Actual ALS Gain of 20
const float GAIN_40   = 40;    // Actual ALS Gain of 40
*/
#define VL6180X_ADDRESS 0x29

VL6180xIdentification identification;
VL6180x sensor(VL6180X_ADDRESS);

void setup()
{

  Serial.begin(115200); // Start Serial at 115200bps
  Wire.begin();         // Start I2C library
  delay(100);           // delay .1s

  sensor.getIdentification(&identification); // Retrieve manufacture info from device memory
  printIdentification(&identification);      // Helper function to print all the Module information

  if (sensor.VL6180xInit() != 0)
  {
    Serial.println("Failed to initialize. Freezing..."); // Initialize device and check for errors
    while (1)
      ;
  }

  sensor.VL6180xDefautSettings(); // Load default settings to get started.

  delay(1000); // delay 1s
}

void loop()
{

  // Get Ambient Light level and report in LUX
  Serial.print("Ambient Light Level (Lux) = ");

  // Input GAIN for light levels,
  //  GAIN_20     // Actual ALS Gain of 20
  //  GAIN_10     // Actual ALS Gain of 10.32
  //  GAIN_5      // Actual ALS Gain of 5.21
  //  GAIN_2_5    // Actual ALS Gain of 2.60
  //  GAIN_1_67   // Actual ALS Gain of 1.72
  //  GAIN_1_25   // Actual ALS Gain of 1.28
  //  GAIN_1      // Actual ALS Gain of 1.01
  //  GAIN_40     // Actual ALS Gain of 40

  Serial.println(sensor.getAmbientLight(GAIN_1));

  // Get Distance and report in mm
  Serial.print("Distance measured (mm) = ");
  Serial.println(sensor.getDistance());

  delay(500);
};

void printIdentification(struct VL6180xIdentification *temp)
{
  Serial.print("Model ID = ");
  Serial.println(temp->idModel);

  Serial.print("Model Rev = ");
  Serial.print(temp->idModelRevMajor);
  Serial.print(".");
  Serial.println(temp->idModelRevMinor);

  Serial.print("Module Rev = ");
  Serial.print(temp->idModuleRevMajor);
  Serial.print(".");
  Serial.println(temp->idModuleRevMinor);

  Serial.print("Manufacture Date = ");
  Serial.print((temp->idDate >> 3) & 0x001F);
  Serial.print("/");
  Serial.print((temp->idDate >> 8) & 0x000F);
  Serial.print("/1");
  Serial.print((temp->idDate >> 12) & 0x000F);
  Serial.print(" Phase: ");
  Serial.println(temp->idDate & 0x0007);

  Serial.print("Manufacture Time (s)= ");
  Serial.println(temp->idTime * 2);
  Serial.println();
  Serial.println();
}

Conclusion