Este é um blog de geral de matemática, física, electrónica, áudio, LISP, Arduino, impressão 3D, etc, ... Já tem uns anitos :)

As entrada antigas estão arquivadas de uma forma não linear.

Happy hacking!

RSS

[Valid RSS]


Vertex Nano 3d printer
... config files and whatnot

2023/09/05-10:51:25

Just got a Velman Vertex Nano 3D printer. Had to hack a glass to replace the original stuff that was over the bed. Works nicely now.

Here's the configuration gdode files. Have fun!

;step1.gcode
M502 ;Revert to the default "factory settings."
M500 ;Store parameters in EEPROM
M117 HOMING...
G28  ;Auto home
M117 POSITIONING NOZZLE
G1 X40 Y40 Z2 F500 ;Position Nozzle
G4 S1 ;Wait a second
M117 MOVE Z TO TOUCH BED
;step2.gcode
M117 POSITIONING NOZZLE
G1 X0 Y80 F500 ;Position Nozzle
G4 S1 ;Wait a second
M117 APPLY HOME OFFSETS

1. Save these files onto a SD-CARD

Save these 2 files onto an SD-CARD you can use for the Vertex Nano (step1.gcode step2.gcode)

2. Run step1.gcode

Insert the SD-CARD into the Vertex Nano and power it up. Navigate to the PRINT FROM SD-CARD menu and choose the step1.gcode file.

The printer will go through some steps and come to a complete stop with the following message on the screen: MOVE Z TO TOUCH BED

3. Move axis (Z touching bed)

Navigate to the MOVE AXIS menu and choose MOVE 0.1mm.

Then choose Move Z and move the HOTEND downwards by turning the knob, until it just touches the bed. You should still be able to slide a piece of normal paper between the BED and the NOZZLE.

If you have completed this part, go back to the main menu.

4. Run step2.gcode

Navigate to the PRINT FROM SD-CARD menu, and choose the setp2.gcode file.

The printer will go through some steps and come to a complete stop with the following message on the screen: APPLY HOME OFFSETS

5. Set home offsets

Lastly, simply click SET HOME OFFSETS in the control menu to finalize the calibration. 'Offsets applied' should now appear on the information screen. If so, continue to the next chapter!

Etiquetas/Tags: vertex nano, 3d, 3d printer


Voight pipe enclosures
A simple speaker enclosure

2022/08/01-10:37:17

Pipe enclosures were design in the 30's by Paul G.A.H. Voigt, it was subject to a patent (GB447749 (A) ― 1936-05-18). The principle is quite simple

Probably inspired by pipe organ tubes.

The image below shows the Herbert Jeschke's Voigt Pipe for a build the pipes for a undetermined 8" driver: the classical way of building the Voigt pipe.

The angle is given by

(atan (/ (+ 8 (/ 3.0 4.0)) 71.0));0.12262114279484264

(/ (* (atan (/ (+ 8 (/ 3.0 4.0)) 71.0)) 180) pi);7.025673961215487

Position of the driver: latex2png equation

Length of the pipe:

latex2png equation

Actually it should be latex2png equation removing the area of the speaker at the bottom, latex2png equation is the speaker resonant frequency.

Here is my hack on it with a Fonestar 3inch=7.5cm speaker (20-14.000 Hz, 8 Ω, 89 dB - 1 W/1 m)

Not really a full-driver, but for 10Eurs, who can complain.

(atan (/ 15.0 108));0.13800602365751946

(/ (* (atan (/ 15.0 108)) 180) pi);7.907162702958458

Top area:

(* 7.0 7.5);52.5

Bottom area:

(* 7.0 15.5);108.5

Speaker position:

(/ 108.0 (+ 2 (pow (/ (* 7.0 7.5)
                      (* 7.0 15.5)) .5)));40.06516757332509

Further reading:

Some more thoughts soon.

Etiquetas/Tags: voigt, speaker, hifi, audio


Word list
Funções em elisp para manipulação de ficheiros de palavras.

2022/04/17-10:30:34

Na antiga versão do jogo do monopólio existia uma carta da sorte que começava com a expressão "Levou um tiro de um amigo..." e normalmente o que se seguia consistia no pagamento de uma conta do hospital.

Um amigo não me deu um tiro mas fez-me uma pergunta, e no meu caso a procura da resposta leva a quase uma visita ao hospital. A pergunta era: " Será que existem palavras de 5 letras em português que verifiquem o padrão seguinte?"

1 5 9 1 7 
2 6 0 5 6 
3 7 3 4 0 
4 8 2 8 9 
Nota: cada número representa uma letra diferente.

