Posts Tagged ‘ raspberry pi

Building the C-Bot 3D printer: Part 31 : Setting up Octoprint

Jump to C-Bot blog index to see all the posts.


My previous post talks about the specifics of getting Octoprint setup, in general.  Here, I’ll talk about actually integrating it with my C-Bot 3D printer.

Up to this point I had a Raspberry Pi (upgraded to a v2 at this point) connected to my router via a USB wifi dongle, with a RaspberryPi Camera hooked to it, connected via a 3′ ribbon cable.  This was all sitting like a pile of spaghetti on my table.  I needed a way to get all this strapped to the C-Bot itself, which is what this post mainly talks about.  I should comment that during this process I gave up on the USB wifi dongle and switched to direct ethernet:  Just too many problems getting the wifi to stream the picam correctly.

Before we get into it, the end result:

3D Printed Items:

I needed a way to mount both the RPi2 to the frame of the C-Bot, and have some sort of adjustable mount for the camera.  Both of the below items were printed on my Makerbot Replicator 1.

RPi2 case:  After searching Thingiverse, I found this great looking “Raspberry Pi 2/B+ case with VESA mounts and more” file:  It both looks slick, has a slot for the RPiCam ribbon cable, and had holes to bolt it directly into the OpenBuilds V-Slot.  I should note the holes provided were too small for the V-Slot bolts:  I had to drill them out slightly, but once that was done it was easily mounted (see above pic, it sits on the right-front vertical arm).

PiCam Mount:  After more Thingiverse searching, I tracked down “B+ PiCam Ultimaker 2 timelapse harness” : This is both an adjustable arm to hold the cam, and a separate bracket for the cam:  I printed out all the files needed for the cam, and realized that it didn’t fit the 20×40 V-Slot: The ‘hook front’ piece was too wide to clamp properly.  I’d figured this would be the case, and created a modified version in Maya to narrow it, which is currently installed on the bot.  But if you don’t want to have to deal with this, I realized you can get a pack of small sticky-notes, and just tear-off the appropriate amount to create an easy-sized shim.  You can download my modified version on Thingiverse here.

Assembly:

  • I bolted the RPi2 case to the right-front 20×40 V-Slot extrusion.
  • I attached the PiCam mount on the right side of the top-front x-extrusion.  Zip-tied it down for safety.
  • My Rumba’s USB now runs directly into the Raspberry Pi 2.

Issues:

  • RPiCam ribbon:  Not easy to route, easy to catch things on.
  • Power to the RPi, the way I mounted it sticks out the side of the bot.  Easy to catch things on.

Final thoughts:  I’ve literally just started printing with it:  I usually print from either the C-Bot’s LCD, or from Simplify3D : So this is a whole new interface to learn (although, obviously similar to what I’m used to).  But I’m excited to start nocking out some timelapse movies :)

Setting up OctoPrint

OctoPiThis post will be a continual scratchpad of info as I use Octoprint…

I’ve toyed around with OctoPrint in the past:  Before I built the C-Bot I was seriously considering buying a Type A Machines Series 1 printer:  They use OctoPrint, so I’d installed it on a spare Raspberry Pi and played around with it and my Replicator 1.

With the C-Bot, based on its large build size, I want a way to be able to remotely track & control my prints:  If I’m not around I can check up on them, pause\stop them if needed in case of failure.  OctoPrint is perfect for this.  So I decided to finally get it installed and configured on my Raspberry Pi.

Below are the rough steps I went though to make this happen.  It’s still not quite ready yet for primetime:  I need a way to get the Raspberry Pi & it’s camera to correctly point at the build plate, and a slick case\mount to stick the RPi to the printer (see the next post).  But technically I have everything up and running now.

Update:  Note that all the trouble I had at any step with the install stemmed in some way from trying to configure wifi successfully:  I later switched over to ethernet, and all my problems went away.

My Tech Specs:

