Author Archives: Ian

MPCNC Post Processor

Published by:

This is my MPCNC post processor, it works for me. Use it at your own risk!

Your mileage may vary!

 

 
# -*- coding: utf-8 -*-
# ***************************************************************************
# * *
# * (c) sliptonic (shopinthewoods@gmail.com) 2014 *
# * (c) Gauthier Briere - 2018, 2019 *
# * (c) Schildkroet - 2019-2020 *
# * (c) Ian Jobson - 2020 - 2021 *
# * *
# * This file is not yet part of the FreeCAD CAx development system. *
# * *
# * 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. *
# * *
# * FreeCAD 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 Lesser General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with FreeCAD; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# ***************************************************************************/

import FreeCAD
from FreeCAD import Units
import PathScripts.PostUtils as PostUtils
import argparse
import datetime
import shlex
import PathScripts.PathUtil as PathUtil

TOOLTIP = '''
Generate g-code from a Path that is compatible with the MPCNC Marlin controller.
import mpcnc_post
mpcnc_post.export(object, "/path/to/file.gcode")
'''

# ***************************************************************************
# * Globals set customization preferences
# ***************************************************************************

# Default values for command line arguments:
NUMBERTOOL = 1 # there has to be one tool to start with
PAUSE_FIRST_TOOL = False # should we create an M0 for the first tool
OUTPUT_COMMENTS = True # default output of comments in output gCode file
OUTPUT_HEADER = True # default output header in output gCode file
OUTPUT_LINE_NUMBERS = False # default doesn't output line numbers in output gCode file
OUTPUT_BCNC = False # default doesn't add bCNC operation block headers in output gCode file
SHOW_EDITOR = True # default show the resulting file dialog output in GUI
PRECISION = 3 # Default precision for metric (see http://linuxcnc.org/docs/2.7/html/gcode/overview.html#_g_code_best_practices)
TRANSLATE_DRILL_CYCLES = False # If true, G81, G82 & G83 are translated in G0/G1 moves
PREAMBLE = '''G90
G21
''' # default preamble text will appear at the beginning of the gCode output file.
POSTAMBLE = '''M117 Job End
''' # default postamble text will appear following the last operation.

SPINDLE_WAIT = 0 # no waiting after M3 / M4 by default
RETURN_TO = ("0","0",) # no movements after end of program

# Customisation with no command line argument
MODAL = False # if true commands are suppressed if the same as previous line.
LINENR = 100 # line number starting value
LINEINCR = 10 # line number increment
OUTPUT_TOOL_CHANGE = True # default output M0 tool changes pause the machine until the resume is hit
DRILL_RETRACT_MODE = 'G98' # Default value of drill retractations (CURRENT_Z) other possible value is G99
MOTION_MODE = 'G90' # G90 for absolute moves, G91 for relative
UNITS = 'G21' # G21 for metric, G20 for us standard
UNIT_FORMAT = 'mm'
UNIT_SPEED_FORMAT = 'mm/min'
PRE_OPERATION = '''''' # Pre operation text will be inserted before every operation
POST_OPERATION = '''''' # Post operation text will be inserted after every operation
TOOL_CHANGE = '''M0
''' # Tool Change commands will be inserted before a tool change

# ***************************************************************************
# * End of customization
# ***************************************************************************

# Parser arguments list & definition
parser = argparse.ArgumentParser(prog='grbl', add_help=False)
parser.add_argument('--comments', action='store_true', help='output comment (default)')
parser.add_argument('--no-comments', action='store_true', help='suppress comment output')
parser.add_argument('--header', action='store_true', help='output headers (default)')
parser.add_argument('--no-header', action='store_true', help='suppress header output')
parser.add_argument('--line-numbers', action='store_true', help='prefix with line numbers')
parser.add_argument('--no-line-numbers', action='store_true', help='don\'t prefix with line numbers (default)')
parser.add_argument('--show-editor', action='store_true', help='pop up editor before writing output (default)')
parser.add_argument('--no-show-editor', action='store_true', help='don\'t pop up editor before writing output')
parser.add_argument('--precision', default='3', help='number of digits of precision, default=3')
parser.add_argument('--translate_drill', action='store_true', help='translate drill cycles G81, G82 & G83 in G0/G1 movements')
parser.add_argument('--no-translate_drill', action='store_true', help='don\'t translate drill cycles G81, G82 & G83 in G0/G1 movements (default)')
parser.add_argument('--preamble', help='set commands to be issued before the first command, default="G17 G90"')
parser.add_argument('--postamble', help='set commands to be issued after the last command, default="M5\nG17 G90\n;M2"')
parser.add_argument('--inches', action='store_true', help='Convert output for US imperial mode (G20)')
parser.add_argument('--tool-change', action='store_true', help='Insert M0 for all tool changes')
parser.add_argument('--wait-for-spindle', type=int, default=0, help='Wait for spindle to reach desired speed after M3 / M4, default=0')
parser.add_argument('--return-to', default='', help='Move to the specified coordinates at the end, e.g. --return-to=0,0')
parser.add_argument('--bcnc', action='store_true', help='Add Job operations as bCNC block headers. Consider suppressing existing comments: Add argument --no-comments')
parser.add_argument('--no-bcnc', action='store_true', help='suppress bCNC block header output (default)')
TOOLTIP_ARGS = parser.format_help()