Não interessa muito de onde aparece a motivação da pergunta, interessa-me mais a procura da resposta. Há largos meses que tinha começado a ler o volume 4 do TAOCP Combinatorial Algorithms, Part 1 onde, entre outras coisas, é usada a Stanford GraphBase, uma lista de 5757 palavras em inglês com cinco letras, para exposição dos vários algoritmos que aí são descritos.

Propus-me então replicar1 alguns dos resultados descritos no TAOCP usando palavras em PT. Para isso precisava de um dicionário e uma maneira de começar a extrair a informação. O resultado é este pequeno conjunto de funções em elisp. Muito ainda está por fazer, por exemplo, o aspell usa um sistema de compressão para prefixos e sufixos, cuja sintaxe só descobri hoje, e que aumenta o número de palavras disponíveis para se brincar.

;;; wlist.el --- Emacs tools for manipulating word-files 
;; word-files, meaning a file with words in it, one word per line.

;; Author: tca
;; Maintainer: tca
;; Created: Fev, 17, 2012
;; Version: .1
;; Keywords: words
;; URL: https://nexp.pt/wlist.html

;; Copyright (c) 2012 Tiago Charters de Azevedo

;; This file is not part of GNU Emacs.

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.

;; This program 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 General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.

;;; Commentary:
;; None.

;; Code:

(defvar wlist-max-lenght 
  0
  "")

(defvar wlist-regexp-pt
  "[aerisontcdmlupvgbfzáhçqjíxãóéêâúõACMPSBTELGRIFVDkHJONôywUKXZWQÁYÍÉàÓèÂÚ].+"
  "Regular expression for a portuguese word; see aspell.")

(defun wlist-looking-at-size ()
  "Returns the length of a word on the beginning of a line (pt-PT)."
  (interactive)
  (if  (looking-at wlist-regexp-pt)
      (length (match-string-no-properties 0))
    0))

(defun  wlist-looking-at-size-plus-1 ()
  (interactive)
  (forward-line 1)
  (wlist-looking-at-size))

(defun wlist (size)
  "Removes all sized SIZE words from `current-buffer'; asks SIZE."
  (interactive "n") 
  (with-current-buffer (current-buffer)
    (goto-char (point-min))
    (save-excursion  
      (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
        (when (not (= size (wlist-looking-at-size)))
          (delete-region (point) (line-end-position)))
        (forward-line 1))))
  (wlist-delete-blank-lines))

(defun wlist-delete-blank-lines ()
  (interactive)
  (with-current-buffer (current-buffer)
    (goto-char (point-min))
    (save-excursion  
      (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
        (delete-blank-lines)
        (forward-line 1)))))

(defun wlist-insert-header ()
  "Inserts a not so beautiful header."
  (goto-char (point-min))
  (insert (format "File name: %s\n" (file-name-nondirectory (buffer-file-name)))
          (format "Number of %s sized words: %s\n" size (line-number-at-pos (point-max)))))

(defun wlist-hamming-dist-list (lst1 lst2)
   "For equal length lists is the number of positions at which the 
corresponding lists are different."
  (if  (and lst1 lst2
            (= (length lst1) (length lst2)))
      (if (equal (car lst1) (car lst2))
          (wlist-hamming-dist-list (cdr lst1) (cdr lst2))
        (+ 1 (wlist-hamming-dist-list (cdr lst1) (cdr lst2))))
    0))

(defun wlist-hamming-dist (str1 str2)
  "For equal length strings is the number of positions at which the 
corresponding strings are different."
  (wlist-hamming-dist-list (string-to-list str1) 
                              (string-to-list str2)))

(defun wlist-remove-bslash ()
  "Remove /* properties form word-file. No plurals or m/f, etc,... 
Needs to be changed correctly for portuguese."
  (interactive)
  (with-current-buffer (current-buffer)
    (goto-char (point-min))
    (save-excursion  
      (while (search-forward-regexp "\\(.+\\)\\(/.+\\)" nil t)
        (let ((word-s (match-string-no-properties 1)))
          (replace-match word-s))))))

(defun wlist-max-size ()
  "Gets the maximum size of all words in a word-file."
  (interactive)
  (with-current-buffer (current-buffer) 
    (goto-char (point-min))
    (save-excursion  
      (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
        (setq wlist-max-lenght (max (wlist-looking-at-size) (wlist-looking-at-size-plus-1) wlist-max-lenght))))))

(defun wlist-file-size (size)
  "Determines and creates a file of all the words with size SIZE."
  (interactive "n")
  (let ((dic-words (buffer-string)))
    (with-temp-buffer
      (insert dic-words)
      (wlist size)
      (append-to-file (point-min) (point-max) 
                      (concat default-directory (format "%s.wl" size))))))

(defun wlist-all-files-sizes ()
  "Determines all the words from size 2 to `wlist-max-size' 
and save them to separate files *.wl; it takes a few minutes to finish."
  (interactive)
  (if (= wlist-max-lenght 0)
      (wlist-max-size))
  (let ((size 2))
    (while (<= size wlist-max-lenght )
      (wlist-file-size size)
      (incf size))))
  
