Archive for category 3D Printer

stl_stats

This is a  small C++ program to iterate over a STL file and to print out a few things:

  1. Max/Min for X, Y and Z –> Bounding Box
  2. Number of layers
  3. “Useful” layers : given a minimum height, if some layers on Z axis are too small it performs a merge. Loosely speaking, if the ratio between “useful” layers and  real layers of the model is too low, it means that the printing of this given model can potentially be not nice in between some layers (it is a sampling issue).
    • Example of problematic details on the bottom of Darth Vader Pen Cup:

NB: For reading the STL file, it is a simple copy-paste from the really good OpenSCAD.

Usage:

stl_stats filename.stl [minLayerHeight]

Dependencies:

boost_regex and boost_system

Output examples:

 

./stl_stats  ../../../Téléchargements/20mm-box.stl
BinarySTL = 0
Layer 0: Axis Z 0
Layer 1: Axis Z 10
—> New Layer height = 10
Number of layers 2
Useful layers 1 (small bug actually it is 2)
Face Number = 12
XMin = -10 XMax = 10, Distance = 20
YMin = -10 YMax = 10, Distance = 20
ZMin = 0 ZMax = 10, Distance = 10
Minimum layer height = 0.3
Max number of layers = 33.3333

./stl_stats  ../../../Téléchargements/darth_vader_pen_cup.stl

Layer 1142: Axis Z 80.001
Previous layer too thin, useless
Number of layers 1143
Useful layers 115
Face Number = 5406
XMin = -36.001 XMax = 54, Distance = 90.001
YMin = -49 YMax = 41.001, Distance = 90.001
ZMin = -0.001 ZMax = 80.001, Distance = 80.002
Minimum layer height = 0.3
Max number of layers = 266.673

./stl_stats  ../../../Téléchargements/darth_vader_pen_cup.stl 0.1

Layer 1142: Axis Z 80.001
Previous layer too thin, useless
Number of layers 1143
Useful layers 214
Face Number = 5406
XMin = -36.001 XMax = 54, Distance = 90.001
YMin = -49 YMax = 41.001, Distance = 90.001
ZMin = -0.001 ZMax = 80.001, Distance = 80.002
Minimum layer height = 0.1
Max number of layers = 800.02

 

Source code:

#include <iostream>
#include <fstream>
#include <sstream>

#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp>
#include <boost/lexical_cast.hpp>

#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
#include <boost/assign/std/vector.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope

#include <boost/detail/endian.hpp>
#include <boost/cstdint.hpp>

#include <map>

//CODE COMING FROM OPENSCAD

#define STL_FACET_NUMBYTES 4*3*4+2
// as there is no 'float32_t' standard, we assume the systems 'float'
// is a 'binary32' aka 'single' standard IEEE 32-bit floating point type
union stl_facet {
	uint8_t data8[ STL_FACET_NUMBYTES ];
	uint32_t data32[4*3];
	struct facet_data {
	  float i, j, k;
	  float x1, y1, z1;
	  float x2, y2, z2;
	  float x3, y3, z3;
	  uint16_t attribute_byte_count;
	} data;
};

inline void uint32_byte_swap( uint32_t &x )
{
#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 3
	x = __builtin_bswap32( x );
#elif defined(__clang__)
	x = __builtin_bswap32( x );
#elif defined(_MSC_VER)
	x = _byteswap_ulong( x );
#else
	uint32_t b1 = ( 0x000000FF & x ) << 24;
	uint32_t b2 = ( 0x0000FF00 & x ) << 8;
	uint32_t b3 = ( 0x00FF0000 & x ) >> 8;
	uint32_t b4 = ( 0xFF000000 & x ) >> 24;
	x = b1 | b2 | b3 | b4;
#endif
}

inline void read_stl_facet( std::ifstream &f, stl_facet &facet )
{
	f.read( (char*)facet.data8, STL_FACET_NUMBYTES );
#ifdef BOOST_BIG_ENDIAN
	for ( int i = 0; i < 12; i++ ) {
		uint32_byte_swap( facet.data32[ i ] );
	}
	// we ignore attribute byte count
#endif
}