# ***************************************************************************
# * Internal global variables
# ***************************************************************************
MOTION_COMMANDS = ['G0', 'G00', 'G1', 'G01', 'G2', 'G02', 'G3', 'G03'] # Motion gCode commands definition
RAPID_MOVES = ['G0', 'G00'] # Rapid moves gCode commands definition
SUPPRESS_COMMANDS = [] # These commands are ignored by commenting them out
COMMAND_SPACE = " "
# Global variables storing current position
CURRENT_X = 0
CURRENT_Y = 0
CURRENT_Z = 0

# ***************************************************************************
# * to distinguish python built-in open function from the one declared below
if open.__module__ in ['__builtin__', 'io']:
pythonopen = open

def processArguments(argstring):

global NUMBERTOOL
global PAUSE_FIRST_TOOL
global OUTPUT_HEADER
global OUTPUT_COMMENTS
global OUTPUT_LINE_NUMBERS
global SHOW_EDITOR
global PRECISION
global PREAMBLE
global POSTAMBLE
global UNITS
global UNIT_SPEED_FORMAT
global UNIT_FORMAT
global TRANSLATE_DRILL_CYCLES
global OUTPUT_TOOL_CHANGE
global SPINDLE_WAIT
global RETURN_TO
global OUTPUT_BCNC

try:
args = parser.parse_args(shlex.split(argstring))
if args.no_header:
OUTPUT_HEADER = False
if args.header:
OUTPUT_HEADER = True
if args.no_comments:
OUTPUT_COMMENTS = False
if args.comments:
OUTPUT_COMMENTS = True
if args.no_line_numbers:
OUTPUT_LINE_NUMBERS = False
if args.line_numbers:
OUTPUT_LINE_NUMBERS = True
if args.no_show_editor:
SHOW_EDITOR = False
if args.show_editor:
SHOW_EDITOR = True
PRECISION = args.precision
if args.preamble is not None:
PREAMBLE = args.preamble
if args.postamble is not None:
POSTAMBLE = args.postamble
if args.no_translate_drill:
TRANSLATE_DRILL_CYCLES = False
if args.translate_drill:
TRANSLATE_DRILL_CYCLES = True
if args.inches:
UNITS = 'G20'
UNIT_SPEED_FORMAT = 'in/min'
UNIT_FORMAT = 'in'
PRECISION = 4
if args.tool_change:
OUTPUT_TOOL_CHANGE = True
if args.wait_for_spindle > 0:
SPINDLE_WAIT = args.wait_for_spindle
if args.return_to != '':
RETURN_TO = [int(v) for v in args.return_to.split(',')]
if len(RETURN_TO) != 2:
RETURN_TO = None
print("--return-to coordinates must be specified as ,, ignoring")
if args.bcnc:
OUTPUT_BCNC = True
if args.no_bcnc:
OUTPUT_BCNC = False

except Exception as e:
return False

return True

# For debug...
def dump(obj):
for attr in dir(obj):
print("obj.%s = %s" % (attr, getattr(obj, attr)))

def export(objectslist, filename, argstring):

if not processArguments(argstring):
return None

global UNITS
global UNIT_FORMAT
global UNIT_SPEED_FORMAT
global MOTION_MODE
global SUPPRESS_COMMANDS

print("Post Processor: " + __name__ + " postprocessing...")
gcode = ""

