Skip to content

Commit

Permalink
Merge pull request #13 from flux3dp/dev
Browse files Browse the repository at this point in the history
Release 0.8b4
  • Loading branch information
yen-von committed Jan 5, 2016
2 parents 1504111 + 52aee42 commit ba94385
Show file tree
Hide file tree
Showing 76 changed files with 1,282 additions and 21,564 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,9 @@ fluxclient contains all toolsets to control FLUX 3D Printer

* Pillow
`pip install Pillow`

* Numpy
`pip install numpy`

* Scipy
`pip install scipy`
4 changes: 2 additions & 2 deletions fluxclient/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ def check_pcl():
try:
from .scanner import _scanner
return True
except ImportError:
except (ImportError, AttributeError):
return False


__version__ = "0.7a5"
__version__ = "0.8b4"
SUPPORT_PCL = check_pcl()
Binary file added fluxclient/assets/grid.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion fluxclient/commands/experiment_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import numpy as np

from fluxclient.scanner.pc_process import PcProcess
from fluxclient.scanner.scan_settings import ScanSetting
from fluxclient.scanner.tools import read_pcd, write_stl, write_pcd
from fluxclient.scanner.pc_process import PcProcess

Expand All @@ -17,7 +18,7 @@ def show_pc(name, pc_in):


def main(in_file, out_file, command=''):
_PcProcess = PcProcess()
_PcProcess = PcProcess(ScanSetting())
tmp = out_file.rfind('.')
prefix, suffix = out_file[:tmp], out_file[tmp + 1:]
print('out_file', prefix, suffix)
Expand Down
5 changes: 4 additions & 1 deletion fluxclient/fcode/fcode_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ def __init__(self):
super(FcodeBase, self).__init__()
self.filament_this_layer = [0., 0., 0.]
self.empty_layer = []
self.counter_between_layers = 0

def process_path(self, comment, moveflag, extrudeflag):
"""
convert to path list(for visualizing)
"""
# TODO?: reconsider if theese two flag necessary
self.counter_between_layers += 1
if moveflag:
if 'infill' in comment:
line_type = 0
Expand All @@ -27,9 +29,10 @@ def process_path(self, comment, moveflag, extrudeflag):
elif 'move' in comment:
line_type = 3
if 'to next layer' in comment:
if self.filament == self.filament_this_layer:
if self.filament == self.filament_this_layer and self.counter_between_layers > 1:
self.empty_layer.append(self.layer_now)
tmp = findall('[0-9]+', comment)[-1]
self.counter_between_layers = 0
self.layer_now = int(tmp)
self.path.append([self.path[-1][-1][:3] + [line_type]])
self.filament_this_layer = self.filament[:]
Expand Down
62 changes: 41 additions & 21 deletions fluxclient/fcode/g_to_f.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@ def __init__(self, version=1, head_type="EXTRUDER", ext_metadata={}):
self.distance = 0. # recording distance go through
self.max_range = [0., 0., 0., 0.] # recording max coordinate, [x, y, z, r]
self.filament = [0., 0., 0.] # recording the filament needed, in mm
self.previous = [0., 0., 0.] # recording previous filament/path
self.md = {'HEAD_TYPE': head_type} # basic metadata, use extruder as default
self.md.update(ext_metadata)

self.record_path = True
self.record_z = 0.0
self.layer_now = 0
self.path = [[[0.0, 0.0, HW_PROFILE['model-1']['height'], 3]]] # recording the path extruder go through

# self.path = [layers], layer = [points], point = [X, Y, Z, path type]

self.config = None
Expand Down Expand Up @@ -112,17 +114,6 @@ def analyze_metadata(self, input_list, comment):
if input_list[0] is not None:
self.current_speed = input_list[0]

extrudeflag = False
for i in range(4, 7): # extruder
if input_list[i] is not None:
extrudeflag = True
if self.absolute:
self.filament[i - 4] += input_list[i] - self.current_pos[i - 1]
self.current_pos[i - 1] = input_list[i]
else:
self.filament[i - 4] += input_list[i]
self.current_pos[i - 1] += input_list[i]

tmp_path = 0.
moveflag = False # record if position change in this command
for i in range(1, 4): # position
Expand All @@ -135,16 +126,41 @@ def analyze_metadata(self, input_list, comment):
tmp_path += (input_list[i] ** 2)
self.current_pos[i - 1] += input_list[i]
if abs(self.current_pos[i - 1]) > self.max_range[i - 1]:
# self.max_range[i - 1] = abs(self.current_pos[i - 1])
self.max_range[i - 1] = self.current_pos[i - 1]
if self.current_pos[0] ** 2 + self.current_pos[1] ** 2: # computer MAX_R
if self.current_pos[0] ** 2 + self.current_pos[1] ** 2 > self.max_range[3]: # computer MAX_R
self.max_range[3] = self.current_pos[0] ** 2 + self.current_pos[1] ** 2
tmp_path = sqrt(tmp_path)

extrudeflag = False
for i in range(4, 7): # extruder
if input_list[i] is not None:
extrudeflag = True
if self.absolute:
if self.config is not None and self.config['flux_refill_empty'] == '1' and tmp_path != 0:
if input_list[i] - self.current_pos[i - 1] == 0:
input_list[i] = self.previous[i - 4] * tmp_path + self.current_pos[i - 1]
self.G92_delta[i - 1] += self.previous[i - 4] * tmp_path
else:
self.previous[i - 4] = (input_list[i] - self.current_pos[i - 1]) / tmp_path

self.filament[i - 4] += input_list[i] - self.current_pos[i - 1]
self.current_pos[i - 1] = input_list[i]
else:
if self.config is not None and self.config['flux_refill_empty'] == '1' and tmp_path != 0:
if input_list[i] == 0:
input_list[i] = self.previous[i - 4] * tmp_path
else:
self.previous[i - 4] = input_list[i] / tmp_path

self.filament[i - 4] += input_list[i]
self.current_pos[i - 1] += input_list[i]

self.distance += tmp_path
self.time_need += tmp_path / self.current_speed * 60 # from minute to sec
# fill in self.path
if self.record_path:
self.process_path(comment, moveflag, extrudeflag)
return input_list

def writer(self, buf, stream):
"""
Expand Down Expand Up @@ -185,11 +201,12 @@ def process(self, input_stream, output_stream):
data[i] += self.G92_delta[i - 1]

# # fix on slic3r bug slowing down in raft but not in real printing
# if self.config is not None and self.layer_now == int(self.config['raft_layers']):
# data[0] = float(self.config['first_layer_speed']) * 60
# subcommand |= (1 << 6)
if self.config is not None and self.config['flux_first_layer'] == '1' and self.layer_now == int(self.config['raft_layers']):
print('hi')
data[0] = float(self.config['first_layer_speed']) * 60
subcommand |= (1 << 6)

self.analyze_metadata(data, comment)
data = self.analyze_metadata(data, comment)
command |= subcommand
self.writer(packer(command), output_stream)

Expand Down Expand Up @@ -298,19 +315,22 @@ def process(self, input_stream, output_stream):
output_stream.write(struct.pack('<I', self.script_length))
output_stream.seek(0, 2) # go back to file end

# warning: fileformat didn't consider multi-extruder, use first extruder instead
if self.empty_layer[0] == 0:
if len(self.empty_layer) > 0 and self.empty_layer[0] == 0:
self.empty_layer.pop(0)

# warning: fileformat didn't consider multi-extruder, use first extruder instead
self.md['FILAMENT_USED'] = ','.join(map(str, self.filament))
self.md['TRAVEL_DIST'] = str(self.distance)

for v, k in enumerate(['Z', 'Y', 'Z', 'R']):
self.max_range[3] = sqrt(self.max_range[3])
for v, k in enumerate(['X', 'Y', 'Z', 'R']):
self.md['MAX_' + k] = str(self.max_range[v])

self.md['TIME_COST'] = str(self.time_need)
self.md['CREATED_AT'] = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.localtime(time.time()))
self.md['AUTHOR'] = getuser() # TODO: use fluxstudio user name?
self.md['SETTING'] = str(comment_list[-130:])
if self.md['HEAD_TYPE'] == 'EXTRUDER':
self.md['SETTING'] = str(comment_list[-130:])
self.write_metadata(output_stream)
except Exception as e:
print('FcodeError:', file=sys.stderr)
Expand Down
2 changes: 1 addition & 1 deletion fluxclient/hw_profile/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
HW_PROFILE = {
'model-1': {
'radius': 17.,
'radius': 85.,
'scan_full_len': 360.,
'height': 240.,
# 'step_setting': {400: (3, 2.7), 800: (7, 3.15)}
Expand Down
1 change: 0 additions & 1 deletion fluxclient/laser/__init__.py

Large diffs are not rendered by default.

54 changes: 26 additions & 28 deletions fluxclient/laser/laser_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from PIL import Image
import numpy as np
from fluxclient.fcode.g_to_f import GcodeToFcode
from . import Grid
import pkg_resources


class LaserBase(object):
Expand Down Expand Up @@ -61,14 +61,15 @@ def header(self, header):
gcode.append(";" + i)

# force close laser
self.laser_on = False
self.laser_on = True
gcode += self.turnOff()

# setting
gcode += ["X3F3", "X3F2", "X3F1"]

# move to proper height
gcode.append("G1 F5000 Z%.5f" % (self.focal_l + self.obj_height))

return gcode

def turnOn(self):
Expand Down Expand Up @@ -213,7 +214,7 @@ def rotate(x, y, rotation, cx=0., cy=0.):
return x, y

pix = Image.frombytes('L', (img_width, img_height), buffer_data)
# pix.save('tmp.png', 'png')
# pix.save('get.png', 'png')

# image center (rotation center)
cx = (x1 + x2) / 2.
Expand All @@ -223,8 +224,11 @@ def rotate(x, y, rotation, cx=0., cy=0.):
ox1, oy1 = rotate(x1, y1, -rotation, cx, cy)
ox3, oy3 = rotate(x2, y2, -rotation, cx, cy)

# 1 4
# 2 3
ox2, oy2 = ox1, oy3
ox4, oy4 = ox3, oy1
pix = pix.resize(tuple(map(lambda x: int(x * self.pixel_per_mm), ((ox3 - ox1), (oy1 - oy3)))))

# rotate four corner
ox1, oy1 = rotate(ox1, oy1, rotation, cx, cy)
Expand All @@ -235,6 +239,7 @@ def rotate(x, y, rotation, cx=0., cy=0.):
# find upper-left corner after rotation(edge)
gx1 = min(ox1, ox2, ox3, ox4)
gy1 = max(oy1, oy2, oy3, oy4)

gy1_on_map = round((gx1 / self.radius * len(self.image_map) / 2.) + (len(self.image_map) / 2.))
gx1_on_map = round(-(gy1 / self.radius * len(self.image_map) / 2.) + (len(self.image_map) / 2.))

Expand All @@ -243,54 +248,47 @@ def rotate(x, y, rotation, cx=0., cy=0.):
gy2_on_map = round((gx2 / self.radius * len(self.image_map) / 2.) + (len(self.image_map) / 2.))
gx2_on_map = round(-(gy2 / self.radius * len(self.image_map) / 2.) + (len(self.image_map) / 2.))

# shrink size if image too big, to avoid white frame disappear
if pix.size[0] >= len(self.image_map) or pix.size[1] >= len(self.image_map):
if pix.size[0] >= pix.size[1]:
new_size = (len(self.image_map), len(self.image_map) * pix.size[1] // pix.size[0])
else:
new_size = (len(self.image_map) * pix.size[0] // pix.size[1], len(self.image_map))
pix = pix.resize(new_size)

# add white frame on each side
new_pix = Image.new('L', (pix.size[0] + 2, pix.size[1] + 2), 255)
new_pix.paste(pix, (1, 1))
new_pix = new_pix.rotate(degrees(rotation), expand=1)

new_pix = new_pix.resize((gy2_on_map - gy1_on_map, gx2_on_map - gx1_on_map))
for h in range(new_pix.size[1]):
# using white frame to find starting and ending index
# find_start, find_end for each row
flag = False # whether find white frame
flag1 = False # whether find white frame
for find_s in range(new_pix.size[0]):
if new_pix.getpixel((find_s, h)) > 0:
if new_pix.getpixel((find_s, h)) > 0: # check this thres?
find_s = find_s + 1
flag = True
flag1 = True
break
if not flag:
find_s = new_pix.size[0]

flag = False
flag2 = False
for find_e in range(new_pix.size[0] - 1, -1, -1):
if new_pix.getpixel((find_e, h)) > 0:
flag = True
find_e = find_e
flag2 = True
break
if not flag:
find_e = 0

for w in range(find_s, find_e):
if (gx1_on_map + h - len(self.image_map) / 2.) ** 2 + (gy1_on_map + w - len(self.image_map) / 2.) ** 2 < (len(self.image_map) / 2.) ** 2:
if new_pix.getpixel((w, h)) <= thres:
self.image_map[gx1_on_map + h][gy1_on_map + w] = new_pix.getpixel((w, h))
# only one white point in this row(cause by resizing)
# if find_e < find_s and abs(h - (new_pix.size[1] / 2)) > 1:
# find_e = new_pix.size[0]

# NOTE: flag1 always equal to flag2
if flag1: # at least one white point in this row
for w in range(find_s, find_e):
if (gx1_on_map + h - len(self.image_map) / 2.) ** 2 + (gy1_on_map + w - len(self.image_map) / 2.) ** 2 < (len(self.image_map) / 2.) ** 2:
if new_pix.getpixel((w, h)) <= thres:
self.image_map[gx1_on_map + h][gy1_on_map + w] = new_pix.getpixel((w, h))

def dump(self, file_name='', mode='save'):
"""
dump the image of this laser class
"""
img = Image.fromarray(self.image_map)
tmp = io.BytesIO()
tmp.write(Grid) # TODO: change file path
grid = pkg_resources.resource_filename("fluxclient", "assets/grid.png")
# magic number just for alignment, don't really important
img_background = Image.open(tmp).resize((img.size[0] + 66, img.size[1] + 66))
img_background = Image.open(grid).resize((img.size[0] + 66, img.size[1] + 66))
img_background.paste(img, (33, 33), img.point(lambda x: 255 if x < 255 else 0))
img = img_background
if mode == 'save':
Expand Down
7 changes: 5 additions & 2 deletions fluxclient/laser/laser_bitmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from math import pi, sin, cos, degrees
import logging
from os import environ

import numpy as np
from PIL import Image
Expand Down Expand Up @@ -90,11 +91,13 @@ def gcode_generate(self, res=1):
gcode += self.turnOff()

gcode += self.turnOff()
gcode += ["G28"]
gcode = "\n".join(gcode) + "\n"
logger.debug("generate gcode done:%d bytes" % len(gcode))
######################## fake code ####################################
self.dump('./preview.png')
if environ.get("flux_debug") == '1':
self.dump('./preview.png')
with open('output.gcode', 'w') as f:
print(gcode, file=f)
#######################################################################
return gcode

Expand Down
5 changes: 3 additions & 2 deletions fluxclient/laser/laser_svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import sys
from math import sin, cos, pi, sqrt
import logging
from os import environ
# cElementTree is the c implement of ElementTree, much faster and memory friendly, but no need to specify in py3
import xml.etree.ElementTree as ET

Expand Down Expand Up @@ -81,9 +82,9 @@ def gcode_generate(self, names, ws=None):
if ready_svg[-1]:
self.add_image(ready_svg[-1], ready_svg[-3], ready_svg[-2], *ready_svg[3:-3], thres=100)
gcode += self.turnOff()
gcode += ["G28"]
################ fake code ##############
self.dump('./preview.png')
if environ.get("flux_debug") == '1':
self.dump('./preview.png')

# output only moving
# tmp = []
Expand Down
Loading

0 comments on commit ba94385

Please sign in to comment.