inline int readStlFile(const char *filename, double minLayerHeight = 0.3 ) {
  // Open file and position at the end
  std::ifstream f(filename, std::ios::in | std::ios::binary | std::ios::ate);
  if (!f.good()) {
    std::cerr << "WARNING: Can't open stl file:" <<  filename << std::endl;
    return -1;
  }

  boost::regex ex_sfe("solid|facet|endloop");
  boost::regex ex_outer("outer loop");
  boost::regex ex_vertex("vertex");
  boost::regex ex_vertices("\\s*vertex\\s+([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)");

  bool binary = false;
  std::streampos file_size = f.tellg();
  f.seekg(80);
  uint32_t facenum = 0;
  if (f.good() && !f.eof()) {
    f.read((char *)&facenum, sizeof(uint32_t));
#ifdef BOOST_BIG_ENDIAN
    uint32_byte_swap( facenum );
#endif
    if (file_size ==  static_cast<std::streamoff>(80 + 4 + 50*facenum)) {
      binary = true;
    }
  }
  f.seekg(0);

  //START OF MY STAT STUFF
  std::cout << "BinarySTL = " << binary << std::endl;

  double XMin = 1000000000.0, XMax = -10000000000.0;
  double YMin = 1000000000.0, YMax = -10000000000.0;
  double ZMin = 1000000000.0, ZMax = -10000000000.0;

  facenum = 0;

  std::map<double, uint32_t> stlLayers; //number of layers

  //END OF MY STAT STUFF

  char data[5];
  f.read(data, 5);
  if (!binary && !f.eof() && f.good() && !memcmp(data, "solid", 5)) {
    int i = 0;
    double vdata[3][3];
    std::string line;
    std::getline(f, line);
    while (!f.eof()) {
      std::getline(f, line);
      boost::trim(line);
      if (boost::regex_search(line, ex_sfe)) {
	continue;
      }
      if (boost::regex_search(line, ex_outer)) {
	i = 0;
	continue;
      }
      boost::smatch results;
      if (boost::regex_search(line, results, ex_vertices)) {
	try {
	  for (int v=0;v<3;v++) {
	    vdata[i][v] = boost::lexical_cast<double>(results[v+1]);
	  }
	}
	catch (const boost::bad_lexical_cast &blc) {
	  std::cout << "WARNING: Can't parse vertex line:" <<  line;
	  i = 10;
	  continue;
	}
	if (++i == 3) { //CREATE TRIANGLE
	  /*	  p->append_poly();
	  p->append_vertex(vdata[0][0], vdata[0][1], vdata[0][2]);
	  p->append_vertex(vdata[1][0], vdata[1][1], vdata[1][2]);
	  p->append_vertex(vdata[2][0], vdata[2][1], vdata[2][2]); */

	  facenum++;

	  //min,max
	  for(unsigned j = 0 ; j < 3 ; j ++ ) {
	    if ( XMin > vdata[j][0] ) {
	      XMin = vdata[j][0];
	    }
	    if ( XMax < vdata[j][0] ) {
	      XMax = vdata[j][0];
	    }
	    if ( YMin > vdata[j][1] ) {
	      YMin = vdata[j][1];
	    }
	    if ( YMax < vdata[j][1] ) {
	      YMax = vdata[j][1];
	    }
	    if ( ZMin > vdata[j][2] ) {
	      ZMin = vdata[j][2];
	    }
	    if ( ZMax < vdata[j][2] ) {
	      ZMax = vdata[j][2];
	    }
	  }

	  //stl layers
	  for(unsigned j = 0 ; j < 3 ; j ++ ) {
	    stlLayers[ vdata[j][2] ] = 1;
	  }

	}
      }
    }
  }
  else if (binary && !f.eof() && f.good())
    {
      f.ignore(80-5+4);
      while (1) {
	stl_facet facet;
	read_stl_facet( f, facet );
	if (f.eof()) break;

	//CREATE TRIANGLE

	facenum++;

// 	p->append_poly(); 
// 	p->append_vertex(facet.data.x1, facet.data.y1, facet.data.z1);
// 	p->append_vertex(facet.data.x2, facet.data.y2, facet.data.z2);
// 	p->append_vertex(facet.data.x3, facet.data.y3, facet.data.z3);

	//min,max
	if ( XMin > facet.data.x1 ) {
	  XMin = facet.data.x1;
	}
	if ( XMin > facet.data.x2 ) {
	  XMin = facet.data.x2;
	}
	if ( XMin > facet.data.x3 ) {
	  XMin = facet.data.x3;
	}
	if ( XMax < facet.data.x1 ) {
	  XMax = facet.data.x1;
	}
	if ( XMax < facet.data.x2 ) {
	  XMax = facet.data.x2;
	}
	if ( XMax < facet.data.x3 ) {
	  XMax = facet.data.x3;
	}

	if ( YMin > facet.data.y1 ) {
	  YMin = facet.data.y1;
	}
	if ( YMin > facet.data.y2 ) {
	  YMin = facet.data.y2;
	}
	if ( YMin > facet.data.y3 ) {
	  YMin = facet.data.y3;
	}
	if ( YMax < facet.data.y1 ) {
	  YMax = facet.data.y1;
	}
	if ( YMax < facet.data.y2 ) {
	  YMax = facet.data.y2;
	}
	if ( YMax < facet.data.y3 ) {
	  YMax = facet.data.y3;
	}

	if ( ZMin > facet.data.z1 ) {
	  ZMin = facet.data.z1;
	}
	if ( ZMin > facet.data.z2 ) {
	  ZMin = facet.data.z2;
	}
	if ( ZMin > facet.data.z3 ) {
	  ZMin = facet.data.z3;
	}
	if ( ZMax < facet.data.z1 ) {
	  ZMax = facet.data.z1;
	}
	if ( ZMax < facet.data.z2 ) {
	  ZMax = facet.data.z2;
	}
	if ( ZMax < facet.data.z3 ) {
	  ZMax = facet.data.z3;
	}

	//stl layers
	stlLayers[ facet.data.z1 ] = 1;
	stlLayers[ facet.data.z2 ] = 1;
	stlLayers[ facet.data.z3 ] = 1;

      }
    }

  std::map<double, uint32_t>::iterator stlLayer_it;
  uint32_t layers = 0, usefulLayers = 0;
  double previousLayer = -10000000.0;
  for( std::map<double, uint32_t>::iterator it = stlLayers.begin();
       it != stlLayers.end();
       ++ it ) {
    std::cout << "Layer " << layers << ": Axis Z " << it->first << std::endl;
    if ( layers > 0 ) {
      if ( minLayerHeight > (it->first - previousLayer) )  {
	std::cout << "Previous layer too thin, useless" << std::endl;
      }
      else {
	usefulLayers++;
	std::cout << "              ---> New Layer height = " << (it->first - previousLayer) << std::endl;
	previousLayer = it->first;
      }
    }
    else {
      previousLayer = it->first;
    }
    layers ++;
  }
  std::cout << "Number of layers " << layers << std::endl;
  std::cout << "Useful layers " << usefulLayers << std::endl;

  std::cout << "Face Number = " << facenum << std::endl;
  std::cout << "XMin = " << XMin << " XMax = " << XMax << ", Distance = " << (XMax - XMin) << std::endl;
  std::cout << "YMin = " << YMin << " YMax = " << YMax << ", Distance = " << (YMax - YMin) << std::endl;
  std::cout << "ZMin = " << ZMin << " ZMax = " << ZMax << ", Distance = " << (ZMax - ZMin) << std::endl;

  std::cout << "Minimum layer height = " << minLayerHeight << std::endl;
  std::cout << "Max number of layers = " << ((ZMax - ZMin)/minLayerHeight) << std::endl;

  return 0;
}