Setup Process:

  • Install OctoPi disk image.
    • GitHub : Download & install docs I followed.  See “Problems Encountered” below….
  • If you plan on accessing OctoPrint via the web, make sure that “Access Control” is on (which it is by default with any modern install of OctoPi), and you have a valid login.  See here.  First line of defense keeping people from taking control of your printer remotely.
  • In your router, give the RPi a static IP.  This allows you to log in consistently (locally or remotely), without worrying that your router can dynamically change the IP at some point.
    • While it was connected to my router (provided via Comcast), via the router’s control panel, I found and stored it’s MAC address.
    • Next I had to make my router “forget” the RPi:  For me, I had to first turn off the RPi, then in the router “block” it, then “delete it”.
    • With the RPi unconnected, using its MAC address I was able to add it it with a staticIP (My static range was 10.0.0.253+), rather than DHCP.
  • To allow for remote (web-based) control, in the router control panel, setup port forwarding based on that static IP, for port 80.
  • To view OctoPrint locally, I can browse directly to the static IP I assigned.  Note I was never able to go to hoctopi.local/ either over ethernet of wifi:  I get a constant “webpage not available”.
  • To view Octoprint over the web, I use a search like “what’s my ipv4” to find my homes IPv4 address.  Plugging that back into the browser takes me directly to the Octoprint control panel (presuming it’s on).
  • I have yet to setup a Dynamic DNS service for my IP.
  • Yet to mess with any of the Haproxy stuff.

Configuring the PiCam:

The defaults for the RaspberyPi Cam appear to be 640×480, I’m not sure of the framerate.  That’s a good base starting point, but it can be better.

  • I edited/boot/octopi.txt to set the res to 1280×720 (720p) at 30fps:  The camera tech-specs claim it can do this at 60fps, but I think that’s unnecessary for 3d printing.
  • In Octoprint, in Settings, under Webcam:
    • Set the ‘Timelapse bitrate’ to 10000k, to improve the timelapse movie quality after conversion.
    • Set ‘FFMPEG threads’ to 4 (since I have a RPi 2B, that is quad-core) : This will make the timelapse movie creation faster.
  • Next, I need to get a pair of +2 reading glasses to help bring the focal distance in.  Right now it seems to focus best at the rear of my printbed.

Problems Encountered:

  • I had decided to update my OctoPi image to current since the last install I had done was a good ten months ago:
    • After following all the install instructions, I was unable to get wifi working.
    • Based on the install instructions (here, under “How To Use It”), they have you modifying the octopi-network.txt file on the SD card:  I’m on a Mac, and used TextEdit to do this.
    • After three hours of being unable to connect over wifi, I finally dug out my spare monitor and keyboard, so I could log into the RPi directly.
    • I used nano to edit octopi-network.txt:  To my surprise, the password and ssid values, that should have been surrounded in quotes “”, were instead surrounded by solid white squares:  Some weird special character:  Changing these to “real quote characters” and rebooting fixed the connection issues.  Thanks a lot Apple…
  • I get terrible camera refresh when connected over wifi:  Maybe 1 new frame every… 30 seconds?  Unusable.  I pay for a smoking hot internet connection, so something is amiss.  My google ping is around 900 ms.  If I switch over to ethernet the cam us up to 1-5fps (just guessing) and my google ping is 10-20ms:  Actually usable.  In either case however, the machine control panel is responsive:  I’m able to remote control it without much lag.  At any rate, I ordered a new wifi adaptor (the one listed above), and I immediately got acceptable refresh:  A 1-2 second lag with 5-10fps.  Which wifi dongle you get really matters…
    • Update:  After two days, my new wifi dongle started behaving the exact same:  Super slow refresh.  I had to drop my capture rate to 3fps, at 640×480 for it to behave.  Any faster capture rate would cause increasingly bad lag in the view.  So I went out, got a 50′ cat5 cable, switched to ethernet, and problem solved.  Super speedy camera refresh.  Ethernet FTW.
  • On a number of occasions the PiCam wouldn’t turn on.  Long story short:  The 3d printed bracket it fits into was causing the small connector on the front of the cam to actually disconnect from the cam’s PCB.
  • For the longest time I couldn’t get OctoPrint to shutdown via its ‘System’ menu.  All the other buttons worked except those.  Long story short:  It appaered that having Chrome auto-log me in was causing this:  Logging out & logging back in (without ‘remember me’ checked) seems to have fixed it.