# write header
if OUTPUT_HEADER:
gcode += linenumber() + ";Exported by FreeCAD\n"
gcode += linenumber() + ";Post Processor: " + __name__ + "\n"
gcode += linenumber() + ";Output Time:" + str(datetime.datetime.now()) + "\n"

# Check canned cycles for drilling
if TRANSLATE_DRILL_CYCLES:
if len(SUPPRESS_COMMANDS) == 0:
SUPPRESS_COMMANDS = ['G98', 'G80']
else:
SUPPRESS_COMMANDS += ['G98', 'G80']

# Write the preamble
if OUTPUT_COMMENTS:
gcode += linenumber() + ";Begin preamble\n"
for line in PREAMBLE.splitlines(True):
gcode += linenumber() + line
# verify if PREAMBLE have changed MOTION_MODE or UNITS
if 'G90' in PREAMBLE:
MOTION_MODE = 'G90'
elif 'G91' in PREAMBLE:
MOTION_MODE = 'G91'
else:
gcode += linenumber() + MOTION_MODE + "\n"
if 'G21' in PREAMBLE:
UNITS = 'G21'
UNIT_FORMAT = 'mm'
UNIT_SPEED_FORMAT = 'mm/min'
elif 'G20' in PREAMBLE:
UNITS = 'G20'
UNIT_FORMAT = 'in'
UNIT_SPEED_FORMAT = 'in/min'
else:
gcode += linenumber() + UNITS + "\n"

for obj in objectslist:
# Debug...
# print("\n" + "*"*70)
# dump(obj)
# print("*"*70 + "\n")
if not hasattr(obj, "Path"):
print("The object " + obj.Name + " is not a path. Please select only path and Compounds.")
return

# Skip inactive operations
if PathUtil.opProperty(obj, 'Active') is False:
continue

# do the pre_op
if OUTPUT_BCNC:
gcode += linenumber() + "(Block-name: " + obj.Label + ")\n"
gcode += linenumber() + "(Block-expand: 0)\n"
gcode += linenumber() + "(Block-enable: 1)\n"
if OUTPUT_COMMENTS:
gcode += linenumber() + ";Begin operation: " + obj.Label + "\n"
for line in PRE_OPERATION.splitlines(True):
gcode += linenumber() + line

# get coolant mode
coolantMode = 'None'
if hasattr(obj, "CoolantMode") or hasattr(obj, 'Base') and hasattr(obj.Base, "CoolantMode"):
if hasattr(obj, "CoolantMode"):
coolantMode = obj.CoolantMode
else:
coolantMode = obj.Base.CoolantMode

# turn coolant on if required
if OUTPUT_COMMENTS:
if not coolantMode == 'None':
gcode += linenumber() + ';(Coolant On:' + coolantMode + ')\n'
if coolantMode == 'Flood':
gcode += linenumber() + 'M8' + '\n'
if coolantMode == 'Mist':
gcode += linenumber() + 'M7' + '\n'

# Parse the op
gcode += parse(obj)

# do the post_op
if OUTPUT_COMMENTS:
gcode += linenumber() + ";Finish operation: " + obj.Label + "\n"
for line in POST_OPERATION.splitlines(True):
gcode += linenumber() + line

# turn coolant off if required
if not coolantMode == 'None':
if OUTPUT_COMMENTS:
gcode += linenumber() + ';(Coolant Off:' + coolantMode + ')\n'
gcode += linenumber() +'M9' + '\n'

# do the post_amble
if OUTPUT_BCNC:
gcode += linenumber() + "(Block-name: post_amble)\n"
gcode += linenumber() + "(Block-expand: 0)\n"
gcode += linenumber() + "(Block-enable: 1)\n"
if OUTPUT_COMMENTS:
gcode += linenumber() + ";Begin postamble\n"
for line in POSTAMBLE.splitlines(True):
gcode += linenumber() + line

if RETURN_TO:
gcode += linenumber() + "G0 X%s Y%s" % tuple(RETURN_TO)

# show the gCode result dialog
if FreeCAD.GuiUp and SHOW_EDITOR:
dia = PostUtils.GCodeEditorDialog()
dia.editor.setText(gcode)
result = dia.exec_()
if result:
final = dia.editor.toPlainText()
else:
final = gcode
else:
final = gcode

print("Done postprocessing.")