static int usage() {

  std::cout << "stl_stats filename.stl [minLayerHeight]" << std::endl;

  return -1;
}

int main(int argc, char **argv) {

  if ( argc < 2 || argc > 3 ) {
    return usage();
  }

  const char *filename = argv[1];
  double minLayerHeight = 0.3;
  if ( argc == 3 ) {
    minLayerHeight = atof(argv[2]);
  }

  return readStlFile(filename,minLayerHeight);

}

syntax highlighted by Code2HTML, v. 0.9.1

No Comments

Velleman K8200 – Rigidifier le haut du support de la vis pour Z

Il y a cette superbe pièce à imprimer directement sur thingiverse (http://www.thingiverse.com/thing:166023), quand on voit la pièce d’origine on comprend :)

Résultat: Amélioration de l’impression au niveau des couches, elles sont un peu moins visibles.

Par contre le support du Z au niveau du moteur pas à pas çà bouge …. mais bon c’est pas nouveau

No Comments

Velleman K8200 – Ventilateur horizontal et tole d’isolation

Je trouve que le montage d’origine est complètement nul, il y a une légion de “guides” pour ce ventilo sur thingiverse.

La version 0.0

A cause de ma précédente mésaventure sur l’extrudeur, çà s’est en fait transformé en opportunité. La tôle que j’ai utilisé est assez grande pour faire aussi office de support pour le ventilateur.

Je ne m’en suis pas privé et j’ai mis directement le ventilateur à souffler horizontalement.

Résultat: la qualité des impressions a bien augmenté très nettement.

Par contre, j’ai vu qu’il y avait beaucoup de variations de température au niveau de la buse.

La version 0.1

Pour contrer les grosses variations de température, j’avais encore un bout de tôle fine.

Ben oui, du coup je l’ai formé grossièrement afin de faire un guide qui n’envoie pas d’air sur la tête.

Résultat: la qualité des impressions a  augmenté légèrement et surtout il y a que très peu de variations de température au niveau de la buse.

 

No Comments

Ubuntu – Repetier Host

Installer Repetier Host

https://github.com/repetier/Repetier-Host/issues/156

Installer automake-1.11 et la mettre par defaut (via alternatives)

sudo update-alternatives --config automake

Reinstaller Mono avec un patch pour la vitesse sur le port série (sinon çà ne marche pas)

wget https://github.com/mono/mono/archive/mono-2-10-8.tar.gz
sudo apt-get install mono-mcs mono-gmcs

tar -xvzf mono-mono-2-10-8.tar.gz
cd mono-mono-2-10-8

wget -O serial.patch https://bugzilla.xamarin.com/attachment.cgi?id=3302&action=diff&context=patch&collapsed=&headers=1&format=raw
patch ./support/serial.c serial.patch

./autogen.sh --prefix=/usr
make
sudo make install

 

No Comments

Velleman K8200 – Extrudeur avec filet foiré –> Support tôle et extrudeur sauvé

Lorsque j’ai monté l’extrudeur, je n’avais pas de joint dans le kit. Du coup, j’ai trop forcé et j’ai bousillé le pas de vis de la tête de l’extrudeur et du support.

Après avoir essayé de mettre de la Loctite Autojoint Bleu, ben çà ne tenait pas et le PLA sortait sur les côtés…

Finalement, j’ai bricolé un support externe à partir d’une fine tôle utilisée pour le support de disque durs pour portable. J’ai découpé un bout de 10mm par 100mm. J’ai fait une mise en forme grossière avec une pince multiprise et un petit marteau. (Attention çà coupe)

J’ai fait 1 trou de 4 mm pour passer la tête de l’extrudeur et 2 autres trous de 4mm pour la fixation.

Sécurité: Lors du perçage il faut absolument bien bloquer le bout de tôle sinon vous risquer de vous couper et de vous faire mal

J’ai du changer les vis M3 avec 5mm de plus. La tôle une fois serrée reste entre 3 à 5 mm du support, de façon à ce que la tôle appuis sur la tête de l’extrudeur.

J’ai tourné à 90 degrés le support chauffant, pour libérer la place afin de passer facilement le nouveau support. (Il faut que je déplace le ventilateur.)

J’ai utilisé pour les joints de la Loctite Bleu. Pas de fuite même en forçant violemment à la main et faire sortir le PLA une fois en température.

Update 26/07/2014: J’utilise toujours ce bignou là sans soucis depuis plusieurs mois. La Loctite bleu c’est bien sympa et c’est difficile à bruler même au chalumeau ;)

No Comments