OllisGit / OctoPrint-SpoolManager

Plugin for managing Spools
169 stars 57 forks source link

Spool Autodetection using Apriltags Proof-of-Concept #282

Closed marcocarnut closed 2 years ago

marcocarnut commented 2 years ago

I often forget to select the correct spool, messing all measurements. I initially thought of putting a new camera near the spool to read the QR code I glued on it, but QR code reading is somewhat unreliable -- rather minor twists on the spool or unfavorable lighting conditions would upset the QR code detection.

Apriltags, however, are very robust -- they're widely used in robotics, being specifically designed to be reliably detected at a distance, at weird angles and unfavorable lighting. They can only carry a small numeric ID, but that's more than enough.

So I printed a ring of Apriltags, glued on the spool, took a picture with the same camera I use to monitor the print, getting something like that:

snap-8

Then I ran the image through the Apriltag "demo" utility, and, to my joy, it detected the tags perfectly, spitting out its ID (which I made the same as my spool databaseId).

Not wanting to mess with the plugin's source code just yet, I wrote the small bash script below to detect and automatically select the spool via the API:

#!/bin/bash

# Create a self-lock so we don't execute more than once

[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :

tmpdir=/dev/shm
imgfile=$tmpdir/snap.jpg
url='http://localhost:8080/?action=snapshot'
action_url=http://localhost/plugin/SpoolManager/selectSpool
api_key=####put-your-api-key-here#####
attempt=0
maxattempts=80
interval=2
echo "Autoselect starting at $(date)"

while [ "$attempt" -ne "$maxattempts" ] ; do
  attempt=$(( attempt + 1 ))
  echo "Attempt $attempt of $maxattempts... " | tee -a  $tmpdir/autoselect.log
  # Get a snapshot from the camera
  wget -O $tmpdir/snap-$attempt.jpg "$url" 2>/dev/null
  # Try to identify it
  spool_ids=( $(
    /home/pi/apriltag_demo -f tagCustom48h12 $tmpdir/snap-$attempt.jpg 2>/dev/null | \
      perl -ne 'print "$1\n" if m{detection.*-(\d+)}o' | \
      sort -u
  ) )

  if [ "${spool_ids[1]}" != "" ] ; then
     echo 'Ambiguous detection, this should not happen!' | tee -a  $tmpdir/autoselect.log
     exit 3
  fi
  echo spool_ids=$spool_ids
  spool_id=${spool_ids[0]}
  if [ "$spool_id" == "" ] ; then
    echo 'Spool identifier tag not detected' | tee -a  $tmpdir/autoselect.log
    sleep $interval
    continue
  fi

  echo "Found identifier: $spool_id" | tee -a  $tmpdir/autoselect.log

  data="{\"databaseId\":$spool_id,\"toolIndex\":0,\"commitCurrentSpoolValues\":false}"
  json="Content-Type: application/json"
  sid=$( curl -X PUT -d "$data" -H "$json" "$action_url?api_key=$api_key" 2>/dev/null | jq -r .selectedSpool.databaseId )
  if [ "$sid" -eq "$spool_id" ] ; then
    echo 'Success!' | tee -a  $tmpdir/autoselect.log
    exit 0
  else
    echo "Failed when trying to set spool in Octoprint" | tee -a  $tmpdir/autoselect.log
    exit 1
  fi
done

echo "Exceeded maximum number of attempts" | tee -a  $tmpdir/autoselect.log
exit 2

At least in my setup, it works just fine and I no longer have to worry about manually selecting the correct spool :) Now my usage measurements are always correct (at least with the new spools after I started using this).

It would be nice to have this feature properly coded in the plugin natively. I'm a C, perl and nodejs guy, but I'm a relative noob in Python and a total noob in Octoprint plugin development, so I'd appreciate any guidance/suggestions you might have.

If anyone wants to reproduce this, you'll need wget, curl, jq and apriltag_demo from the examples directory of:

github-actions[bot] commented 2 years ago

This issue has been automatically marked for closing, because it has not had activity in 30 days. It will be closed if no further activity occurs in 10 days.

github-actions[bot] commented 2 years ago

This issue was closed, because it has been already marked for 10 days with no activity.