# write the file
gfile = pythonopen(filename, "w")
gfile.write(final)
gfile.close()

def linenumber():
global LINENR
global LINEINCR
if OUTPUT_LINE_NUMBERS:
s = "N" + str(LINENR) + " "
LINENR += LINEINCR
return s
return ""

def format_outstring(strTbl):
global COMMAND_SPACE
# construct the line for the final output
s = ""
for w in strTbl:
s += w + COMMAND_SPACE
s = s.strip()
return s

def parse(pathobj):

global DRILL_RETRACT_MODE
global MOTION_MODE
global CURRENT_X
global CURRENT_Y
global CURRENT_Z
global NUMBERTOOL
global TOOL_CHANGE

out = ""
lastcommand = None

precision_string = '.' + str(PRECISION) + 'f'

params = ['X', 'Y', 'Z', 'A', 'B', 'C', 'U', 'V', 'W', 'I', 'J', 'K', 'F', 'S', 'T', 'Q', 'R', 'L', 'P']

if hasattr(pathobj, "Group"): # We have a compound or project.
if OUTPUT_COMMENTS:
out += linenumber() + ";(Compound: " + pathobj.Label + ")\n"
for p in pathobj.Group:
out += parse(p)
return out

else: # parsing simple path
if not hasattr(pathobj, "Path"): # groups might contain non-path things like stock.
return out
if OUTPUT_COMMENTS:
out += linenumber() + ";Path: " + pathobj.Label + "\n"
for c in pathobj.Path.Commands:
outstring = []
command = c.Name
######################################################################
# Intercept the command here and modify it to insert the comment char
######################################################################
message = command
#print(message)
message_start = message[0]
#print(message_start)
if message_start == '(':
message = message.replace(message_start, ';' + message_start)
#print(message)
command = message
message_start = message[0:2]
#print(message_start + "---From Message[0:2]")
if message_start == 'M6':
TOOL_CHANGE = TOOL_CHANGE.rstrip("\n")
if NUMBERTOOL == 1 and PAUSE_FIRST_TOOL == False :
message = message.replace(message_start, ';' + TOOL_CHANGE)
NUMBERTOOL += 1

else:
message = message.replace(message_start, TOOL_CHANGE)
NUMBERTOOL += 1

#print(message)
#print (NUMBERTOOL)
#print ("^^^is the tool number")
command = message
#######################################################################
# End of Intercept mods
#######################################################################
outstring.append(command)

# if modal: only print the command if it is not the same as the last one
if MODAL:
if command == lastcommand:
outstring.pop(0)

# Now add the remaining parameters in order
for param in params:
if param in c.Parameters:
if param == 'F':
if command not in RAPID_MOVES:
speed = Units.Quantity(c.Parameters['F'], FreeCAD.Units.Velocity)
if speed.getValueAs(UNIT_SPEED_FORMAT) > 0.0:
outstring.append(param + format(float(speed.getValueAs(UNIT_SPEED_FORMAT)), precision_string))
elif param in ['T', 'H', 'D', 'S', 'P', 'L']:
outstring.append(param + str(c.Parameters[param]))
elif param in ['A', 'B', 'C']:
outstring.append(param + format(c.Parameters[param], precision_string))
else: # [X, Y, Z, U, V, W, I, J, K, R, Q] (Conversion eventuelle mm/inches)
pos = Units.Quantity(c.Parameters[param], FreeCAD.Units.Length)
outstring.append(param + format(float(pos.getValueAs(UNIT_FORMAT)), precision_string))

# store the latest command
lastcommand = command

# Memorizes the current position for calculating the related movements and the withdrawal plan
if command in MOTION_COMMANDS:
if 'X' in c.Parameters:
CURRENT_X = Units.Quantity(c.Parameters['X'], FreeCAD.Units.Length)
if 'Y' in c.Parameters:
CURRENT_Y = Units.Quantity(c.Parameters['Y'], FreeCAD.Units.Length)
if 'Z' in c.Parameters:
CURRENT_Z = Units.Quantity(c.Parameters['Z'], FreeCAD.Units.Length)

if command in ('G98', 'G99'):
DRILL_RETRACT_MODE = command

if command in ('G90', 'G91'):
MOTION_MODE = command

if TRANSLATE_DRILL_CYCLES:
if command in ('G81', 'G82', 'G83'):
out += drill_translate(outstring, command, c.Parameters)
# Erase the line we just translated
del(outstring[:])
outstring = []

if SPINDLE_WAIT > 0:
if command in ('M3', 'M03', 'M4', 'M04'):
out += linenumber() + format_outstring(outstring) + "\n"
out += linenumber() + format_outstring(['G4', 'P%s' % SPINDLE_WAIT]) + "\n"
del(outstring[:])
outstring = []

# Check for Tool Change:
if command in ('M6', 'M06'):
if OUTPUT_COMMENTS:
out += linenumber() + ";Begin toolchange\n"
if not OUTPUT_TOOL_CHANGE:
outstring[0] = "(" + outstring[0]
outstring[-1] = outstring[-1] + ")"
else:
for line in TOOL_CHANGE.splitlines(True):
out += linenumber() + line

if command == "message":
if OUTPUT_COMMENTS is False:
out = []
else:
outstring.pop(0) # remove the command

if command in SUPPRESS_COMMANDS:
outstring[0] = ";(" + outstring[0]
outstring[-1] = outstring[-1] + ")"

# prepend a line number and append a newline
if len(outstring) >= 1:
out += linenumber() + format_outstring(outstring) + "\n"

return out

def drill_translate(outstring, cmd, params):
global DRILL_RETRACT_MODE
global MOTION_MODE
global CURRENT_X
global CURRENT_Y
global CURRENT_Z
global UNITS
global UNIT_FORMAT
global UNIT_SPEED_FORMAT

strFormat = '.' + str(PRECISION) + 'f'

trBuff = ""

if OUTPUT_COMMENTS: # Comment the original command
outstring[0] = ";" + outstring[0]
outstring[-1] = outstring[-1] + "!"
trBuff += linenumber() + format_outstring(outstring) + "\n"

# Conversion du cycle
# Pour l'instant, on gere uniquement les cycles dans le plan XY (G17)
# les autres plans ZX (G18) et YZ (G19) ne sont pas traites : Calculs sur Z uniquement.
if MOTION_MODE == 'G90': # Deplacements en coordonnees absolues
drill_X = Units.Quantity(params['X'], FreeCAD.Units.Length)
drill_Y = Units.Quantity(params['Y'], FreeCAD.Units.Length)
drill_Z = Units.Quantity(params['Z'], FreeCAD.Units.Length)
RETRACT_Z = Units.Quantity(params['R'], FreeCAD.Units.Length)
else: # G91 Deplacements relatifs
drill_X = CURRENT_X + Units.Quantity(params['X'], FreeCAD.Units.Length)
drill_Y = CURRENT_Y + Units.Quantity(params['Y'], FreeCAD.Units.Length)
drill_Z = CURRENT_Z + Units.Quantity(params['Z'], FreeCAD.Units.Length)
RETRACT_Z = CURRENT_Z + Units.Quantity(params['R'], FreeCAD.Units.Length)

if DRILL_RETRACT_MODE == 'G98' and CURRENT_Z >= RETRACT_Z:
RETRACT_Z = CURRENT_Z

# Recupere les valeurs des autres parametres
drill_Speed = Units.Quantity(params['F'], FreeCAD.Units.Velocity)
if cmd == 'G83':
drill_Step = Units.Quantity(params['Q'], FreeCAD.Units.Length)
elif cmd == 'G82':
drill_DwellTime = params['P']

if MOTION_MODE == 'G91':
trBuff += linenumber() + "G90" + "\n" # Force des deplacements en coordonnees absolues pendant les cycles

# Mouvement(s) preliminaire(s))
if CURRENT_Z < RETRACT_Z: trBuff += linenumber() + 'G0 Z' + format(float(RETRACT_Z.getValueAs(UNIT_FORMAT)), strFormat) + "\n" trBuff += linenumber() + 'G0 X' + format(float(drill_X.getValueAs(UNIT_FORMAT)), strFormat) + ' Y' + format(float(drill_Y.getValueAs(UNIT_FORMAT)), strFormat) + "\n" if CURRENT_Z > RETRACT_Z:
trBuff += linenumber() + 'G0 Z' + format(float(CURRENT_Z.getValueAs(UNIT_FORMAT)), strFormat) + "\n"

