For our cumulative design experience, we made a circuit printer that can be controlled and interacted with via web over a local network. To draw a circuit, you can use the Circuit Pad right above this text.
We created a pen plotter that draws in electrically conductive ink to rapidly create circuits drawn on a webapp.
Our final project was to create a rapid prototyping machine for electrical circuits by repurposing an old pen plotter that we fitted with an electrically conductive pen. Our plotter utilized an atmega 1284P to control the x and y-axis motors, and to raise and lower the pen. We created a web app that allowed a user to draw out circuits quickly, and then send them to be printed out on our plotter over a wifi network as our host computer that maintained the serial connection with the atmega 1284P. The atmega 1284P would receive vectors of x and y coordinates from the host computer that would instruct it on how to move the plotter head. By measuring the position of the plotter head on each axis through the on-chip ADC and two servo potentiometers, we were able move the plotter head to an accuracy of approximately 1/10th of an inch on a typical piece of A4 paper.
With a single pen and only using conductive ink, each sheet of paper can contain only planar circuits. To facsimile multi-layer printed circuit boards (PCBs), we designed the circuit drawing application we made to track which traces are overlapping and to assign them to different virtual layers. The CPU would then send over chunks of vectors in groups we will refer to as “files” based on which layer they were on. A new file would be sent each time the user indicated that they had placed a new piece of paper on the plotting area via a button on the printer . By treating each layer as a new file, the user would end up with a different piece of paper for each layer of the circuit. By using through-hole components and solder paste, stacking these different sheets of paper is analogous to printing a multi-layer PCB.
Check out our Demo Video!
The design of this plotter was motivated by maintaining the highest level of accuracy possible to allow for more densely packed circuits to reliably operate without unintended connections. To do this, we split the project into two discrete parts to separately focus efforts on: maximizing plotter head position accuracy, and improving accuracy with smart control algorithms. Ease of use was another concern of ours that drove our design, so we focused our time in making a smooth, user friendly environment to print and design their own circuits in.
Hardware Design and Testing
To achieve mobility in two dimensions, we knew that we there was a significant mechanical challenge ahead of us. Maintaining structural rigidity while allowing for unimpeded motion in two axis is not a trivial feat. To bypass this challenge, we found a HIPLOT DMP-29 pen plotter from 1983 on craigslist for $20 whose frame we could use as a starting point. This frame came with a plotter head that we fit a Circuit Scribe electrically conductive pen to. This allowed us to print electrically functional drawings on the plotter. We altered the frame by removing the button interface on the front, and by removing the rack of pen-holders on the left of the plotter to increase the area that could be plotted on. This frame also included gearing which connected drive shafts of the motors to strings that would move the plotter head. The gearing was different for the x and the y axis, which made it so that each axis could be traversed in 4.5 revolutions of each respective motor even though the axis lengths are physically different (in proportion to the size of A4 or A5 paper).
There is also a solenoid that actuates a hinge, which controls the vertical position of the plotter head to either raise or lower the pen tip onto or off of the paper. This solenoid and hinge needed to be modified for the Circuit Scribe because of the difference in weight and the rust that built up on the hinge itself. To bias the hinge to make it easier for the solenoid to actuate with the larger pen, a set screw was tapped into the hinge and acted as a negative stop for the plotter head. This made it easier for the solenoid to just barely have to turn on to change the position of the pen.
There were two motors in our final project in addition to one solenoid. One motor would drive the x-axis motion of the plotter head, the second motor would drive the y-axis motion of the plotter head, and the solenoid would control whether or not the pen was being pressed against the paper to draw.
The motors that came in the plotter were thirty-year-old servos that ran on 12 volts. When running, they drew approximately 1.5A each. These parameters were used to determine appropriate controller hardware, and to size the required power supplies. The Toshiba TB6561NG Dual H-Bridge was selected as a suitable motor controller due to its supply current maximum of 2.5A at 12-40V. These H-Bridge chips also offer isolation from the signal to power. Although the datasheet does not specify an exact isolation metric, there are separate power and ground lines for control signals and for motor power. By trying to run both motors while pulsing LEDs on the the atmega, we confirmed that the isolation was large enough to prevent the microcontroller from browning out while running the motors. These h-bridge packages also had short braking diodes, which means that by drawing both control signals low, the voltage across the motor would be held very close to zero, and that the back-EMF would be clipped through the use of four diodes placed between power and ground and each terminal of the motor, which could supply the current for the inductive spike. The end result of this was that stopping a motor could be achieved with minimal backpedalling simply by grounding both control signals. The h-bridge operates via two control signals for each motor. By dragging only one control signal high at a time, you can make the motor go either clockwise or counter-clockwise.
The solenoid was also shown to draw roughly an amp at 12V, and as such was driven with a second DIP of the Toshiba TB6561NG. In this case, because the solenoid is not a polar device, one of the control leads was connected directly to ground. This means that a single control line could be used to control whether or not the pen was drawing on the paper or not. In this specific case, if pin D.5 was set high, the pen would be set against the paper to draw.
All of these circuits were soldered to the board on the opposite side from the ADC circuits (to be described in the next section) to minimize capacitive coupling of noise that could impact to measurements of the current plotter head position. The motors themselves shared a drive shaft with the potentiometers used for these measurements, but the signal lines were shielded and kept separate from the power lines to the motors.
Analog to Digital Conversions and Plotter Position Tracking
In order to determine how the circuit was being drawn, we needed to track where the plotter head currently was. This was achieved through the use of servo potentiometers. These are special potentiometers that are designed to run from 0 Ohms to 5 kOhms at the middle pin through the course of 10 full revolutions. A servo potentiometer was placed on each of the driveshafts of the motors, so a revolution of the servo motor would cause an equal rotation of the potentiometer. By placing Vcc at the top of the servo potentiometer and signal ground at the bottom, we can use the middle pin as a voltage divider, with the voltage at the second pin being proportional to the position of the plotter head.
When the servo potentiometer was collared onto the driveshaft of the servo motor, the potentiometer was at its counter clockwise rotational limit, and the plotter head was at its corresponding minimum position (being mechanically stopped by elements of the frame). This set our coordinate grid’s origin and ensured that we go the maximum amount of rotation from each servo potentiometer to utilize the full voltage range to get the best possible granularity out of the ADC and subsequently the most accuracy for plotter head position. Because the servo motor would only spin 4.5 revolutions to travel from our origin to the maximum value of either axis, less than half of the potentiometer’s range would be used. To compensate for this and to increase accuracy, the on chip ADC’s Aref was set to the internal 2.56V value. This roughly doubled our accuracy because we getting quantized values relative to a range more precise to the values that could be generated by the servo potentiometers (0-1.82V measured).
The ADC on the atmega 1284P is a 10-bit converted, and by displaying the converted values on an LCD we determined that our origin was (16,16), the maximum value for an A4 size sheet of paper was (513,520), and that the maximum value for the plotting area was (715,718). This gave us a theoretical limit on the accuracy of our printer of 2.2% in the x axis and 1.7% in the y axis on an 8.5”x11” (A4) piece of paper. To put this in a physical perspective, this is a resultant accuracy limit of approximately 1/20th of an inch.
User Interaction Hardware
It was important to make sure that the end user could control the printer and would understand what the printer was doing in a manner similar to commercial inkjet/laser printers. This was accomplished by adding a single button and an LCD display to the printer.
The button would poll one of the input pins on the MCU to ground and signify to the printer that the a fresh piece of paper has been placed in the tray and secured. This would be required when printing multiple layers or multiple different files and you need to be able to switch out print media.
The LCD helps to provide instructions as to what the user should be doing. It is connected to the MCU as seen in the schematic below in the documentation section. The LCD will display which state the printer is in, reading either “waiting for file,” “printing,” or “job waiting, press button when ready.”
Isolation, Motor Protection, and Reliable Communications
When using the large motors that came in the HIPLOT plotter, it was important to make sure that we didn’t have noise spikes coming from the motor that would impact the way the MCU was working. In particular, we had to worry about isolating the motor power from the MCU control, keeping the ADC pins and signal lines away from the noisy motor environment, and large back EMFs breaking the control equipment that was driving the motors.
Isolating the motor was handled by the TB6561NG, and provided separate power and signal grounds. Having separate grounds prevents current flooding into the ground from swaying the voltage going into the chip and causing the MCU to “brown-out” and reset. To mitigate the impact of these power electronics on the sensitive signal lines, the TB6561NG chips were kept on the opposite side of the board from the analog signal lines. Additionally, the signal lines from the servo potentiometers were kept as far away from the power lines to the motors as possible inside of the frame and were twisted together to be more noise resistant. Back EMFs were handled by the TB6561NG, again, through the placement of catch diodes on either side of the motors between ground and power. This means that when the transistors in the h-bridge are turned off, the two terminals of the motor will be at the same potential electrically. Because a motor is a large inductor, the catch diodes provide a path for current and prevent large voltage swings that could damage the h-bridge and cause very large noise spikes.
As mentioned in the high level design, the goal of all of this was to be able to measure the position of the plotter head as accurately as possible. This kept our overall accuracy as high as possible on the hardware side.
To test the hardware, each piece was driven separately to verify functionality. The motors were driven, then they were driven with the h-bridge chips, and then they were driven with the h-bridges through the MCU to confirm that they worked as desired. The solenoid went through similar iterations to ensure that it operated as desired even while driven through the Toshiba chip by the MCU. The potentiometers were wired up and the ADC code was written to display the ADC values on the LCD. By manually moving the plotter head, we confirmed that the ADC and potentiometers were working. After these worked separately, we integrated them all together by sending the motors through a random walk while displaying the current plotter head position. This showed that the motors were not affecting the ADC readings while they were running or in a transient.
One change that came out of testing was to add a cooling system to the h-bridge chips. They grew very hot over prolonged running of the motors. By only running one motor at a time, this helped to reduce the burden placed on the motor controller chips, and a heatsink with a fan took care of the rest of the required heat dissipation.
Software Design and Testing
Motor Functions and Controls
To simplify the process of controlling the motors, a series of helper functions were made that could be built together to help logically control the position of the plotter head. This would allow for us to abstract away from the pin-level controls that are required for h-bridge operation. The following methods were implemented:
void move_positive_x(void), void move_positive_y(void), void move_negative_x(void), void move_negative_x(void), void raise_pen(void), void lower_pen(void), void stop_all(void)
These functions will set pins to indefinitely power the respective motor in a given bias. By setting separate functions for moving in each direction, we can guarantee that we do not ever have shorts over the h-bridge. The stop_all() function is called to lower all pins, removing power from both of the motors. Next, a method needed to be created to determine where the plotter head currently is at a given time. This would replace the need for timing how long motors were turned on for, as plotter head position is the end goal.
int start_ADC_measure(channel) was created to read the on-chip ADC for a given pin on PORTA. The channel that you input to the function corresponds to the pin on PORTA that the ADC reads in from. The ADC was configured to read all 10 bits for maximal accuracy, and was set to have an internal reference voltage of 2.56V (as described in the hardware design section).
By pairing this ADC function with the motor power control functions, the method void move_to_XY(x, y, d) was created. By inputting an x-coordinate, a y-coordinate, and a number corresponding to whether the pen should be lowered or raised while the plotter head is moved to the new coordinate pair, controlling to motors became easy. In this function, the pen would first be raised or lowered depending on the d value, and then the plotter head was moved to the new location one axis at a time. By only moving one axis at a time, we could continuously read the ADC value for a given channel, which is four times as fast as if we were to alternate between reading two channels (due to the 25 cycle cost of the first conversion as opposed to the 13 cycle cost of subsequent conversions on the same channel). A motor power controller function would be called and then the ADC value would continuously be read at a rate of 13 cycles per conversion plus an additional 12 machine cycles of register manipulation and comparisons. This means that we were getting a position update for the plotter head roughly once every 2uS. Once the ADC value reported that the plotter head had reached the goal value, the motor would be stopped. Due to the high rate at which the ADC sampled and the ability for the h-bridges to short brake (holding each terminal of the motor at the same voltage), this was shown to sufficiently to stop the motor within 2 units of the desired coordinate (at worst) for each axis.
The motor controller methods were tested in the order they were created, seeing as they all built on one another. The motion controlling methods were written and tested, the ADC code was written and tested with output to the LCD, and finally the move_to_XY function was made by drawing on the previous methods. The move_to_XY function was tested by reading off a string of coordinates that was saved locally, and proved to work as expected.
After this was developed, we set up global variables to utilize these functions. The integer arrays x_vect and y_vect were created to store sets of coordinates to move to, and d_vect was created to store information about pen position for a given coordinate motion. With this structure, we were able to step through the arrays to form series of vectors to draw a file.
Serial Communication with the CPU is handled through the UART on pins D.1 and D.0 on the atmega 1284P. This is similar to the serial communications in lab 4, where the motor controller feedback loop was altered via putty. By defining the standard output and using the UART.c and UART.h libraries made Joerg Wunsch under the BEER-WARE LICENSE, we were able to use the fprintf, sprintf, fscanf, and sscanf to communicate with the terminal on the macbook that was running the server. An initial handshake takes place to tell the microcontroller how many packets to expect in each transaction, and the subsequent communications are segmented by a stop-and-wait system in which the CPU will wait for an acknowledgement statement from the microcontroller. This serial connection forms the basis of motor control from the computer. The strings to be sent that will guide the plotter head are generated and computed on the CPU before being transmitted over this serial connection and then being parsed out on the MCU side into meaningful control statements.
File parsing and Vector Management
Our end goal for the project was to be able to use existing .gerber files to generate layouts on our plotter. gerber files store circuit layout data in terms of x coordinates, y coordinates, and machine control code. We set up our vector transfer program to mirror the structure shown in a gerber file in that we are transmitting coordinate pairs and control code from the CPU in the form:
which corresponds to the command, “move the plotter head to (100,300) with the pen raised. We parse these strings by looking for the values in between X and Y, Y and D, and D and the end. We save these values into our x_vect, y_vect, and d_vect arrays and reference them later once the entire file has been saved on the MCU. To save time printing, the vectors are “terminated” with a directive to move the plotter head to a negative position (which is out of range). At the beginning of each motion step, the MCU will compare the destination coordinate to check that the values are nonnegative.
As discussed in the introduction section, vectors would be sent over in groups that we refer to as files based on which layer of a given circuit they are assigned to. Given that there are several kilobytes of stack space that we can work with, and given that complex circuits will tend to distribute traces over multiple layers, we can simply save an entire file worth of vectors into our global vectors (which allows for 2000 coordinate pairs in a given file). By transmitting a terminator with the “X-1Y-1D2” command, we ignore old data that might have been left over in the integer arrays from previous files.
Accuracy of Printing
As we began to test out the printer and the circuit scribe pen, we began to realize that continuity was an issue. Testing with the circuit scribe pen by itself showed that the ink was much less conductive than advertised. When drawing simple lines by hand, continuity was spotty at best with fewer than 50% of the six-inch, hand-drawn traces showing a connection from end to end. The solution when drawing by hand was to go back over the trace multiple times to get better continuity. We tried to carry this mentality over to our printer by having the plotter head trace out each line five times ("there, back, there, back, and there again"). This improved the quality of the lines that we drew, but reduced the accuracy of our printing. Running motors forwards and then quickly into reverse causes large spikes in backcurrent that would decrease the accuracy of the analog to digital converters. In general, the noise in the environment and the momentum of the motors only allowed us to get an accuracy of roughly 1/10th of an inch, so when we drove the motors back and forth consistently overshooting, our errors would add and our accuracy became only 1/5th of an inch. This provides a significant limitation to the circuits we could print, and could be solved by getting a better kind of conductive ink or by changing the way that we lay ink down. For example, using an inkjet style head we could increase the spray rate to improve conductivity without having to double back over our own lines. The other problem that this posed was the issue of missing connections due to the 1/5th of an inch error as the trace width is roughly only 1/8th of an inch. To solve this problem, we simply designed circuits to connect at intersections instead of at points. By putting in more overlap, we can guarantee that we will connect our lines and reduce the errors.
See embedded video in the Introduction Section!
Overall, we are pretty happy with how this project turned out. We realized early on that there were a lot of different systems that had to come together in order to get the plotter working to our initial specifications, so over the course of this project, we learned how to utilize modular design techniques to effectively distribute work while still advancing towards a goal. The decision to separate the tasks of higher-level control and data acquisition versus lower-level hardware and motor controlling allowed for independent optimization of performance in each section and allowed for us to independently progress based on pre-agreed-upon interfaces between the different systems.
Our initial goal of having a simple script that would allow for user input to control the motions of the motors was surpassed as we developed a web app and wireless infrastructure for using the plotter. This allowed for a better user interface than we had initially hoped for, and made us happier with the final product.
If we had more time on this project, we would have liked to improve some mechanical aspects of the device. It was very difficult to balance the circuit scribe with the plotter head to get a good trace lined out, and making a more custom fit holder for the pen would have improved the quality of the prints. Additionally, making the cooling system more effective and better isolating the servo potentiometers to allow for both motors to run simultaneously, indefinitely would have been nice. We also did not ever manage to parse gerber files into our printer, which we could have implemented with some more time and experience with eCAD tools such as EAGLE. Another notable improvement would have been to use a pen with more conductive ink. The Circuit Scribe pen that we used proved to have very high resistance and poor conductivity in general. This made our circuits difficult to work with.
If this project was to be created on a larger production scale, it would make circuit design less intimidating and would help to get more people interested in electrical design. The idea that people would be able to trivially create physical, functional versions of .gerber and other layout files is exciting and could potentially spur on the genesis of an open-source hardware design community.
Throughout the course of this project, we adhered to the IEEE ethical guidelines by making sure that we were testing in safe ways that avoided placing other lab users and ourselves in harm’s way. We also certify that the work presented as a part of this project is entirely our own - unless otherwise stated. Code from previous portions of this class - ECE 4760 - was used in part or in whole as a starting point for some of the code in this project. For example, the ADC code, serial code, and some LCD code were based off of code from lab 3, lab 4, and lab 1 respectively. Additionally, uart libraries written by Joerg Wunsch under the BEER-WARE LICENSE were used to facilitate serial communication. We also used code from scienceprog.com to send text to the LCD, which is protected the GNU Public License.
This website was designed using the “Profile” template from html5up.com under the CCA 3.0 license, which allows the use of this template for both personal and commercial webdesign.
There are no major legal considerations regarding the FCC because we are not broadcasting or manipulating any data in the RF range. In fact, all the signals that are sent between the MCU and the CPU are control signals, so the relevant FCC article is abided by.
|Frame||HIPLOT pen plotter and motors that were used for the basis of the machine||$20|
|Servo Potentiometers||Potentiometers used for locating the plotter head during motion (scavenged)||$0.00|
|Atmega 1284P||the microcontroller at the head of the project||$5.00|
|SIP Sockets (*55)||Used to hold the LCD and Atmega board into the solder board and the serial cable into pins D.0 and D.1||$2.75|
|Solder Board||Board used for keeping the circuit together||$2.50|
|Motor Power Supply||A large 25A max power supply that could handle the 12V 15A draw on each motor||$5.00|
|MCU Power Supply||A typical 9V or 12VDC power supply that runs into the microcontroller board||$5.00|
|Atmega 1284P PC Board||Standard board from the other labs in the class that handles voltage regulation, the external oscillator, and lays out the output pins||$4.00|
|Circuit Scribe Pen||The electricaly conductive pen that is used to draw the circuits||$20.00|
|Toshiba TB6561NG (*3)||The twin h-bridge IC that drives the two servo motors and the solenoid||$8.00|
|Cooling Fan and Heatsink||A fan on a heatsink that was placed above the two motor driver chips to reduce thermal overload risk. (Salvage)||$0.00|
|LCD||An LCD used for displaying the current status of the printer||$8.00|
|Serial Cable||A cable that connects the USART of the Atmega 1284P||$4.00|
void move_positive_x(void) - sets PORTD so that D.3 is low, delays a few microseconds to ensure that the pin has discharged to low logic levels, and then sets D.4 high. This will send control signals to the TB6561NG to forward bias the x-axis motor.
void move_positive_y(void) - sets PORTD so that D.6 is low, delays a few microseconds to ensure that the pin has discharged to low logic levels, and then sets D.7 high. This will send control signals to the TB6561NG to forward bias the y-axis motor.
void move_negative_x(void) - sets PORTD so that D.4 is low, delays a few microseconds to ensure that the pin has discharged to low logic levels, and then sets D.3 high. This will send control signals to the TB6561NG to reverse bias the x-axis motor.
void move_negative_y(void) - sets PORTD so that D.7 is low, delays a few microseconds to ensure that the pin has discharged to low logic levels, and then sets D.6 high. This will send control signals to the TB6561NG to reverse bias the y-axis motor.
void stop_all (void) - sets PORTD so that D.3,4,6,7 are all pulled low. This will put the TB6561NG into short brake mode to stop the motor. A delay of a few milliseconds was input to ensure that any running motors have come to a complete stop. This helps for isolating direction of motion to give us sharp corners.
int start_ADC_measurement(char channel) - This takes in a channel number corresponding to a pin in PORTA and will output an integer value from the 10-bit ADC conversion of the given channel. This ADC measurement is not interrupt based, and requires polling of the conversion complete flags (ADCSRA and ADSC)).
void raise_pen(void) - This function will set pin D.5 low to remove power from the solenoid that actuates the hinge the pen rests on. This function includes a delay of a few milliseconds to ensure that movement functions right after this function is called will not drag the pen across the page for the first few milliseconds of motion.
void lower_pen(void) - This function will set pin D.5 high to supply power to the solenoid that actuates the hinge through the second TB6561NG h-bridge. A slight delay is included after D.5 is pulled high to make sure that the solenoid has time to mechanically actuate before the plotter head moves, which guarantees the pen will always be in contact with the paper when desired.
void move_to_XY(int x, int y, int d) - This function combines the previous functions to allow for movement of the plotter head to a specific location x,y. The third argument, int d, specifies whether the pen should be raised or lowered during the movement to the new x,y position.
void initialize(void) - This function calls on subfunctions to initialize the registers regarding the ports, the LCD, the UART, and the ADC. This function is called at the start of main.
void print_position(void) - This function will print the current position of the plotter head on the bottom line of the LCD to provide a means for checking accuracy during testing.
void get_frame(void) - This function will handle the entire serial communications section and will download a full frame of vectors each time it is called. This function assumes that the server is currently running and trying to send information. If the server is not running, the printer will be stuck looping in this function because of the blocking nature of fscanf, which is called in this function.
void move_motor(void) - This wrapper function for motor controlling is meant to be called after the get_frame() function and will step through the x and y integer arrays to move the plotter head and draw the entire frame.
To see a full listing of our final code, view it on github: here
Hi! I'm an electrical and computer engineering major in the class of 2015. In this project, I took care of the hardware design and software motor control schemes. I am interested in automotive engineering and I am a member of both the Cornell Formula Racing and Cornell Electric Motorcycle project teams. In my free time, I also do photography.
Hello, I'm an electrical and computer engineering and computer sciences double major in the class of 2015. In this project I took care of the software design and serial communications.