Links:

FAQ Topics:

Time-lapse photography with the Raspberry Pi

Thought it would be fun to setup a time-lapse rig with my Raspberry Pi & it’s camera, having never tried that type of photography before.  A bit of afternoon coding, and success:

11 hours compressed to 60 seconds.

This is what the camera-rig looks like:

SAMSUNG

Used some MircoRax to create a simple frame for the Pi & its camera.

Install dependencies

You can download my Python time-lapse code here.   For the below examples, just stick it in your home (~) folder.

It calls to the fantastic picam library.  Install:

sudo pip install picamera

Record the stills

Executing the timelapse.py code is easy:  It will create a /time-lapse subfolder where it will place all the jpgs.  It doesn’t need any arguments to run:  In that case, it will record for an hour, with enough images to make a one-minute long video at 30fps:  It’s designed to take the guesswork out of trying to figure out how many frames to render at what interval based on the framerate.  It handles it all for you behind the scenes. Plus it’s all configurable.  To query the help:

$ python timelapse.py -h
usage: timelapse.py [-h] [-ct float] [-dur int] [-fps int] [-xres int]
                    [-yres int] [-q int] [-y int] [-m int] [-d int] [-hr int]
                    [-min int] [-s int]

Time for time-lapse! To start recording at a certain time, pass in any or all
of the time related args. If no time-related args are passed in, recording
will start immediately.

optional arguments:
  -h, --help            show this help message and exit
  -ct float, --captureTime float
                        in HOURS, default 1.0
  -dur int, --duration int
                        of final movie in SECOMDS, default 60
  -fps int, --framesPerSecond int
                        of final movie (default 30)
  -xres int, --Xresolution int
                        of image (default 1280)
  -yres int, --Yresolution int
                        of image (default 720)
  -q int, --quality int
                        of jpeg from 1-100 (default 85)
  -y int, --year int    ...to start recording
  -m int, --month int   ...to start recording
  -d int, --day int     ...to start recording
  -hr int, --hour int   ...to start recording
  -min int, --minute int
                        ...to start recording
  -s int, --second int  ...to start recording

So for example, to capture for 12 hours, and end up with a 1 minute long video:

python timelapse.py -ct 12.0 -dur 60

It also supports a delayed start, if you pass in any of the time values.  For example, if you pass in an hour, it will wait for that hour to start recording.   If you pass in a minute, it’ll wait for that minute of the current hour, etc.  You can pass in any of the year, month, day, hour, minute, second, or none.  If none, it starts capturing immediately.

Finally, I’ve learned that if you’re logging in via ssh, you should launch your code via nohup:

nohup python timelapse.py -ct 12.0 -dur 60

If you don’t do that, when you close the remote shell, it’ll kill the process, and no timelapse for you!

Make a movie

After you capture all the stills, how to make into a movie?  The mencoder software can be used on the pi for that.  I found a tutorial here that provides a solution.  To install:

sudo apt-get install mencoder

First make a list of files from your /time-lapse folder (from the above tutorial link):

cd time-lapse
ls *.jpg > stills.txt

Then, to convert them into a movie with mencoder (modified version of the above example):

mencoder -nosound -ovc lavc -lavcopts vcodec=mpeg4:aspect=16/9:vbitrate=8000000 -o tlcam_01.avi -mf type=jpeg:fps=30 mf://@stills.txt

Copy to your PC

This will create a new avi file on the Pi.  To get that moved to your PC, on Mac/Linux you can use scp (below example is my Pi’s IP, change it to match yours).  Note, the below code is executed from your PC, not the Pi, and copies it to my Mac’s home folder:

scp pi@192.168.2.27:~/time-lapse/tlcam_01.avi ~/tlcam_01.avi

Or you can use this great tutorial on how to use SFTP via FileZilla, if you’re more comfortable in a windowed environment.