(defun wlist-same-pos (n)
  (interactive "x")
  (with-current-buffer (current-buffer) 
    (goto-char (point-min))
    (save-excursion  
      (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
        (looking-at wlist-regexp-pt)
        (if (not (equal (nth (- (car n) 1 )
                        (string-to-list (match-string-no-properties 0)))
                   (nth (- (cadr n) 1)
                        (string-to-list (match-string-no-properties 0)))))
;;          (message (match-string-no-properties 0)))
            (delete-region (point) (line-end-position)))
        (forward-line 1)))
    (wlist-delete-blank-lines)))

(defun wlist-file-same-pos (n)
  (interactive "x")
  (let ((i (car n))
        (j (cadr n))
        (words (buffer-string)))
    (with-temp-buffer
      (insert words)
      (wlist-same-pos (list i j))
      (append-to-file (point-min) (point-max) 
                      (concat default-directory (format "%s_%s.wl" i j))))))


(defun wlist-find-all-hamming-dist-word (word dist)
  (with-current-buffer (current-buffer) 
    (goto-char (point-min))
    (save-excursion  
      (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
        (looking-at wlist-regexp-pt)
        (if (not (= dist (wlist-hamming-dist word (match-string-no-properties 0))))
            (delete-region (point) (line-end-position)))
        (forward-line 1)))
    (wlist-delete-blank-lines)))

(defvar wlist-buffer-content-list nil
  "")

(defun wlist-buffer-length ()
  (count-lines (point-min) (point-max)))
  
