tag:blogger.com,1999:blog-17919356427198873242024-02-06T22:27:19.487-08:00OpenSourceDesignToolsMy quest to be free of black box software for manufacturing and designDan Falckhttp://www.blogger.com/profile/08753782465263326147noreply@blogger.comBlogger37125tag:blogger.com,1999:blog-1791935642719887324.post-40424680612796910632014-04-27T14:26:00.000-07:002014-04-27T14:26:15.511-07:00A Parametric Vise in FreeCADThis post is for Normand. I promised him that I would show this a long time ago.<br />
<br />
In FreeCAD, you can create parametric objects with python scripting. What this means is you can create objects that change by altering their parameters. This makes it nice to create geometric objects similar to what you would find in the Draft workbench- rectangles, polygons, circles, and points are some of the parametric objects that Yorik has created. The Draft and Arch workbenches are pure python, so there are many examples of parametric objects to learn from.<br />
<br />
A few months ago, I created a parametric milling machine vise, by importing *.step files from a well know vise manufacturer and worked them into some python scripting. When I first started playing with the script, I was copy/pasting it from my editor constantly, trying it out. This is fine for me to do, at first, when it was just one file to play with, but as the project got larger, it became a pain. I had added an *.svg file for the icon and split the *.step file in two. Things were starting to get a lot larger than my usual one page scripts, so it was time to make a small project out of it.<br />
As the project got a little larger, I realized that this could be a pain for other folks to use, if I didn't clean it up and make it easy to install. I noticed that Yorik had made the dxf import/export part of his Draft workbench into an automatic download with FreeCAD, on the first instance of importing or exporting a DXF file. That looked like a good way to go for my script.<br />
<br />
The small script that downloads the other files is here:<br />
<br />
<a href="https://raw.githubusercontent.com/danielfalck/FCparametric/master/macros/vise_macro.py" target="_blank">https://raw.githubusercontent.com/danielfalck/FCparametric/master/macros/vise_macro.py</a><br />
<br />
Copy and paste it into your FreeCAD python console or into the FreeCAD macro editor and run it with the green play button.<br />
<br />
The vise looks like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgR6chONYlkELQ6oFyHBudhFhY44tf-YDYxLjtj-nEuAXUDNl6um0Ow5II8ibtGoLu0g6IDEXS19pVijKRlEjoMz4ZDMQRm9jnP4gfahGcpAWOhve7qs3L9RolC9FREpQamyrBMvs6IxEL7/s1600/vise1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgR6chONYlkELQ6oFyHBudhFhY44tf-YDYxLjtj-nEuAXUDNl6um0Ow5II8ibtGoLu0g6IDEXS19pVijKRlEjoMz4ZDMQRm9jnP4gfahGcpAWOhve7qs3L9RolC9FREpQamyrBMvs6IxEL7/s1600/vise1.png" height="190" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVnbKOXXl1dz3as9LlDFnyN5UU10YnAuMIt0Xg_YG7H_Jq-dWQCqtPjnMY1wxO32i0I-nv7v6OWP65FJVCBEUPumxpzJZPsm8KgoN6_ELkrCaBPHQV4bebAhOxdRn90gHxK2AI66FCBw0n/s1600/vise2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVnbKOXXl1dz3as9LlDFnyN5UU10YnAuMIt0Xg_YG7H_Jq-dWQCqtPjnMY1wxO32i0I-nv7v6OWP65FJVCBEUPumxpzJZPsm8KgoN6_ELkrCaBPHQV4bebAhOxdRn90gHxK2AI66FCBw0n/s1600/vise2.png" height="217" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiD5acsshYWtPlQVf-nnvVlwdpJXsu4beprFK8_HtCbJvFs0EJOApUwbvsXYT56YIlCFg7teRCE5VFUBi8YTCKXSRY3AV4X_eglhBxPK_O5Q17xozhajQVfPdmdArYTLQUWiM6uXpzJ88af/s1600/vise3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiD5acsshYWtPlQVf-nnvVlwdpJXsu4beprFK8_HtCbJvFs0EJOApUwbvsXYT56YIlCFg7teRCE5VFUBi8YTCKXSRY3AV4X_eglhBxPK_O5Q17xozhajQVfPdmdArYTLQUWiM6uXpzJ88af/s1600/vise3.png" height="168" width="320" /></a></div>
That last image shows the parameter for the jaw opening- it's in metric and you can give it value up to 220 mm and the movable jaw of the vise will open up.<br />
<br />
Have fun with it.Dan Falckhttp://www.blogger.com/profile/02075095285410665278noreply@blogger.com2tag:blogger.com,1999:blog-1791935642719887324.post-66380366165454113112014-01-19T18:50:00.002-08:002014-01-19T18:50:30.590-08:00Helping a Boy Scout<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgUAEEpQW6bO_1e7LNhWZyBP3AHB8A6-r9VKwoFRDXSIyiETWtoCGlrWgHkBQwws1ca5J_ERNStW45z-FDOPnpDwf9AdxO1rnFbESCXaIIJZUvafqE83xFa4qgF5DK_Ye037JFRB2hzHS6/s1600/tables.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgUAEEpQW6bO_1e7LNhWZyBP3AHB8A6-r9VKwoFRDXSIyiETWtoCGlrWgHkBQwws1ca5J_ERNStW45z-FDOPnpDwf9AdxO1rnFbESCXaIIJZUvafqE83xFa4qgF5DK_Ye037JFRB2hzHS6/s1600/tables.JPG" height="240" width="320" /></a></div>
<br />
<br />
My son is in the Boy Scout program, here in the US. I feel that it is a very good program. He has learned some very good skills and had some awesome adventures. We also end up working together on a lot of projects. One of those was helping one of his fellow scouts with his Eagle project. This scout wanted to help a local charitable organization that gives clothes to needy children around the area. The organization didn't have any work tables for sorting clothes or benches for their clients to sit on, while they were waiting outside the door.<br />
<br />
The scout working on this project knows that I like to design and build things, so he contacted me about the project. He started by getting the requirements from the charity director and came back with dimensions. We discussed some general design ideas and what materials he wanted to use. The materials would be construction grade timbers and plywood (laminated sheet).<br />
<br />
I needed to make four different designs for these various tables and benches. There were three tables that needed to be different lengths and two benches that should be the same as each other. The tables were all very short, since they were going to be used for stacking boxes and clothes on. We wanted a similar design on all of them, since they were all going to the same place and it would make things easier for volunteers to assemble. After a group assembled one table, the next should be very familiar to them. We decided to make the benches look similar to the tables.<br />
<br />
I decided to use a combination of FreeCAD for design and DraftSight for dimensioned drawings. I like using FreeCAD for design, because I am comfortable with it and feel that it is very powerful. I could start with one design and then change just a few parameters to make it fit the requirements for the next table or bench.
I could probably even dimension all the drawings for the project in FreeCAD, but I am much more comfortable doing that in DraftSight.<br />
<br />
Since we don't have an assembly workbench in FreeCAD yet- and I wanted all components to be related/driven by the table top, I did a sort of crude hack to keep everything in sync. I used PartDesign workbench with sketches and made a base sketch that represented the outside dimensions of the table or bench top for every set of components. The corners of the table top sketch were mirrored around X0 Y0 to give some consistency to my hack. I copied this same geometry from the table top sketch and pasted into one sketch and changed it into construction geometry<br />
I copied and pasted this base construction geometry into four other sketches- to mimic the table top. Here is an example of the sketch construction:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1FZQ6g6iFV3y9xUPKucsnaJkBKqHKUBUr3jvy-Gj9i4fpUB4zfvLHKZqzy87_WXkYxvbtGIlxW29kXdvq8HnHQWC6ZHcNLmQWUY3rkdkaaZMzn4JI5_p9_3NNVzYN9_0BTCos71yPVkZ7/s1600/constraints.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1FZQ6g6iFV3y9xUPKucsnaJkBKqHKUBUr3jvy-Gj9i4fpUB4zfvLHKZqzy87_WXkYxvbtGIlxW29kXdvq8HnHQWC6ZHcNLmQWUY3rkdkaaZMzn4JI5_p9_3NNVzYN9_0BTCos71yPVkZ7/s320/constraints.png" /></a></div>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
(I am also working in inches on this project but chose not to change units in FreeCAD- so notice that the units in my sketch are in mm)<br />
<br />
Within the sketches for everything, except the table top, I used additional construction geometry to space the padded part of the sketches away from the lip of the table top. This would typically be the over hang of the top and the thickness of the timber next to what I was working on:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaWFGruhNf4Oasv-wZqthgPmJjI5VKZdR_CnqbqFLEqJRO8P_BfbMs1_HLKKiZ6f4ulqVieNtVmjwXBUCYEiKbAF3GNUIuzI4ZHNvtvmtIN8IO_v0nCqpMksfC6APWa6gvb45uzLe80JrB/s1600/construction_geom.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaWFGruhNf4Oasv-wZqthgPmJjI5VKZdR_CnqbqFLEqJRO8P_BfbMs1_HLKKiZ6f4ulqVieNtVmjwXBUCYEiKbAF3GNUIuzI4ZHNvtvmtIN8IO_v0nCqpMksfC6APWa6gvb45uzLe80JrB/s1600/construction_geom.png" /></a></div>
<br />
<br />
<br />
One problem with this approach is that if I needed to change the length of the piece of furniture that I was working on, I had to change the construction geometry in several pieces to make this work. Since I didn't really care to code up a total parametric table in python, I thought that was a fair trade off. In the end, it wasn't a huge hassle to change the parameters for the 4 unique designs.<br />
<br />
I did the components in groups:<br />
1. table top -this was simple- make a sketch and pad it in a positive Z direction.<br />
2. two long timbers for the frame - sketch their perimeters and pad in a negative Z direction.<br />
3. two short cross timbers for frame - sketch their perimeters and pad in a negative Z direction.<br />
4. all four legs - sketch their perimeters and pad in a negative Z direction.<br />
5. two cross braces (mounted towards the floor on outside of legs) - move placement of the sketch to be lower than the table top and pad in a negative Z direction.<br />
6. stretcher (mounted to the inside faces of the cross braces) - move placement of the sketch to be lower than the table top and pad in a negative Z direction.<br />
7. The corner blocks were a little more difficult. They had to be sketched on a plane that was perpendicular to the table sketch. I ended up having to fudge on their locations a bit, but I survived :)<br />
<br />
Here is a screenshot of all of the components put together:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3NbzofaiwW_bMVJxA9HmOtBIIhb7mLPTmfNKp7JImn6tdb4H_upgOOYJMs7EKgcO25RvnMe92eoR-32E54MVMD9MmI-5IX194hPmZH0oJutA3TvSJxnqK3Sn2CihRWenx9a7Uad-0QPt4/s1600/bench2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3NbzofaiwW_bMVJxA9HmOtBIIhb7mLPTmfNKp7JImn6tdb4H_upgOOYJMs7EKgcO25RvnMe92eoR-32E54MVMD9MmI-5IX194hPmZH0oJutA3TvSJxnqK3Sn2CihRWenx9a7Uad-0QPt4/s1600/bench2.png" height="183" width="320" /></a></div>
<br />
In FreeCAD's Draft workbench there is a command to create a 2D projection of a 3D object called Shape2DView. I used that (with the help of a python script to speed up positioning) to create this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaJCi0HHOtFGenNWBvg9sy0Jgm6udtFM49kHDxrJy35UGyX77RFvpiL63UhZ7QEZxIPkJ9fFPe6K_omgp5NRmjhHmX9LsD4fgz3l2BvhBGthtnt8o1HaOW2PVbiIFHoCh3xltgM9icyiqg/s1600/bench.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaJCi0HHOtFGenNWBvg9sy0Jgm6udtFM49kHDxrJy35UGyX77RFvpiL63UhZ7QEZxIPkJ9fFPe6K_omgp5NRmjhHmX9LsD4fgz3l2BvhBGthtnt8o1HaOW2PVbiIFHoCh3xltgM9icyiqg/s1600/bench.png" height="202" width="320" /></a></div>
<br />
<br />
These 2D views were then selected and exported as a *.DXF file for detailing in DraftSight.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDfNdv0JKMT3OXB7xoMVMqF_XNfROoeDV8G67q24lWZAsg6KJAA9-0UkSwN9rtGZrHmCDhyC4LRqchYyhde5hPDUm_KftSw5hJyvn5dd2lglkdudWMJFe3LtZdG3dYTY5txud9K_W9dZXY/s1600/details.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDfNdv0JKMT3OXB7xoMVMqF_XNfROoeDV8G67q24lWZAsg6KJAA9-0UkSwN9rtGZrHmCDhyC4LRqchYyhde5hPDUm_KftSw5hJyvn5dd2lglkdudWMJFe3LtZdG3dYTY5txud9K_W9dZXY/s1600/details.png" height="230" width="320" /></a></div>
<br />
We finished up construction earlier today, with the help of a lot of other scouts.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcqKqK_yip7bd0i41U68fuLS06fPqTcohc5KzbUyGepzNST-vpqpmyY5737P-NuEOqhli1iOhBownxAkUw-_njfXFBqLVcMoTtBO57_Eqitloeb0hcaI1HZAeISsXSkdboPlTFtPfCuVaS/s1600/scouts.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcqKqK_yip7bd0i41U68fuLS06fPqTcohc5KzbUyGepzNST-vpqpmyY5737P-NuEOqhli1iOhBownxAkUw-_njfXFBqLVcMoTtBO57_Eqitloeb0hcaI1HZAeISsXSkdboPlTFtPfCuVaS/s1600/scouts.JPG" height="240" width="320" /></a></div>
<br />Dan Falckhttp://www.blogger.com/profile/02075095285410665278noreply@blogger.com3tag:blogger.com,1999:blog-1791935642719887324.post-15220071488775432732013-11-30T17:57:00.003-08:002013-11-30T17:57:50.406-08:00Parsing Solid Models for HolesI've been playing with a macro to get hole information (coordinates, diameter, etc) out of solid models in FreeCAD. It is a challenge and I don't think I will ever be totally done, because there are so many corner cases. I am concentrating on the types of parts that I would be milling in my shop- ie blocks of metal that I can drill with a simple 3 axis Bridgeport CNC mill. I will leave the 5 axis stuff to others :)
Here is a screenshot of what I have so far:
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixUwFOXmc7Bz4s5oSVOs1cSYN6UwcKy8pHZjiK8PAP536ltabR_TiTTWivW04MYtcjCX-GMXuHURte86dbkZyO6kgk2Fkeqs_n_7AYcJOiAU0tlTaWPZOAa59aIsu97-rxsYDeWQ7CC0eF/s1600/holetest.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixUwFOXmc7Bz4s5oSVOs1cSYN6UwcKy8pHZjiK8PAP536ltabR_TiTTWivW04MYtcjCX-GMXuHURte86dbkZyO6kgk2Fkeqs_n_7AYcJOiAU0tlTaWPZOAa59aIsu97-rxsYDeWQ7CC0eF/s320/holetest.png" /></a></div>
The lines coming up and out of the holes indicate that I am successful.
Here is my macro:
<br />
<br />
<a href="http://pastebin.com/w7wR80hq" target="_blank">FreeCADholefinder.py</a>Dan Falckhttp://www.blogger.com/profile/02075095285410665278noreply@blogger.com3tag:blogger.com,1999:blog-1791935642719887324.post-57203123171781051362013-10-27T09:36:00.000-07:002013-10-27T09:36:06.544-07:00Welcome to the Monkey Lab<br />
I had a client request that I make an aluminum panel for mounting an LCD monitor and touchscreen for his research group. He supplied the monitor, touchscreen, a light, and a drink dispenser. Hmmm- sounds interesting. Who would be using the touch screen? Monkeys of course. Wow...
<br />
Here is how I did it:
To begin with, I found spec sheets for the monitor and touch screen online.
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgb0uNceIC0mwNrnbqf2FqZo6MN9huEwT49UIa79QiOn7pYBP4R9MX08303virVrcwXtBnzQR4h0RssHpBSr5-P3PC5BQNEdxgMh_weJZF8Uylo77VEe6037bsmByoGLcaEzjS_2D1vX3Za/s1600/touch_screen.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgb0uNceIC0mwNrnbqf2FqZo6MN9huEwT49UIa79QiOn7pYBP4R9MX08303virVrcwXtBnzQR4h0RssHpBSr5-P3PC5BQNEdxgMh_weJZF8Uylo77VEe6037bsmByoGLcaEzjS_2D1vX3Za/s200/touch_screen.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
I used FreeCAD to make a 3D model of the components and an assembly.
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaXN4Lk-05NVtup25GN8Rl2NL1iRdnKrMCCmyC4k0ZhdaZpYgITcMHVBgHOPat6S6yz6NnJkQXRyD5eJpbHSE-adZyxRY4Ah0-6_qBHwjf67INRmloObGIdGymZj1m82IxYbKIAgsppqwM/s1600/panel_and_monitor.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="258" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaXN4Lk-05NVtup25GN8Rl2NL1iRdnKrMCCmyC4k0ZhdaZpYgITcMHVBgHOPat6S6yz6NnJkQXRyD5eJpbHSE-adZyxRY4Ah0-6_qBHwjf67INRmloObGIdGymZj1m82IxYbKIAgsppqwM/s320/panel_and_monitor.png" width="320" /></a></div>
Then I used HeeksCNC to create CNC code for milling out the panel.
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2k3o53ailQR7XVgGl_yZw6E9oy_JAYqxGrkUZ6BzEl_o1V9Riqi4aLUdJxLIGcBFN2o44gSPy2VnTf8NzjPQM6JOLRyBnxv0DHZ1iJVJUbc8w4QRvd1Ex4qjLuiBt0QU39c2a_PSGIpJh/s1600/heeks_panel.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2k3o53ailQR7XVgGl_yZw6E9oy_JAYqxGrkUZ6BzEl_o1V9Riqi4aLUdJxLIGcBFN2o44gSPy2VnTf8NzjPQM6JOLRyBnxv0DHZ1iJVJUbc8w4QRvd1Ex4qjLuiBt0QU39c2a_PSGIpJh/s320/heeks_panel.png" width="320" /></a></div>
<br />
Milling the whole thing on my Bridgeport CNC was a challenge. My Y axis travel was barely 10.75" and the cutout for the monitor/touchscreen was 10.3" alone. This meant that I needed to slide the ram that the milling head attaches to back and forth in Y to get the full range. To do that, I had to pick up on a known edge, with my edge finder, several times. That was a bit of a trick, but I got it to work.
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiv9GYxkwaMA_0btonwH8BoTeNIC5-s4d-nCsfOy8hid7rX8vIQAaLObERu8rZt8fyDFYWiUjxwqMvwNg2p3827QY6mSC0TYeQ-jluLVOtlgCg-CdoU-pWfCq6x_hZjMYSXRpai_jyua3qD/s1600/bigpanel.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiv9GYxkwaMA_0btonwH8BoTeNIC5-s4d-nCsfOy8hid7rX8vIQAaLObERu8rZt8fyDFYWiUjxwqMvwNg2p3827QY6mSC0TYeQ-jluLVOtlgCg-CdoU-pWfCq6x_hZjMYSXRpai_jyua3qD/s200/bigpanel.jpg" /></a></div>
Here is a picture of the finished assembly:
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwMDtZljTnRdzl_r3XHxK9e1Y7l33tNOWCKpKMBdp4OvH46RmFjxsQ1fo-2XX3aHFf1FMhCJ7wDZmNyXGzztNTCAlMk5s-u227D3fb5s16Awpz4qgSw-jB9iWraybwBVYaE5WkbVmjpC1J/s1600/finished1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwMDtZljTnRdzl_r3XHxK9e1Y7l33tNOWCKpKMBdp4OvH46RmFjxsQ1fo-2XX3aHFf1FMhCJ7wDZmNyXGzztNTCAlMk5s-u227D3fb5s16Awpz4qgSw-jB9iWraybwBVYaE5WkbVmjpC1J/s200/finished1.jpg" /></a></div>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpbwktpbv6amVtPoxmCVr7YG1EpA2dyGlzIVYJVQo0bza9VhA7dvsbBesDSq27UqwmZq_Yd-lfDu5ZojhVzYBWSP5sKTNMPsbFT3r29wz6bhAGxqKCuE1SHMA7qguWkmPuHC4YKMOW_n6f/s1600/finished2.jpg.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpbwktpbv6amVtPoxmCVr7YG1EpA2dyGlzIVYJVQo0bza9VhA7dvsbBesDSq27UqwmZq_Yd-lfDu5ZojhVzYBWSP5sKTNMPsbFT3r29wz6bhAGxqKCuE1SHMA7qguWkmPuHC4YKMOW_n6f/s200/finished2.jpg.jpg" /></a></div>
My client was very happy with the panel. Maybe I will make another and install it in my kitchen...Dan Falckhttp://www.blogger.com/profile/02075095285410665278noreply@blogger.com0tag:blogger.com,1999:blog-1791935642719887324.post-47753362346300137452013-07-21T09:47:00.000-07:002013-07-26T09:22:04.614-07:00Javascript G-Code Generator<!--#***************************************************************************-->
<!--#* *-->
<!--#* Copyright (c) 2013 *-->
<!--#* Daniel Falck <ddfalck@gmail.com> *-->
<!--#* *-->
<!--#* This program is free software; you can redistribute it and/or modify *-->
<!--#* it under the terms of the GNU Lesser General Public License (LGPL) *-->
<!--#* as published by the Free Software Foundation; either version 2 of *-->
<!--#* the License, or (at your option) any later version. *-->
<!--#* for detail see the LICENCE text file. *-->
<!--#* *-->
<!--#* This program is distributed in the hope that it will be useful, *-->
<!--#* but WITHOUT ANY WARRANTY; without even the implied warranty of *-->
<!--#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *-->
<!--#* GNU Library General Public License for more details. *-->
<!--#* *-->
<!--#* You should have received a copy of the GNU Library General Public *-->
<!--#* License along with this program; if not, write to the Free Software *-->
<!--#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *-->
<!--#* USA *-->
<!--#* *-->
<!--#***************************************************************************-->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Bolt Circle G-Code Generator</title>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/start/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<link rel="stylesheet" href="http://jqueryui.com/resources/demos/style.css" />
<script src="http://d1n0x3qji82z53.cloudfront.net/src-min-noconflict/ace.js" type="text/javascript" charset="utf-8"></script>
<script>
function editor(number){
var name = "editor"+ number;
var objname = ace.edit(name);
objname.setTheme("ace/theme/tomorrow_night_blue");
objname.getSession().setUseWorker(false);
objname.getSession().setMode("ace/mode/yaml");
objname.renderer.setShowGutter(false) //set to true to see line numbers
document.getElementById(name).style.fontSize='16px';
}
function ClearEdit(number){
var name = "editor"+ number;
var objname = ace.edit(name);
objname.setValue("");
}
function PushText(number, text){
var name = "editor"+ number;
var objname = ace.edit(name);
//objname.setValue(text);
objname.insert(text);
var logtext = objname.getValue(); //get all text in the editor
//console.log(logtext);
var cursornum = objname.selection.getCursor();
console.log(cursornum);
console.log(cursornum.row);
console.log(cursornum.column);
//objname.gotoLine(2);
objname.setHighlightActiveLine(false);
}
$(function() {
$("#btnBack").button({
icons: {
primary: "ui-icon-triangle-1-n"
},
text: false,
label: 'Cursor Up'
});
$("#btnForward").button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false,
label: 'Cursor Down'
});
$("#btnPost").button({
icons: {
primary: "ui-icon-check"
},
text: true,
label: 'Post G-Code'
});
$("#clearbtn").button({
icons: {
primary: "ui-icon-closethick"
},
text: true,
label: 'Clear G-Code'
});
$(".input").addClass("ui-widget-content ui-corner-all ");
});
$(function () {
$("#cycle").bind('change', function() {
document.getElementById('additionalvalues').innerHTML ='<input type="text" id = "dwell" class="ui-widget-content ui-corner-all" name="dwell" value="1">Dwell<br>';
var drillcycle = document.getElementById('additionalvalues');
if (document.getElementById('cycle').value =='G81'){
document.getElementById('additionalvalues').innerHTML ='';
}
else if (document.getElementById('cycle').value =='G82'){
document.getElementById('additionalvalues').innerHTML ='<input type="text" id = "dwell" class="ui-widget-content ui-corner-all" name="dwell" value="1">Dwell<br>';
}
else{
document.getElementById('additionalvalues').innerHTML ='<input type="text" id = "peck" class="ui-widget-content ui-corner-all" name="peck" value=".03">Peck<br>';
}
});
});
</script>
<fieldset id = "ops"; class="ui-widget ui-widget-content" style="height: 100%; width:350px;">
<legend class="ui-widget-header ui-corner-all">Bolt Circle G-Code Generator</legend>
<div class="params">
<div>
<fieldset id = "params"; class="ui-widget ui-widget-content" style="height: 100%; width:95%;">
<legend class="ui-widget-header ui-corner-all">Parameters</legend>
<div id = "input" class="ui-widget-content ui-corner-all" style="height: 100%; width:95%;">
<select id ="cycle"class="ui-widget-content ui-corner-all" name="cycles">
<option value="G81">G81</option>
<option value="G82">G82</option>
<option value="G83">G83</option>
</select>
<a>Drill Cycle</a>
<br>
<input type="text" id = "frate" class="input" name="frate" value="10.0">Feed Rate<br>
<input type="text" id = "cplane" class="input" name="cplane" value=".1">Clearance Plane<br>
<div id="additionalvalues" ></div>
<input type="text" id = "xcen" class="input" name="xcen" value="0.0">X Center<br>
<input type="text" id = "ycen" class="input" name="ycen" value="0.0">Y Center<br>
<input type="text" id = "zdepth" class="input" name="zdepth" value="0.0">Z Depth<br>
<input type="text" id = "numholes" class="input" name="numholes" value="4">Number of Holes<br>
<input type="text" id = "bcdiam" class="input" name="bcdiam" value="2.0">Bolt Circle Diameter<br>
<input type="text" id = "startangle" class="input" name="startangle" value="0.0">Start Angle<br>
</div>
<div ><button id="btnPost" onclick="PostCode()">Post G-Code</button></div>
</fieldset>
</div>
</div>
<p></p>
<fieldset id = "output"; class="ui-widget ui-widget-content" style="height: 100%; width:95%;">
<legend class="ui-widget-header ui-corner-all">G-Code</legend>
<div class="gcode">
<div>
<div id="editor1" style="position:relative; height: 250px; width: 100%;"></div>
<button id="btnBack" onclick="MoveUp(1)"></button>
<button id="btnForward" onclick="MoveDown(1)"></button>
<button id="clearbtn" onclick="ClearEdit(1)"></button>
<script>editor(1); </script>
</div>
</div>
</fieldset>
</fieldset>
<script>
function roundNumber(number, digits) {
var multiple = Math.pow(10, digits);
var rndedNum = Math.round(number * multiple) / multiple;
return rndedNum;
}
function PostCode(){
var gcode = "";
var cycle= document.getElementById("cycle").value;
var frate= eval(document.getElementById("frate").value);
var cplane= eval(document.getElementById("cplane").value);
var xcen= eval(document.getElementById("xcen").value);
var ycen= eval(document.getElementById("ycen").value);
var zdepth= eval(document.getElementById("zdepth").value);
var numholes= eval(document.getElementById("numholes").value);
var bcdiam= eval(document.getElementById("bcdiam").value);
var startangle= eval(document.getElementById("startangle").value);
var scale=1.0;
var count = 0;
var anglecount=1;
var circle_division_angle=(360/numholes);
var calc_angle=startangle;
//populate the editor with gcode
gcode += document.getElementById("cycle").value;
gcode += " ";
while (count < numholes)
{
var x1=Math.cos((Math.PI / 180)*(calc_angle))*(bcdiam/2);
var y1=Math.sin((Math.PI / 180)*(calc_angle))*(bcdiam/2);
var x=(x1+xcen)*scale;
var y=(y1+ycen)*scale;
var z=(zdepth)*scale;
if (count == 0){
if (cycle == 'G81'){
gcode += "X"+roundNumber(x,4)+" Y"+roundNumber(y,4)+" Z"+roundNumber(z,4)+" R"+roundNumber(cplane,4)+" F"+roundNumber(frate,2)+"\n";
}
else if (cycle == 'G82'){
var dwell = eval(document.getElementById("dwell").value);
gcode += "X"+roundNumber(x,4)+" Y"+roundNumber(y,4)+" Z"+roundNumber(z,4)+" R"+roundNumber(cplane,4)+" P"+dwell+" F"+roundNumber(frate,2)+"\n";
}
else{
var peck = eval(document.getElementById("peck").value);
gcode += "X"+roundNumber(x,4)+" Y"+roundNumber(y,4)+" Z"+roundNumber(z,4)+" R"+roundNumber(cplane,4)+" Q"+peck+" F"+frate+"\n";
}
}
else{
gcode += "X"+roundNumber(x,4)+" Y"+roundNumber(y,4)+"\n";
}
anglecount=anglecount+1;
calc_angle=calc_angle + circle_division_angle;
count=count+1;
}
gcode += "G80";
gcode += "\n";
PushText(1,gcode);
}
</script>
<script>
function MoveDown(number){
var name = "editor"+ number;
var objname = ace.edit(name);
objname.selection.moveCursorDown();
objname.setHighlightActiveLine(true);
cursornum = objname.selection.getCursor();
console.log(cursornum.row+1);
}
function MoveUp(number){
var name = "editor"+ number;
var objname = ace.edit(name);
objname.selection.moveCursorUp();
objname.setHighlightActiveLine(true);
cursornum = objname.selection.getCursor();
console.log(cursornum.row+1);
}
</script>
</body>
</html>
Dan Falckhttp://www.blogger.com/profile/02075095285410665278noreply@blogger.com0tag:blogger.com,1999:blog-1791935642719887324.post-16788868194896759492012-10-14T06:37:00.000-07:002012-10-14T06:37:54.949-07:00Heekscnc method of getting data to the python scriptIn my last post, I talked about how Heekscnc uses a master python script to coordinate the generation of g-code. In this post, I will try to convey how data is translated from the gui to this python script.<br />
<br />
1. Look at the layout of HeeksCAD with the HeeksCNC installed :<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdV925sy0Zn7mUACLQRs-NjZLANLVJCZn3lXM9q6V6KhtyD4Z7bXzWUoz63h3F9-edJ3CysfafeGuzqHVq1cCsBZaFmHihd0CdjMLGJd-tPO5oiYRPxiuULyFhY37OAL2XETRnZm5V4WyM/s1600/heekscad+layout.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="263" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdV925sy0Zn7mUACLQRs-NjZLANLVJCZn3lXM9q6V6KhtyD4Z7bXzWUoz63h3F9-edJ3CysfafeGuzqHVq1cCsBZaFmHihd0CdjMLGJd-tPO5oiYRPxiuULyFhY37OAL2XETRnZm5V4WyM/s320/heekscad+layout.png" width="320" /></a>Notice that there is an Objects tree on the left side. This is how all the data for the cnc program is graphically represented. Double clicking in items in this tree usually causes the parameters of that particular item to be displayed and editable.</div>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
To create a toolpath in Heeks, you need a 'sketch' (geometry), a 'tool' (end mill, drill, etc...) , and an 'operation' (profile, pocket, drilling...). So the first thing needed to get this ball rolling is the 'sketch'. Here I select the face of a solid and right click on it. A dialog pops up and allows me to create sketches from the face.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKNl5fiEuzfpneLrMq29oPm3XqrkY4klF6lprhEG-NENXwS52f0lI63TizWwaOky5UREXsaGcTKesiV62REcN_azYiRnjlyzLYp0q6sbl2iamuYGWF8G-XK7pnXww_YdbHwd-dl_d37Jiy/s1600/sketch+from+face.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="263" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKNl5fiEuzfpneLrMq29oPm3XqrkY4klF6lprhEG-NENXwS52f0lI63TizWwaOky5UREXsaGcTKesiV62REcN_azYiRnjlyzLYp0q6sbl2iamuYGWF8G-XK7pnXww_YdbHwd-dl_d37Jiy/s320/sketch+from+face.png" width="320" /></a></div>
<br />
The representation of the 'sketch' (or two sketches in this one) appears in the 'Objects tree':<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3CILxC6fhIuEt0rh1rF_RKuMwJcC4nnrV9ntA3t7reUD8Kiw-ZTVZt_rKInD3nk6EiBmLiLZIcNovfQDwBALFhMF_tGL6l7LPibPQ-ByEp8JxI8ClIFOsQbLKkOytcSXe3cqbBf4S0ljx/s1600/sketches.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3CILxC6fhIuEt0rh1rF_RKuMwJcC4nnrV9ntA3t7reUD8Kiw-ZTVZt_rKInD3nk6EiBmLiLZIcNovfQDwBALFhMF_tGL6l7LPibPQ-ByEp8JxI8ClIFOsQbLKkOytcSXe3cqbBf4S0ljx/s320/sketches.png" width="300" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
Notice that in my Objects tree there are already some tools listed. I have a tool table file stored on my hard drive with these tools in it.<br />
I next select a sketch and one of the tools from the tree and then create an operation:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfnveYmelsfY8z-dmQ7PKgBVe6JOntkHTuH73RUstWMCKVlCG9eROfwEuZnR6V4CRBiaEtVdk0JeL-qmbX5SkoFzHe_dwfd5MDY_tjFQzajnWRaFnupMa5RDgAwRvaIZOdR21N2KmVvYjj/s1600/add+new+profile+operation+1.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="328" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfnveYmelsfY8z-dmQ7PKgBVe6JOntkHTuH73RUstWMCKVlCG9eROfwEuZnR6V4CRBiaEtVdk0JeL-qmbX5SkoFzHe_dwfd5MDY_tjFQzajnWRaFnupMa5RDgAwRvaIZOdR21N2KmVvYjj/s400/add+new+profile+operation+1.png" width="400" /></a></div>
I selected a 'Profile' operation because I want to cut around the outside profile of this part.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
I also did the same thing with the inner sketch, but this time used a smaller tool and then selected the 'Pocket' operation. In Heekscnc, the pocket operation dialog looks like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQvT8_aT-KLIaHbk4fkWnj5KwhLVHL2CCl_Pu5AaKf_3_WYR-VIimxdCBypqs9-8eJFcynLytTSknkvnrkrzKDgo4MxMUO3qBHMaB8REhIRgqi76Tqdtqs0AZP-WjUQxV2ENA_0oknKtJt/s1600/pocket+dialog.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="273" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQvT8_aT-KLIaHbk4fkWnj5KwhLVHL2CCl_Pu5AaKf_3_WYR-VIimxdCBypqs9-8eJFcynLytTSknkvnrkrzKDgo4MxMUO3qBHMaB8REhIRgqi76Tqdtqs0AZP-WjUQxV2ENA_0oknKtJt/s320/pocket+dialog.png" width="320" /></a></div>
When I have a few operations set up, I usually get curious and want to see some results, so I usually post process what I have do far to see what the resulting tool paths look like:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmUyOnLwofGqZzdx5VWhrc8R-3wTpUu3k0_kFWOjtSw7VUssBSkIPU9i4WtPulNgRw0PbKZG2Q7wMxpZlwWFgu8ksQOwcJ_3Kp9FtV0aKk3hKfTMm0rLysOK1YBvsfy4Lo82YHW7PMXAVb/s1600/post+process.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="263" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmUyOnLwofGqZzdx5VWhrc8R-3wTpUu3k0_kFWOjtSw7VUssBSkIPU9i4WtPulNgRw0PbKZG2Q7wMxpZlwWFgu8ksQOwcJ_3Kp9FtV0aKk3hKfTMm0rLysOK1YBvsfy4Lo82YHW7PMXAVb/s320/post+process.png" width="320" /></a></div>
Pressing the 'Post-Process' button causes the master python script to be built and placed in the 'Program' panel:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRSY-xIj_UkvrUTXnluQyPKeZ03sOoQsCDrpXcZ_9NJLKrPb_zFAkIjdbBpmQx91JBFSRawzJoeM6VU9_HGLls5soqhPfC2GwM1twXuaQAapN-CpsdV7ocpWuNHsBfZKLYXld5bA3yIyef/s1600/python+Program+script.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRSY-xIj_UkvrUTXnluQyPKeZ03sOoQsCDrpXcZ_9NJLKrPb_zFAkIjdbBpmQx91JBFSRawzJoeM6VU9_HGLls5soqhPfC2GwM1twXuaQAapN-CpsdV7ocpWuNHsBfZKLYXld5bA3yIyef/s320/python+Program+script.png" width="280" /></a></div>
This is the same type of script that I blogged about last time. This script is run and creates a gcode file in the 'Output' panel.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnmcC7vTzd5T5YBPGq1lb4R4cHd9oGfWsk2kV0bLco9X14H36PKx0YVd2OeCR-HZjy82JyQldF9xR9lfOxmZrlaIJKbORZNEBQtVFB5RjyghVOz7uA29jpvNxoPRFzOa9dD78cpuMwKnwo/s1600/Output.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnmcC7vTzd5T5YBPGq1lb4R4cHd9oGfWsk2kV0bLco9X14H36PKx0YVd2OeCR-HZjy82JyQldF9xR9lfOxmZrlaIJKbORZNEBQtVFB5RjyghVOz7uA29jpvNxoPRFzOa9dD78cpuMwKnwo/s320/Output.png" width="282" /></a></div>
So, there you have it- that is a basic rundown of how Heekscnc operates.<br />
<br />
The thing that I want to stress in this post is that anything that is represented in the Objects tree will be translated to the master python script and later converted into gcode.<br />
<br />
<br />
<br />
<br />
<br />
<br />Dan Falckhttp://www.blogger.com/profile/02075095285410665278noreply@blogger.com0tag:blogger.com,1999:blog-1791935642719887324.post-14722737978443999432012-10-05T11:43:00.001-07:002012-10-05T11:43:35.786-07:00Python toolpath generation -HeeksCNC methodIn this post, I want to explain the basics of how HeeksCNC uses python to generate toolpaths. The method that Dan Heeks came up with for doing this was brilliant. I have used bits and pieces of this method with different applications a lot and am just starting to use it with FreeCAD.
Here is a python script (Dan Heeks named it post.py in HeeksCNC) that is the main script for a gcode file.<br />
post.py : <br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>import area
area.set_units(25.4)
import kurve_funcs
from nc.nc import *
import nc.emc2
output('/tmp/test.tap')
program_begin(123, 'Test program')
absolute()
imperial()
set_plane(0)
comment('Feeds and Speeds set for machining Please select a material to machine')
tool_defn( id=3, name='1/4 inch Carbide End Mill', radius=0.125, length=1.25, gradient=-0.1)
#(0.188 inch Carbide End Mill)
workplane(1)
comment('tool change to 1/4 inch Carbide End Mill')
tool_change( id=3)
spindle(7000)
feedrate_hv(33.07086614, 7)
flush_nc()
clearance = float(0.1968503937)
rapid_safety_space = float(0.07874015748)
start_depth = float(0)
step_down = float(0.035)
final_depth = float(-0.07)
tool_diameter = float(0.25)
cutting_edge_angle = float(0)
#absolute() mode
roll_radius = float(0.125)
offset_extra = 0
comment('Sketch')
curve = area.Curve()
curve.append(area.Point(1.25, -0.7))
curve.append(area.Point(-0.65, -0.7))
curve.append(area.Vertex(-1, area.Point(-1.4, 0.05), area.Point(-0.65, 0.05)))
curve.append(area.Point(-1.4, 0.45))
curve.append(area.Vertex(-1, area.Point(-0.65, 1.2), area.Point(-0.65, 0.45)))
curve.append(area.Point(1.25, 1.2))
curve.append(area.Vertex(-1, area.Point(2, 0.45), area.Point(1.25, 0.45)))
curve.append(area.Point(2, 0.05))
curve.append(area.Vertex(-1, area.Point(1.25, -0.7), area.Point(1.25, 0.05)))
roll_on = 'auto'
roll_off = 'auto'
extend_at_start= 0
extend_at_end= 0
lead_in_line_len= 0.25
lead_out_line_len= 0
kurve_funcs.profile(curve, 'left', tool_diameter/2, offset_extra, roll_radius, roll_on, roll_off, rapid_safety_space, clearance, start_depth, step_down, final_depth,extend_at_start,extend_at_end,lead_in_line_len,lead_out_line_len )
absolute()
program_end() </code></pre>
This script is processed like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivYqV9POZe8FxbRWyoO-hZoq04GPpb2D04sWZlOEGSxFZP8Yo6ewjiSyRvzzwgC9eVOXa5gbI_qsf1YXKge6ce5_rFpxfwTVpSilTd6MWABalE5S0bVvccWMBwjo2nYySjyV6iAvjTHX4M/s1600/Python+to+Gcode(1).png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivYqV9POZe8FxbRWyoO-hZoq04GPpb2D04sWZlOEGSxFZP8Yo6ewjiSyRvzzwgC9eVOXa5gbI_qsf1YXKge6ce5_rFpxfwTVpSilTd6MWABalE5S0bVvccWMBwjo2nYySjyV6iAvjTHX4M/s640/Python+to+Gcode(1).png" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
post.py reaches out to other scripts/modules in the heekscnc world for processing and formatting. These other scripts need to be in the python path, as you would expect.<br />
libarea can be had from many places now, although I prefer to use the 'New BSD' licensed version that can be found <a href="https://github.com/danielfalck/libarea-clipper" target="_blank">here.</a><br />
<br />
kurve_funcs.py is used for processing toolpaths for milling profiles. It depends on libarea too. I think we could probably untangle the dual dependency of calling 'import area' in post.py and in kurve_funcs.py, if we looked into it.<br />
<br />
the line 'import nc.emc2' calls upon a user editable script that formats gcode for the emc2 (linuxcnc now) milling machine. There are a lot of other scripts in the nc directory that let one format the gcode for other machines.<br />
<br />
Here is a summary of the components of this system again:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUtooSA-9g-nbgdhdObF548bcdj0Q_PPf5ptScp-1LllwwSxoby1EacaoxjYgiS-uCBBhR_bTVuZi4TrMv7-gqGkCp0iG59QewOYZP_AvQxEkm4SV9ngOgV5bMb3oqfJPFk8kmBI9dsL72/s1600/building+blocks.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUtooSA-9g-nbgdhdObF548bcdj0Q_PPf5ptScp-1LllwwSxoby1EacaoxjYgiS-uCBBhR_bTVuZi4TrMv7-gqGkCp0iG59QewOYZP_AvQxEkm4SV9ngOgV5bMb3oqfJPFk8kmBI9dsL72/s640/building+blocks.png" width="640" /></a></div>
<br />
<br />
<br />
<br />
<br />
Dan Falckhttp://www.blogger.com/profile/02075095285410665278noreply@blogger.com7tag:blogger.com,1999:blog-1791935642719887324.post-50322999997354698702012-09-30T10:20:00.001-07:002012-09-30T10:20:27.808-07:00Our book on FreeCAD has been published<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZSa0xBLRHpfs7dH5sK8MSFfA0hgDu2UP77bu1VskJxogojwiq4GzeTIMlJ1CtLEPV3VweonVFJAZ-5lKQBW_SRQKMGnlKq_XydNNvEkIqHULo4QVBpgUrcgV2WpS7qi8tmBC-m1y9gvKh/s1600/51VIRlvPbcL._SS400_.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZSa0xBLRHpfs7dH5sK8MSFfA0hgDu2UP77bu1VskJxogojwiq4GzeTIMlJ1CtLEPV3VweonVFJAZ-5lKQBW_SRQKMGnlKq_XydNNvEkIqHULo4QVBpgUrcgV2WpS7qi8tmBC-m1y9gvKh/s320/51VIRlvPbcL._SS400_.jpg" width="320" /></a></div>
<a href="http://sliptonic.com/?p=718" target="_blank">Brad</a> and I have been working on a small book on FreeCAD for Packt Publishing, since February of this year. It has now been published and can be purchased through <a href="http://www.packtpub.com/freecad-solid-modeling-with-python/book">Packt</a> and <a href="http://www.amazon.com/FreeCAD-Solid-Modeling-Power-Python/dp/1849518866/ref=sr_1_1?s=books&ie=UTF8&qid=1349025096&sr=1-1&keywords=FreeCAD">Amazon</a>. It was an interesting experience writing the book. I think we initially wrote the whole thing in the span of two weeks and spent the remainder of our time until August editing it. I think we learned a lot about writing and a lot about FreeCAD itself.Dan Falckhttp://www.blogger.com/profile/02075095285410665278noreply@blogger.com0tag:blogger.com,1999:blog-1791935642719887324.post-22207577076778458702012-06-08T19:02:00.000-07:002014-04-16T18:16:35.296-07:00Experimental Online APT360 Processor<title>APT360 WebSockets Demonstration</title>
<br />
<b>Edit-I have disabled the server for this, since I needed it for something else. This doesn't work anymore.</b><br />
I have been playing with websockets and a Linode server. A friend of mine, Brent Muller, set up APT360 on the linode server and I created a python-tornado websocket interface to it.<br />
<br />
Paste Apt code in the top text box and press the Post Code button. If there are no errors (be careful to make sure the first line of code begins on column one and that there is a line after 'fini') you should get gcode in the bottom pane. For those of you who know what APT360 is, have fun.<br />
<br />
Available Post Processors: a1100m, cent1, cent2, dmb, dmb2, e4axvt, e5axtr, e5axvt, emc, webgl2<br />
<form id="interaction">
<input onclick="ClearAPT()" type="button" value="Clear APT Code" />
<textarea cols="60" id="message" rows="10">PARTNO N/C 360 APT SAMPLE PART PROGRAM
machin/emc
clprnt
print/on
SP = POINT/ 0, 0, 0
L1 = LINE/ 4, 0, 0, 4, 8, 0
PT = POINT/ 4.0, 8.0, 0
L2 = LINE/ PT, ATANGL, 45
L3 = LINE/ 8, 12, 0, 12, 12, 0
L4 = LINE/ 14, 5, 0, 14, 10, 0
L5 = LINE/ 0, 2, 0, 10, 2, 0
C1 = CIRCLE/ 12, 10, 0, 2.0
C2 = CIRCLE/ 14, 2, 0, 3.0
INTOL/ 0
OUTTOL/ .005
CUTTER/ .25
SPINDL/ 2000, CLW
COOLNT/ ON
FEDRAT/ 20.0
FROM/ SP
GO/ TO, L1
TLLFT, GOLFT/ L1, PAST, L2
GORGT/ L2, PAST, L3
GORGT/ L3, TANTO, C1
GOFWD/ C1, TANTO, L4
GOFWD/ L4, PAST, C2
GORGT/ C2, PAST, L5
GORGT/ L5, PAST, L1
GOTO/ SP
COOLNT/ OFF
SPINDL/ OFF
FINI
</textarea><br />
<input onclick="PostOutput()" type="button" value="Post Code" />
<input onclick="ClearOutput()" type="button" value="Clear GCode" /><br />
<textarea cols="60" id="gcode" rows="10"> </textarea></form>
<script type="text/javascript">
var ws = new WebSocket("ws://li421-61.members.linode.com:8888/websocket");
ws.onmessage = function(evt){
x = document.createElement("p");
x.innerHTML = evt.data;
document.getElementById("gcode").value += x.innerHTML;
}
function PostOutput(){
var userInput = document.getElementById("message").value;
x = document.createElement("p");
ws.send(userInput);
}
function ClearAPT(){
document.getElementById("message").value = "";
}
function ClearOutput(){
document.getElementById("gcode").value = "";
}
</script>Dan Falckhttp://www.blogger.com/profile/02075095285410665278noreply@blogger.com5tag:blogger.com,1999:blog-1791935642719887324.post-85512748968018552082012-05-13T11:17:00.001-07:002012-05-16T18:39:04.502-07:00Javascript post processingThis is a test to see how javascript could work for post processing. In the left textarea, add terms like 'g0(0,0,0)' for rapid moves, 'g1(1,0,0)' for feed moves and then press the 'Post' button to get some GCode in the right textarea box. Some of you might wonder why? This is just a test for something bigger.
<p>
<br>g0(x,y,z) - rapid</br>
<br>g1(x,y,z) - feed move</br>
<br>g2(x,y,i,j) - clockwise arc - i,js in absolute coordinates</br>
<br>g3(x,y,i,j) - counter clockwise arc</br>
<br>feedrate = 33.0 - feedrate</br>
</p>
I tried to make things modal, so that unneeded terms aren't repeated. At some point the post processor needs to reside on a client machine as an html5 local file. I have a lot to learn...
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html>
<title>GCode Post Processor</title>
<head>
<script>
function init() {
f=document.form1
}
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// Simple javascript gcode post processor
// released under 'New BSD' license
// Copyright (c) <2012>, <Dan Falck ddfalck@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////////////////
//define global variables
description = "Generic Post";
extension = "ngc";
//x=0;y=0;z=0;
Absolute = true;
old_feedrate = 0;
feedrate = 0;
old_x = null;
old_y = null;
old_z = null;
start_x = null;
start_y = null;
start_z = null;
old_i = null;
old_j = null;
old_k = null;
i = null;
j = null;
k = null;
dx = 0; dy=0; dz=0;
var movefmt = 3;
var fdfmt = 2;
temps="";
dx=0;
dy=0;
dz=0;
old_gcode = null;
old_mcode = null;
function gcodeHeader()
{
var currentTime=new Date();
var dateString="";
dateString+=currentTime.getHours()+":";
dateString+=currentTime.getMinutes()+" ";
dateString+=currentTime.getDay()+"-";
dateString+=currentTime.getMonth()+"-";
dateString+=currentTime.getFullYear()+" ";
temps="";
temps+="(Generated by generic_gcodePost.js "+dateString+" )\n";
return temps;
}
function gcodeFooter()
{
temps="M2\n";
return temps;
}
/////////////////////////////////////////////////////////////
// formatting
function mvfmt(number)
{return number_format(number,movefmt,".","");}
function fformat(number)
{return number_format(number,fdfmt,".","");}
function number_format( number, decimals, dec_point, thousands_sep )
{
// http://kevin.vanzonneveld.net
// + original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + bugfix by: Michael White (http://crestidg.com)
// + bugfix by: Benjamin Lupton
// + bugfix by: Allan Jensen (http://www.winternet.no)
// + revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
// * example 1: number_format(1234.5678, 2, '.', '');
// * returns 1: 1234.57
var n = number, c = isNaN(decimals = Math.abs(decimals)) ? 2 : decimals;
var d = dec_point == undefined ? "," : dec_point;
var t = thousands_sep == undefined ? "." : thousands_sep, s = n < 0 ? "-" : "";
var i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "", j = (j = i.length) > 3 ? j % 3 : 0;
return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
}
function Xfmt(x)
{
if (diff_x(x)== true)
{
dx = x - old_x;
if (Absolute == true)
{return "X" + mvfmt(x);}
else
{return "X" + mvfmt(dx);}
}
else{ return "";}
}
function Yfmt(y)
{
if (diff_y(y)== true)
{ dy = y - old_y;
if (Absolute == true)
{return "Y" + mvfmt(y);}
else
{return "Y" + mvfmt(dy);}
}
else{ return "";}
}
function Zfmt(z)
{
if (diff_z(z)== true)
{ dz = z - old_z;
if (Absolute == true)
{return "Z" + mvfmt(z);}
else
{return "Z" + mvfmt(dz);}
}
else{ return "";}
}
// center of arc functions
// centers will come in absolute coords
// most of the posts will need coords
// that are incremental from start point of arc
function Ifmt(i)
{
// if (diff_i(i)== true)
// {
di = i - start_x ;
start_x = old_x;
return "I" + mvfmt(di);
// }
// else{ return "";}
}
function Jfmt(j)
{
// if (diff_j(j)== true)
// {
dj = j - start_y ;
start_y = old_y;
return "J" + mvfmt(dj);
// }
// else{ return "";}
}
function Kfmt(k)
{
// if (diff_k(k)== true)
// {
dk = k - start_z;
start_z = old_z;
return "K" + mvfmt(dk);
// }
// else{ return "";}
}
function Ffmt(feedrate)
{
if (different_feedrate(feedrate))
{ old_feedrate = feedrate;
return "F" + fformat(feedrate);
}
else{ return "";}
}
/////////////////////////////////////////////////////////////
//comparison functions
function same_xyz(x,y,z)
{
if(x != old_x){return false;}
else if(y != old_y){return false;}
else if(z != old_z){return false;}
else{ return true;}
}
function different_feedrate(feedrate)
{ if(feedrate != old_feedrate){return true;}
else{ return false;}
}
function diff_x(x){
if(x!= old_x){return true;}
else {return false;}
}
function diff_y(y){
if(y!= old_y){return true;}
else {return false;}
}
function diff_z(z){
if(z!= old_z){return true;}
else {return false;}
}
function diff_a(a){
if(a!= old_a){return true;}
else {return false;}
}
function diff_b(b){
if(b!= old_b){return true;}
else {return false;}
}
function diff_c(c){
if(c!= old_c){return true;}
else {return false;}
}
function diff_i(i){
if(i!= old_i){return true;}
else {return false;}
}
function diff_j(j){
if(j!= old_j){return true;}
else {return false;}
}
function diff_k(k){
if(k!= old_k){return true;}
else {return false;}
}
/////////////////////////////////////////////////////////////
//section for defining G and M codes
function rapid()
{ return 'G0'; }
function feed()
{ return 'G1'; }
function absolute()
{ Absolute = true;
return 'G90'; }
function incremental()
{ Absolute = false;
return 'G91'; }
function arc_cw()
{ return 'G2';}
function arc_ccw()
{ return 'G3';}
/////////////////////////////////////////////////////////////
// Moves
// rapid straight line move
function g0(x, y, z)
{ temps="";
if (same_xyz(x,y,z) == true) {return temps;}
if (old_gcode != rapid()){temps+=rapid();}
if (x != null)
{ temps+=Xfmt(x);
old_x = x;
}
if (y != null)
{ temps+=Yfmt(y);
old_y = y;
}
if (z != null)
{ temps+=Zfmt(z);
old_z = z;
}
temps+="\n";
old_gcode =rapid();
return temps;
}
// feed move in a straight line
function g1(x, y, z)
{ temps="";
if (same_xyz(x,y,z) == true) return;
if (old_gcode != feed()){temps+=feed();}
if (x != null)
{ temps+=Xfmt(x);
old_x = x;
}
if (y != null)
{ temps+=Yfmt(y);
old_y = y;
}
if (z != null)
{ temps+=Zfmt(z);
old_z = z;
}
temps+= Ffmt(feedrate);
temps+="\n";
old_gcode =feed();
return temps;
}
///////////////////////////////////////
// arcs
// arcs will most likely come in with centers
// in absolute coordinates so they will be
// converted to incremental coords in the
// I J K formatting functions Ifmt, Jfmt, Kfmt
///////////////////////////////////////
// simple 2D clockwise arc
function g2(x,y,i,j)
{ temps="";
if (old_gcode != arc_cw()){temps+=arc_cw();}
start_x = old_x;
start_y = old_y;
if (x != null)
{ temps+=Xfmt(x);
old_x = x;
}
if (y != null)
{ temps+=Yfmt(y);
old_y = y;
}
if (i != null)
{ temps+=Ifmt(i);
old_i = i;
}
if (j != null)
{ temps+=Jfmt(j);
old_j = j;
}
temps+= Ffmt(feedrate);
temps+="\n";
old_gcode = arc_cw();
return temps;
}
// simple 2D counter clockwise arc
function g3(x,y,i,j)
{ temps="";
if (old_gcode != arc_ccw()){temps+=arc_ccw();}
start_x = old_x;
start_y = old_y;
if (x != null)
{ temps+=Xfmt(x);
old_x = x;
}
if (y != null)
{ temps+=Yfmt(y);
old_y = y;
}
if (i != null)
{ temps+=Ifmt(i);
old_i = i;
}
if (j != null)
{ temps+=Jfmt(j);
old_j = j;
}
temps+= Ffmt(feedrate);
temps+="\n";
old_gcode = arc_ccw();
return temps;
}
///////////////////////////////////////////////////////////////////////////
function post()
{ feedrate = 0;
var gcode=f.AreaOriginal.value.split('\n');
f.AreaOutput.value='';
for (var i=0; gcode.length>i; i++)
{
a = gcode[i];
if (a !="")
{
b = a+"\n";
var s = a;
if (s.indexOf("feed")!=-1)
{ eval(b);}
else {f.AreaOutput.value +=eval(b);}
// }
// else { eval(b);}
}
}
}
</script>
</head>
<body onload="init()">
<h1>JavaScript Post Processor</h1>
<br>
<form name="form1">
<table border=3 cellpadding=10>
<tr>
<td>
<b>Program Data</b>
<br><textarea cols=15 rows=10 name="AreaOriginal">feedrate=44
g0(0,0,0)
g1(1,0,0)
g3(0,1,0,0)
g3(-1,0,0,0)
feedrate=22
g1(0,0,0)
</textarea>
</td><td>
<b>GCode output</b>
<br><textarea cols=25 rows=10 name="AreaOutput"></textarea
</td>
</tr>
</table>
<p><input type=button name="Post GCode" Value="Post" onclick="post()"></p>
</form>
</html>Dan Falckhttp://www.blogger.com/profile/08753782465263326147noreply@blogger.com0tag:blogger.com,1999:blog-1791935642719887324.post-32461538739609094802012-05-12T16:47:00.000-07:002012-05-12T16:47:12.647-07:00Javascript blogger test<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Cut and Paste JavaScript-JavaScript calculator</title>
</head>
<body>
I just want to try something out with this blogger software. I want to see if I put inline javascript in a post. This post might be deleted later, after the test.
<FORM NAME="Calc">
<TABLE BORDER=4>
<TR>
<TD>
<INPUT TYPE="text" NAME="Input" Size="16">
<br>
</TD>
</TR>
<TR>
<TD>
<INPUT TYPE="button" NAME="one" VALUE=" 1 " OnClick="Calc.Input.value += '1'">
<INPUT TYPE="button" NAME="two" VALUE=" 2 " OnCLick="Calc.Input.value += '2'">
<INPUT TYPE="button" NAME="three" VALUE=" 3 " OnClick="Calc.Input.value += '3'">
<INPUT TYPE="button" NAME="plus" VALUE=" + " OnClick="Calc.Input.value += ' + '">
<br>
<INPUT TYPE="button" NAME="four" VALUE=" 4 " OnClick="Calc.Input.value += '4'">
<INPUT TYPE="button" NAME="five" VALUE=" 5 " OnCLick="Calc.Input.value += '5'">
<INPUT TYPE="button" NAME="six" VALUE=" 6 " OnClick="Calc.Input.value += '6'">
<INPUT TYPE="button" NAME="minus" VALUE=" - " OnClick="Calc.Input.value += ' - '">
<br>
<INPUT TYPE="button" NAME="seven" VALUE=" 7 " OnClick="Calc.Input.value += '7'">
<INPUT TYPE="button" NAME="eight" VALUE=" 8 " OnCLick="Calc.Input.value += '8'">
<INPUT TYPE="button" NAME="nine" VALUE=" 9 " OnClick="Calc.Input.value += '9'">
<INPUT TYPE="button" NAME="times" VALUE=" x " OnClick="Calc.Input.value += ' * '">
<br>
<INPUT TYPE="button" NAME="clear" VALUE=" c " OnClick="Calc.Input.value = ''">
<INPUT TYPE="button" NAME="zero" VALUE=" 0 " OnClick="Calc.Input.value += '0'">
<INPUT TYPE="button" NAME="DoIt" VALUE=" = " OnClick="Calc.Input.value = eval(Calc.Input.value)">
<INPUT TYPE="button" NAME="div" VALUE=" / " OnClick="Calc.Input.value += ' / '">
<br>
</TD>
</TR>
</TABLE>
</FORM>
<p align="center"><font face="arial" size="-2">This free script provided by</font><br>
<font face="arial, helvetica" size="-2"><a href="http://javascriptkit.com">JavaScript
Kit</a></font></p>
</body>
</html>Dan Falckhttp://www.blogger.com/profile/08753782465263326147noreply@blogger.com3tag:blogger.com,1999:blog-1791935642719887324.post-69203936700954219842012-04-15T13:38:00.004-07:002012-04-15T13:53:32.343-07:00Cloud CADCAM via twisted pythonI have been working a bit with Julian Todd of <a href="http://www.freesteel.co.uk/wpblog/frontpage/">FreeSteel </a>. We have started working on a way of serving out toolpaths, using his 'Slicer' routine from a server. The server takes triangle vertices in and returns tool location paths, for waterline type machining. Julian is very familiar with twisted python and plans on using it for his own server. At the moment, I am running his library locally.<br /><br />Here is an image of a part that I designed in FreeCAD and applied this 'Slicer' scheme to:<br /><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgueT9JB9j_ZYnHCq5JmFF3hyphenhyphenOf3_Q7fk6ZThi4lOwtrD6reyjz46Oz0Is5QCF4XuQ5vsfx6wM7Tyq7kJqPgOfgU4WvLlxl8-qNCj0QolocakZDNlG-7F4-iVim8HhaS94Angui-Z67-KJZ/s1600/freesteel1.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 162px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgueT9JB9j_ZYnHCq5JmFF3hyphenhyphenOf3_Q7fk6ZThi4lOwtrD6reyjz46Oz0Is5QCF4XuQ5vsfx6wM7Tyq7kJqPgOfgU4WvLlxl8-qNCj0QolocakZDNlG-7F4-iVim8HhaS94Angui-Z67-KJZ/s320/freesteel1.png" alt="" id="BLOGGER_PHOTO_ID_5731731627189688242" border="0" /></a><br />The python code that I used for this doesn't post process into actual g-code, but it could.<br /><br />import Mesh<br />import Part,FreeCAD<br />from FreeCAD import Base,Vector<br />import freesteelpy as kernel<br /><br />s=Gui.Selection.getSelectionEx()<br />s1 = s[0]<br />m1 = s1.Object<br />m1.Mesh.write("/home/danfalck/mesh1.py") #write the triangle list to a file<br />f1 = m1.Mesh.Facets #returns out a list of facets<br /><br />fssurf = kernel.FsSurf.New()<br />for f in f1:<br /> fssurf.PushTriangle(f.Points[0][0],f.Points[0][1],f.Points[0][2], f.Points[1][0],f.Points[1][1],f.Points[1][2], \<br /> f.Points[2][0],f.Points[2][1],f.Points[2][2])<br /><br />def doit(fssurf, z , rad):<br /> fssurf.Build(1.0)<br /><br /> fshoriztoolsurf = kernel.FsHorizontalToolSurface.New()<br /> fshoriztoolsurf.AddSurf(fssurf)<br /> fshoriztoolsurf.AddCylinder(rad, z, 10.0, 0) #cylinder radius, lower Z, upper Z, how the cylinder is connected to the rest of the tool -tangential etc.<br /> fsimplicitarea = kernel.FsImplicitArea.New(0)<br /> fsimplicitarea.AddHorizToolSurf(fshoriztoolsurf)<br /> fsimplicitarea.SetContourConditions(0.99, -1.0, 0.002, 2, -1.0, 0.9)<br /> fsweave = kernel.FsWeave.New()<br /> fsweave.SetShape(-25, 25, -25, 25,.1) #(-x, -y, x , y of bounding area, last arg is granularity of path)<br /> fsimplicitarea.GenWeaveZProfile(fsweave)<br /> fsweave.GetNContours()<br /><br /> fspath2x = kernel.FsPath2X.New(0)<br /> fspath2x.RecordContour(fsweave, False, 0, 0.0)<br /><br /> fspath2x.GetNpts()<br /><br /> [ (fspath2x.GetD(i,0), fspath2x.GetD(i,1)) for i in range(fspath2x.GetNpts()) ]<br /><br /> [ (fspath2x.GetD(i,0), fspath2x.GetD(i,1), fspath2x.GetD(i,2)) for i in range(fspath2x.GetNpts()) ]<br /><br /> pt0 = (fspath2x.GetD(0,0), fspath2x.GetD(0,1), fspath2x.GetD(0,2))<br /><br /> #FreeCAD.ActiveDocument.addObject("Part::Feature","rapids)\n")<br /> c = Part.Compound([])<br /><br /> for i in range(fspath2x.GetNpts()-1):<br /> line = ( Part.makeLine( (fspath2x.GetD(i,0), fspath2x.GetD(i,1), fspath2x.GetD(i,2) ) , ( fspath2x.GetD(i+1,0), fspath2x.GetD(i+1,1), fspath2x.GetD(i+1,2) ) ) )<br /> c.add(line)<br /><br /> c.Placement=Base.Placement(Base.Vector(0.00,0.00,z),Base.Rotation(0.00,0.00,0.00,1.00))<br /><br /> Part.show(c)<br /><br />rad = 1.0<br />startdepth = 2.5<br />zdepth = -3.0<br />stepdown = .25<br />steps = startdepth<br /><br />while startdepth >= zdepth:<br /> z = startdepth<br /> doit(fssurf,z,rad)<br /> startdepth =startdepth-stepdown<br /><br /><br />Sorry for the poor formatting of the source code- I need to figure that out soon.Dan Falckhttp://www.blogger.com/profile/08753782465263326147noreply@blogger.com0tag:blogger.com,1999:blog-1791935642719887324.post-9171142970701116822012-01-13T10:26:00.000-08:002012-01-13T12:17:03.709-08:00Demo of Profiling<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dxqarSrftKf_FHfFt81y9tv98bXrtzZUWjun7sb8hRHpOM7NjZZF822aaopVzzEsf6W3Bh-7lw2ZYNgHsY7FQ' class='b-hbp-video b-uploaded' frameborder='0'></iframe>Dan Falckhttp://www.blogger.com/profile/08753782465263326147noreply@blogger.com3tag:blogger.com,1999:blog-1791935642719887324.post-10303369079490992702012-01-01T09:36:00.001-08:002012-01-01T09:38:56.283-08:00More Progress<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjc5whyphenhyphenR14SmNaZl4cPwbO63KWoMQUEriHz1AwVF3hkDlQY_SY9_WNSZOzybV9DfZ_WxkaBmfVoiDBNwFmX0w3tn2h2QRUFAykc8MySoF17nZyyuoEJ_WUCJr_6zmxNyWEFsk91SAbSAfCy/s1600/ProfileMachining.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjc5whyphenhyphenR14SmNaZl4cPwbO63KWoMQUEriHz1AwVF3hkDlQY_SY9_WNSZOzybV9DfZ_WxkaBmfVoiDBNwFmX0w3tn2h2QRUFAykc8MySoF17nZyyuoEJ_WUCJr_6zmxNyWEFsk91SAbSAfCy/s320/ProfileMachining.png" alt="" id="BLOGGER_PHOTO_ID_5692718988428385154" border="0" /></a>I was able to hack together a crude 'Profile Operation' dialog and connect it to heekscnc and libarea functions this weekend. Now I can bring up the dialog, select the edges of a solid, and then backplot the code.<br />It's definitely a rough hack, but it shows some potential.Dan Falckhttp://www.blogger.com/profile/08753782465263326147noreply@blogger.com3tag:blogger.com,1999:blog-1791935642719887324.post-83787714702300995982011-12-31T18:40:00.000-08:002011-12-31T18:42:39.645-08:00Using QtDesigner!!!!<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7VRkhkuVufvD2UewjdbUOsmP8JTwPJRJ2JfhoXdRaJEC7DBkRRb7tDY9_eNvHw8EPoXO6EOLoGwj3zzv7BeYZtDk-3Kmz7sOup_JcaDCU9OkPmUCM5W7vwPnAU_q_fTH84Yen_rE9ea5W/s1600/early+dialogs.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7VRkhkuVufvD2UewjdbUOsmP8JTwPJRJ2JfhoXdRaJEC7DBkRRb7tDY9_eNvHw8EPoXO6EOLoGwj3zzv7BeYZtDk-3Kmz7sOup_JcaDCU9OkPmUCM5W7vwPnAU_q_fTH84Yen_rE9ea5W/s320/early+dialogs.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5692488411849748530" /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0yUFUuoiG-IkQL4NNEOLPRwLiYl12zboUnIPlj2oSItJdj3t6GnYT8PGvblRejNXMRTNVkTxHUcgBZl8VdrqjSbsXTSwNWtZT8j31kU4mXI8WEMzabe3PALDg4sOva648EkCWnFR7IwAy/s1600/qtdesigner.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0yUFUuoiG-IkQL4NNEOLPRwLiYl12zboUnIPlj2oSItJdj3t6GnYT8PGvblRejNXMRTNVkTxHUcgBZl8VdrqjSbsXTSwNWtZT8j31kU4mXI8WEMzabe3PALDg4sOva648EkCWnFR7IwAy/s320/qtdesigner.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5692488406406985522" /></a><br />I'm starting to get the hang of using QtDesigner for making pyQt Dialogs with FreeCAD/HeeksCNC. I love it!!!!Dan Falckhttp://www.blogger.com/profile/08753782465263326147noreply@blogger.com0tag:blogger.com,1999:blog-1791935642719887324.post-8387599127527485292011-12-31T08:27:00.000-08:002011-12-31T08:38:13.419-08:00A little progress reportI'm still learning the internals of FreeCAD. I helped the main project a little by creating a lowly 'Point' class, which Yorik integrated into the Draft workbench. Doing this helped me get familiar with the source. Having this object class will also be useful later on for CAM work (start and end points for profiles etc).<br />I have also made some scripts for extracting libarea 'curve' elements from objects in the FreeCAD document. Right now, I can click on edges of solids or lines and arcs in Sketches or Draft elements and then run a macro to produce some python code that can be pasted into a HeeksCNC python script for producing g-code.<br />The resulting code looks like this:<br /><br />curve = area.Curve()<br />#open path<br />curve.append(area.Point(62.244881,-33.935955))<br />curve.append(area.Vertex(-1 , area.Point( 57.129109, -39.051727), area.Point(57.129109, -33.935955)))<br />curve.append(area.Point( -56.043546, -39.051727))<br />curve.append(area.Vertex(-1 , area.Point( -64.821892, -30.273381), area.Point(-56.043546, -30.273381)))<br /><br />If you've ever used HeeksCNC, this code should look familiar.<br />I can take this code and paste it into a script such as this one:<br /><br />import sys<br />sys.path.insert(0,'/usr/lib/heekscnc/')<br />import math<br />import area<br />area.set_units(1)<br />import kurve_funcs<br />from nc.nc import *<br />import nc.emc2b<br /><br />output('/home/danfalck/Documents/freecad/curve_output/test.tap')<br />program_begin(123, 'Test program')<br />absolute()<br />metric()<br />flush_nc()<br /><br />set_plane(0)<br /><br />workplane(1)<br /><br />#(4.7752 mm Carbide End Mill)<br />tool_defn( id=4, name='4.7752 mm Carbide End Mill', radius=2.3876, length=23.876, gradient=-0.1)<br />tool_diameter = float(4.7752)<br />cutting_edge_angle = float(0)<br /><br />#path/geometry section<br />curve = area.Curve()<br />curve.append(area.Point(62.244881,-33.935955))<br />curve.append(area.Vertex(-1 , area.Point( 57.129109, -39.051727), area.Point(57.129109, -33.935955)))<br />curve.append(area.Point( -56.043546, -39.051727))<br />curve.append(area.Vertex(-1 , area.Point( -64.821892, -30.273381), area.Point(-56.043546, -30.273381)))<br />#end of path/geometry section<br /><br />#program action:<br />comment('tool change to 4.7752 mm Carbide End Mill')<br />tool_change( id=4)<br />spindle(7000)<br />feedrate_hv(840, 100)<br />clearance = float(5)<br />rapid_safety_space = float(2)<br />start_depth = float(0)<br />step_down = float(2)<br />final_depth = float(-10)<br />roll_radius = float(5.0)<br />offset_extra = 0<br />roll_on = 'auto'<br />roll_off = 'auto'<br />extend_at_start= 0<br />extend_at_end= 0<br />lead_in_line_len= 5.0<br />lead_out_line_len= 5.0<br />kurve_funcs.profile(curve, 'left', tool_diameter/2, offset_extra, roll_radius, roll_on, roll_off, rapid_safety_space, clearance, start_depth, step_down, final_depth,extend_at_start,extend_at_end,lead_in_line_len,lead_out_line_len )<br /><br />absolute()<br /><br />program_end()<br /><br /><br /><br />The resulting gcode might give something like this (backplotted in FreeCAD):<br /><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpjvQlQT6tlGngp5kix5WiKG-DqHDsq-j7LMUgnm6_MAgbHqPXTv8mMZu58eFEAwk_ZsYKGh329SLfJpt5KF3jYb8x5q4532KJm9hiCR2_muNDvh25NuMcJZrua3fd4etNg7ScnU1FXqUB/s1600/teaser.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpjvQlQT6tlGngp5kix5WiKG-DqHDsq-j7LMUgnm6_MAgbHqPXTv8mMZu58eFEAwk_ZsYKGh329SLfJpt5KF3jYb8x5q4532KJm9hiCR2_muNDvh25NuMcJZrua3fd4etNg7ScnU1FXqUB/s320/teaser.png" alt="" id="BLOGGER_PHOTO_ID_5692332525205494322" border="0" /></a>Dan Falckhttp://www.blogger.com/profile/08753782465263326147noreply@blogger.com0tag:blogger.com,1999:blog-1791935642719887324.post-77723865516845489162011-11-05T08:37:00.000-07:002013-11-16T07:39:07.363-08:00FreeCADLately I've gotten interested in <a href="http://www.freecadweb.org/">FreeCAD</a> .<br />FreeCAD is "a a general purpose Open Source 3D CAD/MCAD/CAx/CAE/PLM modeler" written in C++, with python scripting built in. It runs on Windows, Linux, and supposedly Mac OS X. FreeCAD is built "with a modular software architecture which makes it easy to provide additional functionality without modifying the core system."<br />I am interested in adapting some of the HeeksCNC libraries to a plugin for FreeCAD. My motives are practical, I think:<br /><br />1. FreeCAD's is maintained by a core group of developers already. They are very active.<br />2. It has python scripting built in by default. HeeksPython is great,but is broken frequently by changes to HeeksCAD itself.<br />3. The OS related build system is already taken care of for all desktop platforms. I don't want to deal with this at all.<br />4. There is an active FreeCAD <a href="https://sourceforge.net/apps/phpbb/free-cad/index.php">forum</a>.<br />5. I just want to work on CADCAM and import/export issues.<br /><br />I have been working on improving the DXF import/export scripts that are already in FreeCAD and have started on a DXF to constraints/Sketcher importer. I have also started work on backplotting CNC g-code into FreeCAD:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPn_Ry7V2nsp6NIAJc7KeCa6Xj29Loxd77p4xup78vosuFr62GTlXaGpzLpeupjXY3JPTAQG2sEWanQ7unw9o9VRhqGb5Z721aIOzg-9bN7aJEsuHDGQ8WyrsrLPm5zZfx1VA7uZMd2U0B/s1600/cone_and_waterline.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPn_Ry7V2nsp6NIAJc7KeCa6Xj29Loxd77p4xup78vosuFr62GTlXaGpzLpeupjXY3JPTAQG2sEWanQ7unw9o9VRhqGb5Z721aIOzg-9bN7aJEsuHDGQ8WyrsrLPm5zZfx1VA7uZMd2U0B/s320/cone_and_waterline.png" alt="" id="BLOGGER_PHOTO_ID_5671542583594198482" border="0" /></a><br /><br />The screenshot is from some g-code that I generated in HeeksCNC and backplotted using the HeeksCNC python scripting, adapted to FreeCAD.Dan Falckhttp://www.blogger.com/profile/08753782465263326147noreply@blogger.com4tag:blogger.com,1999:blog-1791935642719887324.post-58835770129832019722011-08-27T06:55:00.000-07:002011-08-27T07:19:08.545-07:00Waterline MachiningI have been machining a part that has a draft angle of 20 degrees on two walls and I think I found a good method.
<br />Here is a screenshot of one version of the part, where I tried using 'zigzag' machining with Heekscnc:
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXoG6ImZGzsJWj1RHBsjOHsYpdxCWHl-Tl13iZioxKm0auNJOt2Rsr1WYA_3fxUSam1vATIcrQK0nm9Yi6gcmsx3S_Sc1MPi8hzC3DAFDfvO78q5F0SoOc9q7RSVGUzfGaDlNpzj2cF8ut/s1600/solid.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXoG6ImZGzsJWj1RHBsjOHsYpdxCWHl-Tl13iZioxKm0auNJOt2Rsr1WYA_3fxUSam1vATIcrQK0nm9Yi6gcmsx3S_Sc1MPi8hzC3DAFDfvO78q5F0SoOc9q7RSVGUzfGaDlNpzj2cF8ut/s320/solid.png" alt="" id="BLOGGER_PHOTO_ID_5645534689930749570" border="0"></a>
<br />When I actually did machine the part, it took about an hour and 20 minutes. I knew that I would have to set my boundaries closer to the tapered walls, if I wanted to save any time on the next part. Also notice the extra tool paths that are cutting air. I wanted to eliminate them.
<br />Heekscnc uses 3D machining methods from Opencamlib http://code.google.com/p/opencamlib/ . There are several strategies for 3D milling there and 'waterline' is one of them. Waterline machining makes the tool path run at a constant Z level around the part. This seemed like a perfect strategy for the part I was working on. I tried out the HeeksCNC implementation of ocl waterline using a flat bottomed end mill and got a tool path that looked like this:
<br />
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRyOZL3icc6oDlT8rugQ_ZWlETaQ953FTMkPw8HnhLVFROyEZ2MRio7DTkIOb9YPwAp8eTHdYc43LBav0HbvAp_yK75EG6myxyPaoJgPSeELoU0zsUMgiOgRQZw_5ZriaLJnBfkYRKf9wM/s1600/string_bar.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRyOZL3icc6oDlT8rugQ_ZWlETaQ953FTMkPw8HnhLVFROyEZ2MRio7DTkIOb9YPwAp8eTHdYc43LBav0HbvAp_yK75EG6myxyPaoJgPSeELoU0zsUMgiOgRQZw_5ZriaLJnBfkYRKf9wM/s320/string_bar.png" alt="" id="BLOGGER_PHOTO_ID_5645537008239057458" border="0"></a>
<br />
<br />I liked the approach, but I only wanted to machine the tapered walls of the part. There were some entries in the Heekscnc waterline operation for boundaries, but they weren't functioning. I looked at the source code and added some logic to 'ocl_funcs.py' to connect them and was then able to get the tool path to look like this:
<br />
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFgN-qakHdIhz4-5bjouWxi1-WT-oqpmq2_zDEp0JX-vfCVtrLLIG6cjR99vRi4kCJAgMGSa0nU7_chNqA6a2AUjd8hniXif0VS8rinHkl4z6U7TYbLRowiNis6pvmoQLCdbs8eM0YRt4X/s1600/boundaries2.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFgN-qakHdIhz4-5bjouWxi1-WT-oqpmq2_zDEp0JX-vfCVtrLLIG6cjR99vRi4kCJAgMGSa0nU7_chNqA6a2AUjd8hniXif0VS8rinHkl4z6U7TYbLRowiNis6pvmoQLCdbs8eM0YRt4X/s320/boundaries2.png" alt="" id="BLOGGER_PHOTO_ID_5645537730439372850" border="0"></a>
<br />
<br />Ahh! That's much better. When I actually milled the part, my cycle time was down to 20 minutes.
<br />
<br /><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dwWOUcTe6YiO-wcvVb4fGrh0rL_CUKdJC2RjXLW677Fz00yFRlEkX8Xboq88Z2QQnBj8adon6KnvZ8BSI6N5g' class='b-hbp-video b-uploaded' frameborder='0'></iframe>Dan Falckhttp://www.blogger.com/profile/08753782465263326147noreply@blogger.com0tag:blogger.com,1999:blog-1791935642719887324.post-65742470746303051072011-07-10T17:04:00.000-07:002011-07-10T18:23:01.261-07:00Translating toolpaths with scriptopI have committed a change to my git repo that lets me snap new coordinates anywhere on the drawing and then have my toolpaths generated relative to it. This becomes useful if I import a dxf file and the geometry isn't anywhere near where it needs to be for sensible fixture offsets. Here's an example:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRHxIllpAq1r_63o_-W0b56Exb09-kwfuoNapE8YYE1PtnPSipeNPS_SnslKbqNkjDE5Xv4gyiNRTC8y5YRTk9I2bUxNsmTh5VYr88OWdPN-IsP5UjsU0aS0TKR5U0oWVk4AppZPEhYbiF/s1600/path1.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRHxIllpAq1r_63o_-W0b56Exb09-kwfuoNapE8YYE1PtnPSipeNPS_SnslKbqNkjDE5Xv4gyiNRTC8y5YRTk9I2bUxNsmTh5VYr88OWdPN-IsP5UjsU0aS0TKR5U0oWVk4AppZPEhYbiF/s320/path1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5627879967712219442" /></a><br /><br />Notice how the origin/datum is to the far left of the rectangular sketch. To make things a little easier, create a new coordinate system with 'Set Origin' (I like to use the 'Pick 1 Point' option).<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwxZfQRIxkWdqhMJKlcHqAXQRBgA2exeWOlEfKWPu3baFa-xliJ3ji-9gYzn5ScugJK9bNy3bc6F1z_-ONQCTG1goJBiSc3AIJknT7jyPZEqT2G3d5V-RyCmljlGAswthm0QdLeVqQnSv7/s1600/coordinate1.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwxZfQRIxkWdqhMJKlcHqAXQRBgA2exeWOlEfKWPu3baFa-xliJ3ji-9gYzn5ScugJK9bNy3bc6F1z_-ONQCTG1goJBiSc3AIJknT7jyPZEqT2G3d5V-RyCmljlGAswthm0QdLeVqQnSv7/s320/coordinate1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5627880457099218098" /></a><br /><br />Snap the new coordinate datum to the upper left corner of the sketch:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcrMi4CYmmR_E-gagXIvjy0hp1SE12NvC6oi-FjC-ikRMvEvzfG4xTTw_xzGFe_TdX6H02d8xwbJu-fk5wxSmQHHv24TNyKHertNF3bDLR4lXIcsEKvb5kCpiZotwtobx2ZKwvWkjIGzqw/s1600/upper+corner.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcrMi4CYmmR_E-gagXIvjy0hp1SE12NvC6oi-FjC-ikRMvEvzfG4xTTw_xzGFe_TdX6H02d8xwbJu-fk5wxSmQHHv24TNyKHertNF3bDLR4lXIcsEKvb5kCpiZotwtobx2ZKwvWkjIGzqw/s320/upper+corner.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5627885983379858530" /></a><br /><br />Create a 'ScriptOp' operation and copy/paste the new coordinate object into it. Then you can position the ScriptOp operation just before a regular machining operation,such as Profiling. When you post process, the gcode will be shifted by the distance that the new coordinate object is away from the original origin:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmxWRxh2yn_7xRym7__jkHucR1RFH4TaKxUo48Fbl4VVIZNoQwa9hkIHWfHfoVPTS2HcJRvvdv9RMFPpjG3ao6EE49ZbsjB9GOB1eTeAinyuA3TqGP6dzhvep-V8r1sbd748hMCx3-tMi6/s1600/shifted.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmxWRxh2yn_7xRym7__jkHucR1RFH4TaKxUo48Fbl4VVIZNoQwa9hkIHWfHfoVPTS2HcJRvvdv9RMFPpjG3ao6EE49ZbsjB9GOB1eTeAinyuA3TqGP6dzhvep-V8r1sbd748hMCx3-tMi6/s320/shifted.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5627886840946228162" /></a><br /><br />This is useful if you want to place your fixture offset in a familiar place. In the case of this sketch, the fixture offset (G54-G59) is placed in the upper left corner. I like to place a fixture offset on that corner because I touch off to the fixed back jaw of my vise and the left side of the part. There are always other ways of doing things, but that is a common one.<br /><br />Note for my fellow git brothers: I changed nc.py, iso.py, and ScriptOp.cpp to make this happen :)Dan Falckhttp://www.blogger.com/profile/08753782465263326147noreply@blogger.com0tag:blogger.com,1999:blog-1791935642719887324.post-49164557627792283722011-07-09T21:09:00.000-07:002011-07-10T08:48:11.209-07:00Manual Tool Changer CarouselMy Bridgeport CNC mill uses 'Quick Switch 30' tooling. I like it for prototype work- it's easy to change out a tool by hand. All that's required is a spanner wrench at the spindle nose to loosen and tighten the knurled ring. It only takes a quarter turn to secure the tool in the taper. When I bought the mill, it came with a small aluminum plate that had 5 holes in it for holding tools, that could be clamped down to the table. This made it convenient to have 5 tools within reach while running programs. This is not enough for the programs that I am running nowadays. Right now, I have 29 Quick Switch 30 toolholders and I like to use the hell out of them during a program. Sometimes I have 8 different tools in a program.<br />I have been thinking about using an old Heathkit turntable platter that I have had in my stock pile (junk pile) for many years- to make a tool carousel. It's a substantial aluminum casting that's .20" thick in it's cross section and about 11" diameter. It looked like I could put 10 holes in it that would comfortably hold 10 QC 30 tools.<br />I ended up writing a program in HeeksCNC, using scriptop to bore holes with an end mill. It ended up being pretty slick- it descends in a helical motion and then spirals out with an even chip load on the tool. It was kind of fun to write and use.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLIiyuNIFJgHpZGd_Y_YdHBV27mnIsdHRjh-wN1G3zEREarJTPOWhWZUz4FkBe8t0NXZplGe4aV1WxNilpqdvOWoa5RYqsxzySozSKN-IQ8iBdOhEwkdX9L6uGoQEJsjEzEbMDPtiCHuRG/s1600/helical+array.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLIiyuNIFJgHpZGd_Y_YdHBV27mnIsdHRjh-wN1G3zEREarJTPOWhWZUz4FkBe8t0NXZplGe4aV1WxNilpqdvOWoa5RYqsxzySozSKN-IQ8iBdOhEwkdX9L6uGoQEJsjEzEbMDPtiCHuRG/s320/helical+array.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5627581682921137378" /></a><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzsb9_di_FzEur_pSgndxbkkiAycXeaI8-fBuJvoQDxyw7hFHtcQdtkctssV-QJCyPcbnzJWalc9h5Yqhmqm8BkSnvw5-gdpsNJMKs3fP5Pn9xgDbzeT8NIa5600oOEgWXedXlG6OYjicU/s1600/IMAG1338.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzsb9_di_FzEur_pSgndxbkkiAycXeaI8-fBuJvoQDxyw7hFHtcQdtkctssV-QJCyPcbnzJWalc9h5Yqhmqm8BkSnvw5-gdpsNJMKs3fP5Pn9xgDbzeT8NIa5600oOEgWXedXlG6OYjicU/s320/IMAG1338.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5627695823602322418" /></a><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEih8Fl50O7H9SYBoeZgezVqFnUfDdrBfS6KmHIPcVRS4QA0bmHJxWVKdSwhukE6bFz1v5YmfvdeRcUD8nPEfQtrDf9xbou3xuz1dV3IkxYtJlLQrbiyg5rR9v4skM8VczjiRWKWCWOhTfae/s1600/IMAG1341.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEih8Fl50O7H9SYBoeZgezVqFnUfDdrBfS6KmHIPcVRS4QA0bmHJxWVKdSwhukE6bFz1v5YmfvdeRcUD8nPEfQtrDf9xbou3xuz1dV3IkxYtJlLQrbiyg5rR9v4skM8VczjiRWKWCWOhTfae/s320/IMAG1341.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5627695825306170850" /></a><br /><br />Here's a link to my 'array_of_holes.heeks' file that was used for this project:<br />https://github.com/danielfalck/heekscnc/blob/master/contrib/scriptop/array_of_holes.heeksDan Falckhttp://www.blogger.com/profile/08753782465263326147noreply@blogger.com0tag:blogger.com,1999:blog-1791935642719887324.post-45360094852208719822011-07-01T18:28:00.000-07:002011-07-01T18:32:03.527-07:00Creating a rectangle with radiused corners (fillets)I am just copy pasting this in from a reply to a question on the heekscad user's list on google groups. This might be helpful to some.<br /><br /><div id="qhide_35305" style="display: block;" class="qt"><br />Q: How do I create a rectangular cut-out, but with rounded<br />corners?<br /><br /></div>A: Doing a rectangle with fillets in heekscad is pretty easy- use the sketch toolbar and look for the icon that is square- the tooltip for this is 'Start drawing rectangles'. After you select this, a box with appear in the left hand column of HeeksCAD that is titled 'input'. There is an entry for 'radius'. It might not work for you on the first try, so fill it in with a radius value and attempt to draw your rectangle on the screen. If your rectangle doesn't have fillets, right click with the mouse 'stop drawing' and then try making the rectangle all over again- then your fillet/radius values should stick this time.Dan Falckhttp://www.blogger.com/profile/08753782465263326147noreply@blogger.com0tag:blogger.com,1999:blog-1791935642719887324.post-51577768582860744042011-05-22T07:24:00.000-07:002011-05-22T08:27:06.530-07:00Cutter Radius CompensationI do a lot of milling in my home shop with my CNC Bridgeport mill. This machine has a Centroid M40 control on it that works pretty well. It has a feature called 'cutter radius compensation' in it that is standard on most modern controls. This allows for variations in cutter size or cutting conditions such that the machine operator (me) can make the toolpath run closer or further from the part profile. Cutter radius compensation is a subject that is covered pretty well in cnc programming textbooks, so I won't get into it much here, except to mention a few things about programming to 'part profile' or programming to 'cutter centerline'. Over 20 years ago, I was taught to program a part to 'part profile' like this, when using cutter radius comp:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6nwIBul4Zn31m4U0_hvr5R5u4ybI5Z9lVQP10M5B37pB_nDOhSrqqgjmmbb-Wlx612TAMxdPyx3BTijGAqlyqgFE3M_-0CCAojPOB2H-dOKjwDziNNif9KfRtFQ9iFPDC4tdrxXBoWZll/s1600/crc_2.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 130px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6nwIBul4Zn31m4U0_hvr5R5u4ybI5Z9lVQP10M5B37pB_nDOhSrqqgjmmbb-Wlx612TAMxdPyx3BTijGAqlyqgFE3M_-0CCAojPOB2H-dOKjwDziNNif9KfRtFQ9iFPDC4tdrxXBoWZll/s320/crc_2.png" alt="" id="BLOGGER_PHOTO_ID_5609556308389425762" border="0" /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCUXbPzAJUVqz4gvJ80whv84uFlgRX0ubS0NQmBUXlIeVbnKduaGX6vIbtkkmrY7btV5i0lqKOhu7VDrRujEPzltZqR-dmj2Ukq51sHi08Bmz6mNp3T4MGHPvlDDmnHvZ3mP3Gc34Asb-9/s1600/crc_1.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 209px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCUXbPzAJUVqz4gvJ80whv84uFlgRX0ubS0NQmBUXlIeVbnKduaGX6vIbtkkmrY7btV5i0lqKOhu7VDrRujEPzltZqR-dmj2Ukq51sHi08Bmz6mNp3T4MGHPvlDDmnHvZ3mP3Gc34Asb-9/s320/crc_1.png" alt="" id="BLOGGER_PHOTO_ID_5609556305111758898" border="0" /></a><br /><br />Using this method, it's easy to look at a blueprint and just write the program by hand. You can just enter the end points and center points of lines and radius' and add a G41 (or G42) to your code. Once the program is done,it's pretty intuitive to change the diameter value in the control to the actual diameter of the cutter and get a reasonable part milled. If your end mill is .499 inches in diameter, just enter that as the D value in your control. If you want to make the part a bit bigger all around, enter the value as .501 and 'trick' the control into moving the path away from the part profile. With just a little simple math, done in your head, it's easy to manipulate the size of the part.<br /><br />After moving across the country, to the west coast, I was taught a different way of using cutter radius compensation. A part programmer can use a CAM system to make the cutter path the radius value of the cutter away from the part profile and then use very small values in the D value of the control to manipulate the size of the part.<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBr51lh2ADG6G4NEs3ADgAoLXrYew6AUyPMVsJ0ZXuHhgsVJ395PejLysRvbjggkvXFDcdfkhQFXFxKkiYhb_pXZHhXIkGECEg3tmUCplQOGBMpInmPlfoeAwKCkasqmWlYZ9yDYbSMPUC/s1600/crc_4.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 228px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBr51lh2ADG6G4NEs3ADgAoLXrYew6AUyPMVsJ0ZXuHhgsVJ395PejLysRvbjggkvXFDcdfkhQFXFxKkiYhb_pXZHhXIkGECEg3tmUCplQOGBMpInmPlfoeAwKCkasqmWlYZ9yDYbSMPUC/s320/crc_4.png" alt="" id="BLOGGER_PHOTO_ID_5609558550894448658" border="0" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj8K_GyUHtOHPv0FE454aPJBq1UoHixV8jkaXKPQUGnIWtbvl4dId7XB_PnlB5M9vTnBFJVPZcLwkf2zMYE8iqAnvxYzDOszlCFfXOJm1n-G_3BpySGYerbRlvXY_tu8G7_NkS1EW8ocMg/s1600/crc_3.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 171px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj8K_GyUHtOHPv0FE454aPJBq1UoHixV8jkaXKPQUGnIWtbvl4dId7XB_PnlB5M9vTnBFJVPZcLwkf2zMYE8iqAnvxYzDOszlCFfXOJm1n-G_3BpySGYerbRlvXY_tu8G7_NkS1EW8ocMg/s320/crc_3.png" alt="" id="BLOGGER_PHOTO_ID_5609558548696406130" border="0" /></a><br />The cutter value can be .000" to be 'on the line' and you can change it by .001" or -.001" to manipulate the part profile.<br />I guess you could call this the 'West Coast' method. Nowadays, I am using this method with my home shop mill. I've just gotten used to it. I'm using my Centroid post processor with HeeksCNC and things work well for this. In the post, there is a bit of code that adds a lead in line to the roll on radius. This is needed to give the control a bit of distance to move the cutter before it reaches an arc, while doing the cutter compensation. If I don't have a straight line on the first line of a crc move, the control gives an error. It works the same way on the lead out line just after the roll off radius. I don't think EMC2 works this way- I think you can start with a roll on radius with a crc command, without getting an error. This seems to be an exception in the cnc control world though. Most commercial controls expect a straight line.Dan Falckhttp://www.blogger.com/profile/08753782465263326147noreply@blogger.com0tag:blogger.com,1999:blog-1791935642719887324.post-20107712427646777522010-11-05T13:53:00.001-07:002010-11-06T08:59:46.829-07:00Creating Cross Sections of Parts in HeeksPythonOk, I worked out a scheme for creating a cross sectional view of a simple assembly in HeeksPython. I altered my dxf_to_heekspython script slightly to let the sketches have unique IDs. Then it's possible to create objects out of them and do CSG operations to the unique objects.<br />Here is a sample script:<br /><br /><span style="color: rgb(51, 102, 255);">import HeeksPython as cad</span><br /><span style="color: rgb(51, 102, 255);">import sys</span><br /><span style="color: rgb(51, 102, 255);">sys.path.insert(0,'/home/dan/heeks/heekspython2/examples')</span><br /><span style="color: rgb(51, 102, 255);">import dxf_to_heekspython</span><br /><span style="color: rgb(51, 102, 255);">from math import pi</span><br /><br /><span style="color: rgb(51, 102, 255);">a1 = 90*(pi/180)</span><br /><br /><br /><span style="color: rgb(51, 102, 255);">units = 25.4 #inch units</span><br /><span style="color: rgb(51, 102, 255);">cad.setcolor(255,255,255)</span><br /><span style="color: rgb(51, 102, 255);">r1='/home/dan/Documents/drawings/revolve1.dxf'</span><br /><span style="color: rgb(51, 102, 255);">part1 = "cad.setcolor(0,0,0)\n"</span><br /><span style="color: rgb(51, 102, 255);">part1 = dxf_to_heekspython.gen_heekspython_entities(r1,1)</span><br /><span style="color: rgb(51, 102, 255);">part1 = part1 +"cad.scale(sketch1,0,0,0,units)\n"</span><br /><span style="color: rgb(51, 102, 255);">part1 = part1 +"cad.setcolor(255,255,255)\n"</span><br /><span style="color: rgb(51, 102, 255);">part1 = part1 +"cad.revolve(sketch1,360)\n"</span><br /><span style="color: rgb(51, 102, 255);">part1 = part1 +"cup = cad.getlastobj()\n"</span><br /><span style="color: rgb(51, 102, 255);">exec(part1)</span><br /><span style="color: rgb(51, 102, 255);">cad.setcolor(0,255,0)</span><br /><span style="color: rgb(51, 102, 255);">r2='/home/dan/Documents/drawings/revolve2.dxf'</span><br /><span style="color: rgb(51, 102, 255);">part2 = "cad.setcolor(0,0,0)\n"</span><br /><span style="color: rgb(51, 102, 255);">part2 = dxf_to_heekspython.gen_heekspython_entities(r2,2)</span><br /><span style="color: rgb(51, 102, 255);">part2 = part2 +"cad.scale(sketch2,0,0,0,units)\n"</span><br /><span style="color: rgb(51, 102, 255);">part2 = part2 +"cad.setcolor(0,255,0)\n"</span><br /><span style="color: rgb(51, 102, 255);">part2 = part2 +"cad.revolve(sketch2,360)\n"</span><br /><span style="color: rgb(51, 102, 255);">part2 = part2 +"sleeve = cad.getlastobj()\n"</span><br /><span style="color: rgb(51, 102, 255);">exec(part2)</span><br /><br /><span style="color: rgb(51, 102, 255);">cad.view_extents()</span><br /><br /><span style="color: rgb(51, 102, 255);">c1= '/home/dan/Documents/drawings/cutaway.dxf'</span><br /><span style="color: rgb(51, 102, 255);">cut = dxf_to_heekspython.gen_heekspython_entities(c1,3)</span><br /><span style="color: rgb(51, 102, 255);">cut = cut + "cad.scale(sketch3,0,0,0,units)\n"</span><br /><span style="color: rgb(51, 102, 255);">cut = cut + "cad.revolve(sketch3,90)\n"</span><br /><span style="color: rgb(51, 102, 255);">cut = cut + "cutter = cad.getlastobj()\n"</span><br /><span style="color: rgb(51, 102, 255);">cut = cut + "cad.rotate(cutter,0,0,0,1,0,0,a1)"</span><br /><span style="color: rgb(51, 102, 255);">exec(cut)</span><br /><br /><span style="color: rgb(51, 102, 255);">cad.cut(cup,cutter)</span><br /><span style="color: rgb(51, 102, 255);">cad.cut(sleeve,cutter)</span><br /><span style="color: rgb(51, 102, 255);"></span><br />Here is the assembly:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiD18fya5AWLA3GgUOfFz3d8UbYncpC_ewTfOoHu9YFcp00KTNsw-G7ERpbUKa2QuNs4BeoGPJqLAF6MiqTcGAL1MEvNmigL55FOXsz6jqPB6hc6B8rivQd6qzNWsrepH8sNGUYIxm8tp5q/s1600/cross_section.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiD18fya5AWLA3GgUOfFz3d8UbYncpC_ewTfOoHu9YFcp00KTNsw-G7ERpbUKa2QuNs4BeoGPJqLAF6MiqTcGAL1MEvNmigL55FOXsz6jqPB6hc6B8rivQd6qzNWsrepH8sNGUYIxm8tp5q/s320/cross_section.png" alt="" id="BLOGGER_PHOTO_ID_5536172760737769842" border="0" /></a><br />Just prior to importing these dxf files into HeeksPython I had also added fillets to all the corners in <a href="http://www.caduntu.org/">Caduntu</a> (yes, this works well now Ries!). So now I can work in my favorite 2D CAD program and my favorite 3D CADCAM program to create assemblies with python.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGpACe1HDQ3_uwVwiLSLryjeXKs7B4acgA_sT4syQ2nozrtpWdZW68K2aCx7cPuCYc1fscalL9hAKSzwVqxoO6UpFaX3ARUtzn9f8mkSvAIMM5tfUCZTFWlbQVTh9-quG29NfOe0RjAIfB/s1600/caduntu1.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGpACe1HDQ3_uwVwiLSLryjeXKs7B4acgA_sT4syQ2nozrtpWdZW68K2aCx7cPuCYc1fscalL9hAKSzwVqxoO6UpFaX3ARUtzn9f8mkSvAIMM5tfUCZTFWlbQVTh9-quG29NfOe0RjAIfB/s320/caduntu1.png" alt="" id="BLOGGER_PHOTO_ID_5536177115276059746" border="0" /></a><br />It's easy to alter the design of the parts in this assembly by simply changing them in the dxf files:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyhAzJ4NVzOPBwKlm-KQSMPHSfowXaCg9Kspn4Hk8ve1RcnpW3mF2t3R_m45hgDhIzx9rR7ZHm5C7c3-kG3X72Wx5CGG0Et4-QCLDE2_IyfWa7dz6ww7C_piBgpiCo4BEowdmWrWy7kCC2/s1600/caduntu.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyhAzJ4NVzOPBwKlm-KQSMPHSfowXaCg9Kspn4Hk8ve1RcnpW3mF2t3R_m45hgDhIzx9rR7ZHm5C7c3-kG3X72Wx5CGG0Et4-QCLDE2_IyfWa7dz6ww7C_piBgpiCo4BEowdmWrWy7kCC2/s320/caduntu.png" alt="" id="BLOGGER_PHOTO_ID_5536462009057958194" border="0" /></a><br /><br />Then re run the python script in HeeksPython:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBqhLsNJcWNo9fWjL0nQazLM59te8EblwJKwjqN_P-optbnJD4JTL6xMiYH_iIo85UWaQDhwxsudCpWmVLDscCgvQqfrcJAeCYpYV5mJ0FGv4kCC3LYr_i48NAitOha0lM-qpwGhu3FWdh/s1600/assembly.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBqhLsNJcWNo9fWjL0nQazLM59te8EblwJKwjqN_P-optbnJD4JTL6xMiYH_iIo85UWaQDhwxsudCpWmVLDscCgvQqfrcJAeCYpYV5mJ0FGv4kCC3LYr_i48NAitOha0lM-qpwGhu3FWdh/s320/assembly.png" alt="" id="BLOGGER_PHOTO_ID_5536462224068511762" border="0" /></a><br /><br />One major improvement that I would like to do is to make the dxf_to_heekspython script deal with layers. Then I could do all the dxf editing in one file in Caduntu.<br />As I learn more about C++ programming, I might be able to utilize the functions in dxf.cpp from HeeksCAD itself. Importing would run much faster and I could take advantage of the things that already work well, like layers and importing polylines (which isn't currently implemented in the python script).Dan Falckhttp://www.blogger.com/profile/08753782465263326147noreply@blogger.com0tag:blogger.com,1999:blog-1791935642719887324.post-63355742673081654242010-11-05T10:50:00.000-07:002010-11-05T12:02:33.078-07:00More DXF to HeeksPython ExperimentsI created a python script to import a dxf file into HeeksPython, using parts of Doug Blanding's excellent python program 'Cadvas'. Doug and I have emailed back and forth over the years and he is happy to see his creation used for different things. He's not supporting it anymore, but in it's present state, it's a very good program to study. It's very simple and well laid out.<br />Included with Cadvas is the dxf.py module. I have copied some of it and altered it to suite my needs for dxf to heekspython conversion and uploaded the script into the /examples directory in the HeeksPython project. This script is called dxf_to_heekspython.py. Here are two profiles created in Qcad, that I want to manipulate in HeeksPython:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6kNgkTqLgXtItBJ5XUbdxehF0TodYHCoFIGy3KrBxhvzEYvWihRFxpvaMXt4ZDs_d06HdCY_pHQ_aSJwghCKaCxFayL_mY_8g_BOqimyBD7eUXxPsc2ChPB5DLs9uDRv94ATrEbtsk2s4/s1600/revolve1.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6kNgkTqLgXtItBJ5XUbdxehF0TodYHCoFIGy3KrBxhvzEYvWihRFxpvaMXt4ZDs_d06HdCY_pHQ_aSJwghCKaCxFayL_mY_8g_BOqimyBD7eUXxPsc2ChPB5DLs9uDRv94ATrEbtsk2s4/s200/revolve1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5536142402498935154" /></a><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKOdFb2XK2M19Sa8riY2KU9YBkMDG_O8D1Q0kaNKyWsI6Cdr3z4VdXazisgL3Fj0-BZXAV87Mzn5N5DkAt9mNZPU455M6nD8oAkKVJk5wXc97mqztcjQKcfxNVcIPoM9MjdHcJ9LA5-EBx/s1600/revolve2.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKOdFb2XK2M19Sa8riY2KU9YBkMDG_O8D1Q0kaNKyWsI6Cdr3z4VdXazisgL3Fj0-BZXAV87Mzn5N5DkAt9mNZPU455M6nD8oAkKVJk5wXc97mqztcjQKcfxNVcIPoM9MjdHcJ9LA5-EBx/s200/revolve2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5536142527557407570" /></a><br /><br />Here is a script to bring them into HeeksPython as separate revolved solid parts:<br /><br /><span style="color: rgb(51, 102, 255);">import HeeksPython as cad<br />import sys<br />sys.path.insert(0,'/home/dan/heeks/heekspython2/examples')<br />import dxf_to_heekspython<br /><br /><br />units = 25.4 #inch units<br />cad.setcolor(255,255,255)<br />r1='/home/dan/Documents/drawings/revolve1.dxf'<br />part1 = "cad.setcolor(0,0,0)\n"<br />part1 = dxf_to_heekspython.gen_heekspython_entities(r1)<br />part1 = part1 +"cad.scale(sketch,0,0,0,units)\n"<br />part1 = part1 +"cad.setcolor(255,255,255)\n"<br />part1 = part1 +"cad.revolve(sketch,360)"<br />exec(part1)<br />cad.setcolor(0,255,0)<br />r2='/home/dan/Documents/drawings/revolve2.dxf'<br />part2 = "cad.setcolor(0,0,0)\n"<br />part2 = dxf_to_heekspython.gen_heekspython_entities(r2)<br />part2 = part2 +"cad.scale(sketch,0,0,0,units)\n"<br />part2 = part2 +"cad.setcolor(0,255,0)\n"<br />part2 = part2 +"cad.revolve(sketch,360)\n"<br />part2 = part2 +"p1 = cad.getlastobj()\n"<br />exec(part2)<br /><br />cad.view_extents()</span><br />Here is a screenshot of the resulting parts generated with this script:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgB-GOp2Z5TVbR2qfvvOBOLLwxXmQ_7M3tC_exrAqyf0wMjoEuVNibBQEBZOk8xFZofNYUqgrsj6dmPPKwyB6QUGcPDEimj-5u32u4-WNwRDLQRP2HqqL1txY1ksAtb5z7EYoCgn0EKb8sx/s1600/dxf_to_heekspython.png"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgB-GOp2Z5TVbR2qfvvOBOLLwxXmQ_7M3tC_exrAqyf0wMjoEuVNibBQEBZOk8xFZofNYUqgrsj6dmPPKwyB6QUGcPDEimj-5u32u4-WNwRDLQRP2HqqL1txY1ksAtb5z7EYoCgn0EKb8sx/s320/dxf_to_heekspython.png" alt="" id="BLOGGER_PHOTO_ID_5536138647788971506" border="0" /></a><br /><br />The advantage of using this dxf_to_heekspython is that the dxf entities can be manipulated/transformed as they are brought in. I have some things that I would like to do with some dxf files - create solids by revolving them around the X axis. Eventually I will create cutaway views using this technique.Dan Falckhttp://www.blogger.com/profile/08753782465263326147noreply@blogger.com0tag:blogger.com,1999:blog-1791935642719887324.post-55718237856181646422010-10-29T09:35:00.000-07:002010-11-06T08:57:33.371-07:00Well, it's been quite a long since I posted anything (obviously). I've been busy trying to learn a bit of C++ coding, in my quest to learn the ins and outs of HeeksCAD,HeeksCNC, and HeeksPython.<br />I am mostly doing the 'learn by example' route, plus a few good tutorials, books, and some very helpful advice from Dan Heeks himself. If I get into a bind, he usually can point to some example code that helps me understand things.<br />I have been able to add quite a few new functions to HeeksPython and a few things to HeeksCAD itself. HeeksPython is fun to add functions to, because there is a lot of 'low hanging fruit' so to speak. It's pretty easy to add a python binding to HeeksCAD, if there is already a C++ function in /interface/HeeksCADInterface.cpp . I started out by copying jonpry's existing functions ('NewArc', 'NewLine' etc). As I have gotten a little more experience, I have gotten more adventurous and added functions for deriving point data from the GraphicsCanvas itself. I also found a way of adding fillets to pairs of 2D lines. Over the last month, I have added ways of creating a new coordinate system,returning the parameters of coordinate systems,text,and a way of importing dxf files from python.<br />The HeeksPython function 'importdxf' is exiting for me because I have plans for creating solids quickly with the aid of other 2D cad programs like caduntu , qcad, or even true-type-tracer-dxf. Having HeeksPython loaded with functionality will help automate the design process somewhat.<br />Here is an example of a script that uses <a href="http://www.timeguy.com/cradek/truetype">true-type-tracer-dxf </a>to create some text on the HeeksCAD graphics screen:<br /><br /><div style="text-align: left; color: rgb(51, 102, 255);">import os<br />import HeeksPython as cad<br /><br />path = '''/home/dan/Documents/drawings/ttt/'''<br />program = '''truetype-tracer-dxf'''<br />phrase = ''' \' this is a test \' '''<br />pipe = ''' > '''<br />file = '''aphrase.dxf'''<br /><br />out = program + phrase + pipe + path + file<br />os.system(out)<br /><br />f = path + file<br /><br />cad.importdxf(f)<br />cad.view_extents()<br /></div>Dan Falckhttp://www.blogger.com/profile/08753782465263326147noreply@blogger.com0