Once I got my first movie copied over, I couldn’t play it (on my Mac) via the Quicktime player.  However, my install of VLC opened it no problem.  From there it was uploaded to YouTube: Done!

Scrolling the Adafruit 16×2 LCD+Keypad

I wanted to add additional functionality to my Raspberry FM project by having any long station names \ song names scroll on the Adafruit 16×2 LCD+keypad for Raspberry Pi: While the lcd Python module Adafruit provides has methods to scroll the text (scrollDisplayLeft, scrollDisplayRight, autoScroll), I was unable to get them to work nor find any good examples.  Maybe it’s completely possible with what they provide, but I had no luck with it.  If anyone does know how, please comment! :)

Why not write my own?  That’s a fun thing to do on a Saturday afternoon, right? 😉  Find a snapshot of the Python source below, and a link to the most current version on Bitbucket here: lcdScroll.py

To see it in action:

It’s a standalone module I designed to work with any sized lcd:  It’s really just a text formatter:  All the drawing to the LCD would be handled by some other application.  A very simple example can also be found on Bitbucket here: lcdScrollTest.py Or of course you could check out the Raspberry FM source here:  raspberryFm01.py

For either the top or bottom line, if they are longer than 16 characters (which is completely adjustable based on the type of lcd used), they will auto-scroll.  If less than 16 characters, no scrolling happens.  So you can have completely independent scrolling on any line based on their length.

#!/usr/bin/python
"""
lcdScroll.py
Author             :  Eric Pavey 
Creation Date      :  2014-02-08
Blog               :  http://www.akeric.com/blog

Free and open for all to use.  But put credit where credit is due.

OVERVIEW:-----------------------------------------------------------------------
Create scrolling text on a LCD display.  Designed to work on the the 
Adafruit LCD  + keypad, but it's not tied to any specific hardware, and should
work on a LCD of any size.

See lcdScrollTest.py for simple example usage.
"""

class Scroller(object):
    """
    Object designed to auto-scroll text on a LCD screen.  Every time the scroll()
    method is called to, it will scroll the text from right to left by one character
    on any line that is greater than the provided with.
    If the lines ever need to be reset \ updated, call to the setLines() method.
    """
    def __init__(self, lines=[], space = " :: ", width=16, height=2):
        """
        Instance a LCD scroller object.

        Parameters:
        lines : list / string : Default empty list : If a list is passed in, each 
            entry in the list is a  string that should be displayed on the LCD, 
            one line after the next.  If a string, it will be split by any embedded 
            linefeed \n characers into a list of multiple lines . 
            Ultimately, the number of entries in this list must be equal to or 
            less than the height argument.
        space : string : Default " :: " : If a given line is longer than the width
            argument, this string will be added to the end to help designate the
            end of the line has been hit during the scroll.
        width : int : Default 16 : The width of the LCD display, number of columns.
        height : int : Default 2 : the height of the LCD, number of rows.
        """
        self.width = width
        self.height = height
        self.space = space
        self.setLines(lines)

    def setLines(self, lines):
        """
        Set (for the first time) or reset (at any time) the lines to display.
        Sets self.lines

        Parameters:
        lines : list : Each entry in the list is a string
            that should be displayed on the LCD, one line after the next.  The 
            number of entries in this list must be equal to or less than the 
            height argument.
        """
        # Just in case a string is passed in, turn it into a list, and split
        # by any linefeed chars:
        if isinstance(lines, basestring):   
            lines = lines.split("\n")
        elif not isinstance(lines, list):
            raise Exception("Argument passed to lines parameter must be list, instead got: %s"%type(lines))
        if len(lines) > self.height:
            raise Exception("Have more lines to display (%s) than you have lcd rows (%s)"%(len(lines), height))            
        self.lines = lines
        # If the line is over the width, add in the extra spaces to help separate
        # the scroll:
        for i,ln in enumerate(self.lines[:]):
            if len(ln) > self.width:
                self.lines[i] = "%s%s"%(ln,self.space)

    def scroll(self):
        """
        Scroll the text by one character from right to left each time this is
        called to.

        Return : string : The message to display to the LCD.  Each line is separated
            by the \n (linefeed) character that the Adafruit LCD expects.  Each line
            will also be clipped to self.width, so as to not confuse the LCD when
            later drawn.
        """
        for i,ln in enumerate(self.lines[:]):
            if len(ln) > 16:
                shift = "%s%s"%(ln[1:], ln[0])
                self.lines[i] = shift
        truncated = [ln[:self.width] for ln in self.lines]
        return "\n".join(truncated)