(defun wlist-buffer-alist ()
  (interactive)
  (with-current-buffer (current-buffer) 
    (goto-char (point-min))
    (let ((wl-buffer-list nil))
      (save-excursion  
        (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
          (looking-at wlist-regexp-pt)
          ;;    (push 'new-item accumulator)
        (push (match-string-no-properties 0) wl-buffer-list)
        (forward-line 1)))
      (reverse wl-buffer-list))))

(defvar wlist-word-link nil
  "")

(defun wlist-hamming-dist-word-insert (word dist)
  "Looks for the hamming DIST of word WORD, inserts all the words found after WORD."
  (setq wlist-word-link nil)
  (with-current-buffer (current-buffer) 
    (goto-char (point-min))
    (save-excursion
      (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
        (looking-at wlist-regexp-pt)
        ;; Looks for word in file and save point, for inserting.
        (if (equal word (match-string-no-properties 0))
            (setq w-point (list (point) (line-end-position))))
        (forward-line 1)))
    (save-excursion  
      (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
        (looking-at wlist-regexp-pt)
        (if (= dist (wlist-hamming-dist word (match-string-no-properties 0)))
            (push (match-string-no-properties 0) wlist-word-link))
        (forward-line 1)))
    (goto-char (cadr w-point))
    (insert (format " %s" (mapconcat 'concat word-link " ")))))

(defun wlist-hamming-dist-insert-buffer (dist)
  "Builds the world link with DIST and inserts the result after every word in buffer."
  (let ((wlist-list (wlist-buffer-alist)  ))
    (dolist (word wlist-list)
      (wlist-hamming-dist-word-insert word dist))))

(defun wlist-insert-after-word (word in-word)
  "Insert IN-WORD in `curren-buffer' after WORD."
  (with-current-buffer (current-buffer) 
    (goto-char (point-min))
    (save-excursion
      (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
        (looking-at wlist-regexp-pt)
        (if (equal word (match-string-no-properties 0))
            (replace-match (format "%s %s" word in-word)))
        (forward-line 1)))))

(defun wlist-hamming-dist-word-list (word dist)
  "Looks for the words with hamming DIST of word WORD; returns all of the in a list."
  (setq wlist-word-link nil)
  (with-current-buffer (current-buffer) 
    (goto-char (point-min))
    (save-excursion  
      (while (< (line-number-at-pos) (line-number-at-pos (point-max)))
        (looking-at wlist-regexp-pt)
        (if (= dist (wlist-hamming-dist word (match-string-no-properties 0)))
            (push (match-string-no-properties 0) wlist-word-link))
        (forward-line 1))))
  (reverse wlist-word-link))

(defun wlist-word-link-next (word dist)
  "Returns the next link of word-link with hamming DIST of word WORD."
  (car (wlist-hamming-dist-word-list word dist)))

(defun wlist-one-word-link (word dist n)
  "Returns a word-link from WORD whit hamming distance DIST."
  (let ((word-link word)
        (new-word (wlist-word-link-next word dist)))
    (while (and new-word (<= 0 n))
      (push new-word word-link)
      (wlist-one-word-link new-word dist (- n 1)))))
            
(provide 'wlist)


1. Existe tamanho palavrão em português?.

Etiquetas/Tags: aspell, emacs, elisp


How to add a delay control to a pen plotter running grbl
A simple hack to add a delay after a servo move...

2022/04/13-21:59:37

grbl is a wonderful piece of software. One of the issues that lacks solution is the delay control when, instead of using the typical CNC spindle, one uses a servo to control a pen plotter. Here's a simple hack: download grbl, look for the gcode.c file and locate the following part:

// [4. Set spindle speed ]:
  if ((gc_state.spindle_speed != gc_block.values.s) || bit_istrue(gc_parser_flags,GC_PARSER_LASER_FORCE_SYNC)) {
    if (gc_state.modal.spindle != SPINDLE_DISABLE) { 
      #ifdef VARIABLE_SPINDLE
        if (bit_isfalse(gc_parser_flags,GC_PARSER_LASER_ISMOTION)) {
          if (bit_istrue(gc_parser_flags,GC_PARSER_LASER_DISABLE)) {
             spindle_sync(gc_state.modal.spindle, 0.0);
          } else { spindle_sync(gc_state.modal.spindle, gc_block.values.s); }
        }
      #else
        spindle_sync(gc_state.modal.spindle, 0.0);
      #endif
    }
    gc_state.spindle_speed = gc_block.values.s; // Update spindle speed state.
  }

add the following line mc_dwell(0.2); (see below).

// [4. Set spindle speed ]:
  if ((gc_state.spindle_speed != gc_block.values.s) || bit_istrue(gc_parser_flags,GC_PARSER_LASER_FORCE_SYNC)) {
    if (gc_state.modal.spindle != SPINDLE_DISABLE) { 
      #ifdef VARIABLE_SPINDLE
        if (bit_isfalse(gc_parser_flags,GC_PARSER_LASER_ISMOTION)) {
          if (bit_istrue(gc_parser_flags,GC_PARSER_LASER_DISABLE)) {
             spindle_sync(gc_state.modal.spindle, 0.0);
          } else { spindle_sync(gc_state.modal.spindle, gc_block.values.s); }
        }
      #else
        spindle_sync(gc_state.modal.spindle, 0.0);
      #endif
    }
    gc_state.spindle_speed = gc_block.values.s; // Update spindle speed state.

    mc_dwell(0.2); // add this line to set delay for servo motion (in mseconds !?)
  }

Compile the code and upload it. That's it.

Happy hacking!

P.S.

I'm using this spindle_control.c. Servo is controlled by M3 Sx where x take the values 0-255.

Etiquetas/Tags: grbl, plotter, servo, delay, arduino


Planner and look-ahead code from different firmware
Controlling speed is an important factor which determines the quality of computer generated motion profiles.

2022/02/09-14:22:38

3 examples.

From Teacup

 /**
   * What we want is (for each axis):
   *
   *   delta velocity = dv = |v1 - v2| < max_jerk
   *
   * In case this isn't satisfied, we can slow down by some factor x until
   * the equitation is satisfied:
   *
   *   x * |v1 - v2| < max_jerk
   *
   * Now computation is pretty straightforward:
   *
   *        max_jerk
   *   x = -----------
   *        |v1 - v2|
   *
   *   if x > 1: continue full speed
   *   if x < 1: v = v_max * x
   *
   * See also: https://github.com/Traumflug/Teacup_Firmware/issues/45
   */

From Marlin

/**
 * planner.cpp
 *
 * Buffer movement commands and manage the acceleration profile plan
 *
 * Derived from Grbl
 * Copyright (c) 2009-2011 Simen Svale Skogsrud
 *
 * The ring buffer implementation gleaned from the wiring_serial library by David A. Mellis.
 *
 *
 * Reasoning behind the mathematics in this module (in the key of 'Mathematica'):
 *
 * s == speed, a == acceleration, t == time, d == distance
 *
 * Basic definitions:
 *   Speed[s_, a_, t_] := s + (a*t)
 *   Travel[s_, a_, t_] := Integrate[Speed[s, a, t], t]
 *
 * Distance to reach a specific speed with a constant acceleration:
 *   Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, d, t]
 *   d -> (m^2 - s^2)/(2 a) --> estimate_acceleration_distance()
 *
 * Speed after a given distance of travel with constant acceleration:
 *   Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, m, t]
 *   m -> Sqrt[2 a d + s^2]
 *
 * DestinationSpeed[s_, a_, d_] := Sqrt[2 a d + s^2]
 *
 * When to start braking (di) to reach a specified destination speed (s2) after accelerating
 * from initial speed s1 without ever stopping at a plateau:
 *   Solve[{DestinationSpeed[s1, a, di] == DestinationSpeed[s2, a, d - di]}, di]
 *   di -> (2 a d - s1^2 + s2^2)/(4 a) --> intersection_distance()
 *
 * IntersectionDistance[s1_, s2_, a_, d_] := (2 a d - s1^2 + s2^2)/(4 a)
 *
 * --
 *
 * The fast inverse function needed for Bézier interpolation for AVR
 * was designed, written and tested by Eduardo José Tagle on April/2018
 */

From grbl

/*                            PLANNER SPEED DEFINITION
                                     +--------+   <- current->nominal_speed
                                    /          \
         current->entry_speed ->   +            \
                                   |             + <- next->entry_speed (aka exit speed)
                                   +-------------+
                                       time -->
  Recalculates the motion plan according to the following basic guidelines:
    1. Go over every feasible block sequentially in reverse order and calculate the junction speeds
        (i.e. current->entry_speed) such that:
      a. No junction speed exceeds the pre-computed maximum junction speed limit or nominal speeds of
         neighboring blocks.
      b. A block entry speed cannot exceed one reverse-computed from its exit speed (next->entry_speed)
         with a maximum allowable deceleration over the block travel distance.
      c. The last (or newest appended) block is planned from a complete stop (an exit speed of zero).
    2. Go over every block in chronological (forward) order and dial down junction speed values if
      a. The exit speed exceeds the one forward-computed from its entry speed with the maximum allowable
         acceleration over the block travel distance.
  When these stages are complete, the planner will have maximized the velocity profiles throughout the all
  of the planner blocks, where every block is operating at its maximum allowable acceleration limits. In
  other words, for all of the blocks in the planner, the plan is optimal and no further speed improvements
  are possible. If a new block is added to the buffer, the plan is recomputed according to the said
  guidelines for a new optimal plan.
  To increase computational efficiency of these guidelines, a set of planner block pointers have been
  created to indicate stop-compute points for when the planner guidelines cannot logically make any further
  changes or improvements to the plan when in normal operation and new blocks are streamed and added to the
  planner buffer. For example, if a subset of sequential blocks in the planner have been planned and are
  bracketed by junction velocities at their maximums (or by the first planner block as well), no new block
  added to the planner buffer will alter the velocity profiles within them. So we no longer have to compute
  them. Or, if a set of sequential blocks from the first block in the planner (or a optimal stop-compute
  point) are all accelerating, they are all optimal and can not be altered by a new block added to the
  planner buffer, as this will only further increase the plan speed to chronological blocks until a maximum
  junction velocity is reached. However, if the operational conditions of the plan changes from infrequently
  used feed holds or feedrate overrides, the stop-compute pointers will be reset and the entire plan is
  recomputed as stated in the general guidelines.
  Planner buffer index mapping:
  - block_buffer_tail: Points to the beginning of the planner buffer. First to be executed or being executed.
  - block_buffer_head: Points to the buffer block after the last block in the buffer. Used to indicate whether
      the buffer is full or empty. As described for standard ring buffers, this block is always empty.
  - next_buffer_head: Points to next planner buffer block after the buffer head block. When equal to the
      buffer tail, this indicates the buffer is full.
  - block_buffer_planned: Points to the first buffer block after the last optimally planned block for normal
      streaming operating conditions. Use for planning optimizations by avoiding recomputing parts of the
      planner buffer that don't change with the addition of a new block, as describe above. In addition,
      this block can never be less than block_buffer_tail and will always be pushed forward and maintain
      this requirement when encountered by the plan_discard_current_block() routine during a cycle.
  NOTE: Since the planner only computes on what's in the planner buffer, some motions with lots of short
  line segments, like G2/3 arcs or complex curves, may seem to move slow. This is because there simply isn't
  enough combined distance traveled in the entire buffer to accelerate up to the nominal speed and then
  decelerate to a complete stop at the end of the buffer, as stated by the guidelines. If this happens and
  becomes an annoyance, there are a few simple solutions: (1) Maximize the machine acceleration. The planner
  will be able to compute higher velocity profiles within the same combined distance. (2) Maximize line
  motion(s) distance per block to a desired tolerance. The more combined distance the planner has to use,
  the faster it can go. (3) Maximize the planner buffer size. This also will increase the combined distance
  for the planner to compute over. It also increases the number of computations the planner has to perform
  to compute an optimal plan, so select carefully. The Arduino 328p memory is already maxed out, but future
  ARM versions should have enough memory and speed for look-ahead blocks numbering up to a hundred or more.
*/

Etiquetas/Tags: CNC, Marlin, grbl, Teacup, 3d print, 3D, 3D printing


Ball vertical strip vase
... with a vertical line patter do trick your brain and hide the layer lines.

2021/12/06-10:10:02

Inspired by Bubble pencil holder here's an OpenSCAD version. Enjoy!

// Author: Tiago Charters de Azevedo 
// Maintainer: Tiago Charters de Azevedo 

// Copyright (c) - 2021 Tiago Charters de Azevedo

// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3, or (at your option)
// any later version.

// This program 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 General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor,
// Boston, MA 02110-1301, USA.

//Notes:
// Based on: https://www.prusaprinters.org/prints/86837-bubble-pencil-holder

$fn= $preview ? 16 : 32;

n=10;
m=5;
h=1.2;
eps=1;

rball=10;
rvase=30;

spacing=.75*rball;
lvase=m*rball+(m-1)*spacing;

echo("Height:");
echo(lvase);
echo("Radius:");
echo(rvase);

module balls(l=30,r=rball,theta=.25*360/(n-1),spacing=spacing){
    for(j=[0:m-2]){
        for(i=[0:n-2]){
            rotate([0,0,i*360/(n-1)+pow(-1,j)*theta])
            translate([rvase-.1*rball,0,(r+spacing)*j+r+spacing/2])
            sphere(r=r);}}}

module verts(r=rvase,l=lvase,hh=1.2){
    N=1.25*PI*rvase/hh;
    for(i=[0:N]){
        rotate([0,0,i*360/N])
        translate([rvase-h,0,lvase/2])
        cube([3*rball,hh,lvase+eps],center=true);}}


module cylinder1(r=rvase,l=lvase,h=h){
    translate([0,0,l/2])
    difference(){
        cylinder(h=l,r=r,center=true);
        translate([0,0,h])
        cylinder(h=l+eps,r=r-h,center=true);}}

module vase1(hollow=false){
    if (hollow==true){
        //balls
        difference(){
            balls(r=rball);
            cylinder(h=lvase,r=rvase-h);}
        // cylinder
        difference(){
            cylinder1(r=rvase,l=lvase,h=h);
            balls(r=rball);
        }}
    else{
        balls(r=rball);
        cylinder(r=rvase,h=lvase);}}

module vasesolid(){
        vasescale=(rvase-h)/rvase;
        union(){
            scale(vasescale*[1,1,1/vasescale])
            vase1(hollow=false);
            intersection(){
                vase1(hollow=false);
                verts();}}}

module vase(hollow=false){
    vasescale=(rvase-h)/rvase;
    if (hollow==false){
        vasesolid();}
    else{
        difference(){
            vasesolid();
            translate([0,0,lvase/2+h])
            cylinder(h=lvase+eps,r=rvase-2*h,center=true);
             for(j=[0:m-2])
            {
                for(i=[0:n-2])
                {
                    rotate([0,0,i*360/(n-1)+pow(-1,j)*.25*360/(n-1)])
                    translate([rvase-.1*rball,0,(rball+spacing)*j+rball+spacing/2])
                    sphere(r=rball-2*h);}}
            translate([0,0,2*h])
            cylinder(h=lvase,r=rvase-2*h);
            }
    }}




//show
vase(hollow=false);

Etiquetas/Tags: 3dprint, vase, openscad, opensource


Trippy vase
... in OpenSCAD

2021/11/29-16:15:08

Spiral it!

step=$preview ? 1 : 1;    

phi=(1+sqrt(5))/2;

function surf(theta,z,height,R)=R*(1+sin(phi*90*z/height))*(1+.25*(cos(1*360*z/height)+.5*sin(10*theta+sqrt(2)*360*z/height)+.5*sin(5*theta-sqrt(3)*360*z/height)));

eps=.1;
h=1.2;
module vase(height=100,sides=360,R=30,top=true,bottom=true){
    points=[
        for(z=[0:step:height])
        for(theta=[0:sides-1])
        let(r=surf(theta,z,height,R),
            x=r*cos(theta),
            y=r*sin(theta))    
        [x,y,z]];
    
    faces=concat(
        [
            // Triangle #1
            for(z=[0:(height-1)/step])
            for(s=[0:sides-1])
            let(// clockwise from left-down corner
                f1=s+sides*z,
                f2=s+sides*(z+1),
                f3=((s+1)%sides)+sides*(z+1),
                f4=((s+1)%sides)+sides*z)
            [f1,f2,f3]],
        [
            // Triangle #2
            for(z=[0:(height-1) / step])
            for(s=[0:sides-1])
            let(// clockwise from left-down corner
                f1=s+sides*z,
                f2=s+sides*(z+1),
                f3=((s+1)%sides)+sides*(z+1),
                f4=((s+1)%sides)+sides*z)
            [f3,f4,f1]],

        [if (bottom==true) [for(s=[0:sides-1]) s]],  //bottom;          

        [if (top==true) [for(s=[sides-1:-1:0]) (height/step)*(sides)+s]] //top        
    );   
    
    polyhedron(points=points, faces=faces);
}

vase(height=180,sides=360,R=30,top=true,bottom=true);

Etiquetas/Tags: 3dprint, openscad, stl, math, Fourier


Vaso 3D
... obtido por rotação em torno de um eixo

2021/11/15-17:58:02

A visualização tridimensional é um ingrediente importante na comunicação e estudo da matemática. Figuras e modelos expressam ideias e antecipam o estabelecimento de um formalismo matemático mais rigoroso. Embora a imaginação visual não substitua o conceito de demonstração dá-nos uma prova visual convincente e permite construir uma intuição sobre os resultados a perseguir e ideias a aprofundar.

A figura seguinte mostra a modelação 3D de uma "jarra" construída através da rotação em torno de um eixo.

Ao contrário do que acontece com outros tipos de software, os softwares usados em matemática permitem de uma forma muito económica a modelação e construção de estruturas não triviais, especificando simplesmente a expressão que as definem.

phi=(1+sqrt(5))/2;

n=100;

r=40;
l=152;
mu=3;
mv=2;
a=.25;
b=a/phi;
lambda=1.5;

nu=.2;
[u,v]=meshgrid([linspace(0,2*pi,n) 2*pi/n],linspace(0,l,n));
 
x=r*cos(u).*abs(cos(u)).^nu.*(1+a*cos(mu*u+mv*pi*v/l).^5+b*cos(mv*2*pi*v/l));
y=r*sin(u).*abs(sin(u)).^nu.*(1+a*cos(mu*u+mv*phi*pi*v/l).^5+b*cos(mv*2*pi*v/l));
z=v;

simplef2stl("vase.stl",x,y,z)

Depois de impresso o resultado é muito apelativo!

... e não é uma curva.

Função para gerar STL em GNU/Octave

## Author: Tiago Charters de Azevedo 
## Maintainer: Tiago Charters de Azevedo 

## Copyright (c) - 2016 Tiago Charters de Azevedo

## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3, or (at your option)
## any later version.

## This program 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 General Public License for more details.

## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 51 Franklin Street, Fifth Floor,
## Boston, MA 02110-1301, USA.

function simplef2stl(filename,x,y,z)
  fid=fopen(filename,'w');
  title_str=sprintf('%s',datestr(now));
  fprintf(fid,'solid %s\r\n',title_str);

  zmin=min(min(z));
  z=z-zmin;
  nfacets=0;
  nx=size(z,1);
  ny=size(z,2);
  for i=1:nx-1;
    for j=1:ny-1
      p1=[x(i,j) y(i,j) z(i,j)];
      p2=[x(i,j+1) y(i,j+1) z(i,j+1)];
      p3=[x(i+1,j+1) y(i+1,j+1) z(i+1,j+1)];
      writefacet(fid,p1,p2,p3);

      p1=[x(i+1,j+1) y(i+1,j+1) z(i+1,j+1)];
      p2=[x(i+1,j) y(i+1,j) z(i+1,j)];
      p3=[x(i,j) y(i,j) z(i,j)];        
      writefacet(fid,p1,p2,p3);
    end
  end
  fprintf(fid,'endsolid');
  fclose(fid);
end  
  
function num=writefacet(fid,p1,p2,p3)
    n=normal(p1,p2,p3);
    fprintf(fid,'facet normal %.7E %.7E %.7E\r\n',n(1),n(2),n(3));
    fprintf(fid,'outer loop\r\n');        
    fprintf(fid,'vertex %.7E %.7E %.7E\r\n',p1);
    fprintf(fid,'vertex %.7E %.7E %.7E\r\n',p2);
    fprintf(fid,'vertex %.7E %.7E %.7E\r\n',p3);
    fprintf(fid,'endloop\r\n');
    fprintf(fid,'endfacet\r\n');
end

function n=normal(p1,p2,p3)
  v1=p2-p1;
  v2=p3-p1;
  v3=cross(v1,v2);
  n=v3./sumsq(v3);
end

Etiquetas/Tags: 3d, print, reprap, GNU/Octave, STL


Proposta para o Laboratório de Cidadãos
para a Rede de Bibliotecas de Lisboa

2021/10/28-11:47:08

Proposta para o Laboratório de Cidadãos "Peças de Jardim"

Título do seu projeto

Mesa de musgo para leitura

Motivação

A construção de uma mesa de musgo com um candeeiro LED alimentado com baterias BPV (Biological Photo Voltaic cells) concretiza numa mesma ideia a reutilização de madeira ou mobiliário, geração renovável de energia elétrica através de um processo natural de crescimento das plantas, a fotossíntese, a geração local de energia de fontes renováveis e a sua utilização num local de atividade humana. Permitirá criar um local de leitura onde a iluminação é gerada por um processo natural e que pode ser implementada no interior da biblioteca ou no exterior do edifício. Permite também a replicação da mesma estrutura em locais diferentes para o qual foi projetado e.g. em nossas casas ou escolas.

Engloba competências de fabrico artesanal com madeira, o design colaborativo e partilhado, trabalho em equipa na construção e recolha de materiais, e disciplinas científicas como a biologia, a química e a física. Permite enquadrar o fabrico e conhecimento teórico-prático em todos os níveis de ensino e para todas as idades. No fundo uma forma válida de divulgação científica e participação em ciência feita por cidadãos.

Toda a documentação produzida será libertada segundo uma licença Creative Commons cc-by-sa de modo catalisar a produção e réplicas em outros locais.

Breve descrição do projeto

Pretende-se reaproveitar e reutilizar uma mesa, ou fabricá-la com madeira reciclada, de modo a que contenha um conjunto significativo de baterias BPV (Biological Photo voltaic cells) de modo a acender um candeeiro de mesa providenciando uma fonte de luz a quem sobre ela trabalha ou lê. Estas baterias, que estão no início do seu desenvolvimento mas têm o potencial de produzir eletricidade para alimentar pequenos aparelhos elétricos tais como relógios ou LEDs, podem ser construídas localmente com materiais facilmente acessíveis . As BPV podem ter uma vantagem competitiva numa pequena escala relativamente às renováveis usuais (https://www.cam.ac.uk/research/news/the-hidden-power-of-moss).

A vantagem das BPV está na sua capacidade de armazenar energia através de um processo natural que ocorre à nossa volta: a fotossíntese. Para além de usar a energia do sol para converter o dióxido de carbono em compostos orgânicos, que as plantas usam para crescer, a fotossíntese que ocorre nos musgos liberta compostos orgânicos no solo que são por sua vez digeridos por bactérias libertando nesse processo eletrões que podem ser capturados e armazenados para alimentar pequeno eletrodomésticos (https://royalsocietypublishing.org/doi/full/10.1098/rsos.160249).

Estas baterias, que na realidade são, ao olho não treinado, apenas plantas num vaso, serão acomodadas na estrutura das mesas integrando-as como parte funcional da estrutura e podem ser usadas no interior ou exterior dos edifícios.

Espera-se que a utilização desta estrutura tenha impacto na perceção nas diferentes possibilidade na utilização das plantas na geração limpa de energia elétrica, na manutenção e equilíbrio necessário entre a utilização dos ecossistemas onde as pessoas são parte integrante.

Porque todo o conhecimento necessário para a construção da mesa de musgo é aberto e está acessível online é fácil reproduzir a sua construção em outros locais através de projetos na escola, em casa ou juntas de freguesia. Este projeto tem também o objetivo de produzir um manual de construção, sob uma licença de direitos de autor aberta Creative Commons cc-by-sa, que ficará disponível para consulta e distribuição junto da mesa.

Recursos necessários para o desenvolvimento do projeto

Para este projeto serão necessárias ferramentas usuais que podem ser encontradas em qualquer oficina de reparação de móveis ou nas ferramentas de um qualquer entusiasta de DIY; mesas, ou madeira para reaproveitamento que as permita fabricar.

Para as baterias BPV serão necessários: musgo que poderá ser apanhado localmente e.g. no próprio jardim; folha de alumínio usada em culinária; feltro de carbono; e pó de zeolite (usado em cosméticos), ver método de construção (https://www.instructables.com/Indoor-Moss-Microbial-Fuel-Cell/). O candeeiro será construido com LED.

Um conjunto de 3 a 4 pessoas serão necessárias para construção de cada uma das mesas de musgo.

Os detalhes específicos de design serão decididos durante a construção pelos elementos que a fabricarão adaptado ao espaço e local, à função e aos possíveis utilizadores da estrutura.

Outras informações relevantes

Etiquetas/Tags: musgo, diy, cidadãos, mesa, energia, BPV


Comprei um Filastruder
Para reciclar plástico e produzir filamento para impressão 3D

2021/10/10-16:20:46

Comprei-o em segunda mão, um filastruder, versão 1.6.

Dizem-me que não será fácil usá-lo para produzir filamento para impressão 3D usando plástico reciclado, que o plástico triturado é irregular, pouco homogéneo e que se já é difícil usar pellets para produzir filamento então pedacinhos de plástico ainda pior!

A ver vamos!

As primeiras experiências correram bem. Se não vejamos: com pellets ABS temos 1.62mm

Os dois rolos ABS (branco) e PLA (preto) não têm tolerâncias muito longe disto.

Mas podemos melhorar!

Etiquetas/Tags: impressão 3D, filamento, filastruder


Created: NaN

Last updated: 11-09-2023 [22:52]


(cc-by-sa) Tiago Charters