Foam Cutter Manual

User Manual:

Open the PDF directly: View PDF PDF.
Page Count: 92

UCSD Design/Build/Fly
Foamcutter Manual
Yuting Huang
ythuang96@gmail.com
Updated:
December 6, 2018
Preface
Before operating the foamcutter, please read this manual carefully to avoid
injuries and damages to the equipment. All content in the text boxes are ex-
tremely important and should be given extra attention.
This foamcutter project was completed with funds from University of California San
Diego Design/Build/Fly, and is intended to make the manufacturing process of composite
planes easier.
All SolidWorks files, C code, MatLab scripts and operation manual are available for
download at the author’s Github page: https://github.com/ythuang96/FoamCutter. Please
email the author at ythuang96@gmail.com to report any bug in code or any improvement
suggestions.
This project was an improvement on the foamcutter design by Derek Ung and David
Cruz. Special thanks to Dr. Mark Anderson, UCSD MAE department for support of the
project. And thanks to Geo Lopez for his help during the project.
1
2
Contents
Preface 1
1 Preparations 5
1 Laptop Setup ................................... 5
1.1 PuTTY Setup ............................... 5
1.2 WinSCP Setup .............................. 7
2 Assemble the Foamcutter ............................. 10
2.1 Connect the two Side Frames ...................... 11
2.2 Connect two Molex Connector ...................... 12
2.3 Install the Work Panel .......................... 12
2.4 Install the Wire .............................. 15
3 Foamcutter Software Setup ............................ 18
3.1 Connect to the Pi ............................. 18
3.2 Calibrate Wire Origin .......................... 19
3.3 Install the Foamcutter Software ..................... 21
3.4 Update the Foamcutter Software .................... 22
4 G-Code Generation ................................ 22
4.1 G-Code for Wing ............................. 22
4.2 G-Code for General Shapes ....................... 25
2 Operate the FoamCutter 33
1 Switches ...................................... 33
2 Start a Cut .................................... 34
3 Secure the Foam ................................. 34
4 End a Cut ..................................... 37
3
5 Cleaning Up .................................... 38
3 Raspberry Pi Setup 39
1 Install Raspbian on the Raspberry Pi ...................... 39
2 Install WiringPi on the Raspberry Pi ...................... 40
3 Making the Pi into a Wireless Hotspot ..................... 41
Appendices 43
A C Code for the Foamcutter Program 44
1 foamcutter.c .................................... 44
2 foamcutter_setup.h ................................ 61
B MatLab Code for G-code Generation 63
1 DBF_foamcutter_general_shape.m ....................... 63
2 DBF_foamcutter_wing.m ............................ 69
C Drawings 74
D Part List 86
E Purchase History 89
4
Chapter 1
Preparations
1 Laptop Setup
The foamcutter is controlled by a Raspberry Pi 3 B+. In order to communicate with
the Pi, a Windows laptop has to install PuTTY (or similar) to enable secure shell (SSH)
connection to the Pi, and WinSCP (or similar) for graphical file management on the Pi. A
Linux laptop have SSH capability built in, therefore, no software required.
Note:
This setup process is only required once per laptop. If already per-
formed, skip this section and continue to section 4.
1.1 PuTTY Setup
Please follow the following steps for install and setup of PuTTY:
1. Download PuTTY at https://www.putty.org/ then install.
2. Launch PuTTY and a window similar to fig 1.1 below should show up:
5
Figure 1.1: PuTTY Launch Window
3. As shown in fig 1.2 below, in the “Host Name” field, enter “foamcutter.local", then
make sure Connection type is SSH. Next, in “Saved Session field”, enter “foamcutter",
and lastly, click save.
Figure 1.2: PuTTY Setup
4. The session with name “foamcutter" should show up in Saved Session as shown in
6
fig 1.3 below, and the PuTTY setup is completed.
Figure 1.3: Saved PuTTY Session
5. Note on using PuTTY: to copy text from PuTTY, simply select the text, do not press
“Control + C”. To paste text to PuTTY, simply right click mouse, do not press “Control
+ V”.
1.2 WinSCP Setup
Please follow the following steps for install and setup of WinSCP:
1. Download WinSCP at https://winscp.net/eng/download.php then install.
2. Launch WinSCP and a window similar to fig 1.4 below should show up:
7
Figure 1.4: WinSCP Launch Window
3. As shown in fig 1.5 below, make sure the protocol is “SFTP", then enter “foamcut-
ter.local" for the host name, “pi" for the user name, and “ucsdaiaadbf" for the pass-
word.
Figure 1.5: WinSCP Setup
4. Click save, and a window shown in fig 1.6 below should pop up. Both “Save pass-
word" and “Create desktop shortcut" are recommended. Click “OK" and the setup for
WinSCP is completed.
8
Figure 1.6: WinSCP Setup continued
9
2 Assemble the Foamcutter
The entire foamcutter as shown in fig 1.7 below consists of two side frames each
having two axis of motion, four 4-feet long connection rods, and a work panel for securing
the foam.
Figure 1.7: Foamcutter Overview
Caution:
Side frames are extremely heavy, lift with caution;
Avoid bumping head onto the connection rods when leaning into and
out of the frame.
10
Do:
Always make sure the two side frames are connected with the con-
nection rods;
Always push the two side frames firmly against each other before
tightening the thumb screws;
Remember to plug in the two Molex connectors.
Don’t:
Never let the side frames stand on their own;
Never over tighten the thumb screws on the work panel;
Never unscrew screws that are not thumb screws unless performing
repairs.
2.1 Connect the two Side Frames
The two side frames are connected with 4 connection rods, use the 4ft long connection
rods for performing cutting and use the 2ft long connection rods (not purchased yet) for
storage of the foamcutter. Each of the 4 connection rods are secured with two thumb screws
at each end shown in fig 1.8, loosen the thumb screws to remove the connection rod.
Figure 1.8: Thumb Screws for Connection Rods
11
During the installation of the connection rods, do not let the side frames stand on
their own. The side frames are capable of standing on their own, but are not designed to do
so: deformation will occur and degrade the accuracy. When installing the connection rods,
push the two side frames firmly against each other to make sure there are no gaps between
the side frames and the connection rods. Then tighten the thumb screws. An Allen key is
recommended to further tighten the thumb screws.
2.2 Connect two Molex Connector
There are two Molex connectors located at the two top corners of the foamcutter as
shown in fig 1.9 below. Make sure to connect them before operating the foamcutter. The
Molex connectors are foolproof, do not force it when unable to plug in.
Figure 1.9: Molex Connectors
2.3 Install the Work Panel
The work panel is connected to the two side frames at the four corners of the panel.
Each corner is secured with two thumb screws as shown in fig 1.10 below.
12
Figure 1.10: Work Panel Thumb Screws
The work panel should be oriented so that the guiding block, which is a long piece
of PVC screwed to the work panel (pointed by the red arrows in the fig 1.11 below) should
be at the closer side relative to the two horizontal motors (marked by the red circle in the
fig 1.11 below).
13
Figure 1.11: Work Panel Guiding Block Orientation
To install the work panel, first slide the work panel into the 4 supporting rods at the
4 corners with the correct orientation. Make sure all 4 corners sit securely in the supporting
rods, then tighten all 8 thumb screws.
14
2.4 Install the Wire
The wire is held to tension of approximately 10 lbs with a constant force spring. To
install the wire, follow the steps shown below.
(a) Step 1 (b) Step 2
(c) Step 3 (d) Step 4
Figure 1.12: Steps 1-4
1. Feed the wire through the small guiding hole on the side without the pulley.
2. Make a hoop at the end of the wire.
3. Put the hoop around the Nylon bolt and straighten the wire across the entire span of
the foamcutter.
4. Cut the wire at about 3ft longer than the span of the foamcutter. Then feed the end
of the wire through the small guiding hole on the side with the pulley.
15
(a) Step 5 (b) Step 6
(c) Step 7 (d) Step 8
Figure 1.13: Steps 5-8
5. On the back side of the pulley, feed the wire around the copper sleeve bearing.
6. Feed the end of the wire through one of the small mounting holes on the acrylic pulley.
7. Remove the nut stored on the alligator clip.
8. Wrap the wire around the nut.
16
(a) Step 9 (b) Step 10
(c) Step 11 (d) Step 12
(e) Step 13 (f) Step 14
Figure 1.14: Steps 9-12
9. Twist the wire around the nut.
10. Rotate the acrylic pulley clockwise to tighten the wire.
11. Hold the acrylic pulley by hand. Use a wrench to further tighten the spring by holding
17
onto the mounting screw of the spring and rotate counterclockwise.
12. Further tighten the spring with the wrench.
13. Tighten the spring to the approximate position shown in the figure.
14. Clip the alligator click next to the pulley. On the other end, clip the other alligator
clip on the back side of the guiding hole, and make sure the alligator clip does
not touch anything other than the hot wire.
3 Foamcutter Software Setup
3.1 Connect to the Pi
1. Perform the Laptop setup guide in Chapter 1 Section 1if not already completed.
2. Plug in the power cord to the foamcutter to power on the Pi.
3. Connect to the WiFi hotspot named “foamcutter” with password “ucsdaiaadbfor
connect to the ethernet port to the ethernet port of the laptop with a ethernet cable.
4. SSH into the Pi by opening PuTTY and double click on the saved session named
“foamcutter”. Enter the user name “pi” then password “ucsdaiaadbf.
5. Open WinSCP, a window similar to fig 1.15 below should show up. The left hand side
are folders and files on your computer, while the right hand side is files on the Pi.
Make sure the right hand side is in the folder “/home/pi”, if not, navigate to it. To
create new folder on the Pi, use the “new directory” button. To upload files from
your computer to the Pi, simply drag the file/folder from the left half to the right half.
Figure 1.15: WinSCP Window
18
3.2 Calibrate Wire Origin
The 4 axes of the foamcutter each have one limit switch installed. Upon starting of
the program, the foamcutter moves all axes towards the negative direction until hitting the
limit switches. Then the foamcutter moves the 4 axes each a distance specified in the setting
file to reach the Origin. This calibration only needs to be performed once in a while
to improve accuracy. Please follow the steps to calibrate the wire origin:
1. Download the “User Package.zip” from https://github.com/ythuang96/FoamCutter,
and unzip it.
2. Create a new folder on the Pi called “foamcutter” in the directory of “/home/pi”.
3. Upload the files named “foamcutter.c”,“foamcutter_setup.h” and “Makefile”
from the ”User Package” just downloaded into the “foamcutter” folder just created
on the Pi.
4. Open PuTTY and run the following commands line by line:
cd
cd foamcutter
make foamcutter
sudo ./foamcutter
This will launch the foamcutter program.
5. When the program reads “I see the system is not homed yet, please press
ENTER to home the system:” press the Enter key. The foamcutter will move all
4 axes towards the negative direction until touching the limit switch. Then all 4 axes
will move towards the positive direction to the origin.
6. Place a Aluminum block on the work panel against the work panel guiding block, and
observe from top down as shown in fig 1.16 below. Both the far left and far right of
the wire should sit right against the aluminum block, measure the amount that needs
to be adjusted in millimeters.
19
Figure 1.16: Calibrate Wire Origin in the Horizontal Direction
7. Again, place a Aluminum block on the work panel against the work panel guiding
block, but observe horizontally as shown in fig 1.17 below. Both the far left and the
far right of the wire should sit at the same height. The height could be arbitrary,
but should be higher than the thumb screws on the work panel. Again, measure the
amount that needs to be adjusted in millimeters.
20
Figure 1.17: Calibrate Wire Origin in the Vertical Direction
8. Open WinSCP, navigate to “/home/pi/foamcutter” on the Pi (the right hand side
of the WinSCP window), and double click on the file “foamcutter_setup.h” to edit
it.
9. Find the 5 lines that read as the following:
// position of limit switch relative to cutter origin
#define LIM2ORIGIN_LX -4100
#define LIM2ORIGIN_RX -3550
#define LIM2ORIGIN_LY -2500
#define LIM2ORIGIN_RY -2400
and adjust the four numbers: if wish to move an axis 1mm further away (or closer) from
the limit switch, subtract (or add) 157 from the number corresponding to the axis. All
4 numbers must be negative integers, no decimal, and no equations (please
calculated the number yourself and replace the original number).
10. Save the file then repeat the process from step 4 to adjust the 4 numbers until the wire
sits at the desired location. Then save the 4 numbers on your computer.
3.3 Install the Foamcutter Software
1. Perform the Wire Origin Calibration guide in Chapter 1 Section 3.2 if not already
completed.
2. Open PuTTY and run the following commands line by line:
cd
21
cd foamcutter
sudo make install foamcutter
3. Delete the folder “/home/pi/foamcutter” on the Pi.
4. You can now use sudo foamcutter to run the foamcutter program.
3.4 Update the Foamcutter Software
1. If a new version is available, download the “User Package.zip” from
https://github.com/ythuang96/FoamCutter, and unzip it.
2. Create a new folder on the Pi called “foamcutter” in the directory of “/home/pi”.
3. Upload the files named “foamcutter.c”,“foamcutter_setup.h” and “Makefile”
from the ”User Package” just downloaded into the “foamcutter” folder just created
on the Pi.
4. If wish to perform Wire Origin Calibration, proceed to Chapter 1 Section 3.2 step
4 to step 10. Then continue to the steps in Chapter 1 Section 3.3.
If wish to use the previously calibrated parameters, open WinSCP, edit the file
“/home/pi/foamcutter_setup.h”, find the 5 lines that read as the following:
// position of limit switch relative to cutter origin
#define LIM2ORIGIN_LX -4100
#define LIM2ORIGIN_RX -3550
#define LIM2ORIGIN_LY -2500
#define LIM2ORIGIN_RY -2400
and change the 4 numbers to the previously calibrated parameters. Then proceed
to Chapter 1 Section 3.3 step 2 to step 4.
4 G-Code Generation
4.1 G-Code for Wing
1. Download the needed airfoil coordinates at
http://m-selig.ae.illinois.edu/ads/coord_database.html#S
2. Place the needed airfoil coordinate files in the same folder as the MatLab code
“DBF_foamcutter_wing.m” which is provided in the “User Package.zip” from
https://github.com/ythuang96/FoamCutter.
3. Enter the parameters into the MatLab script and run the script. A figure tracing the
the motion of the two ends of the wire should show up, and the G-code should be saved
in the same folder.
Note:
When cutting extremely tampered parts, figure similar to the fig 1.18 below might
show up during the G-code generation process:
22
Figure 1.18: Example Figure During G-code Generation for a Wing
The parameters used for this figure is shown below:
23
Figure 1.19: Example Parameters During G-code Generation for a Wing
Note that the root and tip cord length differed a lot, and the span is significantly
smaller than the cutter width, therefore, this is an extremely tapered cut. As a result, the
inverted airfoil shown in fig 1.18 above is expected. As explained in fig 1.20 below, for
extremely tapered cuts, the two ends of the wire could move in opposite directions, resulting
in the inverted airfoil shown in fig 1.18.
Figure 1.20: Sketch of an Extremely Tapered Cut
24
4.2 G-Code for General Shapes
Key Points:
Make sure to increase AutoCAD precision;
Make sure to scale the drawing by 25.4 in AutoCAD if the SolidWorks
file is in inches;
Make sure to run “Explode” command in AutoCAD;
Make sure there are no overlapping lines;
Make sure to convert spline to polyline in AutoCAD and explode
again.
1. Export the projection of the top or side (or both) profiles from SolidWorks into .dxf
files, the steps are demonstrated with the payload bay shown in fig 1.21 below.
Figure 1.21: Sample Payload Bay
The projection of the side profile can be obtained by slicing the part vertically in
the center: go to “Insert Features Split” as shown in fig 1.22 below:
25
Figure 1.22: SolidWorks Split Command
In the pop up window, as shown in fig 1.23 below, in “Trim Tools” selected the
desired plane (the front plane in this case) then click “Cut Body”. In the “Resulting
Bodies” box, select one of the resulting bodies. Lastly, make sure the “Consume
cut bodies” check box is selected, and click the top left green check mark. This
will delete the selected half of the part (the brown half in fig 1.23).
26
Figure 1.23: SolidWorks Split Menu
Right click on the cut plane and select “Export to DXF/DEG” to export the
projection of the side profile as shown in fig 1.24 below:
27
Figure 1.24: Export Side Profile
The top plane of the part is the projection from above, therefore, skip the split
command and directly right click on the plane and export:
Figure 1.25: Export Top Profile
2. Open AutoCAD, increase the precision by clicking the top left red AutoCAD sign,
select “Drawing Utilities Units” and increase the precision to 4 decimal points, as
shown in fig 1.26 below.
28
Figure 1.26: Increase AutoCAD Precision
3. Import the dxf files from SolidWorks.
4. Scale the drawing by 25.4 if the SolidWorks file is in inches.
5. Select all objects and run “Explode” command.
6. Select all Spline (if any), right click and select “Spline Convert to Polyline” as shown
in fig 1.27 below. When ask to enter accuracy, enter 1 and press enter.
Figure 1.27: Convert Spline
7. Explode again (explode the polylines converted from spline).
29
8. Rotate and delete overlapping lines if necessary.
9. Select all lines and run “eattext” command, a window similar to fig 1.28 should pop
up, select “Edit an existing data extraction” then click the browse button.
Figure 1.28: Eattext Page 1
10. Browse for the extraction templates, select the template with or without arc depending
on the drawing. (The templates are included in the “User Package.zip” from
https://github.com/ythuang96/FoamCutter)
Figure 1.29: Browse for Data Extraction Templates
11. On page 2, check “include current drawing”, select the one that is not the current
drawing (if any) and click remove.
30
Figure 1.30: Eattext Page 2 Step 1
12. Then select the current drawing and click “Next”.
Figure 1.31: Eattext Page 2 Step 2
13. On page 3, make sure the drawing only has lines, or only has lines and arcs, depending
on the template used. If not, cancel the process, fix the drawing, and redo the “eattext”
command.
Figure 1.32: Eattext Page 3
14. Continue clicking “Next” until reaching page 6, name the data point file and save to
the desired location. Click “Next” then “Finish”.
31
Figure 1.33: Eattext Page 6
15. Put the .csv file from AutoCAD into the same folder as the MatLAB script
“DBF_foamcutter_general_shape.m” (provided in the “User Package.zip” from
https://github.com/ythuang96/FoamCutter) and run the MatLAB code. Follow the
prompts, and the G-code should be ready.
32
Chapter 2
Operate the FoamCutter
1 Switches
The foamcutter has 3 switches installed as shown in fig 2.1 below.
Figure 2.1: Three Switches of the Foamcutter
Left most switch: Exit switch
Only operational when the foamcutter software is running.
Hold the switch for 4 seconds will stop all motor movement, exit the foamcutter soft-
ware and shutdown the Raspberry Pi.
33
Middle switch: Pause switch
Only operational when the foamcutter software is running. Toggle the switch up to
pause the motor movements.
Toggle the switch down to resume the motor movements.
Right most switch: Wire Control switch
Operational regardless of foamcutter software.
Toggle the switch up will enable the wire heating when the wire power supply is turned
on and connected.
Toggle the switch down will enable the foamcutter software to control the wire heating.
The software automatically turns on the wire heating when starting the cut and turns
off the wire heating when cut ends. This switch should generally be left at the
down position for safety.
2 Start a Cut
Please follow the steps below to operate the foamcutter:
1. Prepare the G-code following guide from Chapter 1 Section 4.
2. Assemble the foamcutter following guide from Chapter 1 Section 2.
3. Check that the Wire Control switch (right most switch) is toggled to the down position.
4. Plug in the power cord.
5. Plug in the power supply for the hot wire but do not turn it on.
6. On your laptop, connect to the WiFi network named “foamcutter”, with password
“ucsdaiaadbf or connect to the ethernet port to the ethernet port of the laptop with
a ethernet cable.
7. Open PuTTY and connect to the Pi with user name “pi” and password
“ucsdaiaadbf.
8. Open WinSCP and connect to the Pi. Upload the G-code file to the Pi folder
“/home/pi”.
9. In PuTTY, run: sudo foamcutter
10. The software will first check the Pause switch status and will prompt to toggle the
switch down if needed.
11. The software will then ask to perform the homing process. Double check that the
Molex connectors are connected, then press enter to perform homing.
12. The software will then enter the main menu, follow the prompts to select desired
options to perform cuts or move the wire.
3 Secure the Foam
The foam can be secured with acrylic plates with thumb screws on the three sides.
Follow the steps below to secure the foam on the work panel:
1. Measure the width of the foam that need to be cut.
34
2. Set one acrylic plate half of the width of the foam so that the foam will be centered
on the work panel. Make sure both ruler reads the same so that the acrylic plate is in
the vertical direction as shown in fig 2.2 below.
Figure 2.2: Secure the Foam Step 2
3. Secure the first plate with 3 thumb screws. Do not over tighten the thumbscrews,
or the threads on the work panel might be destroyed.
4. Place the foam on the work panel with one side firmly against the guiding block and
another side firmly against the first acrylic plate.
5. Place a second acrylic plate firmly against the foam and secure with 3 thumb screws
as shown in fig 2.3 below.
35
Figure 2.3: Secure the Foam Step 5
6. Secure the back of the foam with another acrylic plate and secure with 3 thumb screws
as shown in fig 2.4 below.
Figure 2.4: Secure the Foam Step 6
7. Place a small piece of aluminum block on top of the foam to prevent vertical movement
as shown in fig 2.5 below.
36
Figure 2.5: Secure the Foam Step 7
8. To secure very small pieces of foam, one of the acrylic plates can be flipped as shown
in fig 2.6 below.
Figure 2.6: Secure the Foam Step 6
4 End a Cut
To the cutting operation half way through a G-code:
In the PuTTY session, press “Control + C”. This will stop the cut and exit the
program. It will also ask if desired to shutdown the Pi immediately.
37
Or hold the Exit switch for more than 3 seconds. This will stop the cut and exit the
program, but will also immediately shutdown the Pi.
To exit the program after the cut is finished, apart form the two options listed above,
the user can also select the menu options to return to the main menu, and select the third
option to exit the program. It will also ask if desired to shutdown the Pi immediately.
5 Cleaning Up
After the Pi is properly turned off by:
Press Enter when seeing “If you would like to shutdown the Pi now. Please
press ENTER. Otherwise, press ’n’ then press ENTER:” when exiting the
foamcutter software.
Or run “sudo shutdown now” in PuTTY.
the green LED should flash a couple of times indicating the operating system is reading/writ-
ing to the SD card. After the green LED turns off, unplug the power cord and wrap it around
the acrylic electronics box. Also remember to turn off the power supply for the hot wire and
wrap the power cables for the hot wire around the two screws.
38
Chapter 3
Raspberry Pi Setup
Note:
All steps in this chapter are already performed on the currently used
Raspberry Pi, and do not need to be performed again unless the Raspberry
Pi or the SD card is damaged and needs replacement.
1 Install Raspbian on the Raspberry Pi
Raspbian is one of the recommended operating system for the Raspberry Pi. The
following steps are used to install Raspbian and setup the Pi.
1. Perform the Laptop setup guide in Chapter 1 Section 1if not already completed.
2. Download the Raspbian Sketch Lite version at:
https://www.raspberrypi.org/downloads/raspbian/ The Lite version does not have
desktop support, but should be sufficient for the foamcutter.
3. Download and install Etcher at https://etcher.io/.
4. Plug in the SD card into a laptop and run Etcher.
5. In Etcher, select the raspbian image just downloaded, then select the SD card. Lastly,
click flash.
6. Wait for flash to complete, the SD card should now have two partition with one named
“boot”.
7. Enable SSH on the Pi by creating a file name “ssh” without any extension in the
partition named “boot” on the SD card.
8. Unplug the SD card from the laptop and plug into the Pi. Connect a Ethernet cable
from the Pi to same router your laptop is currently connected to.
9. Connect power to the Pi.
10. SSH into the Pi by opening up PuTTY and create a new session with host name:
“raspberrypi.local”. Note on using PuTTY: to copy text from PuTTY, simply select
the text, do not press “Control + C”. To paste text to PuTTY, simply right click mouse,
39
do not press “Control + V”.
11. Enter the user name “pi” then password “raspberry”.
12. Change the log in password: enter “passwd” on the command line and press Enter.
Enter the current password “raspberry”, then enter the new password “ucsdaiaadbf
twice.
13. Change the name of the Pi by entering “sudo raspi-config”, select “Network Op-
tions Hostname”, then enter the new hostname: “foamcutter”, then press Enter.
14. Select “Finish”, then press Enter. When asked to reboot, select “Yes”.
2 Install WiringPi on the Raspberry Pi
WiringPi is a GPIO Interface library written for the Raspberry Pi. A complete guide
can be found at: http://wiringpi.com/. To install on the pi, follow the complete guide at:
http://wiringpi.com/download-and-install/ or follow the steps below:
1. Power on the Pi and open PuTTY on your laptop.
2. Double click on the saved PuTTY session named “foamcutter” as shown in fig 3.1
below.
Figure 3.1: SSH to the Raspberry Pi
3. Enter user name “pi” and password “ucsdaiaadbf.
4. Update the operating system using the following two command:
sudo apt-get update
sudo apt-get upgrade
5. Install GIT using:
40
sudo apt-get install git-core
6. Install WiringPi using:
cd
git clone git://git.drogon.net/wiringPi
cd /wiringPi
./build
7. Completed when seeing:
All Done.
NOTE: To compile programs with wiringPi, you need to add:
-lwiringPi
to your compile line(s) To use the Gertboard, MaxDetect, etc.
code (the devLib), you need to also add:
-lwiringPiDev
to your compile line(s).
3 Making the Pi into a Wireless Hotspot
Do not perform the following procedure. This method seems to have
unsolved connection problems and is not recommended currently. Connection
through an Ethernet cable is recommended.
Making the Pi into a Wireless Hotspot will enable operation of the foamcutter even in
areas without a wireless network. The following steps are adapted from: https://elinux.org/RPI-
Wireless-Hotspot
1. SSH into the Pi via PuTTY.
2. Run: sudo apt-get install hostapd udhcpd
3. Run: sudo nano /etc/udhcpd.conf This will open a text editor, use keyboard
instead of mouse to navigate.
Find the line starting with interface and change to interface wlan0
Find the line starting with opt router and change to opt router 192.168.42.1
Press Control + O then Enter then Control + X to save and close file.
4. Run: sudo nano /etc/default/udhcpd
Add #to the front of the line DHCPD_ENABLED="no"
Press Control + O then Enter then Control + X to save and close file.
5. Run: sudo ifconfig wlan0 192.168.42.1
6. Run: sudo nano /etc/network/interfaces
Add the following lines to the bottom of the file if the line iface wlan0 inet
dhcp is not present, otherwise replace it:
iface wlan0 inet static
address 192.168.42.1
41
netmask 255.255.255.0
Add #to the beginning of each of the following lines if present:
allow-hotplug wlan0
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet manual
Press Control + O then Enter then Control + X to save and close file.
7. Run: sudo nano /etc/hostapd/hostapd.conf
Add the following lines to the bottom of the file:
interface=wlan0
driver=nl80211
ssid=foamcutter
hw_mode=g
channel=6
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=2
wpa_passphrase=ucsdaiaadbf
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
channel=1
ieee80211n=1
wmm_enabled=1
ht_capab=[HT40+][SHORT-GI-20][DSSS_CCK-40]
Press Control + O then Enter then Control + X to save and close file.
8. Run: sudo nano /etc/default/hostapd
Change the line from #DAEMON_CONF="" to
DAEMON_CONF="/etc/hostapd/hostapd.conf"
Press Control + O then Enter then Control + X to save and close file.
9. Run: sudo nano /etc/default/hostapd
Add net.ipv4.ip_forward=1 to the bottom of the file.
Press Control + O then Enter then Control + X to save and close file.
10. Run: sudo update-rc.d hostapd enable
11. Run: sudo update-rc.d udhcpd enable
12. Run: sudo reboot
42
Appendices
43
Appendix A
C Code for the Foamcutter Program
1 foamcutter.c
The C code for the foamcutter program, foamcutter.c is attached below. Verison
1.0.0, lasted updated: 6/30/2018.
44
1 /***********************************************************************
2 * FoamCutter
3 * This code is written for Design/Build/Fly CNC foamcutter.
4 * Written by Yuting Huang (ythuang96@gmail.com).
5 * Please report any bug to my email address.
6 *
7 * Last update: 6/30/2018
8 *
9 * Current Version: V 1.0.0
10 ***********************************************************************/
11 #define VERSION_A 1
12 #define VERSION_B 0
13 #define VERSION_C 0
14 #include "foamcutter_setup.h"
15
16 typedef enum state_t{
17 HOMED, GCODE, EXITING
18 } state_t;
19 typedef struct position_t{
20 int32_t LX, LY, RX, RY;
21 } position_t;
22 typedef struct speed_t{
23 float LX, LY, RX, RY;
24 } speed_t;
25 typedef struct coord_t{
26 float LX_old, LY_old, RX_old, RY_old;
27 float LX, LY, RX, RY;
28 } coord_t;
29 typedef struct coord_lim_t{
30 float LX_max, LY_max, RX_max, RY_max;
31 float LX_min, LY_min, RX_min, RY_min;
32 } coord_lim_t;
33
34 /***********************************************************************
35 ************************** GLOBAL VARIABLES ****************************
36 ***********************************************************************/
37 state_t state_;
38 position_t target_position_;
39 position_t current_position_;
40 position_t reached_position_;
41 position_t stop_;
42 speed_t set_speed_;
43 coord_t coord_;
44 coord_lim_t coord_lim_;
45
46 float coord_offset_x_;
47 float coord_offset_y_;
48 int gcode_menu_option_;
49 int ETA_;
50 struct timespec start_time_;
51 FILE *ptr_file_;
52
53 int state_STOP_ =0;
54
55 // Threads
56 pthread_t LX_thread;
57 pthread_t LY_thread;
58 pthread_t RX_thread;
59 pthread_t RY_thread;
60 pthread_t printing_thread;
61 pthread_t cut_manager;
62 pthread_t switch_thread;
63 struct sched_param params_motor_thread;
64 struct sched_param params_print_thread;
65 struct sched_param params_cut_manager;
66 struct sched_param params_switch_thread;
67
68 /***********************************************************************
69 *********************** FUNCTION DECLARATIONS **************************
70 ***********************************************************************/
71 // THREADS
72 void*LX_thread_func(void*ptr);
73 void*LY_thread_func(void*ptr);
74 void*RX_thread_func(void*ptr);
75 void*RY_thread_func(void*ptr);
76 void*cut_manager_func(void*ptr);
77 void*print_func(void*ptr);
78 void*switch_thread_func(void*ptr);
79
80 // SYSTEM FUNCTIONS
81 void initialize_pin();
82 void home();
83 int loadtext(char*filename);
84 int check_cord(char*str);
85 int allreached();
86 void stop_all();
87 float cut_length_func();
45
88 void drive(int pin_pul,int pin_dir,float speed,int32_t delta_pulse,int*ptr_current,int*ptr_stop,int polarity );
89 void cut_gcode(char*filename);
90 void moveto(float x,float y);
91
92 // MENU FUNCTIONS
93 void main_menu();
94 void gcode_menu();
95 void move_menu();
96 int menu(int numb_of_options);
97 int menu_enter();
98 int menu_yes();
99 int menu_enter_one(float*output,char*string);
100 int menu_enter_two(float*output1,float*output2,char*string);
101
102 // OTHER FUNCTIONS
103 void nsleep(uint64_t ns);
104 int file_filter(const struct dirent *entry);
105 void removespace(char*str);
106 void SigHandler(int dummy);
107 float max(float a,float b);
108 float min(float a,float b);
109 void print_time(int sec);
110 int str2f(char*str,float*output);
111
112
113 /***********************************************************************
114 ******************************** MAIN **********************************
115 ***********************************************************************/
116
117 int main(){
118 // Setup GPIO pins
119 if (wiringPiSetupGpio () == -1) {
120 printf("Initialization failed. Most likely you are not root\n");
121 printf("Please remember to use 'sudo foamcutter'.\n");
122 return 1;
123 }
124 initialize_pin(); digitalWrite(PIN_RELAY, LOW);
125 // Setup signal handler for CTRL+C
126 signal(SIGINT, SigHandler);
127
128 // Start motor threads
129 params_motor_thread.sched_priority =90;
130 pthread_setschedparam(LX_thread, SCHED_FIFO, &params_motor_thread);
131 pthread_create(&LX_thread, NULL, LX_thread_func, (void*)NULL);
132 pthread_setschedparam(LY_thread, SCHED_FIFO, &params_motor_thread);
133 pthread_create(&LY_thread, NULL, LY_thread_func, (void*)NULL);
134 pthread_setschedparam(RX_thread, SCHED_FIFO, &params_motor_thread);
135 pthread_create(&RX_thread, NULL, RX_thread_func, (void*)NULL);
136 pthread_setschedparam(RY_thread, SCHED_FIFO, &params_motor_thread);
137 pthread_create(&RY_thread, NULL, RY_thread_func, (void*)NULL);
138
139 stop_.LX = stop_.LY = stop_.RX = stop_.RY =0;
140
141 // Print Header
142 printf("\n");
143 printf("+---------------------------------------------------------------+\n");
144 printf("| DBF Foamcutter Program by Yuting Huang |\n");
145 printf("| Current Version is V%d.%d.%d |\n" \
146 , VERSION_A, VERSION_B, VERSION_C);
147 printf("| Contact me at ythuang96@gmail.com to report bugs |\n");
148 printf("| |\n");
149 printf("|---------------------------------------------------------------|\n");
150 printf("| Brief User Instructions |\n");
151 printf("| At any time in the program: |\n");
152 printf("| 1. Press CTRL+C to exit the prgram |\n");
153 printf("| 2. Long press EXIT button exit the prgram and shutdown the Pi |\n");
154 printf("| 3. Toggle PAUSE button to pause/resume all motor momevments |\n");
155 printf("+---------------------------------------------------------------+\n\n");
156
157 // Check Pause Switch
158 int counter1 =0;
159 if (state_ != EXITING) {
160 for (int i =1; i<= 21; i++) {
161 if (digitalRead(PIN_PAUSE)) counter1 ++;
162 nsleep(500000);
163 }
164 if (counter1 >10)printf("Please toggle the PAUSE switch to resume\n\n");
165 }
166 while (state_ != EXITING && counter1 >10) {
167 counter1 =0;
168 for (int i =1; i<= 21; i++) {
169 if (digitalRead(PIN_PAUSE)) counter1 ++;
170 nsleep(500000);
171 }
172 }
173
174 // Start Switch Thread
46
175 params_switch_thread.sched_priority =50;
176 pthread_setschedparam(switch_thread, SCHED_FIFO, &params_switch_thread);
177 pthread_create(&switch_thread, NULL, switch_thread_func, (void*)NULL);
178
179 // Home the system
180 if (state_ != EXITING) home();
181
182 while (state_ != EXITING) main_menu();
183
184 // stop all motors
185 stop_all();
186 // end swtich thread
187 pthread_join(switch_thread, NULL);
188 // end all motor threads
189 pthread_join(LX_thread, NULL); pthread_join(LY_thread, NULL);
190 pthread_join(RX_thread, NULL); pthread_join(RY_thread, NULL);
191 // print exit messages
192 printf("EXIT successful, Thank you for using the FoamCutter program.\n");
193 if (state_STOP_) {
194 printf("\nShuting down ... ...\n");
195 system("shutdown -P now");
196 return 0;
197 }
198 printf("\nIf you would like to shutdown the Pi now. Please press ENTER.\n");
199 printf("Otherwise, press 'n' then press ENTER: "); fflush(stdout);
200
201 /****************** SHUTDOWN MENU OPTIONS ****************************/
202 fd_set input_set; struct timeval timeout;
203 timeout.tv_sec =10; timeout.tv_usec =0;
204
205 // Listening for input stream for any activity
206 FD_ZERO(&input_set); FD_SET(0,&input_set);
207 while (!select(1,&input_set, NULL,NULL,&timeout)) {
208 timeout.tv_sec =10;
209 FD_ZERO(&input_set ); FD_SET(0,&input_set);
210 }
211
212 // get input
213 char input_option[256]; fgets(input_option,256,stdin);
214 // determine length of input
215 int i; for(i=0; input_option[i]!='\0'; i++); i --;
216
217 if (i == 1&& (input_option[0]== 'n' || input_option[0]== 'N')) {
218 // if chose not to shutdown
219 printf("\nOk, Please remember to use 'sudo shutdown now'\n");
220 printf("to shutdown the Pi before unpluging the power.\n\n");
221 }
222 else {// chose to shutdown
223 printf("\nShuting down ... ...\n");
224 system("shutdown -P now");
225 }
226
227 return 0;
228 }
229
230 /***********************************************************************
231 ****************************** THREADS *********************************
232 ***********************************************************************/
233 void*LX_thread_func(void*ptr){
234 while (state_ != EXITING) {
235 if (set_speed_.LX == 0|| reached_position_.LX == 1|| stop_.LX == 1) {
236 if (current_position_.LX == target_position_.LX){
237 reached_position_.LX =1;
238 }
239 digitalWrite(PIN_LX_PUL, LOW);
240 nsleep(1000000);
241 }
242 else {
243 drive(PIN_LX_PUL, PIN_LX_DIR, set_speed_.LX, \
244 target_position_.LX - current_position_.LX, \
245 &(current_position_.LX), &(stop_.LX), POLARITY_LX);
246 if (!stop_.LX) reached_position_.LX =1;
247 }
248 }
249 return NULL;
250 }
251
252 void*LY_thread_func(void*ptr){
253 while (state_ != EXITING) {
254 if (set_speed_.LY == 0|| reached_position_.LY == 1|| stop_.LY == 1) {
255 if (current_position_.LY == target_position_.LY){
256 reached_position_.LY =1;
257 }
258 digitalWrite(PIN_LY_PUL, LOW);
259 nsleep(1000000);
260 }
261 else {
47
262 drive(PIN_LY_PUL, PIN_LY_DIR, set_speed_.LY, \
263 target_position_.LY - current_position_.LY, \
264 &(current_position_.LY), &(stop_.LY), POLARITY_LY);
265 if (!stop_.LY) reached_position_.LY =1;
266 }
267 }
268 return NULL;
269 }
270
271 void*RX_thread_func(void*ptr){
272 while (state_ != EXITING) {
273 if (set_speed_.RX == 0|| reached_position_.RX == 1|| stop_.RX == 1) {
274 if (current_position_.RX == target_position_.RX){
275 reached_position_.RX =1;
276 }
277 digitalWrite(PIN_RX_PUL, LOW);
278 nsleep(1000000);
279 }
280 else {
281 drive(PIN_RX_PUL, PIN_RX_DIR, set_speed_.RX, \
282 target_position_.RX - current_position_.RX, \
283 &(current_position_.RX), &(stop_.RX), POLARITY_RX);
284 if (!stop_.RX) reached_position_.RX =1;
285 }
286 }
287 return NULL;
288 }
289
290 void*RY_thread_func(void*ptr){
291 while (state_ != EXITING) {
292 if (set_speed_.RY == 0|| reached_position_.RY == 1|| stop_.RY == 1) {
293 if (current_position_.RY == target_position_.RY){
294 reached_position_.RY =1;
295 }
296 digitalWrite(PIN_RY_PUL, LOW);
297 nsleep(1000000);
298 }
299 else {
300 drive(PIN_RY_PUL, PIN_RY_DIR, set_speed_.RY, \
301 target_position_.RY - current_position_.RY, \
302 &(current_position_.RY), &(stop_.RY), POLARITY_RY);
303 if (!stop_.RY) reached_position_.RY =1;
304 }
305 }
306 return NULL;
307 }
308
309 void*cut_manager_func(void*ptr){
310 char buf[500];
311 while(state_ == GCODE && fgets(buf,500, ptr_file_)!=NULL){
312 while (state_ == GCODE && !allreached()) {
313 nsleep(10000000);
314 }// wait till last coord is reached
315 removespace(buf); // remove spaces
316 if (!strncmp(buf,"G4P",3)) { // check if is a pause statement
317 float temp; str2f(buf+3,&temp);
318 nsleep((uint64_t)(floor(temp*1.0E9)));
319 }
320 else if (!strncmp(buf,"G1",2)) { // if a cut statement
321 check_cord(buf); // read coordinates and update global coord_
322 // Update new target position
323 target_position_.LX =(int32_t)floor((coord_.LX + coord_offset_x_) * MM2PULSE);
324 target_position_.LY =(int32_t)floor((coord_.LY + coord_offset_y_) * MM2PULSE);
325 target_position_.RX =(int32_t)floor((coord_.RX + coord_offset_x_) * MM2PULSE);
326 target_position_.RY =(int32_t)floor((coord_.RY + coord_offset_y_) * MM2PULSE);
327 // Calculate time to move to the next coord
328 float dL =sqrt(pow(target_position_.LX - current_position_.LX,2.0) \
329 +pow(target_position_.LY - current_position_.LY,2.0));
330 float dR =sqrt(pow(target_position_.RX - current_position_.RX,2.0) \
331 +pow(target_position_.RY - current_position_.RY,2.0));
332 float time =(dL + dR)/2.0/FEEDRATE/MM2PULSE;
333 // Set speed for all 4 axis
334 set_speed_.LX =(target_position_.LX - current_position_.LX)/time/MM2PULSE;
335 set_speed_.LY =(target_position_.LY - current_position_.LY)/time/MM2PULSE;
336 set_speed_.RX =(target_position_.RX - current_position_.RX)/time/MM2PULSE;
337 set_speed_.RY =(target_position_.RY - current_position_.RY)/time/MM2PULSE;
338 if (state_ == GCODE) {
339 // Start the cut by setting reached_position_ to 0
340 reached_position_.LX = reached_position_.LY =0;
341 reached_position_.RX = reached_position_.RY =0;
342 // wait till new coord is reached
343 nsleep((uint64_t)(floor(time*1.0E9)));
344 }
345 }// end while --- read line by line
346 }
347 // if the state_ is still GCODE, but the while loop ended;
348 // means the end of file is reached, and therefore cut is complete
48
349 if (state_ == GCODE) { state_ = HOMED;}
350 return NULL;
351 }
352
353 void*print_func(void*ptr){
354 struct timespec current_time;
355 int elapsed_time =0;
356 int remain_time;
357 while(state_ == GCODE){
358 clock_gettime( CLOCK_REALTIME, &current_time);
359 elapsed_time = current_time.tv_sec - start_time_.tv_sec;
360 remain_time = ETA_ - elapsed_time;
361 printf("\r");
362 printf("%7.3f/%8.3f|%7.3f/%8.3f|%7.3f/%8.3f|%7.3f/%8.3f| ", \
363 current_position_.LX/MM2PULSE*MM2IN , current_position_.LX/MM2PULSE, \
364 current_position_.LY/MM2PULSE*MM2IN , current_position_.LY/MM2PULSE, \
365 current_position_.RX/MM2PULSE*MM2IN , current_position_.RX/MM2PULSE, \
366 current_position_.RY/MM2PULSE*MM2IN , current_position_.RY/MM2PULSE);
367 print_time(elapsed_time); printf(" | ");
368 print_time(remain_time); printf(" |");
369 fflush(stdout);
370 nsleep(1000000000); // run at 1 Hz
371 }
372 return NULL;
373 }
374
375 void*switch_thread_func(void*ptr){
376 int state_P =0;
377 int counter_P, counter_S;
378 int counter_S2 =0;
379 while (state_ != EXITING) {
380 counter_P = counter_S =0;
381 for (int i =1; i<= 41; i++) {
382 if (digitalRead(PIN_PAUSE)) counter_P ++;
383 if (digitalRead(PIN_STOP )) counter_S ++;
384 nsleep(500000);
385 }
386
387 if (counter_P >25 && !state_P) {
388 stop_all();
389 state_P =1;
390 }
391 else if (counter_P <= 15 && state_P && state_ == GCODE) {
392 state_P =0;
393 stop_.LX = stop_.LY = stop_.RX = stop_.RY =0;
394 digitalWrite(PIN_RELAY, HIGH);
395 }
396 else if (counter_P <= 15 && state_P && state_ == HOMED) {
397 state_P =0;
398 stop_.LX = stop_.LY = stop_.RX = stop_.RY =0;
399 }
400
401 if (counter_S >25) counter_S2 ++;
402 else counter_S2 =0;
403
404 if (counter_S2 == 100){
405 state_ = EXITING; stop_all(); state_STOP_ =1;
406 printf("\n\n**************************** EXITING PROGRAM ****************************\n");
407 }
408 }
409 return NULL;
410 }
411
412 /***********************************************************************
413 ************************** SYSTEM FUNCTIONS ****************************
414 ***********************************************************************/
415
416 void initialize_pin(){
417 // Setup limit switch pins
418 pinMode(PIN_LX_LIM,INPUT); pullUpDnControl(PIN_LX_LIM,PUD_DOWN);
419 pinMode(PIN_LY_LIM,INPUT); pullUpDnControl(PIN_LY_LIM,PUD_DOWN);
420 pinMode(PIN_RX_LIM,INPUT); pullUpDnControl(PIN_RX_LIM,PUD_DOWN);
421 pinMode(PIN_RY_LIM,INPUT); pullUpDnControl(PIN_RY_LIM,PUD_DOWN);
422 // Setup motor dive pins
423 pinMode(PIN_LX_DIR,OUTPUT); pinMode(PIN_LX_PUL,OUTPUT);
424 pinMode(PIN_LY_DIR,OUTPUT); pinMode(PIN_LY_PUL,OUTPUT);
425 pinMode(PIN_RX_DIR,OUTPUT); pinMode(PIN_RX_PUL,OUTPUT);
426 pinMode(PIN_RY_DIR,OUTPUT); pinMode(PIN_RY_PUL,OUTPUT);
427 // Setup switches pins
428 pinMode(PIN_PAUSE,INPUT); pullUpDnControl(PIN_PAUSE,PUD_DOWN);
429 pinMode(PIN_STOP ,INPUT); pullUpDnControl(PIN_STOP ,PUD_DOWN);
430 // Setup relay control pin
431 pinMode(PIN_RELAY,OUTPUT);
432 return;
433 }
434
435 void home(){
49
436 // Print Header
437 printf("I see the system is not homed yet, please press ENTER to home the system: ");
438 fflush(stdout);
439 if (menu_enter() == -2)return;// if EXITING state, end function
440 printf("Homing ... "); fflush(stdout);
441
442 // Home the system
443 current_position_.LX = current_position_.LY = current_position_.RX = current_position_.RY =0;
444 reached_position_.LX = reached_position_.LY = reached_position_.RX = reached_position_.RY =0;
445 target_position_.LX = target_position_.LY = target_position_.RX = target_position_.RY = -640000;
446
447 // Home X axis
448 set_speed_.LY = set_speed_.RY =0.0;
449 set_speed_.LX = set_speed_.RX = -1.0;
450
451 int counter1, counter2;
452 int state1 =0;int state2 =0;
453
454 while (state_ != EXITING && (!state1 || !state2)) {
455 counter1 = counter2 =0;
456 for (int i =1; i<= 41; i++) {
457 if (digitalRead(PIN_LX_LIM)) counter1 ++;
458 if (digitalRead(PIN_RX_LIM)) counter2 ++;
459 nsleep(20000);
460 }
461 if (counter1 >30 && !state1) {
462 state1 =1;
463 stop_.LX =1;
464 set_speed_.LX =0.0;
465 current_position_.LX = LIM2ORIGIN_LX;
466 reached_position_.LX =1;
467 }
468 if (counter2 >30 && !state2) {
469 state2 =1;
470 stop_.RX =1;
471 set_speed_.RX =0.0;
472 current_position_.RX = LIM2ORIGIN_RX;
473 reached_position_.RX =1;
474 }
475 }
476
477 if (state_ == EXITING) return;
478 nsleep(200000000);
479 target_position_.LX = LIM2ORIGIN_LX +1000;
480 target_position_.RX = LIM2ORIGIN_RX +1000;
481 set_speed_.LX = set_speed_.RX = +FEEDRATE;
482 stop_.LX = stop_.RX =0;
483 reached_position_.LX = reached_position_.RX =0;
484 while (state_ != EXITING && (!reached_position_.LX || !reached_position_.RX)) { nsleep(1000000);}
485
486 // Home Y axis
487 if (state_ == EXITING) return;
488 nsleep(500000000);
489 set_speed_.LX = set_speed_.RX =0.0;
490 set_speed_.LY = set_speed_.RY = -1.0;
491
492 counter1 = counter2 = state1 = state2 =0;
493 while (state_ != EXITING && (!state1 || !state2)) {
494 counter1 = counter2 =0;
495 for (int i =1; i<= 41; i++) {
496 if (digitalRead(PIN_LY_LIM)) counter1 ++;
497 if (digitalRead(PIN_RY_LIM)) counter2 ++;
498 nsleep(20000);
499 }
500 if (counter1 >30 && !state1) {
501 state1 =1;
502 stop_.LY =1;
503 set_speed_.LY =0.0;
504 current_position_.LY = LIM2ORIGIN_LY;
505 reached_position_.LY =1;
506 }
507 if (counter2 >30 && !state2) {
508 state2 =1;
509 stop_.RY =1;
510 set_speed_.RY =0.0;
511 current_position_.RY = LIM2ORIGIN_RY;
512 reached_position_.RY =1;
513 }
514 }
515 if (state_ == EXITING) return;
516 nsleep(500000000);
517
518 // Move to orgin
519 if (state_ == EXITING) return;
520 printf("All limits reached, Moving to Origin ... "); fflush(stdout);
521
522 target_position_.LX = target_position_.LY = target_position_.RX = target_position_.RY =0;
50
523 set_speed_.LX = set_speed_.LY = set_speed_.RX = set_speed_.RY = +FEEDRATE;
524 stop_.LX = stop_.LY = stop_.RX = stop_.RY =0;
525
526 reached_position_.LY = reached_position_.RY = reached_position_.LX = reached_position_.RX =0;
527 while (state_ != EXITING && !allreached()) { nsleep(1000000);}
528
529 if (state_ == EXITING) return;
530 state_ = HOMED;
531 printf("Homing Complete! \n\n");
532
533 return;
534 }
535
536 int loadtext(char*filename){
537 float pause_time =0.0;
538 float cut_length =0.0;
539 int asym_cut =0;
540 int error =0;// set error to 1 will return to main menu
541 float span;
542 float coord_x_min;
543 float coord_y_min;
544 float width;
545 float height;
546
547 coord_lim_.LX_max = coord_lim_.LX_min =0.0;
548 coord_lim_.LY_max = coord_lim_.LY_min =0.0;
549 coord_lim_.RX_max = coord_lim_.RX_min =0.0;
550 coord_lim_.RY_max = coord_lim_.RY_min =0.0;
551
552 coord_.LX_old = coord_.LX =0.0;
553 coord_.LY_old = coord_.LY =0.0;
554 coord_.RX_old = coord_.RX =0.0;
555 coord_.RY_old = coord_.RY =0.0;
556
557 coord_offset_x_ = coord_offset_y_ =0.0;
558 /*************************** READ FILE *******************************/
559 FILE *ptr_file; char buf[500];
560 ptr_file =fopen(filename, "r");
561
562 int line_numb =1;
563 while (fgets(buf,500, ptr_file)!=NULL){ // get line by line
564 removespace(buf); // remove spaces
565 if (!strncmp(buf,"G4P",3)) { // check if is a pause statement
566 float temp;
567 if (str2f(buf+3,&temp)) {pause_time += temp;}
568 else {
569 printf("G-code error at line %d. Returning to Main Menu.\n\n",line_numb);
570 error =1;
571 return 1;
572 }
573 }
574 else if (!strncmp(buf,"G1",2)) { // if a cut statement
575 if (check_cord(buf)) { // check if statement is valid
576 cut_length += cut_length_func();
577 if (fabs(coord_.LX - coord_.RX) +fabs(coord_.LY - coord_.RY) >0.0001 ) {
578 asym_cut ++;
579 }
580 // update the max/min coordinates
581 coord_lim_.LX_max =max(coord_lim_.LX_max, coord_.LX);
582 coord_lim_.LX_min =min(coord_lim_.LX_min, coord_.LX);
583 coord_lim_.LY_max =max(coord_lim_.LY_max, coord_.LY);
584 coord_lim_.LY_min =min(coord_lim_.LY_min, coord_.LY);
585 coord_lim_.RX_max =max(coord_lim_.RX_max, coord_.RX);
586 coord_lim_.RX_min =min(coord_lim_.RX_min, coord_.RX);
587 coord_lim_.RY_max =max(coord_lim_.RY_max, coord_.RY);
588 coord_lim_.RY_min =min(coord_lim_.RY_min, coord_.RY);
589 }
590 // if not a valid line, print error message and stop reading
591 else {
592 printf("G-code error at line %d. Returning to Main Menu.\n\n",line_numb);
593 error =1;
594 return 1;
595 }
596 }
597 line_numb ++;
598 }// end while --- read line by line
599 fclose(ptr_file); // read complete
600
601 if (!error && state_ != EXITING) { // if no reading error occured
602 coord_x_min =min(coord_lim_.LX_min,coord_lim_.RX_min);
603 coord_y_min =min(coord_lim_.LY_min,coord_lim_.RY_min);
604 }// end if --- check error
605 /**************** FIRST: check if offset is needed *******************/
606 // check x
607 if (coord_x_min <0&& state_ != EXITING && !error){
608 printf("I see you have a min x coordinate of %7.3f in (%8.3f mm)\n", \
609 coord_x_min*MM2IN, coord_x_min);
51
610 printf("A negative value is not allowed\n");
611 printf("You can use the minimum offset, or enter one yourself\n");
612 printf("Would you like to use the minimum offset for x?\n");
613 if (!menu_yes()){
614 while(state_ != EXITING) {
615 int temp =menu_enter_one(&coord_offset_x_,"Please enter the x offset");
616 if (temp == -1) {printf("Invalid input, please enter again.\n\n");}
617 else if (temp == 1) {
618 if (coord_offset_x_ < - coord_x_min) {
619 printf("Insufficient x offset, please enter a bigger x offset\n\n");
620 }
621 else break;
622 }
623 }
624 }
625 else { coord_offset_x_ = - coord_x_min;}
626 }
627 // check y
628 if (coord_y_min <0&& state_ != EXITING && !error){
629 printf("I see you have a min y coordinate of %7.3f in (%8.3f mm)\n", \
630 coord_y_min*MM2IN, coord_y_min);
631 printf("A negative value is not allowed\n");
632 printf("You can use the minimum offset, or enter one yourself\n");
633 printf("If you are cutting part of a 3-piece wing\n");
634 printf("I would recommend enter the same offset for all 3 pieces.\n");
635 printf("It will make the vaccum bagging easier\n\n");
636 printf("Would you like to use the minimum offset for y?\n");
637 if (!menu_yes()){
638 while(state_ != EXITING) {
639 int temp =menu_enter_one(&coord_offset_y_,"Please enter the y offset");
640 if (temp == -1) {printf("Invalid input, please enter again.\n\n");}
641 else if (temp == 1) {
642 if (coord_offset_y_ < - coord_y_min) {
643 printf("Insufficient y offset, please enter a bigger y offset\n\n");
644 }
645 else break;
646 }
647 }
648 }
649 else { coord_offset_y_ = - coord_y_min;}
650 }
651 coord_y_min += coord_offset_x_;
652 coord_y_min += coord_offset_y_;
653 coord_lim_.LX_max += coord_offset_x_; coord_lim_.LX_min += coord_offset_x_;
654 coord_lim_.LY_max += coord_offset_y_; coord_lim_.LY_min += coord_offset_y_;
655 coord_lim_.RX_max += coord_offset_x_; coord_lim_.RX_min += coord_offset_x_;
656 coord_lim_.RY_max += coord_offset_y_; coord_lim_.RY_min += coord_offset_y_;
657
658 if (coord_lim_.LX_max > X_MAX || coord_lim_.RX_max > X_MAX) {
659 printf("X axis out of bound, maximum X distance is 29 inches\n");
660 printf("Returning to G-code Menu\n\n");
661 error =1; gcode_menu_option_ = -1;
662 }
663 if (coord_lim_.LY_max > Y_MAX || coord_lim_.RY_max > Y_MAX) {
664 printf("Y axis out of bound, maximum Y distance is 16 inches\n");
665 printf("Returning to G-code Menu\n\n");
666 error =1; gcode_menu_option_ = -1;
667 }
668 /************** SECOND: determine and check foamsize *****************/
669 if(!asym_cut && state_ != EXITING && !error){ // if not an asymetric cut
670 printf("I see this is a symmetric cut\n");
671 printf("The minimum require foam size is:\n");
672 width = coord_lim_.LX_max;
673 height = coord_lim_.LY_max;
674 printf("Width (x-direction): %7.3f in (%8.3f mm)\n", width*MM2IN, width);
675 printf("Thickness (y-direction): %7.3f in (%8.3f mm)\n", height*MM2IN, height);
676 printf("Please leave some extra space.\n");
677 }
678 else if (asym_cut && state_ != EXITING && !error){ // if an asymetric cut
679 printf("I see this is an asymmetric cut\n");
680 printf("The minimum require foam size depends on the span of the cut.\n");
681 printf("Please enter the span size of the cut.\n");
682 while(state_ != EXITING && menu_enter_one(&span,"Please enter the span size")== -1) {
683 printf("Invalid input, please enter again.\n\n");
684 }
685 width =min(coord_lim_.LX_max,coord_lim_.RX_max) + \
686 fabs(coord_lim_.LX_max-coord_lim_.RX_max)*(CUTTERWIDTH + span)/2.0/CUTTERWIDTH;
687 height =min(coord_lim_.LY_max,coord_lim_.RY_max) + \
688 fabs(coord_lim_.LY_max-coord_lim_.RY_max)*(CUTTERWIDTH + span)/2.0/CUTTERWIDTH;
689 if (state_ != EXITING){
690 printf("Width (x-direction): %7.3f in (%8.3f mm)\n", width*MM2IN, width);
691 printf("Thickness (y-direction): %7.3f in (%8.3f mm)\n", height*MM2IN, height);
692 printf("Please leave some extra space.\n");
693 }
694 }
695 if(state_ != EXITING && !error){
696 printf("Does this look correct and matches your foam size?\n"); fflush(stdout);
52
697 if (!menu_yes()){
698 printf("Looks like there's something wrong. Returning to G-code Menu.\n\n");
699 error =1; gcode_menu_option_ = -1;
700 }
701 }
702 /******************* THIRD: review cut settings **********************/
703 if (state_ != EXITING && !error){
704 printf("***************************** CUT SETTINGS ******************************\n");
705 printf("G-code file: %s.\n", filename);
706 if (asym_cut) {
707 printf("Asymetric Cut of span %7.3f in (%8.3f mm)\n", span*MM2IN, span);
708 }
709 else {printf("Symmetric Cut\n");}
710 printf("Minimum Foam Size:\n");
711 printf("Width (x-direction): %7.3f in (%8.3f mm)\n", width*MM2IN, width);
712 printf("Thickness (y-direction): %7.3f in (%8.3f mm)\n", height*MM2IN, height);
713 if (coord_offset_x_) {
714 printf("x offset of %7.3f in (%8.3f mm)", coord_offset_x_*MM2IN, coord_offset_x_);
715 }
716 else {printf("No x offset");}
717 printf(" and ");
718 if (coord_offset_y_) {
719 printf("y offset of %7.3f in (%8.3f mm)", coord_offset_y_*MM2IN, coord_offset_y_);
720 }
721 else {printf("No y offset");}
722 printf("\n");
723 printf("Estimate total time of cut: ");
724 ETA_ =round(pause_time + cut_length/FEEDRATE );
725 print_time(ETA_); printf("\n");
726
727 if (asym_cut) {printf("Please make sure the foam is centered.\n");}
728 printf("\nWould you like to start the cut?\n");
729
730 if (!menu_yes()){
731 printf("OK, setting incorrect. Returning to G-code Menu.\n\n");
732 error =1; gcode_menu_option_ = -1;
733 }
734 }
735 return error;
736 }
737
738 int check_cord(char*str){
739 coord_.LX_old = coord_.LX; coord_.LY_old = coord_.LY;
740 coord_.RX_old = coord_.RX; coord_.RY_old = coord_.RY;
741 char* ptr_X =strchr(str, 'X');
742 char* ptr_Y =strchr(str, 'Y');
743 char* ptr_Z =strchr(str, 'Z');
744 char* ptr_A =strchr(str, 'A');
745 if (ptr_X && ptr_Y && ptr_Z && ptr_A && \
746 (ptr_X < ptr_Y) && (ptr_Y < ptr_Z) &&(ptr_Z < ptr_A) ){
747 char temp1[20], temp2[20], temp3[20], temp4[20];
748 float tempf1, tempf2, tempf3, tempf4;
749 strncpy(temp1,ptr_X+1,ptr_Y-ptr_X-1); temp1[(ptr_Y-ptr_X-1)] ='\0';
750 strncpy(temp2,ptr_Y+1,ptr_Z-ptr_Y-1); temp2[(ptr_Z-ptr_Y-1)] ='\0';
751 strncpy(temp3,ptr_Z+1,ptr_A-ptr_Z-1); temp3[(ptr_A-ptr_Z-1)] ='\0';
752 strncpy(temp4,ptr_A+1,10 );
753
754 if(str2f(temp1, &tempf1) && str2f(temp2, &tempf2) && \
755 str2f(temp3, &tempf3) && str2f(temp4, &tempf4)){
756 coord_.LX = tempf1; coord_.LY = tempf2;
757 coord_.RX = tempf3; coord_.RY = tempf4;
758 return 1;
759 }
760 else return 0;
761 }
762 else return 0;
763 }
764
765 int allreached() {
766 return reached_position_.LX * reached_position_.LY * reached_position_.RX * reached_position_.RY;
767 }
768
769 void stop_all() {
770 stop_.LX = stop_.LY = stop_.RX = stop_.RY =1;
771 digitalWrite(PIN_RELAY,LOW);
772 return;
773 }
774
775 float cut_length_func(){
776 float L_length =sqrt(pow((coord_.LX - coord_.LX_old),2.0)+pow((coord_.LY - coord_.LY_old),2.0));
777 float R_length =sqrt(pow((coord_.RX - coord_.RX_old),2.0)+pow((coord_.RY - coord_.RY_old),2.0));
778 return (L_length + R_length)/2.0;
779 }
780
781 void drive(int pin_pul,int pin_dir,float speed,int32_t delta_pulse,int*ptr_current,int*ptr_stop,int polarity ){
782 int inc;
783 if (speed*polarity >0) { digitalWrite(pin_dir, HIGH); inc =1*polarity;}
53
784 else if (speed*polarity <0) { digitalWrite(pin_dir, LOW ); inc = -1*polarity;}
785 // the time between pulses, calculated from speed
786 // 4000 is the sleep time in the loop;
787 // 100000 is the approximate code execution time;
788 uint64_t sleep_time =floor(1000000000.0/MM2PULSE/fabs(speed)) -4000 -100000;
789 nsleep(5000); // ensure dir pin leads by at least 5 microsec
790 for (int i =0; i <abs(delta_pulse); i++) { // send out desired number of pulses
791 digitalWrite(pin_pul, HIGH);
792 nsleep(4000); // ensure pulse width of at least 2 microsec
793 digitalWrite(pin_pul, LOW );
794 *ptr_current += inc;
795 if (*ptr_stop) break;// stop the motor if stop is a 1;
796 nsleep(sleep_time);
797 }
798 return;
799 }
800
801 void cut_gcode(char*filename){
802 state_ = GCODE;
803 if (state_ == EXITING) return;
804 moveto(-5.0,0.0);
805 while (state_ != EXITING && !allreached()){ nsleep(1000000);}
806 if (state_ == EXITING) return;
807 printf("Please connect and turn on the power supply for the hot wire\n");
808 printf("Please make sure the voltage is approximately 10V, and press ENTER to continue: ");
809 fflush(stdout);
810 if (menu_enter() == -2)return;
811 digitalWrite(PIN_RELAY,HIGH);
812 printf("Please now adjust the power supply to the desired current.\n");
813 printf("Recommend 2.1 to 2.3 Amps, depending on the cut span.\n");
814 printf("Use higher current for wider cuts.\n");
815 printf("Increase current if wire bows significantly.\n");
816 printf("Press ENTER to start cutting: ");
817 fflush(stdout);
818 if (menu_enter() == -2)return;
819 printf("Heating wire ... ..."); fflush(stdout);
820 if (state_ != EXITING) nsleep(5000000000);
821 if (state_ == EXITING) return;
822 printf(" Cut Starting\n");
823 moveto(0.0,0.0);
824 while (state_ != EXITING && !allreached()) nsleep(1000000);
825 if (state_ == EXITING) return;
826
827 coord_.LX_old = coord_.LX =0.0;
828 coord_.LY_old = coord_.LY =0.0;
829 coord_.RX_old = coord_.RX =0.0;
830 coord_.RY_old = coord_.RY =0.0;
831 clock_gettime( CLOCK_REALTIME, &start_time_);
832
833 ptr_file_ =fopen(filename, "r");
834 printf(" LX | LY | RX | RY | TIME |\n");
835 printf(" in / mm | in / mm | in / mm | in / mm | Elapsed | Remaining |\n");
836
837 params_print_thread.sched_priority =40;
838 params_cut_manager.sched_priority =99;
839 pthread_setschedparam(printing_thread, SCHED_FIFO, &params_print_thread);
840 pthread_create(&printing_thread, NULL, print_func, (void*)NULL);
841 pthread_setschedparam(cut_manager, SCHED_FIFO, &params_cut_manager);
842 pthread_create(&cut_manager, NULL, cut_manager_func, (void*)NULL);
843
844 while (state_ == GCODE) nsleep(100000);
845
846 fclose(ptr_file_); // read complete
847
848 if (state_ != EXITING) moveto(-5.0,0.0);
849 while (state_ != EXITING && !allreached()) nsleep(1000000);
850 digitalWrite(PIN_RELAY,LOW);
851 if (state_ != EXITING) moveto( 0.0,0.0);
852 while (state_ != EXITING && !allreached()) nsleep(1000000);
853 if (state_ != EXITING) printf("\nCut Complete, Returning to Main Menu.\n\n");
854
855 pthread_join(cut_manager, NULL);
856 pthread_join(printing_thread, NULL);
857 return;
858 }
859
860 void moveto(float x,float y){
861 target_position_.LX = target_position_.RX =(int32_t)floor(x * MM2PULSE);
862 target_position_.LY = target_position_.RY =(int32_t)floor(y * MM2PULSE);
863 // Set speed for all 4 axis
864 if (target_position_.LX > current_position_.LX) set_speed_.LX = +FEEDRATE;
865 else if (target_position_.LX < current_position_.LX) set_speed_.LX = -FEEDRATE;
866 else if (target_position_.LX == current_position_.LX) set_speed_.LX =0.0;
867
868 if (target_position_.LY > current_position_.LY) set_speed_.LY = +FEEDRATE;
869 else if (target_position_.LY < current_position_.LY) set_speed_.LY = -FEEDRATE;
870 else if (target_position_.LY == current_position_.LY) set_speed_.LY =0.0;
54
871
872 if (target_position_.RX > current_position_.RX) set_speed_.RX = +FEEDRATE;
873 else if (target_position_.RX < current_position_.RX) set_speed_.RX = -FEEDRATE;
874 else if (target_position_.RX == current_position_.RX) set_speed_.RX =0.0;
875
876 if (target_position_.RY > current_position_.RY) set_speed_.RY = +FEEDRATE;
877 else if (target_position_.RY < current_position_.RY) set_speed_.RY = -FEEDRATE;
878 else if (target_position_.RY == current_position_.RY) set_speed_.RY =0.0;
879
880 if (state_ != EXITING) {
881 // Start the cut by setting reached_position_ to 0
882 reached_position_.LX = reached_position_.LY =0;
883 reached_position_.RX = reached_position_.RY =0;
884 }
885 return;
886 }
887
888 /***********************************************************************
889 *************************** MENU FUNCTIONS *****************************
890 ***********************************************************************/
891
892 void main_menu() {
893 printf("******************************* MAIN MENU *******************************\n");
894 printf("Please choose from the following options:\n");
895 printf("a. Load and cut from G-Code;\n");
896 printf("b. Move wire to specified location;\n");
897 printf("c. Exit Program.\n");
898 printf("Please enter the corresponding letter and press ENTER key: ");
899 fflush(stdout);
900
901 switch (menu(3)) {
902 case 0: {gcode_menu(); break; }
903 case 1: {move_menu(); break; }
904 case 2: {state_ = EXITING; break; }
905 case -1: {printf("Invalid option. Let's try again.\n\n"); break; }
906 case -2: { break; }
907 }
908 return;
909 }
910
911 void gcode_menu() {
912 if (state_ != EXITING && (current_position_.LX || \
913 current_position_.LY || current_position_.RX || current_position_.RY)){
914 printf("I see the wire is not at origin. Plesse press ENTER to move wire to origin: ");
915 fflush(stdout);
916 if (menu_enter() != -2) {
917 moveto(0.0,0.0);
918 while (state_ != EXITING && !allreached()){ nsleep(1000000);}
919 printf("Origin Reached\n\n");
920 }
921 }
922
923 gcode_menu_option_ = -1;
924 int n =10;
925 while (state_ != EXITING && gcode_menu_option_ == -1){
926 printf("****************************** GCODE MENU *******************************\n");
927 // keep looping when menu selection is invalid
928 struct dirent **namelist;
929 n =scandir("/home/pi/",&namelist, file_filter, alphasort);
930 // scan for files with .txt extension
931 if (n == 0) {
932 printf("I do not see any txt files in '/home/pi/' directory\n");
933 printf("Please put the desired gcode file in '/home/pi/' directory.\n");
934 printf("Returning to Main Menu.\n\n");
935 break;
936 }
937 else if (n >9){
938 printf("Too many txt files in '/home/pi/' directory\n");
939 printf("Please clean it up.\n");
940 printf("Returning to Main Menu.\n\n");
941 break;
942 }
943 else{
944 printf("I see there are %d txt files listed below:\n\n",n);
945 int i =0;
946 while (i++ < n){
947 printf("%d: %s\n", i, namelist[i-1]->d_name);
948 }
949 printf("0: None of the above, or Return to Main Menu\n\n");
950 printf("Please select one by entering the corresponding number then press ENTER: ");
951 fflush(stdout);
952 gcode_menu_option_ =menu(n+1);
953
954 if (gcode_menu_option_ >= 1) {
955 printf("You selected: '%s' is that correct?\n",namelist[gcode_menu_option_-1]->d_name);
956 switch (menu_yes()){
957 case 1:
55
958 if (state_ != EXITING && !loadtext(namelist[gcode_menu_option_-1]->d_name) ) {
959 if (state_ != EXITING) cut_gcode(namelist[gcode_menu_option_-1]->d_name);
960 return;
961 }
962 break;
963 case 0:
964 printf("OK, Let try again\n\n");
965 gcode_menu_option_ = -1;
966 break;
967 }
968 }
969 else if (gcode_menu_option_ == 0) {
970 printf("Please put the desired gcode file in the working directory.\n");
971 printf("Returning to Main Menu.\n\n");
972 break;
973 }
974 else if (gcode_menu_option_ == -1) { // Invalid input
975 printf("Invalid Input, let's try again.\n\n");
976 }
977 else if (gcode_menu_option_ == -2) { // EXITING state
978 break;
979 }// end of if --- menu input check
980 }// end of if --- file number check
981 }// end of while
982 return;
983 }// end of gcode_menu
984
985 void move_menu(){
986 float x,y;
987 while (state_ != EXITING){
988 float current_x =(current_position_.LX + current_position_.RX)/2.0/MM2PULSE;
989 float current_y =(current_position_.LY + current_position_.RY)/2.0/MM2PULSE;
990 printf("******************************* MOVE MENU *******************************\n");
991 printf("The current wire position is (x,y) = (%.3f,%.3f) in = (%.3f,%.3f) mm\n", \
992 current_x*MM2IN,current_y*MM2IN,current_x,current_y);
993 printf("Please choose from the following options:\n");
994 printf("a. Move wire to a specific location relative to origin (Absolute Location);\n");
995 printf("b. Move wire to a specific location relative to current position (Increment);\n");
996 printf("c. Move wire to origin;\n");
997 printf("d. Return to Main Menu;\n");
998 printf("Please enter the corresponding letter and press ENTER key: ");
999 fflush(stdout);
1000 switch (menu(4)) {
1001 case 0: { // Move to a specific location
1002 while(state_ != EXITING && \
1003 (menu_enter_two(&x,&y,"Please enter the destination x and y coordinates RELATIVE TO ORIGIN")== -1 \
1004 || x <0|| y <0)) {
1005 printf("Invalid input, please enter again. Please note that negative destination is not allowed.\n\n");
1006 }
1007 if (state_ != EXITING) {
1008 printf("| | Current | Increment | Destination |\n");
1009 printf("| Inch | %7.3f, %7.3f | %7.3f, %7.3f | %7.3f, %7.3f |\n", \
1010 current_x*MM2IN, current_y*MM2IN, (x-current_x)*MM2IN, (y-current_y)*MM2IN, x*MM2IN, y*MM2IN);
1011 printf("| MM | %8.3f, %8.3f | %8.3f, %8.3f | %8.3f, %8.3f |\n", \
1012 current_x, current_y, (x-current_x), (y-current_y), x, y);
1013 printf("Continue?\n");
1014 switch (menu_yes()){
1015 case 1:
1016 if (state_ != EXITING ) {
1017 printf("Moving ... ..."); fflush(stdout);
1018 moveto(x,y);
1019 while (state_ != EXITING && !allreached()){ nsleep(1000000);}
1020 if (state_ != EXITING) printf(" Destination Reached\n\n");
1021 }
1022 break;
1023 case 0:
1024 printf("OK, Let try again\n\n");
1025 break;
1026 }
1027 }
1028 break;}// end case --- move to a specific location
1029
1030 case 1: { // Move to a specific location
1031 while(state_ != EXITING && \
1032 (menu_enter_two(&x,&y,"Please enter the destination x and y coordinates RELATIVE TO CURRENT POSITION")== -1 \
1033 || x+current_x <0|| y+current_y <0)) {
1034 printf("Invalid input, please enter again. Please note that negative destination is not allowed.\n\n");
1035 }
1036 if (state_ != EXITING) {
1037 printf("| | Current | Increment | Destination |\n");
1038 printf("| Inch | %7.3f, %7.3f | %7.3f, %7.3f | %7.3f, %7.3f |\n", \
1039 current_x*MM2IN, current_y*MM2IN, x*MM2IN, y*MM2IN, (x+current_x)*MM2IN, (y+current_y)*MM2IN);
1040 printf("| MM | %8.3f, %8.3f | %8.3f, %8.3f | %8.3f, %8.3f |\n", \
1041 current_x, current_y, x, y, (x+current_x), (y+current_y));
1042 printf("Continue?\n");
1043 switch (menu_yes()){
1044 case 1:
56
1045 if (state_ != EXITING ) {
1046 printf("Moving ... ..."); fflush(stdout);
1047 moveto(x+current_x,y+current_y);
1048 while (state_ != EXITING && !allreached()){ nsleep(1000000);}
1049 if (state_ != EXITING) printf(" Destination Reached\n\n");
1050 }
1051 break;
1052 case 0:
1053 printf("OK, Let try again\n\n");
1054 break;
1055 }
1056 }
1057 break;}// end case --- move to a specific location
1058
1059 case 2: { //case --- move to origin
1060 if (!current_position_.LX && !current_position_.LY && \
1061 !current_position_.RX && !current_position_.RY) {
1062 printf("Already at Origin\n\n");
1063 }
1064 else{
1065 printf("Move to Orignin. Continue?\n");
1066 switch (menu_yes()){
1067 case 1:
1068 printf("Moving ... ..."); fflush(stdout);
1069 moveto(0.0,0.0);
1070 while (state_ != EXITING && !allreached()){ nsleep(1000000);}
1071 if (state_ != EXITING) printf(" Origin Reached\n\n");
1072 break;
1073 case 0:
1074 printf("OK, Let try again\n\n");
1075 break;
1076 }
1077 }
1078 break;}// end case --- move to origin
1079 case -1: {printf("Invalid option. Let's try again.\n\n"); break; }
1080 default: {return;break; }
1081 }// end switch
1082 }// end while
1083 return;
1084 }
1085
1086 int menu(int numb_of_options){
1087 // pass in number of menu options, maximum of 10 options
1088 // return 0 to (numb_of_options - 1) if input is within the range
1089 // return -1 for invalid input
1090 // return -2 when state_ is exiting
1091
1092 if (state_ == EXITING) return -2;
1093 fd_set input_set;
1094 struct timeval timeout;
1095 timeout.tv_sec =10;
1096 timeout.tv_usec =0;
1097
1098 // Listening for input stream for any activity
1099 // If there
1100 FD_ZERO(&input_set );
1101 FD_SET(0,&input_set);
1102 while (state_ != EXITING && !select(1,&input_set, NULL,NULL,&timeout)) {
1103 timeout.tv_sec =1;
1104 FD_ZERO(&input_set );
1105 FD_SET(0,&input_set);
1106 }
1107
1108 if (state_ == EXITING) return -2;
1109
1110 // get input
1111 char input_option[256]; fgets(input_option,256,stdin);
1112 // determine length of input
1113 int i; for(i=0; input_option[i]!='\0'; i++); i --;
1114 int result;
1115
1116 if (i == 1) {
1117 if (input_option[0]>= 48 && input_option[0]<= 57) {
1118 result = input_option[0]-48;
1119 }
1120 else if(input_option[0]>= 65 && input_option[0]<= 74) {
1121 result = input_option[0]-65;
1122 }
1123 else if(input_option[0]>= 97 && input_option[0]<= 106) {
1124 result = input_option[0]-97;
1125 }
1126 else result = -1;
1127 }
1128 else result = -1;
1129 if (result >= numb_of_options) result = -1;
1130
1131 printf("\n");
57
1132 return result;
1133 }
1134
1135 int menu_enter(){
1136 // return 1 if anthing is entered, including ENTER key
1137 // return 0 if m is entered
1138 // return -2 when state_ is exiting
1139 if (state_ == EXITING) return -2;
1140 fd_set input_set;
1141 struct timeval timeout;
1142 timeout.tv_sec =10;
1143 timeout.tv_usec =0;
1144
1145 // Listening for input stream for any activity
1146 FD_ZERO(&input_set );
1147 FD_SET(0,&input_set);
1148 while (state_ != EXITING && !select(1,&input_set, NULL,NULL,&timeout)) {
1149 timeout.tv_sec =1;
1150 FD_ZERO(&input_set );
1151 FD_SET(0,&input_set);
1152 }
1153
1154 if (state_ == EXITING) return -2;
1155
1156 // get input
1157 char input_option[256]; fgets(input_option,256,stdin);
1158 // determine length of input
1159 int i; for(i=0; input_option[i]!='\0'; i++); i --;
1160
1161 if (i == 1&& (input_option[0]== 'm' || input_option[0]== 'M')) {
1162 printf("\n"); return 0;// return 0 if input is 'm' or 'M'
1163 }
1164 else {printf("\n"); return 1; }
1165 }
1166
1167 int menu_yes(){
1168 // return 1 if anthing is entered, including ENTER key
1169 // return 0 if n is entered
1170 // return -2 when state_ is exiting
1171 if (state_ == EXITING) return -2;
1172 printf("Press ENTER for YES, or 'n' then ENTER for NO: "); fflush(stdout);
1173 fd_set input_set;
1174 struct timeval timeout;
1175 timeout.tv_sec =10;
1176 timeout.tv_usec =0;
1177
1178 // Listening for input stream for any activity
1179 FD_ZERO(&input_set );
1180 FD_SET(0,&input_set);
1181 while (state_ != EXITING && !select(1,&input_set, NULL,NULL,&timeout)) {
1182 timeout.tv_sec =1;
1183 FD_ZERO(&input_set );
1184 FD_SET(0,&input_set);
1185 }
1186
1187 if (state_ == EXITING) return -2;
1188
1189 // get input
1190 char input_option[256]; fgets(input_option,256,stdin);
1191 // determine length of input
1192 int i; for(i=0; input_option[i]!='\0'; i++); i --;
1193
1194 if (i == 1&& (input_option[0]== 'n' || input_option[0]== 'N')) {
1195 printf("\n"); return 0;// return 0 if input is 'm' or 'M'
1196 }
1197 else {printf("\n"); return 1;}
1198 }
1199
1200 int menu_enter_one(float*output,char*string){
1201 float scale =1.0;
1202 if (state_ == EXITING) return -2;
1203 printf("Would you like to enter the coordinate in inches?\n");
1204 switch (menu_yes()) {
1205 case 1: scale =25.4;printf("%s in inches then press ENTER: ", string); break;
1206 case 0: scale =1.0;printf("%s in millimeters then press ENTER: ", string); break;
1207 }
1208 fflush(stdout);
1209 if (state_ == EXITING) return -2;
1210
1211
1212 fd_set input_set;
1213 struct timeval timeout;
1214 timeout.tv_sec =10;
1215 timeout.tv_usec =0;
1216
1217 // Listening for input stream for any activity
1218 // If there
58
1219 FD_ZERO(&input_set );
1220 FD_SET(0,&input_set);
1221 while (state_ != EXITING && !select(1,&input_set, NULL,NULL,&timeout)) {
1222 timeout.tv_sec =1;
1223 FD_ZERO(&input_set );
1224 FD_SET(0,&input_set);
1225 }
1226
1227 if (state_ == EXITING) return -2;
1228
1229 // get input
1230 char input_option[256]; fgets(input_option,256,stdin);
1231 // remove white spaces
1232 removespace(input_option);
1233 float temp;
1234 if (str2f(input_option, &temp)) {
1235 *output = temp*scale;
1236 printf("\n"); return 1;
1237 }
1238 else {printf("\n"); return -1;}
1239 }
1240
1241 int menu_enter_two(float*output1,float*output2,char*string){
1242 float scale =1.0;
1243 if (state_ == EXITING) return -2;
1244 printf("Would you like to enter the coordinate in inches?\n");
1245 switch (menu_yes()) {
1246 case 1:
1247 scale =25.4;
1248 printf("%s in INCHES \nseparated with comma then press ENTER: ", string);
1249 break;
1250 case 0:
1251 scale =1.0;
1252 printf("%s in MM \nseparated with comma then press ENTER: ", string);
1253 break;
1254 }
1255 fflush(stdout);
1256 if (state_ == EXITING) return -2;
1257
1258 fd_set input_set;
1259 struct timeval timeout;
1260 timeout.tv_sec =10;
1261 timeout.tv_usec =0;
1262
1263 // Listening for input stream for any activity
1264 // If there
1265 FD_ZERO(&input_set );
1266 FD_SET(0,&input_set);
1267 while (state_ != EXITING && !select(1,&input_set, NULL,NULL,&timeout)) {
1268 timeout.tv_sec =1;
1269 FD_ZERO(&input_set );
1270 FD_SET(0,&input_set);
1271 }
1272 if (state_ == EXITING) return -2;
1273
1274 // get input
1275 char input_option[256]; fgets(input_option,256,stdin);
1276 // remove white spaces
1277 removespace(input_option);
1278 // get the two
1279 char* ptr =strchr(input_option, ',');
1280 if (ptr == NULL) {return -1;}
1281 char temp1[20]; strncpy(temp1,input_option,ptr-input_option);
1282 temp1[(ptr-input_option)] ='\0';
1283 char temp2[20]; strncpy(temp2,ptr+1,20);
1284 float temp1f, temp2f;
1285 if (str2f(temp1, &temp1f) && str2f(temp2, &temp2f)) {
1286 *output1 = temp1f*scale;
1287 *output2 = temp2f*scale;
1288 printf("\n"); return 1;
1289 }
1290 else {return -1;}
1291 }
1292
1293 /***********************************************************************
1294 *************************** OTHER FUNCTIONS ****************************
1295 ***********************************************************************/
1296
1297 // Sleep for nanoseconds
1298 void nsleep(uint64_t ns){
1299 struct timespec req,rem;
1300 req.tv_sec = ns/1000000000;
1301 req.tv_nsec = ns%1000000000;
1302 // loop untill nanosleep sets an error or finishes successfully
1303 errno=0;// reset errno to avoid false detection
1304 while(nanosleep(&req, &rem) && errno==EINTR){
1305 req.tv_sec = rem.tv_sec;
59
1306 req.tv_nsec = rem.tv_nsec;
1307 }
1308 return;
1309 }
1310
1311 // Filter out file without .txt extension
1312 int file_filter(const struct dirent *entry){
1313 return !strcmp(entry->d_name +strlen(entry->d_name) -4,".txt");
1314 }
1315
1316 // Remove space in a string
1317 void removespace(char*str) {
1318 int i,j=0;
1319 for(i=0;str[i]!='\0';i++) {
1320 if(str[i]!=' ' && str[i] != 10 && str[i] != 13)
1321 str[j++]=str[i];
1322 }
1323 str[j]='\0';
1324 return;
1325 }
1326
1327 // Signal Handler for CTRL+C
1328 void SigHandler(int dummy) {
1329 state_ = EXITING; stop_all();
1330 printf("\n\n**************************** EXITING PROGRAM ****************************\n");
1331 return;
1332 }
1333
1334 float max(float a,float b) {
1335 if(a >= b) return a;
1336 else return b;
1337 }
1338
1339 float min(float a,float b) {
1340 if(a >= b) return b;
1341 else return a;
1342 }
1343
1344 void print_time(int sec){
1345 if (sec <= 0)printf("00:00");
1346 else printf("%02d:%02d", (int)floor(sec /60.0),sec %60);
1347 return;
1348 }
1349
1350 int str2f(char*str,float*output){
1351 removespace(str);
1352 float out =0;
1353 int dec_location;
1354 int dec_numb =0;
1355 int i; for(i=0; str[i] !='\0'; i++);
1356 int length = i;
1357 int j =1;
1358 for(int i = length-1; i >= 0; i--) {
1359 if (str[i]>=48 && str[i]<=57){out = out+j*(str[i]-48); j = j*10;}
1360 else if (str[i] == 46) {dec_numb ++; dec_location = i;}
1361 else if (i == 0&& str[i] == 43) {out = +out;}
1362 else if (i == 0&& str[i] == 45) {out = -out;}
1363 else return 0;
1364 }
1365 if (dec_numb == 0) {out = out;}
1366 else if (dec_numb == 1) {out = out/pow(10.0,length-1-dec_location);}
1367 else {return 0;}
1368 *output = out;
1369 return 1;
1370 }
60
2 foamcutter_setup.h
The setting file, foamcutter_setup.h is attached below.
61
1 /*******************************************************************************
2 * foamcutter_setup.h
3 *******************************************************************************/
4
5 #ifndef FOAMCUTTER_SETUP
6 #define FOAMCUTTER_SETUP
7
8 #include <pthread.h>
9 #include <signal.h>
10 #include <unistd.h>
11 #include <wiringPi.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdint.h>
15 #include <string.h>
16 #include <dirent.h>
17 #include <time.h>
18 #include <errno.h>
19 #include <math.h>
20 #include <sys/resource.h>
21 #include <sys/types.h>
22
23 // Cutter Width
24 #define CUTTERWIDTH (36.0*IN2MM) // inches
25
26 // Unit Conversion
27 #define IN2MM 25.4
28 #define MM2IN (1.0/25.4)
29 #define IN2REV 10.0 // Lead screw 10 TPI
30 #define REV2PULSE 400.0 // depend on the switch settings on the motor drive
31 #define MM2PULSE ( IN2REV / IN2MM * REV2PULSE) // 157.48 PULSE = 1 mm
32
33 // Settings
34 #define FEEDRATE 0.8 // unit: mm/s
35 #define FEEDRATE_PUL (FEEDRATE*MM2PULSE)
36
37 // position of limit switch relative to cutter origin
38 #define LIM2ORIGIN_LX -4100
39 #define LIM2ORIGIN_RX -3550
40 #define LIM2ORIGIN_LY -2500
41 #define LIM2ORIGIN_RY -2400
42
43 // Motor Drive Pins
44 #define PIN_LX_DIR 14
45 #define PIN_LX_PUL 15
46 #define PIN_LY_DIR 18
47 #define PIN_LY_PUL 23
48 #define PIN_RX_DIR 24
49 #define PIN_RX_PUL 25
50 #define PIN_RY_DIR 8
51 #define PIN_RY_PUL 7
52
53 // Limit Switches
54 #define PIN_LX_LIM 6
55 #define PIN_LY_LIM 13
56 #define PIN_RX_LIM 19
57 #define PIN_RY_LIM 26
58
59 // Relay
60 #define PIN_RELAY 12
61
62 // Buttons
63 #define PIN_PAUSE 17
64 #define PIN_STOP 27
65
66 // Motor Polarity
67 // set to +1 or -1
68 // reverse the setting if the wire moves away from the limit switch during homing.
69 #define POLARITY_LX +1
70 #define POLARITY_LY -1
71 #define POLARITY_RX +1
72 #define POLARITY_RY -1
73
74 // MAX cut area
75 #define X_MAX (29.0*IN2MM) // 29 in
76 #define Y_MAX (16.0*IN2MM) // 16 in
77
78 #endif //FOAMCUTTER_SETUP
62
Appendix B
MatLab Code for G-code Generation
1 DBF_foamcutter_general_shape.m
The MatLab code for generating G-code for general shape,
DBF_foamcutter_general_shape.m is attached below. Last updated: 8/26/2018.
63
1 %% DBF Foamcutter for Genearl Shapes
2 % This code is written by Yuting Huang (ythuang96@gmail.com);
3 % Please report all bug to the author's email address.
4 % Last updated: 8/26/2018
5
6 % This is written for DBF foamcutting, to generate G-code from general shape
7 % AutoCAD drawings.
8
9 %% User Manual
10 % 1. Export lines and arcs form AutoCAD, save as csv file.
11 % 2. Copy the csv file to the same folder as this MatLab code.
12 % 3. Run Code and done!
13 % Press CRT+C at anytime to terminate code.
14
15 %% ------------------------------------------------------------------------
16 %% ------------------------------------------------------------------------
17 %% ------------------------------------------------------------------------
18 %% ------------------------------------------------------------------------
19 clear all; close all; clc;
20 tolerance = 0.0002;
21 accuracy = 2; % length in mm of segments when breaking arc
22 %% Determine Units
23 % GUI stuff
24 UIControl_FontSize_bak = get(0, 'DefaultUIControlFontSize' );
25 set(0, 'DefaultUIControlFontSize' , 30);
26 unit = menu('Is Drawing in millimeters?' ,'Yes','No');
27 if unit == 1; % if drawing is in mm, continue generation of G-code
28 %% Check the current folder for csv files
29 D = dir('*.csv');
30 if ~length(D) % if no .csv file exsist print error message
31 fprintf( 'I could not find any file with .csv' );
32 fprintf( ' estension in the current folder.\n' );
33 fprintf( 'Please move the .csv file created by AutoCAD ' );
34 fprintf( '''eattext'' command into the current ' );
35 fprintf( 'working folder and try again.\n' );
36 else
37 % Create a menu to select csv files in the current folder
38 string = [ 'file = menu(''I detected ' num2str(length(D)) ...
39 ' csv files list below, please select one'',' ];
40 for i = 1:length(D); string = [string '''' D(i).name ''',']; end
41 string = [string '''None of the above'');' ];
42 eval(string);
43 if file <= length(D);
44 filename = D(file).name(1:end-4); clear string;
45 if file <= length(D) && file;
46 %% Inport File
47 inport = csvread([filename '.csv'],1,2);
48 [m,n] = size(inport);
49 % make changes if there are only lines
50 if n ==4; inport = [zeros(m,5) , inport]; end
51 %% Eliminate 0 length lines
52 k = 1;
53 for i = 1:size(inport,1);
54 if any(inport(i,6:9) ~= [0 0 0 0]) && ...
64
55 all(inport(i,6:7) == inport(i,8:9));
56 m = m-1;
57 else temp(k,:) = inport(i,:); k = k+1;
58 end
59 end
60 inport = temp; clear temp k i D file;
61 %% Seperate Arc With line
62 n_arc = 0; n_line = 0;
63 for i = 1:m;
64 if all(inport(i,6:9) == [0 0 0 0]);
65 n_arc = n_arc + 1; arc(n_arc,:) = inport(i,1:5);
66 else n_line = n_line + 1;
67 line(n_line,:) = inport(i,6:9);
68 end
69 end
70 %% Break Arcs into lines
71 alllines = line;
72 for i = 1:n_arc;
73 n_segment = ceil(2*pi*arc(i,3)*arc(i,5)/360/accuracy);
74 dtheta = arc(i,5)/n_segment;
75 arcpoints = zeros(n_segment+1,2);
76 for j = 1:n_segment+1; % break arc into points
77 theta = arc(i,4) + (j-1)*dtheta;
78 arcpoints(j,:) = arc(i,1:2) + ...
79 arc(i,3).*[cosd(theta),sind(theta)];
80 end
81 % chage the start and end point so that the arc join
82 % the lines
83 for j = 1:n_line;
84 if abs(arcpoints(1,:) - line(j,1:2)) <= 0.01;
85 arcpoints(1,:) = line(j,1:2);
86 elseif abs(arcpoints(1,:) - line(j,3:4)) <= 0.01;
87 arcpoints(1,:) = line(j,3:4);
88 end
89 if abs(arcpoints(end,:) - line(j,1:2)) <= 0.01;
90 arcpoints(end,:) = line(j,1:2);
91 elseif abs(arcpoints(end,:) - line(j,3:4)) <= 0.01;
92 arcpoints(end,:) = line(j,3:4);
93 end
94 end
95 % put all lines with arc points together
96 alllines = [alllines ; arcpoints(1:end-1,:) , ...
97 arcpoints(2:end,:)];
98 end
99 %% Sort the lines in order
100 sort(1,:) = alllines(1,:);
101 alllines(1,:) = [];
102 for i = 2:size(alllines,1)+1;
103 compare = sort(i-1,3:4);
104 [n2,~] = size(alllines);
105 for j = 1:n2;
106 if all(abs(compare - alllines(j,1:2)) <= tolerance);
107 sort(i,:) = alllines(j,:);
108 alllines(j,:) = []; check = 1; break;
65
109 elseif all(abs(compare - alllines(j,3:4)) <= tolerance);
110 sort(i,1:2) = alllines(j,3:4);
111 sort(i,3:4) = alllines(j,1:2);
112 alllines(j,:) = []; check = 1; break;
113 end
114 end
115 if ~check
116 % cannot find the another line that connects with
117 % the previous
118 fprintf( 'There is an open countour.\n' );
119 fprintf( 'This is most likely caused by an ' );
120 fprintf( 'extra line underneath a long line.\n' );
121 fprintf( 'Please check your drawing.\n' );
122 return;
123 end
124 check = 0;
125 end
126 sort2 = [sort(:,1:2); sort(end,3:4)];
127 %% Shift to positive
128 min_x = min(sort2(:,1)); min_y = min(sort2(:,2));
129 sort2(:,1) = sort2(:,1) - min_x;
130 sort2(:,2) = sort2(:,2) - min_y;
131 max_x = max(sort2(:,1)); max_y = max(sort2(:,2));
132 %% Plot Curve
133 figure(1); set(1, 'position',[0 0 1920 1080]); hold on;
134 plotx = sort2(:,1); ploty = sort2(:,2); plot(plotx,ploty );
135 title( 'Drawing Unit mm' ,'fontsize',30);
136 axis equal;
137 %% Plot number
138 [n,~] = size(sort2);
139 j = 1; index = [];
140 for i = 1:n-1;
141 if sort2(i,1) == 0 || sort2(i,1) == max_x ...
142 || sort2(i,2) == 0 || sort2(i,2) == max_y;
143 text(plotx(i),ploty(i),sprintf( '%d',j),'fontsize',20);
144 j = j+1; index = [index, i];
145 end
146 end
147 hold off;
148 %% Determine Start Point
149 start = index(input( 'Which point would you like to start? ' ));
150 sort3 = [sort2(start:end-1,:) ; sort2(1:start-1,:); ...
151 sort2(start,:)];
152 %% Cut Direction Reverse if chosen to
153 direction = menu([ 'The Current Cut Direction is shown in' , ...
154 'the Figure with Increasing Number,' , ...
155 'Reverse Cut Direction?' ,'N0','YES']);
156 if direction == 2; final = rot90(sort3',1);
157 elseif direction == 1; final = sort3; end
158 %% Final Plot
159 clf; hold on;
160 finalx = final(:,1); finaly = final(:,2);
161 plot(finalx,finaly);
162 title( 'Final shape on Foam Cutter, Drawing Unit mm' , ...
66
163 'fontsize',30);
164 j = 1;
165 for i = 1:n
166 if final(i,1) == 0 || final(i,1) == max_x ...
167 || final(i,2) == 0 || final(i,2) == max_y;
168 text(finalx(i),finaly(i),sprintf( '%d',j),'fontsize',20);
169 j = j+1;
170 if j == 4; break; end
171 end
172 end
173 axis equal; hold off;
174 set(0, 'DefaultUIControlFontSize' , UIControl_FontSize_bak);
175 %% Generate G-code
176 fidw = fopen([filename '.txt'],'wt');
177 fprintf(fidw, 'G21\n'); fprintf(fidw, 'M49\n');
178 fprintf(fidw, 'F80\n'); fprintf(fidw, 'S80\n');
179 fprintf(fidw, 'G1 X % 8.3f Y % 8.3f Z % 8.3f A % 8.3f\n' ...
180 ,0,0,0,0);
181 fprintf(fidw, 'G1 X % 8.3f Y % 8.3f Z % 8.3f A % 8.3f\n' ,...
182 finalx(1),finaly(1),finalx(1),finaly(1));
183 for i = 2:length(finalx)-1
184 fprintf(fidw, 'G1 X % 8.3f Y % 8.3f Z % 8.3f A % 8.3f\n' ...
185 ,finalx(i),finaly(i),finalx(i),finaly(i));
186
187 % Calculate Length
188 length = sqrt((finalx(i)-finalx(i-1))^2 + ...
189 (finaly(i)-finaly(i-1))^2);
190 if length >= 100;
191 fprintf(fidw,sprintf( 'G4 P%d\n',floor(length/100) ) );
192 end
193 % Add 1 sec pause per 100 mm cut for long cuts
194 end
195 fprintf(fidw, 'G1 X % 8.3f Y % 8.3f Z % 8.3f A % 8.3f\n' ...
196 ,finalx(end),finaly(end),finalx(end),finaly(end));
197 fprintf(fidw, 'G1 X % 8.3f Y % 8.3f Z % 8.3f A % 8.3f\n' ...
198 ,0,0,0,0);
199 fprintf(fidw, 'M2');
200 fclose(fidw);
201 disp([ 'The G-Code is saved as ''' filename ...
202 '.txt'' in this folder. ' ]);
203 set(gcf, 'PaperUnits','inches','PaperPosition',[0 0 16 9]);
204 print(filename, '-dpng','-r240');
205 else % if 'none of the above selectee'
206 fprintf( 'Please move your desired file to the current' );
207 fprintf( ' folder and try again.\n' );
208 end
209 else % if no file selected
210 fprintf( 'Please move your desired file to the current' );
211 fprintf( ' folder and try again.\n' );
212 end % end file selection check
213 end % end file exsistence check
214 else % if drawing not in mm, print error message
215 fprintf('Please go back to AutoCAD and use the ''Scale''' );
216 fprintf(' command to scale the drawing by 25.4. \n' );
67
217 fprintf('Inches do not provide high enough accuracy\n' );
218 end % end 'unit' check
68
2 DBF_foamcutter_wing.m
The MatLab code for generating G-code for wing, DBF_foamcutter_wing.m is
attached below. Last updated: 8/23/2018.
69
1 %% DBF Foamcutter for Wing
2 % This code is modified by Yuting Huang (ythuang96@gmail.com) based on
3 % Dr.Anderson's code written on Scilab.
4 % Please report all bug to the author's email address.
5 % Last updated: 8/23/2018
6
7 % This is written for DBF foamcutting, to generate G-code from wing
8 % prameters.
9 clear all; close all; clc;
10
11 %% Enter Parameters Below
12 % airfoil section file for root
13 root_filename = 'AH-79-100.dat';
14 % root chord length [in]
15 root_chord = 6;
16
17 % airfoil section file for tip
18 tip_filename = 'E216.dat';
19 % tip chord length [in]
20 tip_chord = 3;
21 % root chord has to be greater or equal to tip chord
22
23 % +1 for right wing, -1 for left wing
24 right_wing = 1;
25
26 % semi-span [in]
27 semi_span = 3;
28
29 % leading edge sweep [deg]
30 LE_sweep = 0;
31
32 % twist [deg]
33 twist = 0.0;
34
35 % g-code output file name
36 g_filename = 'HTail';
37
38 % width of CNC cutter [in]
39 cutter_width = 39;
40 % scale the cord length to accomodaate for broken trailing edge
41 % recommend using 1.2, then cut trailing edge with a blade to desired
42 % length.
43 scale_factor = 1.2;
44
45 %% ------------------------------------------------------------------------
46 %% ------------------------------------------------------------------------
47 %% ------------------------------------------------------------------------
48 %% ------------------------------------------------------------------------
49 %% Open File
50 fid = fopen(root_filename);
51 temp = textscan(fid, '%f %f','headerLines', 1);
52 fclose(fid);
53 root_pts = [temp{1}, temp{2}];
54 70
55 fid = fopen(tip_filename);
56 temp = textscan(fid, '%f %f','headerLines', 1);
57 fclose(fid);
58 tip_pts = [temp{1}, temp{2}];
59 clear temp fid;
60
61 %% Deconstruct Airfoil into Upper and Lower Parts
62 root_size = size(root_pts,1);
63 root_turn_point = find(root_pts(:,2)<0,1) - 1;
64 root_upper_x = root_pts(1:root_turn_point, 1);
65 root_upper_y = root_pts(1:root_turn_point, 2);
66 root_lower_x = root_pts(root_turn_point:root_size, 1);
67 root_lower_y = root_pts(root_turn_point:root_size, 2);
68
69 tip_size = size(tip_pts,1);
70 tip_turn_point = find(tip_pts(:,2)<0,1) - 1;
71 tip_upper_x = tip_pts(1:tip_turn_point, 1);
72 tip_upper_y = tip_pts(1:tip_turn_point, 2);
73 tip_lower_x = tip_pts(tip_turn_point:tip_size, 1);
74 tip_lower_y = tip_pts(tip_turn_point:tip_size, 2);
75
76 %% Interpolate
77 n = 301;
78 root_upper_yp = interp1(root_upper_x,root_upper_y,linspace(1,0,n)');
79 root_upper_xp = linspace(1,0,n)';
80 root_lower_yp = interp1(root_lower_x,root_lower_y,linspace(0,1,n)');
81 root_lower_xp = linspace(0,1,n)';
82
83 tip_upper_yp = interp1(tip_upper_x,tip_upper_y,linspace(1,0,n)');
84 tip_upper_xp = linspace(1,0,n)';
85 tip_lower_yp = interp1(tip_lower_x,tip_lower_y,linspace(0,1,n)');
86 tip_lower_xp = linspace(0,1,n)';
87
88 %% Scale to Chord Length
89 % chord length on machine
90 root_chord_ext = root_chord + ...
91 0.5*(root_chord - tip_chord)*(cutter_width - semi_span)/semi_span;
92 tip_chord_ext = root_chord - ...
93 0.5*(root_chord - tip_chord)*(cutter_width + semi_span)/semi_span;
94
95 root_upper_xp = root_chord_ext*root_upper_xp;
96 root_upper_yp = root_chord_ext*root_upper_yp;
97
98 root_lower_xp = root_chord_ext*root_lower_xp;
99 root_lower_yp = root_chord_ext*root_lower_yp;
100
101 tip_upper_xp = tip_chord_ext*tip_upper_xp;
102 tip_upper_yp = tip_chord_ext*tip_upper_yp;
103
104 tip_lower_xp = tip_chord_ext*tip_lower_xp;
105 tip_lower_yp = tip_chord_ext*tip_lower_yp;
106
107 %% Rotate Tip by Twist Angle
108 c4 = tip_chord/4; 71
109 twist_rad = (pi/180)*twist;
110
111 tip_upper_xpr = tip_upper_xp*cos(twist_rad) ...
112 + tip_upper_yp*sin(twist_rad) + c4*(1.0-cos(twist_rad));
113 tip_upper_ypr = -tip_upper_xp*sin(twist_rad) ...
114 + tip_upper_yp*cos(twist_rad) + c4*sin(twist_rad);
115
116 tip_lower_xpr = tip_lower_xp*cos(twist_rad) ...
117 + tip_lower_yp*sin(twist_rad) + c4*(1.0-cos(twist_rad));
118 tip_lower_ypr = -tip_lower_xp*sin(twist_rad) ...
119 + tip_lower_yp*cos(twist_rad) + c4*sin(twist_rad);
120
121 %% Use Sweep Angle to Shift Tip Relative to Root
122 sweep_shift = cutter_width*tan(LE_sweep*pi/180);
123
124 tip_upper_xpr = tip_upper_xpr + sweep_shift;
125 tip_lower_xpr = tip_lower_xpr + sweep_shift;
126
127 %% Swap x-axis to Start Cut on Trailing Edge
128 root_upper_xp = root_chord_ext - root_upper_xp;
129 root_lower_xp = root_chord_ext - root_lower_xp;
130 tip_upper_xpr = root_chord_ext - tip_upper_xpr;
131 tip_lower_xpr = root_chord_ext - tip_lower_xpr;
132
133 %% Combine Upper and Lower Surfaces
134 root_x = [root_upper_xp; root_lower_xp];
135 root_y = [root_upper_yp; root_lower_yp];
136
137 tip_x = [tip_upper_xpr; tip_lower_xpr];
138 tip_y = [tip_upper_ypr; tip_lower_ypr];
139
140 %% Make a Plot of Root and Tip
141 set(0,'defaultlinelinewidth' ,2)
142 set(0,'defaultaxeslinewidth' ,1)
143 set(0,'defaultaxesfontsize' ,20)
144
145 figure(1); set(1, 'position',[0 0 1920 1080]); hold on;
146 plot(root_x,root_y);
147 plot(tip_x,tip_y);
148 legend1 = legend( 'Root','Tip');
149 set(legend1,'interpreter','latex'); set(legend1,'fontsize',18);
150 title('Wing on FoamCutter' ,'interpreter','latex','fontsize',25);
151 xlabel('X [in]','interpreter','latex','fontsize',25);
152 ylabel('Y [in]','interpreter','latex','fontsize',25);
153 axis equal; grid on;
154
155 %% Write G-code File
156 root_x = scale_factor*root_x*25.4;
157 root_y = scale_factor*root_y*25.4;
158 tip_x = scale_factor*tip_x*25.4;
159 tip_y = scale_factor*tip_y*25.4;
160
161 fidw = fopen([g_filename '.txt'],'wt');
162 72
163 fprintf(fidw,'G21\n'); fprintf(fidw, 'M48\n');
164 fprintf(fidw,'F80\n'); fprintf(fidw, 'S80\n');
165
166 fprintf(fidw,'G1 X % 8.3f Y % 8.3f Z % 8.3f A % 8.3f\n' ,0,0,0,0);
167
168 if right_wing > 0
169 fprintf(fidw, 'G1 X % 8.3f Y % 8.3f Z % 8.3f A % 8.3f\n' , ...
170 root_x(1),root_y(1),tip_x(1),tip_y(1));
171 fprintf(fidw, 'G4 P5\n');
172 for i=length(root_x):-1:1
173 fprintf(fidw, 'G1 X % 8.3f Y % 8.3f Z % 8.3f A % 8.3f\n' , ...
174 root_x(i),root_y(i),tip_x(i),tip_y(i));
175 end
176 else
177 fprintf(fidw, 'G1 X % 8.3f Y % 8.3f Z % 8.3f A % 8.3f\n' , ...
178 tip_x(1),tip_y(1),root_x(1),root_y(1));
179 fprintf(fidw, 'G4 P5\n');
180 for i=length(root_x):-1:1
181 fprintf(fidw, 'G1 X % 8.3f Y % 8.3f Z % 8.3f A % 8.3f\n' , ...
182 tip_x(i),tip_y(i),root_x(i),root_y(i));
183 end
184 end
185
186 fprintf(fidw, 'G1 X % 8.3f Y % 8.3f Z % 8.3f A % 8.3f\n' ,0,0,0,0);
187 fprintf(fidw,'M2');
188
189 fclose(fidw);
190
191
73
Appendix C
Drawings
The complete SolidWorks drawings can be found at
https://github.com/ythuang96/FoamCutter. The following is the complete assembly in
SolidWorks:
Drawings attached below are all aluminum pieces that required machining. But the
drawings are not drawn in compliance with engineering standards and therefore should only
be used as a reference when machining yourself.
74
Appendix D
Part List
The parts used for this project are listed below.
86
Appendix E
Purchase History
The purchase history of this project are listed below.
89

Navigation menu