The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

Category: Software

General-purpose computers doing something specific

  • MakerGear M2: Slic3r Config for PETG

    Changing from PLA to PETG with a V4 hot end and 24 V power required several slicing adjustments, some of which weren’t at all obvious. It’s not all settled down, but what you see here comes from a bunch of test objects and tweaks that you’ll see over the next few days; this is basically a peek into the future.

    M2 V4 Calibration Objects
    M2 V4 Calibration Objects

    The obvious changes:

    • Extrusion temperature: 250 °C
    • Platform temperature: 90 °C

    Hot PETG seems rather sticky and produces hair-fine strings that aren’t due to poor retraction. Running at 230 °C is possible, but the strings are nasty. The V4 hot end shouldn’t run over 250 °C; fortunately, some tests suggest the stringing doesn’t Go Away at 260 °C, so moah powah! isn’t required.

    Hair spray on glass works well above 90 °C and not at all below 80 °C. A stick of Elmer’s Washable Glue Stick, chosen because it was on the Adhesive Shelf, produced exactly zero adhesion at any platform temperature I was willing to use. Its “washable” nature surely contributed to the failure; you want something that’s gonna stick with you forever.

    The eSun PETG filament diameter varies from 1.63 to 1.72 mm, which seems like a lot compared to the MakerGear PLA I’d been using; I’ve told Slic3r to run with 1.70 mm. In practice, it doesn’t seem to matter; the average over a meter works out to 1.70, I haven’t seen any abrupt bulges, and the objects come out fine. This spool arrived late last year, early in eSun’s production, so perhaps they’ve smoothed things out by now.

    A few iterations of thinwall box building put the Extrusion Multiplier at 1.11, producing a spot-on 0.40 mm thread width at either 0.20 or 0.25 mm thread thickness.

    Infill:

    • Infill overlap: 10%
    • Max infill: 40%
    • Infill pattern: 3D Honycomb
    • Top/bottom pattern: Hilbert Curve
    • Combine infill: 3 layers

    The first attempt at a solid box (left of center, first row) became so overstuffed I canceled the print; the top bulges upward. A few parameter tweak iterations produced the perfect 100% filled solid box to its right, but in actual practice a 40% 3D Honeycomb will be entirely strong enough for anything I build.

    Reducing the overlap from 15% to 10% reduced the obviously overstuffed junction just inside the perimeter threads.

    Cooling:

    • Fan for layers below 20 s
    • Minimum layer time: 10 s
    • Minimum speed: 10 mm/s

    PETG wants to go down hot, but printing a single thinwall box requires that much cooling to prevent slumping. Might be excessive; we shall see.

    Speeds:

    • First layer: 15 mm/s
    • External perimeters: 25 mm/s
    • Perimeters: 50 mm/s
    • Infill: 75 mm/s
    • Travel: 300 mm/s

    Slower XY speeds seem to produce better results, although those values aren’t based on extensive experience.

    The first layer doesn’t work well at higher speeds, with acute corners and edges pulling up as the nozzle moves away. Using the Hilbert Curve pattern not only looks pretty, but also ensures the nozzle spends plenty of time in the same general area. Higher platform temperatures work better, too, and I may goose the 40 V supply a bit to improve the 0.2 °C/s warmup rate.

    The travel speed went up from 250 mm/s in an attempt to reduce stringing, but it may be too aggressive for the Y axis with the new 24 V supply. On very rare occasions, the Y axis stalls during homing, despite not changing the speeds in the startup G-Code, and I’m still accumulating experience with that.

    Bridging isn’t nearly as clean as PLA. After some tinkering, a bridge speed of 25 mm/s and flow of 0.90 seems to work, but some chain mail patches suggest there’s plenty of room for improvement.

    Mechanically, PETG is softer and more resilient than PLA, with a much higher glass transition temperature. Larger objects with 40% infill are essentially rigid and smaller objects are bendy, rather than brittle.

    On the whole, PETG seems like it will work well for the stuff I build, although magenta isn’t my favorite color…

    CAUTION: Don’t use this Slic3r configuration unless:

    The Slic3r configuration:

    # generated by Slic3r 1.2.7-dev on Mon Mar  9 19:51:37 2015
    avoid_crossing_perimeters = 0
    bed_shape = -100x-125,100x-125,100x125,-100x125
    bed_temperature = 90
    before_layer_gcode =
    bottom_solid_layers = 3
    bridge_acceleration = 0
    bridge_fan_speed = 100
    bridge_flow_ratio = 0.9
    bridge_speed = 25
    brim_width = 0
    complete_objects = 0
    cooling = 1
    default_acceleration = 0
    disable_fan_first_layers = 2
    dont_support_bridges = 1
    duplicate_distance = 6
    end_gcode = ;-- Slic3r End G-Code for M2 starts --\n;  Ed Nisley KE4NZU - 15 November 2013\nM104 S0		; drop extruder temperature\nM140 S0		; drop bed temperature\nM106 S0		; bed fan off\nG1 Z160 F2000	; lower bed\nG1 X135 Y100 F30000	; nozzle to right, bed front\nM84     	; disable motors\n;-- Slic3r End G-Code ends --
    external_fill_pattern = hilbertcurve
    external_perimeter_extrusion_width = 0
    external_perimeter_speed = 25
    external_perimeters_first = 0
    extra_perimeters = 1
    extruder_clearance_height = 25
    extruder_clearance_radius = 15
    extruder_offset = 0x0
    extrusion_axis = E
    extrusion_multiplier = 1.11
    extrusion_width = 0.4
    fan_always_on = 0
    fan_below_layer_time = 20
    filament_diameter = 1.7
    fill_angle = 45
    fill_density = 40%
    fill_pattern = 3dhoneycomb
    first_layer_acceleration = 0
    first_layer_bed_temperature = 90
    first_layer_extrusion_width = 0.4
    first_layer_height = 100%
    first_layer_speed = 15
    first_layer_temperature = 250
    gap_fill_speed = 50
    gcode_arcs = 0
    gcode_comments = 0
    gcode_flavor = reprap
    infill_acceleration = 0
    infill_every_layers = 3
    infill_extruder = 1
    infill_extrusion_width = 0
    infill_first = 1
    infill_only_where_needed = 0
    infill_overlap = 10%
    infill_speed = 75
    interface_shells = 0
    layer_gcode =
    layer_height = 0.25
    max_fan_speed = 100
    min_fan_speed = 100
    min_print_speed = 10
    min_skirt_length = 15
    notes =
    nozzle_diameter = 0.35
    octoprint_apikey =
    octoprint_host =
    only_retract_when_crossing_perimeters = 1
    ooze_prevention = 0
    output_filename_format = [input_filename_base].gcode
    overhangs = 1
    perimeter_acceleration = 0
    perimeter_extruder = 1
    perimeter_extrusion_width = 0.4
    perimeter_speed = 50
    perimeters = 3
    post_process =
    pressure_advance = 0
    raft_layers = 0
    resolution = 0.005
    retract_before_travel = 1
    retract_layer_change = 0
    retract_length = 1
    retract_length_toolchange = 5
    retract_lift = 0
    retract_restart_extra = 0
    retract_restart_extra_toolchange = 0
    retract_speed = 60
    seam_position = aligned
    skirt_distance = 3
    skirt_height = 1
    skirts = 3
    slowdown_below_layer_time = 10
    small_perimeter_speed = 25
    solid_infill_below_area = 1
    solid_infill_every_layers = 0
    solid_infill_extruder = 1
    solid_infill_extrusion_width = 0
    solid_infill_speed = 75
    spiral_vase = 0
    standby_temperature_delta = -5
    start_gcode = ;-- Slic3r Start G-Code for M2 starts --\n;  Ed Nisley KE4NZU - 2015-03-07\n;  Makergear V4 hot end\n; Z-min switch at platform, must move nozzle to X=135 to clear\nM140 S[first_layer_bed_temperature]	; start bed heating\nG90				; absolute coordinates\nG21				; millimeters\nM83				; relative extrusion distance\nM17				; enable steppers\nG4 P250			;  ... wait for power up\nG92 Z0			; set Z to zero, wherever it might be now\nG1 Z10 F1000	; move platform downward to clear nozzle; may crash at bottom\nG28 Y0			; home Y to clear plate, origin in middle\nG92 Y-127\nG28 X0			; home X, origin in middle\nG92 X-100\nG1 X130 Y0 F30000	; move off platform to right side, center Y\nG28 Z0			; home Z to platform switch, with measured offset\nG92 Z-2.07\nG0 Z2.0			; get air under switch\nG0 Y-127 F10000	; set up for priming, zig around corner\nG0 X0			;  center X\nG0 Y-125.0		; just over platform edge\nG0 Z0 F500	; exactly at platform\nM109 S[first_layer_temperature]	; set extruder temperature and wait\nM190 S[first_layer_bed_temperature]	; wait for bed to finish heating\nG1 E20 F300		; prime to get pressure, generate blob on edge\nG0 Y-123		; shear off blob\nG1 X15 F20000	; jerk away from blob, move over surface\nG4 P500			; pause to attach\nG1 X45 F500		; slowly smear snot to clear nozzle\nG1 Z1.0 F2000	; clear bed for travel\n;-- Slic3r Start G-Code ends --
    support_material = 0
    support_material_angle = 0
    support_material_contact_distance = 0.2
    support_material_enforce_layers = 0
    support_material_extruder = 1
    support_material_extrusion_width = 0
    support_material_interface_extruder = 1
    support_material_interface_layers = 3
    support_material_interface_spacing = 0
    support_material_interface_speed = 100%
    support_material_pattern = pillars
    support_material_spacing = 2.5
    support_material_speed = 50
    support_material_threshold = 0
    temperature = 250
    thin_walls = 1
    threads = 2
    toolchange_gcode =
    top_infill_extrusion_width = 0
    top_solid_infill_speed = 25
    top_solid_layers = 3
    travel_speed = 300
    use_firmware_retraction = 0
    use_relative_e_distances = 0
    use_volumetric_e = 0
    vibration_limit = 0
    wipe = 0
    xy_size_compensation = 0
    z_offset = 0
    
  • RPi: Logitech Camera Data

    After installing things like imagemagick and mjpg_streamer on the Raspberry Pi, I exhumed a quartet of Logitech cameras from the heap to see how they worked. None bear any identification, apart from a tag on the cable, so here’s what I found out for later reference.

    They’re all reasonably good for still pictures, if you don’t mind terrible initial exposures. The default program works OK:

    fswebcam -d /dev/video0 -r 320x240 image.jpg
    

    On the other hand, getting any streaming video requires searching through the parameter space, which wasn’t helped by the total lack of documentation. The Arch Linux wiki has a useful summary of camera & drivers, with pointers to additional lists-of-lists. The OctoPrint repo documents the mjpg-streamer plugin parameters.

    So, we begin…

    This camera, one of two identical cameras in the heap, has a clip that used to fit on the upper edge of a laptop display:

    Logitech QuickCam for Notebook Plus - front
    Logitech QuickCam for Notebook Plus – front

    One has a tag:

    Logitech QuickCam for Notebook Plus - tag
    Logitech QuickCam for Notebook Plus – tag

    To make the tag data more useful for search engine inquiries:

    • M/N: V-UBG35
    • P/N: 861228-0000
    • PID: CE64105

    From lsusb:

    Bus 001 Device 008: ID 046d:08d8 Logitech, Inc. QuickCam for Notebook Deluxe
    

    With Raspbian on the RPi, 640×480 video tears and stutters, leaving 320×240 as the least-worst alternative:

    mjpg_streamer -i "/usr/local/lib/input_uvc.so -r 320x240" -o "/usr/local/lib/output_http.so -w /usr/local/www"
    

    The cameras don’t support YUYV at all and the video quality is mediocre, at best, but they do have a manual focus ring that lets you snuggle the camera right up against the subject.

    This ball camera:

    Logitech QuickCam Pro 5000 - on tripod
    Logitech QuickCam Pro 5000 – on tripod

    Has a tag:

    Logitech QuickCam Pro 5000 - tag
    Logitech QuickCam Pro 5000 – tag

    Which reads:

    • M/N: V-UAX16
    • P/N: 861306-0000
    • PID: LZ715BQ

    From lsusb:

    Bus 001 Device 009: ID 046d:08ce Logitech, Inc. QuickCam Pro 5000
    

    It requires YUYV at 320×240 (on the Pi) and nothing else works at all:

    mjpg_streamer -i "/usr/local/lib/input_uvc.so -r 320x240 -y" -o "/usr/local/lib/output_http.so -w /usr/local/www"
    

    It produces even worse video than the Notebook camera.

    This HD 720p camera has C130 scrawled on the front in my handwriting:

    Logitech HD Webcam C510 - front
    Logitech HD Webcam C510 – front

    And a tag:

    Logitech HD Webcam C510 - tag
    Logitech HD Webcam C510 – tag

    Bearing this text:

    • M/N: V-U0016
    • P/N: 860-000261
    • PID: LZ114SF

    The scrawled C130 doesn’t match up with what lsusb reports:

    Bus 001 Device 010: ID 046d:081d Logitech, Inc. HD Webcam C510
    

    It produces very nice results in many resolutions, using YUYV mode, although I think its native resolution is 1280×720 and that works perfectly on the Pi:

    mjpg_streamer -i "/usr/local/lib/input_uvc.so -r 1280x720 -y" -o "/usr/local/lib/output_http.so -w /usr/local/www"
    

    Video over USB is mysterious…

  • Raspberry Pi Setup Tweaks

    Things to remember during Raspberry Pi setups…

    You can do some of this through raspi-config.

    The NOOBS setup configures the HDMI video parameters to work with the worst possible display, so edit the /boot/config.txt (per the Official Doc):

    • Comment out all the NOOBS auto-configuration entires at the bottom
    • Set disable_overscan=1

    The highest mutually compatible setting for the U2711 monitor was 1920×1080@60Hz, which turned out to be CEA Mode 16 and was automagically selected as the monitor’s “native” mode. Disabling overscan lets the X session use the entire monitor screen, rather than being confined within the (huge) black overscan borders.

    That requires a power off-on cycle to take effect. Shut down properly with sudo shutdown -H now or just sudo halt.

    To set the default size of the lxterminal window so that it’s big enough to be useful, edit the Exec entry (down near the bottom) in /usr/share/raspi-ui-overrides/applications/lxterminal.desktop to read:

    Exec=lxterminal --geometry=80x60
    

    The Droid font family seems more readable than the default selection.

    Create a user for yourself, just so SSH will eventually work the way it does for all the other boxes. The group list comes from the default pi user:

    sudo adduser ed
    sudo usermod -a -G pi,adm,dialout,cdrom,sudo,audio,video,plugdev,games,users,netdev,input,spi,gpio ed
    

    Regrettably, the default pi user has the same numeric ID as the one I use on all the other boxes, which leads to problems with file sharing permissions. I may need to swap numeric IDs to make this work out correctly.

    To set a static IP, edit /etc/network/interfaces thusly:

    #iface eth0 inet dhcp     <-- comment this out to stop DHCP
    
    auto eth0
    iface eth0 inet static
     address 192.168.1.9      <-- obviously, pick your own
     gateway 192.168.1.1
     netmask 255.255.255.0
     network 192.168.1.0
     broadcast 192.168.1.255
    

    Change the hostname in /etc/hostname and /etc/hosts.

    Set up SSH for public-key access on an unusual port by editing /etc/ssh/sshd_config:

    1. Port 12345 <— choose your own
    2. PermitRootLogin no
    3. PasswordAuthentication no

    Create the ~/.ssh directory and put your own public key in it, which you can do from the remote system:

    scp ~/.ssh/id_rsa.pub octopi-1:.ssh/authorized_keys
    # a dummy line to reveal underscores in the previous line
    

    Twiddle ~/.ssh/config on the remote box to include the Pi and specify the unusual port:

    Host octopi-1 thisone thatone anotherone
    	ForwardX11	yes
    	Port	12345   <--- pick your own
    	User	ed
    

    Using ssh-agent -t 4h helps relieve the tedium of typing your passphrase all the time. Then sudo service ssh restart on the pi will require you to use your key passphrase; it’s a Good Idea to remain signed in through Port 22 with the original authorization while you fiddle with this stuff, then sign out when it all works.

    Update with the usual routine:

    sudo apt-get update
    sudo apt-get upgrade
    sudo apt-get dist-upgrade    <-- for system-level update
    sudo apt-get clean           <-- flushes /var/cache/apt/archives to save space
    
  • MakerGear M2: Marlin 1.0.2 Firmware Tweaks

    Given that I’m throwing all the balls in the air at once:

    • V4 hot end / filament drive
    • 24 VDC motor / logic power supply
    • PETG filament

    It seemed reasonable to start with the current Marlin firmware, rather than the MakerGear version from long ago. After all, when you file a bug report, the first question is whether it happens with the Latest Version.

    Marlin has undergone a Great Refactoring that moved many of the constants around. I suppose I should set up a whole new Github repository, but there aren’t that many changes and I’ve gotten over my enthusiasm for forking projects.

    Anyhow, just clone the Marlin repo and dig in.

    In Marlin_main.cpp, turn on the Fan 1 output on Arduino pin 6 that drives the fans on the extruder and electronics box:

    pinMode(6,OUTPUT);	// kickstart Makergear M2 extruder fan
    digitalWrite(6,HIGH);
    

    You could use the built-in extruder fan feature that turns on when the extruder temperature exceeds a specific limit. I may try that after everything else works; as it stands, this shows when the firmware gets up & running after a reset.

    In Configuration_adv.h, lengthen the motor-off time and set the motor currents:

    #define DEFAULT_STEPPER_DEACTIVE_TIME 600
    #define DIGIPOT_MOTOR_CURRENT {185,215,185,185,135}
    

    The Configuration.h file still has most of the tweaks:

    #define STRING_CONFIG_H_AUTHOR "(Ed Nisley - KE4ZNU - Hotrod M2)"
    #define STRING_SPLASH_LINE2 STRING_VERSION_CONFIG_H
    
    #define BAUDRATE 115200
    
    #define MOTHERBOARD BOARD_RAMBO
    
    #define TEMP_SENSOR_0 1
    #define TEMP_SENSOR_BED 1
    
    #define HEATER_0_MAXTEMP 290
    #define HEATER_1_MAXTEMP 290
    #define HEATER_2_MAXTEMP 290
    #define HEATER_3_MAXTEMP 290
    
    #define X_MAX_POS 136
    #define X_MIN_POS -100
    #define Y_MAX_POS 125
    #define Y_MIN_POS -127
    #define Z_MAX_POS 175
    #define Z_MIN_POS 0
    
    #define HOMING_FEEDRATE {75*60, 75*60, 30*60, 0}
    
    #define DEFAULT_AXIS_STEPS_PER_UNIT   {88.88,88.88,400,424.4}
    #define DEFAULT_MAX_FEEDRATE          {450, 450, 100, 94}
    #define DEFAULT_MAX_ACCELERATION      {5000,2500,2000,10000}
    
    #define DEFAULT_ACCELERATION          10000
    #define DEFAULT_RETRACT_ACCELERATION  10000
      
    

    I missed the max & min position settings on the first pass (they’re new!), which matter because I put the origin in the middle of the platform, rather than the front-left corner. Marlin now clips coordinates outside that region, so the first thinwall calibration box only had lines in Quadrant 1…

  • Bookleting a PDF with Landscape Pages

    For reasons not relevant here, we had to make a booklet out of a PDF file that contained several wide tables that should print in landscape mode, but were tagged as portrait pages. As a further complication, the pdftops utility I normally use complained vociferously about nearly every page:

    Syntax Warning: FoFiType1::parse a line has more than 255 characters, we don't support this
    

    A bit of fiddling produced this recipe, with pdf2ps in place of the usual pdftops:

    pdfcrop --margins "36 0 10 0" FileName.pdf 
    pdftk FileName-crop.pdf rotate 41-46east output FileName-crop-rotate.pdf
    pdf2ps -dLanguageLevel=3 -sPAPERSIZE=letter -dFIXEDMEDIA FileName-crop-rotate.pdf FileName-crop-rotate.ps
    ps2book.pl -f 1 FileName-crop-rotate.ps
    ps2pdf FileName-crop-rotate_book.ps
    

    The gymnastics in pdf2ps forces letter-size pages, no matter what the internal size specifies.

    That was not particularly obvious, but hooray for pdftk…

  • ID3 Tagging Audio Book Files

    For whatever reason, the audio books we get at the library sale generally don’t have CDDB database entries, so I fill in the appropriate values by hand. Weirdly, some individual CDs within a single book do have entries, which confuses the process (well, me) no end unless I notice it first; I’ve turned off auto-lookup to make that problem Go Away. Perhaps a different database would help, but I don’t do this nearly often enough to care that much.

    Given that:

    • Mary plays the tracks sequentially from start to finish
    • The tracks don’t correspond to book divisions
    • She doesn’t care about the details

    I concluded a simple track naming convention that sorts in ascending alphabetic order would suffice.

    Asunder auto-fills the fields after the first CD. After a bit of manual wrestling to extract an error-filled track, I had a directory full of MP3 files with informative, albeit slightly redundant, names:

    1901-01 - Track 01.mp3

    Alas, the ID3 fields apply to a single music CD, with track numbers and names within a single album and no notion of a multi-CD set. I use the “year” field as a CD sequence number; it must be a four-digit year and, seeing as how Asunder defaults to 1900, the first CD becomes 1901.

    So the following fields apply:

    • Genre: “Audio Book” (for v2 tags) or Speech (v1 tag = 101)
    • Artist: author
    • Album: book title
    • Year: 19 + CD number within set as 1901
    • Track Name = CD number + track number as “D:01 T:01”

    But the real gotcha is that the Most Favorite MP3 Player (remember MP3 players?) recognizes only ID3 v1 tags and Asunder writes only ID3 v2 tags.

    Fortunately, the id3v2 utility can do this thing. Rather than screw around selecting each file, extracting the v2 tags, doing something horrible involving bash or sed or awk or whatever, and ramming the results into v1 tags, I just fed in the appropriate number of CDs and more than enough tracks, then ignored any errors concerning missing files.

    Firing a Bash cannon broadside:

    for d in {01..15} ; do id3v2 -1 -a "Who Wrote It" -A "The Book Title" -y 19$d -g Speech 19${d}* ; done
    for d in {01..15} ; do for t in {01..15} ; do id3v2 -1 -t "D:${d} T:$t" -T $t 19${d}-${t}* ; done ; done
    for d in {01..15} ; do for t in {01..15} ; do id3v2 -2 -t "D:${d} T:$t" -T $t 19${d}-${t}* ; done ; done
    

    The last line tightens up the title name tag in v2 format to fit the MP3 player’s teeny display. The next time around, I should remove the “Track” text from the file name for consistency.

    And then it just worked…

  • CD Ripping: Fractional Tracks

    Mary gets books-on-CD at the annual library book sale, but she’s found they’re easier to use in MP3 format. We regard format transformation for our own use as covered by the First Sale Doctrine and Fair Use, but, obviously, various legal opinions differ.

    I use Asunder to rip audio CDs, although it doesn’t handle non-recoverable errors very well at all. Wiping the offending disc with nose oil or ripping from a different drive will resolve most of the issues, but a recent acquisition had a nasty circumferential scratch in the middle of Track 7 that just didn’t respond to Black Magic.

    CDparanoia can rip portions of a track, so a little binary search action extracts the usable data from Track 7:

    cdparanoia "7-7[4:35]" Track7a.wav
    cdparanoia III release 10.2 (September 11, 2008)
    
    Ripping from sector  177155 (track  7 [0:00.00])
    	  to sector  197780 (track  7 [4:35.00])
    
    outputting to Track7a.wav
    
     (== PROGRESS == [                              | 197780 00 ] == :^D * ==)   
    
    Done.
    
    cdparanoia "7[5:30]-7" Track7b.wav
    cdparanoia III release 10.2 (September 11, 2008)
    
    Ripping from sector  201905 (track  7 [5:30.00])
    	  to sector  208894 (track  7 [7:03.14])
    
    outputting to Track7b.wav
    
     (== PROGRESS == [                              | 208894 00 ] == :^D * ==)   
    
    Done.
    

    With that in hand, you import the two WAV files into Audacity with a five second gap between them, drop two seconds of A-440 sine wave in the gap, and export to MP3.

    The M3U playlist entry has the track time in seconds, so I hand-carved that entry to match the abbreviated length:

    #EXTINF:376,Disc 14 Track 7
    14-07 - Track 7.mp3
    

    Done!