# Mouvement de percage
if cmd in ('G81', 'G82'):
trBuff += linenumber() + 'G1 Z' + format(float(drill_Z.getValueAs(UNIT_FORMAT)), strFormat) + ' F' + format(float(drill_Speed.getValueAs(UNIT_SPEED_FORMAT)), '.2f') + "\n"
# Temporisation eventuelle
if cmd == 'G82':
trBuff += linenumber() + 'G4 P' + str(drill_DwellTime) + "\n"
# Sortie de percage
trBuff += linenumber() + 'G0 Z' + format(float(RETRACT_Z.getValueAs(UNIT_FORMAT)), strFormat) + "\n"
else: # 'G83'
next_Stop_Z = RETRACT_Z - drill_Step
while 1:
if next_Stop_Z > drill_Z:
trBuff += linenumber() + 'G1 Z' + format(float(next_Stop_Z.getValueAs(UNIT_FORMAT)), strFormat) + ' F' + format(float(drill_Speed.getValueAs(UNIT_SPEED_FORMAT)), '.2f') + "\n"
trBuff += linenumber() + 'G0 Z' + format(float(RETRACT_Z.getValueAs(UNIT_FORMAT)), strFormat) + "\n"
next_Stop_Z -= drill_Step
else:
trBuff += linenumber() + 'G1 Z' + format(float(drill_Z.getValueAs(UNIT_FORMAT)), strFormat) + ' F' + format(float(drill_Speed.getValueAs(UNIT_SPEED_FORMAT)), '.2f') + "\n"
trBuff += linenumber() + 'G0 Z' + format(float(RETRACT_Z.getValueAs(UNIT_FORMAT)), strFormat) + "\n"
break

if MOTION_MODE == 'G91':
trBuff += linenumber() + 'G91' # Restore le mode de deplacement relatif

return trBuff

print(__name__ + ": GCode postprocessor loaded.")

FreeCAD Beginner Series

Published by:

Keeping up with the changes

Published by:

It’s been a while since we posted a new update. FreeCAD has become our go-to CAD/CAM package. It’s working out nicely as a tool to create 3D models for either CNC routing or 3D printing. The Path module is good but not 100% complete yet. It continues to improve with time.

We are working on creating some helpful videos for other users that want to get the most out of FreeCAD and their maker experience. Check out our channel http://www.youtube.com/adventuresincreation

MPCNC inlays

Published by:

Iron Man

I am still working on creating a flawless inlay. I have found some wood that I can use but now I have to find a good subject. I am starting to get a feel for the type of graphic that would make a good inlay candidate.

 

Take a look at this page MPCNC vcarve inlay technique it should give you a good idea of where I am with this.

I have created some videos on the subject you can find them here YouTube video

Blender 2.8 Video Green Screen

Published by:

Using Blender 2.8 it is possible to create a “green screen” video. Essentially you record a video in front of a green screen then superimpose that video over another background. To do this in Blender is fairly simple but you have to know what you are doing. It’s certainly not intuitive.

This picture shows the compositor window it’s important to understand that Blender has many different work benches in which you can manipulate “things” The compositor window allows us to take the source and apply nodes making it possible to filter out the green screen. This blog is just showing the very basic process of making a green screen video. It’s not intended to be perfect and much of the “tweaking” will depend on the final video used.

Here you can see three work benches are open the video editing, the rendering, and the compositing. You can switch between these work benches but for now it’s only necessary to use the compositing work bench. If the compositing work bench is not open, click on the + to the right and select compositing.

When you check the use nodes box (see previous picture) you will be presented with a rendering node and a composite node. You can delete the rendering node as we are not working a rendering as our source. To delete it, right click on the rendering node and select delete.  Instead we are working with our green screen movie. Click add then input from the menu and insert a Movie Clip node. To place the node just move the mouse and left click in the position you want it to stay. It doesn’t really matter where you put it but input is usually left to right. At the bottom of the node you  can see a file search box. Click that and select your green screen video. Of course at this point the green screen video is just something in front of a green screen that you can see, no magic has been applied.
Now add a keying node. You can find that under the Matte menu item. You will see that the keying node will allow you to select many different adjustment factors. More on this later.
Now connect the image output of the green screen movie clip node to the image input of the keying node. Don’t adjust anything yet, there are more nodes to add that will make the adjustment easier. Now add an Alpha Over node, you will find it under the color menu. Connect the image output of the keying node to lower image input of the Alpha Over node. You will see why later.
Finally add viewer node now connect the image out from the alpha over to the image input of both the composite node and the viewer node. This will show you the green screen picture in the background. You can adjust this image to make the green screen disappear. To start you will need to go back to the keying node.