Raspberry FM Part 2, the sequal

Nearly a year ago I wrapped up a project I called “Raspberry FM“:  A Raspberry Pi based internet radio streamer coupled with a MaKey MaKey as the interface.   Why the name Raspberry FM?  It’s a mashup of a Raspberry Pi, and my favorite internet radio station, Soma FM.   It worked, but had a few problems:

  • There was no visual feedback, the MaKey MaKey was purely an input.
  • I was having a hard time getting Python to interface with with MPlayer (probably due to my own ignorance), the audio player I had chosen, so everything was done via bash.

Fast forward nearly a year:  After learning about the Mpd audio player/server, and (one of) its clients Mpc, it re-piqued my interest in programming a Python app to play music on the Pi.  Second time around, it all turned out really well:  New software combined with new hardware and a 3d-printed case turned it into a good looking compact unit.

Overview of the whole process below (pic on top, video on bottom).  During the development I decided to write my own Python music player around mpc & Adafruit’s LCD library.  At this point there are several others online, but I enjoyed coding it from scratch.

adaLcdCase

Raspberry FM Features:

  • Auto-on with the Pi
  • If no internet is present or it drops out, app will go into holding pattern until it returns.
  • Can change between any number of stations. (left\right buttons).
  • Stations are easy to add via the commandline:  No need to update Python source: SSH into the Pi, and add\remove what you need.
  • Increase\decrease volume (up\down buttons).
  • Station and song info is displayed and auto-scrolls.
  • Shutdown Pi  (select+left) or turn off program (for debugging, select+right)
  • Lots of color changing when buttons are pressed!

Hardware needed:

  • Raspberry Pi (I used a B model)
  • Adafruit RGB 16×2 LCD+Keypad Kit : Solder and install!
  • Optional:  Custom 3D printed case I designed (well, I designed the top part), download on Thingiverse.  Print & install!  Took me about an 1:20 on my Makerbot Replicator (1).
  • I stream the internet radio over cat5, but I’ve also had success with wifi.
  • I use the headphone jack for audio out.

Software needed:

  • This was all done on the Raspbian distro via NOOBS.
  • My “Raspberry FM” Python program.  Find on Bitbucket.
  • You’ll need Adafruits CharLCDPlate library.
  • FYI, I coded this all via the Adafruit WebIDE, I’d recommend anyone else to use it as well to help manage the various Python modules on the Pi.
  • MPD & MPC:  sudo apt-get install mpc mpd

Steps:

  • I presume you already have your Pi setup.  If not, see my notes here on the general steps needed to get a Pi live and kicking.
  • Setup Pi to auto-login.  See notes here.
  • Download the Raspberry FM Python program to a folder of your choosing.  Since I coded this via the WebIDE, both the creation of my code and the integration of the Adafruit LCD modules was all handled via the WebIDE.  Make sure you download all the Adafruit CharLCDPlate modules as well and put them in the same directory.
  • Install MPD & MPC.
  • Add stations to MPC.  This is super easy on the commandline.  May I recommend anything from SomaFM?
    mpc add http://ice.somafm.com/groovesalad
  • Setup Pi to auto-run a program on start.  See notes here.  You will point that script to wherever you saved the Raspberry FM Python script.  For example, my startup.sh script looks like:
  • #!/bin/bash
    echo startup.sh : Launching raspberryFm.py
    sudo python /usr/share/adafruit/webide/repositories/my-pi-projects/Adafruit_CharLCDPlate/raspberryFm01.py
  • Restart the Pi and listen to the music!

The final result in action: