This commit is contained in:
dfriedrich 2019-03-21 10:43:51 -03:00
commit 60ece440f6
553 changed files with 361616 additions and 0 deletions

View file

@ -0,0 +1,256 @@
/**************************************\
* *
* OpenSCAD Mesh Display *
* by Thinkyhead - April 2017 *
* *
* Copy the grid output from Marlin, *
* paste below as shown, and use *
* OpenSCAD to see a visualization *
* of your mesh. *
* *
\**************************************/
//$t = 0.15; // comment out during animation
//
// Mesh info and points
//
mesh_width = 200; // X Size in mm of the probed area
mesh_height = 200; // Y Size...
zprobe_offset = 0; // Added to the points
NAN = 0; // Z to use for un-measured points
measured_z = [
[ -1.20, -1.13, -1.09, -1.03, -1.19 ],
[ -1.16, -1.25, -1.27, -1.25, -1.08 ],
[ -1.13, -1.26, -1.39, -1.31, -1.18 ],
[ -1.09, -1.20, -1.26, -1.21, -1.18 ],
[ -1.13, -0.99, -1.03, -1.06, -1.32 ]
];
//
// Geometry
//
max_z_scale = 100; // Scale at Time 0.5
min_z_scale = 10; // Scale at Time 0.0 and 1.0
thickness = 0.5; // thickness of the mesh triangles
tesselation = 1; // levels of tesselation from 0-2
alternation = 2; // direction change modulus (try it)
//
// Appearance
//
show_plane = true;
show_labels = true;
arrow_length = 5;
label_font_lg = "Arial";
label_font_sm = "Arial";
mesh_color = [1,1,1,0.5];
plane_color = [0.4,0.6,0.9,0.6];
//================================================ Derive useful values
big_z = max_2D(measured_z,0);
lil_z = min_2D(measured_z,0);
mean_value = (big_z + lil_z) / 2.0;
mesh_points_y = len(measured_z);
mesh_points_x = len(measured_z[0]);
xspace = mesh_width / (mesh_points_x - 1);
yspace = mesh_height / (mesh_points_y - 1);
// At $t=0 and $t=1 scale will be 100%
z_scale_factor = min_z_scale + (($t > 0.5) ? 1.0 - $t : $t) * (max_z_scale - min_z_scale) * 2;
//
// Min and max recursive functions for 1D and 2D arrays
// Return the smallest or largest value in the array
//
function min_1D(b,i) = (i<len(b)-1) ? min(b[i], min_1D(b,i+1)) : b[i];
function min_2D(a,j) = (j<len(a)-1) ? min_2D(a,j+1) : min_1D(a[j], 0);
function max_1D(b,i) = (i<len(b)-1) ? max(b[i], max_1D(b,i+1)) : b[i];
function max_2D(a,j) = (j<len(a)-1) ? max_2D(a,j+1) : max_1D(a[j], 0);
//
// Get the corner probe points of a grid square.
//
// Input : x,y grid indexes
// Output : An array of the 4 corner points
//
function grid_square(x,y) = [
[x * xspace, y * yspace, z_scale_factor * (measured_z[y][x] - mean_value)],
[x * xspace, (y+1) * yspace, z_scale_factor * (measured_z[y+1][x] - mean_value)],
[(x+1) * xspace, (y+1) * yspace, z_scale_factor * (measured_z[y+1][x+1] - mean_value)],
[(x+1) * xspace, y * yspace, z_scale_factor * (measured_z[y][x+1] - mean_value)]
];
// The corner point of a grid square with Z centered on the mean
function pos(x,y,z) = [x * xspace, y * yspace, z_scale_factor * (z - mean_value)];
//
// Draw the point markers and labels
//
module point_markers(show_home=true) {
// Mark the home position 0,0
color([0,0,0,0.25]) translate([1,1]) cylinder(r=1, h=z_scale_factor, center=true);
for (x=[0:mesh_points_x-1], y=[0:mesh_points_y-1]) {
z = measured_z[y][x];
down = z < mean_value;
translate(pos(x, y, z)) {
// Label each point with the Z
if (show_labels) {
v = z - mean_value;
color(abs(v) < 0.1 ? [0,0.5,0] : [0.25,0,0])
translate([0,0,down?-10:10]) {
$fn=8;
rotate([90,0])
text(str(z), 6, label_font_lg, halign="center", valign="center");
translate([0,0,down?-6:6]) rotate([90,0])
text(str(down ? "" : "+", v), 3, label_font_sm, halign="center", valign="center");
}
}
// Show an arrow pointing up or down
rotate([0, down ? 180 : 0]) translate([0,0,-1])
cylinder(
r1=0.5,
r2=0.1,
h=arrow_length, $fn=12, center=1
);
}
}
}
//
// Split a square on the diagonal into
// two triangles and render them.
//
// s : a square
// alt : a flag to split on the other diagonal
//
module tesselated_square(s, alt=false) {
add = [0,0,thickness];
p1 = [
s[0], s[1], s[2], s[3],
s[0]+add, s[1]+add, s[2]+add, s[3]+add
];
f1 = alt
? [ [0,1,3], [4,5,1,0], [4,7,5], [5,7,3,1], [7,4,0,3] ]
: [ [0,1,2], [4,5,1,0], [4,6,5], [5,6,2,1], [6,4,0,2] ];
f2 = alt
? [ [1,2,3], [5,6,2,1], [5,6,7], [6,7,3,2], [7,5,1,3] ]
: [ [0,2,3], [4,6,2,0], [4,7,6], [6,7,3,2], [7,4,0,3] ];
// Use the other diagonal
polyhedron(points=p1, faces=f1);
polyhedron(points=p1, faces=f2);
}
/**
* The simplest mesh display
*/
module simple_mesh(show_plane=show_plane) {
if (show_plane) color(plane_color) cube([mesh_width, mesh_height, thickness]);
color(mesh_color)
for (x=[0:mesh_points_x-2], y=[0:mesh_points_y-2])
tesselated_square(grid_square(x, y));
}
/**
* Subdivide the mesh into smaller squares.
*/
module bilinear_mesh(show_plane=show_plane,tesselation=tesselation) {
if (show_plane) color(plane_color) translate([-5,-5]) cube([mesh_width+10, mesh_height+10, thickness]);
tesselation = tesselation % 4;
color(mesh_color)
for (x=[0:mesh_points_x-2], y=[0:mesh_points_y-2]) {
square = grid_square(x, y);
if (tesselation < 1) {
tesselated_square(square,(x%alternation)-(y%alternation));
}
else {
subdiv_4 = subdivided_square(square);
if (tesselation < 2) {
for (i=[0:3]) tesselated_square(subdiv_4[i],i%alternation);
}
else {
for (i=[0:3]) {
subdiv_16 = subdivided_square(subdiv_4[i]);
if (tesselation < 3) {
for (j=[0:3]) tesselated_square(subdiv_16[j],j%alternation);
}
else {
for (j=[0:3]) {
subdiv_64 = subdivided_square(subdiv_16[j]);
if (tesselation < 4) {
for (k=[0:3]) tesselated_square(subdiv_64[k]);
}
}
}
}
}
}
}
}
//
// Subdivision helpers
//
function ctrz(a) = (a[0][2]+a[1][2]+a[3][2]+a[2][2])/4;
function avgx(a,i) = (a[i][0]+a[(i+1)%4][0])/2;
function avgy(a,i) = (a[i][1]+a[(i+1)%4][1])/2;
function avgz(a,i) = (a[i][2]+a[(i+1)%4][2])/2;
//
// Convert one square into 4, applying bilinear averaging
//
// Input : 1 square (4 points)
// Output : An array of 4 squares
//
function subdivided_square(a) = [
[ // SW square
a[0], // SW
[a[0][0],avgy(a,0),avgz(a,0)], // CW
[avgx(a,1),avgy(a,0),ctrz(a)], // CC
[avgx(a,1),a[0][1],avgz(a,3)] // SC
],
[ // NW square
[a[0][0],avgy(a,0),avgz(a,0)], // CW
a[1], // NW
[avgx(a,1),a[1][1],avgz(a,1)], // NC
[avgx(a,1),avgy(a,0),ctrz(a)] // CC
],
[ // NE square
[avgx(a,1),avgy(a,0),ctrz(a)], // CC
[avgx(a,1),a[1][1],avgz(a,1)], // NC
a[2], // NE
[a[2][0],avgy(a,0),avgz(a,2)] // CE
],
[ // SE square
[avgx(a,1),a[0][1],avgz(a,3)], // SC
[avgx(a,1),avgy(a,0),ctrz(a)], // CC
[a[2][0],avgy(a,0),avgz(a,2)], // CE
a[3] // SE
]
];
//================================================ Run the plan
translate([-mesh_width / 2, -mesh_height / 2]) {
$fn = 12;
point_markers();
bilinear_mesh();
}

View file

@ -0,0 +1,50 @@
#!/usr/bin/env python
""" Generate the stepper delay lookup table for Marlin firmware. """
import argparse
__author__ = "Ben Gamari <bgamari@gmail.com>"
__copyright__ = "Copyright 2012, Ben Gamari"
__license__ = "GPL"
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('-f', '--cpu-freq', type=int, default=16, help='CPU clockrate in MHz (default=16)')
parser.add_argument('-d', '--divider', type=int, default=8, help='Timer/counter pre-scale divider (default=8)')
args = parser.parse_args()
cpu_freq = args.cpu_freq * 1000000
timer_freq = cpu_freq / args.divider
print "#ifndef SPEED_LOOKUPTABLE_H"
print "#define SPEED_LOOKUPTABLE_H"
print
print '#include "Marlin.h"'
print
print "const uint16_t speed_lookuptable_fast[256][2] PROGMEM = {"
a = [ timer_freq / ((i*256)+(args.cpu_freq*2)) for i in range(256) ]
b = [ a[i] - a[i+1] for i in range(255) ]
b.append(b[-1])
for i in range(32):
print " ",
for j in range(8):
print "{%d, %d}," % (a[8*i+j], b[8*i+j]),
print
print "};"
print
print "const uint16_t speed_lookuptable_slow[256][2] PROGMEM = {"
a = [ timer_freq / ((i*8)+(args.cpu_freq*2)) for i in range(256) ]
b = [ a[i] - a[i+1] for i in range(255) ]
b.append(b[-1])
for i in range(32):
print " ",
for j in range(8):
print "{%d, %d}," % (a[8*i+j], b[8*i+j]),
print
print "};"
print
print "#endif"

View file

@ -0,0 +1,155 @@
#!/usr/bin/python
"""Thermistor Value Lookup Table Generator
Generates lookup to temperature values for use in a microcontroller in C format based on:
http://en.wikipedia.org/wiki/Steinhart-Hart_equation
The main use is for Arduino programs that read data from the circuit board described here:
http://reprap.org/wiki/Temperature_Sensor_v2.0
Usage: python createTemperatureLookupMarlin.py [options]
Options:
-h, --help show this help
--rp=... pull-up resistor
--t1=ttt:rrr low temperature temperature:resistance point (around 25 degC)
--t2=ttt:rrr middle temperature temperature:resistance point (around 150 degC)
--t3=ttt:rrr high temperature temperature:resistance point (around 250 degC)
--num-temps=... the number of temperature points to calculate (default: 36)
"""
from math import *
import sys
import getopt
"Constants"
ZERO = 273.15 # zero point of Kelvin scale
VADC = 5 # ADC voltage
VCC = 5 # supply voltage
ARES = pow(2,10) # 10 Bit ADC resolution
VSTEP = VADC / ARES # ADC voltage resolution
TMIN = 0 # lowest temperature in table
TMAX = 350 # highest temperature in table
class Thermistor:
"Class to do the thermistor maths"
def __init__(self, rp, t1, r1, t2, r2, t3, r3):
l1 = log(r1)
l2 = log(r2)
l3 = log(r3)
y1 = 1.0 / (t1 + ZERO) # adjust scale
y2 = 1.0 / (t2 + ZERO)
y3 = 1.0 / (t3 + ZERO)
x = (y2 - y1) / (l2 - l1)
y = (y3 - y1) / (l3 - l1)
c = (y - x) / ((l3 - l2) * (l1 + l2 + l3))
b = x - c * (l1**2 + l2**2 + l1*l2)
a = y1 - (b + l1**2 *c)*l1
if c < 0:
print "//////////////////////////////////////////////////////////////////////////////////////"
print "// WARNING: negative coefficient 'c'! Something may be wrong with the measurements! //"
print "//////////////////////////////////////////////////////////////////////////////////////"
c = -c
self.c1 = a # Steinhart-Hart coefficients
self.c2 = b
self.c3 = c
self.rp = rp # pull-up resistance
def resol(self, adc):
"Convert ADC reading into a resolution"
res = self.temp(adc)-self.temp(adc+1)
return res
def voltage(self, adc):
"Convert ADC reading into a Voltage"
return adc * VSTEP # convert the 10 bit ADC value to a voltage
def resist(self, adc):
"Convert ADC reading into a resistance in Ohms"
r = self.rp * self.voltage(adc) / (VCC - self.voltage(adc)) # resistance of thermistor
return r
def temp(self, adc):
"Convert ADC reading into a temperature in Celcius"
l = log(self.resist(adc))
Tinv = self.c1 + self.c2*l + self.c3* l**3 # inverse temperature
return (1/Tinv) - ZERO # temperature
def adc(self, temp):
"Convert temperature into a ADC reading"
x = (self.c1 - (1.0 / (temp+ZERO))) / (2*self.c3)
y = sqrt((self.c2 / (3*self.c3))**3 + x**2)
r = exp((y-x)**(1.0/3) - (y+x)**(1.0/3))
return (r / (self.rp + r)) * ARES
def main(argv):
"Default values"
t1 = 25 # low temperature in Kelvin (25 degC)
r1 = 100000 # resistance at low temperature (10 kOhm)
t2 = 150 # middle temperature in Kelvin (150 degC)
r2 = 1641.9 # resistance at middle temperature (1.6 KOhm)
t3 = 250 # high temperature in Kelvin (250 degC)
r3 = 226.15 # resistance at high temperature (226.15 Ohm)
rp = 4700; # pull-up resistor (4.7 kOhm)
num_temps = 36; # number of entries for look-up table
try:
opts, args = getopt.getopt(argv, "h", ["help", "rp=", "t1=", "t2=", "t3=", "num-temps="])
except getopt.GetoptError as err:
print str(err)
usage()
sys.exit(2)
for opt, arg in opts:
if opt in ("-h", "--help"):
usage()
sys.exit()
elif opt == "--rp":
rp = int(arg)
elif opt == "--t1":
arg = arg.split(':')
t1 = float(arg[0])
r1 = float(arg[1])
elif opt == "--t2":
arg = arg.split(':')
t2 = float(arg[0])
r2 = float(arg[1])
elif opt == "--t3":
arg = arg.split(':')
t3 = float(arg[0])
r3 = float(arg[1])
elif opt == "--num-temps":
num_temps = int(arg)
t = Thermistor(rp, t1, r1, t2, r2, t3, r3)
increment = int((ARES-1)/(num_temps-1));
step = (TMIN-TMAX) / (num_temps-1)
low_bound = t.temp(ARES-1);
up_bound = t.temp(1);
min_temp = int(TMIN if TMIN > low_bound else low_bound)
max_temp = int(TMAX if TMAX < up_bound else up_bound)
temps = range(max_temp, TMIN+step, step);
print "// Thermistor lookup table for Marlin"
print "// ./createTemperatureLookupMarlin.py --rp=%s --t1=%s:%s --t2=%s:%s --t3=%s:%s --num-temps=%s" % (rp, t1, r1, t2, r2, t3, r3, num_temps)
print "// Steinhart-Hart Coefficients: a=%.15g, b=%.15g, c=%.15g " % (t.c1, t.c2, t.c3)
print "// Theoretical limits of thermistor: %.2f to %.2f degC" % (low_bound, up_bound)
print
print "const short temptable[][2] PROGMEM = {"
for temp in temps:
adc = t.adc(temp)
print " { OV(%7.2f), %4s }%s // v=%.3f\tr=%.3f\tres=%.3f degC/count" % (adc , temp, \
',' if temp != temps[-1] else ' ', \
t.voltage(adc), \
t.resist( adc), \
t.resol( adc) \
)
print "};"
def usage():
print __doc__
if __name__ == "__main__":
main(sys.argv[1:])

View file

@ -0,0 +1,47 @@
#!/usr/bin/env bash
#
# findMissingTranslations.sh
#
# Locate all language strings needing an update based on English
#
# Usage: findMissingTranslations.sh [language codes]
#
# If no language codes are specified then all languages will be checked
#
[ -d "Marlin" ] && cd "Marlin"
FILES=$(ls language_*.h | grep -v -E "(_en|_test)\.h" | sed -E 's/language_([^\.]+)\.h/\1/')
declare -A STRING_MAP
# Get files matching the given arguments
TEST_LANGS=$FILES
if [[ -n $@ ]]; then
TEST_LANGS=""
for K in "$@"; do
for F in $FILES; do
[[ "$F" != "${F%$K*}" ]] && TEST_LANGS="$TEST_LANGS $F"
done
done
fi
echo -n "Building list of missing strings..."
for i in $(awk '/#ifndef/{print $2}' language_en.h); do
[[ $i == "LANGUAGE_EN_H" || $i == "CHARSIZE" ]] && continue
LANG_LIST=""
for j in $TEST_LANGS; do
[[ $(grep -c " ${i} " language_${j}.h) -eq 0 ]] && LANG_LIST="$LANG_LIST $j"
done
[[ -z $LANG_LIST ]] && continue
STRING_MAP[$i]=$LANG_LIST
done
echo
for K in $( printf "%s\n" "${!STRING_MAP[@]}" | sort ); do
case "$#" in
1 ) echo $K ;;
* ) printf "%-35s :%s\n" "$K" "${STRING_MAP[$K]}" ;;
esac
done

View file

@ -0,0 +1,186 @@
#!/usr/bin/python3
# This file is for preprocessing gcode and the new G29 Autobedleveling from Marlin
# It will analyse the first 2 Layer and return the maximum size for this part
# After this it will replace with g29_keyword = ';MarlinG29Script' with the new G29 LRFB
# the new file will be created in the same folder.
# your gcode-file/folder
folder = './'
my_file = 'test.gcode'
# this is the minimum of G1 instructions which should be between 2 different heights
min_g1 = 3
# maximum number of lines to parse, I don't want to parse the complete file
# only the first plane is we are interested in
max_g1 = 100000000
# g29 keyword
g29_keyword = 'g29'
g29_keyword = g29_keyword.upper()
# output filename
output_file = folder + 'g29_' + my_file
# input filename
input_file = folder + my_file
# minimum scan size
min_size = 40
probing_points = 3 # points x points
# other stuff
min_x = 500
min_y = min_x
max_x = -500
max_y = max_x
last_z = 0.001
layer = 0
lines_of_g1 = 0
gcode = []
# return only g1-lines
def has_g1(line):
return line[:2].upper() == "G1"
# find position in g1 (x,y,z)
def find_axis(line, axis):
found = False
number = ""
for char in line:
if found:
if char == ".":
number += char
elif char == "-":
number += char
else:
try:
int(char)
number += char
except ValueError:
break
else:
found = char.upper() == axis.upper()
try:
return float(number)
except ValueError:
return None
# save the min or max-values for each axis
def set_mima(line):
global min_x, max_x, min_y, max_y, last_z
current_x = find_axis(line, 'x')
current_y = find_axis(line, 'y')
if current_x is not None:
min_x = min(current_x, min_x)
max_x = max(current_x, max_x)
if current_y is not None:
min_y = min(current_y, min_y)
max_y = max(current_y, max_y)
return min_x, max_x, min_y, max_y
# find z in the code and return it
def find_z(gcode, start_at_line=0):
for i in range(start_at_line, len(gcode)):
my_z = find_axis(gcode[i], 'Z')
if my_z is not None:
return my_z, i
def z_parse(gcode, start_at_line=0, end_at_line=0):
i = start_at_line
all_z = []
line_between_z = []
z_at_line = []
# last_z = 0
last_i = -1
while len(gcode) > i:
try:
z, i = find_z(gcode, i + 1)
except TypeError:
break
all_z.append(z)
z_at_line.append(i)
temp_line = i - last_i -1
line_between_z.append(i - last_i - 1)
# last_z = z
last_i = i
if 0 < end_at_line <= i or temp_line >= min_g1:
# print('break at line {} at heigth {}'.format(i, z))
break
line_between_z = line_between_z[1:]
return all_z, line_between_z, z_at_line
# get the lines which should be the first layer
def get_lines(gcode, minimum):
i = 0
all_z, line_between_z, z_at_line = z_parse(gcode, end_at_line=max_g1)
for count in line_between_z:
i += 1
if count > minimum:
# print('layer: {}:{}'.format(z_at_line[i-1], z_at_line[i]))
return z_at_line[i - 1], z_at_line[i]
with open(input_file, 'r') as file:
lines = 0
for line in file:
lines += 1
if lines > 1000:
break
if has_g1(line):
gcode.append(line)
file.close()
start, end = get_lines(gcode, min_g1)
for i in range(start, end):
set_mima(gcode[i])
print('x_min:{} x_max:{}\ny_min:{} y_max:{}'.format(min_x, max_x, min_y, max_y))
# resize min/max - values for minimum scan
if max_x - min_x < min_size:
offset_x = int((min_size - (max_x - min_x)) / 2 + 0.5) # int round up
# print('min_x! with {}'.format(int(max_x - min_x)))
min_x = int(min_x) - offset_x
max_x = int(max_x) + offset_x
if max_y - min_y < min_size:
offset_y = int((min_size - (max_y - min_y)) / 2 + 0.5) # int round up
# print('min_y! with {}'.format(int(max_y - min_y)))
min_y = int(min_y) - offset_y
max_y = int(max_y) + offset_y
new_command = 'G29 L{0} R{1} F{2} B{3} P{4}\n'.format(min_x,
max_x,
min_y,
max_y,
probing_points)
out_file = open(output_file, 'w')
in_file = open(input_file, 'r')
for line in in_file:
if line[:len(g29_keyword)].upper() == g29_keyword:
out_file.write(new_command)
print('write G29')
else:
out_file.write(line)
file.close()
out_file.close()
print('auto G29 finished')