Here you can see an item called Key Color. Click on the color and choose the color picker (pipet) and select a darker portion of the green screen in the video image. This will set the key color so that Blender will try to remove it. Now you can tweak all the settings in the keying node to try and make the green screen disappear. – You should wait for the change to render before you try another tweak. Eventually you may add other nodes to assist with removing the green screen but for now, let’s keep it very simple. Once you have the green screen removed (in my example it’s not quite gone but I don’t want to be perfect here just get the principle worked out.Now we can add a second movie clip node, this will be our background. It can be a static image or another video. The choice is yours. Once you have added the node use the file selector to insert the media you want to use. Make sure that it is large enough to fill the background. If it is not adjust it before you use it.

Once you have the media loaded in the second movie clip node just connect the output of that movie clip node directly to the upper image input of the Alpha Over node. This should put your image in the background.Before you render the video you need to make sure you have everything set up properly. The output should look like the picture above. Select an output folder and ensure you have ffmpeg video selected or it will just render frames. Select RGB for color output and an MPEG4 container. Make sure your end Frame is the end of the video you want, too short and you won’t get it all, too long and you will have a lot of black. And finally, and most importantly. Blender will by default render the sequencer (video editing work bench) you need to select just compositing in the post processing. Then just render the animation. I normally render the image first just to make sure it’s rendering what you want to see. Rendering takes a while, go get a drink and come back later and you should have a video in the output folder that you selected. You can take that video into the video editing work bench and manipulate it like any other video.

NOTES:

If you want to use a box matte to remove areas of the video that are not on the green screen. Ensure you connect to the garbage input on the keying node. The box matte node should connect right after the movie clip node and before the keying node.

Home Automation

Published by:

Openhab

As you may have seen I have the Amazon Echo at home. I liked the potential to make the echo the hub for home automation. The first step is to get something you can control so I set out to find something that works with Alexa natively so there would be no issues with integration. I searched Amazon for the a switchable plug that I could plug my living room light in to. I found the TP-LINK HS100.打印

This is a wifi enabled smart plug. You plug it in and from an Android app set it up on your wi-fi network. Once it’s set up you just ask Alexa to look for new devices and it will find the smart plug. Through the set up you designate a name for the device so now you can say something like “Alexa turn on the living room light” and it will switch it on and say “OK”. This is cool and how I work my living room light today. Of course the light is just one thing you can turn any item on that is plugged in to the smart plug. It is just a simple way to power on and power off. This is the beginning of automating the home of course, the smart plug is about $30 so this could be an expensive way to avoid turning a light switch. I will admit that I got mine a lot cheaper than that, it was on sale and I had a gift card from a survey so I ended up paying about $4 out of pocket.  Since we have had that light operated by Alexa we have wished that we had one for the bedroom light so that it would be on when we go upstairs. Now imagine, instead of saying “Alexa turn off the living room light” at the end of the day we could say “Alexa its bed time” and have her turn off the living room light, turn off the tv and the tuner, turn on the bedroom light, set the alarm, check the garage door is closed, and start the sounds of the sea music. – Well, this is possible if you introduce something like Openhab. What is this you ask, here’s a brief description of Openhab

Continue reading

Cat Wheel Chair

Published by:

I met a sweetheart little cat who had been hit by a car and injured his spine. Regardless of this horrific injury he is a lively and inquisitive little fellow that can move his front legs and scoot around on his bottom. This can cause issues with wear and tear on his rear end. His back legs appear to have some feeling but are not working as they should. He needs a “cat wheel chair” so I thought how can we create something light enough, strong enough and cheap enough that we can make it a reality for him. How about some some plastic plumbing pipe and pair of wheels?

20160906_222415

Here’s the first attempt. The idea is his back legs will sit in the sling and the front of the wheelchair will be attached to a harness.

 

wp-1473257931767.jpg

Here he is trying it on for the first time. It needs some adjusting, it’s a little too tall for him yet. We will get that right and do a final fitting then hopefully, he will be able to move himself around without hurting himself.

Great news! Thanks to the dedication of the folks at Hoof and Paw Vets this little guy is able to walk again…  Just look here.

20161014_075453