quarta-feira, 30 de agosto de 2023

Coordenadas dos Vértices do Icosaedro Truncado

- Este código em python gera as coordenadas dos vértices de um icosaedro truncado (não regular).

- Um icosaedro truncado regular possui 90 arestas, 60 vértices e 32 faces, sendo 12 pentágonos e 20 hexágonos.

import numpy as np

def format_coordinate(value):
    rounded_value = round(value, 1)
    if rounded_value.is_integer():
        return str(int(rounded_value))
    else:
        return str(rounded_value)

# Definindo os pontos de referência para um icosaedro
phi = (1 + np.sqrt(5)) / 2

icosahedron_vertices = np.array([
    [0, 1, phi],
    [0, 1, -phi],
    [0, -1, phi],
    [0, -1, -phi],
    [1, phi, 0],
    [1, -phi, 0],
    [-1, phi, 0],
    [-1, -phi, 0],
    [phi, 0, 1],
    [phi, 0, -1],
    [-phi, 0, 1],
    [-phi, 0, -1]
])

# Definindo a matriz de truncamento
truncation_matrix = np.array([
    [1, 0, 1],
    [0, 1, 1],
    [-1, 0, 1],
    [0, -1, 1],
    [1, 1, 0],
    [-1, 1, 0],
    [1, -1, 0],
    [-1, -1, 0],
    [1, 0, -1],
    [0, 1, -1],
    [-1, 0, -1],
    [0, -1, -1]
])

# Calculando o centro do icosaedro truncado
center = np.mean(icosahedron_vertices, axis=0)

# Calculando as coordenadas dos vértices dos pentágonos
unique_vertices = []

for i in range(12):
    pentagon_vertices = icosahedron_vertices + truncation_matrix[i]
    pentagon_vertices_center = np.mean(pentagon_vertices, axis=0)
    pentagon_vertices = [
        vertex for vertex in pentagon_vertices if
        np.count_nonzero(vertex == 0) != 2 and
        not (np.all(vertex > 0) and np.all(vertex < 1)) and
        not np.all((np.abs(vertex[0]) > 0 and np.abs(vertex[0]) < 1) or
                   (np.abs(vertex[1]) > 0 and np.abs(vertex[1]) < 1) or
                   (np.abs(vertex[2]) > 0 and np.abs(vertex[2]) < 1))
    ]
    pentagon_vertices = np.unique(pentagon_vertices, axis=0)
    unique_vertices.extend(pentagon_vertices)

# Convertendo para um array numpy para eliminar duplicatas
unique_vertices = np.array(unique_vertices)

# Calculando as distâncias entre os vértices e o centro
distances_to_center = np.linalg.norm(unique_vertices - center, axis=1)

# Encontrando a distância máxima entre os vértices dos pentágonos
max_distance_pentagon = np.max(np.linalg.norm(icosahedron_vertices, axis=1))

# Eliminando os vértices mais próximos do centro do que qualquer vértice dos pentágonos
filtered_vertices = unique_vertices[distances_to_center > max_distance_pentagon]

# Imprimindo as coordenadas dos vértices formatadas com duas vírgulas entre cada valor
for i, vertex in enumerate(filtered_vertices):
    formatted_coords = [format_coordinate(coord) for coord in vertex]
    formatted_coords_str = ', '.join(formatted_coords)
    #print(f"Vértice {i + 1}: [{formatted_coords_str}]")
    print(f"translate ([{formatted_coords_str}]) pnt(0.1);")
   

-Para visualizar a forma aproximada deste sólido geométrico no OpenScad use o código abaixo:




IcosaedroVertices = [
 [10, -10, 26], //0
[10, 10, 26], //1
[0, 20, 26],  //2
[-10, 10, 26], //3
[-10, -10, 26], //4
[0, -20, 26],  //5

[26, -10, -10], //6
[26, -10, 10],  //7
[26, 0, 20],   //8
[26, 10, -10],  //10
[26, 10, 10],  //9
[26, 0, -20],  //11

[10, -10, -26], //12
[10, 10, -26],  //13
[0, 20, -26],  //14
[-10, -10, -26],  //16
[-10, 10, -26],  //15
[0, -20, -26],  //17

[-26, -10, -10], //18
[-26, -10, 10],  //19
[-26, 0, 20],  //20
[-26, 10, -10], //22
[-26, 10, 10],  //21
[-26, 0, -20],  //23

[-20, -26, 0],  //24
[-10, -26, 10],  //25
[10, -26, 10],  //26
[20, -26, 0],   //27
[10, -26, -10],  //28
[-10, -26, -10],  //29

[20, 26, 0],  //30
[10, 26, 10],  //31
[-10, 26, 10],  //33
[-20, 26, 0],  //32
[-10, 26, -10],  //34
[10, 26, -10],  //35

/*[-20, 16, 10],  //36 triângulos internos
[-10, 20, 16],  //37
[-16, 10, 20],  //38

[20, -16, 10],   //39
[10, -20, 16],   //40
[16, -10, 20],   //41

[20, 16, -10],   //42
[10, 20, -16],  //43
[16, 10, -20],  //44

[20, 16, 10],   //45
[10, 20, 16],   //46
[16, 10, 20],   //47

[-20, -16, 10],  //48
[-10, -20, 16],  //49
[-16, -10, 20],  //50

[20, -16, -10],  //51
[10, -20, -16],  //52
[16, -10, -20],  //53

[-20, -16, -10],  //54
[-10, -20, -16],  //55
[-16, -10, -20],  //56

[-20, 16, -10],  //57
[-10, 20, -16],  //58
[-16, 10, -20]];  //59 */
];
 
 IcosaedroFaces = [
  [0,1,2,3,4,5],  // hexágonos centrais
  [6,7,8,10,9,11],  
  [12,13,14,16,15,17],
  [18,19,20,22,21,23],
  [24,25,26,27,28,29],  
  [31,32,33,34,35,30],
 /* [36,37,38], // triângulos internos
  [39,40,41],
  [42,43,44],
  [45,46,47],
  [48,49,50],
  [51,52,53],
  [54,55,56],
  [57,58,59],
  [2,37,46],
  [5,40,49],
  [14,43,58],
  [17,52,55],
  [24,48,54],
  [27,39,51],
  [11,44,53],
  [23,56,59],
  [8,41,47],
  [20,50,38],
  [30,42,45],
  [33,36,57]];*/
  [2,31,32], // triângulos externos
  [5,25,26],
  [8,0,1],
  [11,12,13],
  [14,34,35],
  [17,28,29],
  [20,3,4],
  [23,15,16],
  [24,18,19],
  [27,6,7],
  [30,9,10],
  [33,21,22],
  [2,33,20], // hexágonos laterais abertos
  [2,30,8],
  [5,8,27],
  [5,20,24],
  [11,14,30],
  [11,17,27],
  [17,23,24],
  [14,23,33],
  //[5,26,27,7,20,4],
 ];
 
polyhedron( IcosaedroVertices, IcosaedroFaces );
color ("blue") {
translate ([10, -10, 26]) linear_extrude(8) text("0", 5); //0
translate ([10, 10, 26]) linear_extrude(8) text("1", 5); //1
translate ([0, 20, 26]) linear_extrude(8) text("2", 5);  //2
translate ([-10, 10, 26]) linear_extrude(8) text("3", 5); //3
translate ([-10, -10, 26]) linear_extrude(8) text("4", 5); //4
translate ([0, -20, 26]) linear_extrude(8) text("5", 5);  //5

translate ([26, -10, -10]) linear_extrude(8) text("6", 5); //6
translate ([26, -10, 10]) linear_extrude(8) text("7", 5);  //7
translate ([26, 0, 20]) linear_extrude(8) text("8", 5);   //8
translate ([26, 10, -10]) linear_extrude(8) text("10", 5);  //10
translate ([26, 10, 10]) linear_extrude(8) text("9", 5);  //9
translate ([26, 0, -20]) linear_extrude(8) text("11", 5);  //11

translate ([10, -10, -26]) linear_extrude(8) text("12", 5); //12
translate ([10, 10, -26]) linear_extrude(8) text("13", 5);  //13
translate ([0, 20, -26]) linear_extrude(8) text("14", 5);  //14
translate ([-10, -10, -26]) linear_extrude(8) text("16", 5);  //16
translate ([-10, 10, -26]) linear_extrude(8) text("15", 5);  //15
translate ([0, -20, -26]) linear_extrude(12) text("17", 8);  //17

translate ([-26, -10, -10]) linear_extrude(8) text("18", 5); //18
translate ([-26, -10, 10]) linear_extrude(8) text("19", 5);  //19
translate ([-26, 0, 20]) linear_extrude(8) text("20", 5);  //20
translate ([-26, 10, -10]) linear_extrude(8) text("22", 5); //22
translate ([-26, 10, 10]) linear_extrude(8) text("21", 5);  //21
translate ([-26, 0, -20]) linear_extrude(12) text("23", 8);  //23

translate ([-20, -26, 0]) linear_extrude(8) text("24", 5);  //24
translate ([-10, -26, 10]) linear_extrude(8) text("25", 5);  //25
translate ([10, -26, 10]) linear_extrude(8) text("26", 5);  //26
translate ([20, -26, 0]) linear_extrude(8) text("27", 5);   //27
translate ([10, -26, -10]) linear_extrude(8) text("28", 5);  //28
translate ([-10, -26, -10]) linear_extrude(8) text("29", 5);  //29

translate ([20, 26, 0]) linear_extrude(8) text("30", 5);  //30
translate ([10, 26, 10]) linear_extrude(8) text("31", 5);  //31
translate ([-10, 26, 10]) linear_extrude(8) text("32", 5);  //32
translate ([-20, 26, 0]) linear_extrude(8) text("33", 5);  //33
translate ([-10, 26, -10]) linear_extrude(8) text("34", 5);  //34
translate ([10, 26, -10]) linear_extrude(8) text("35", 5);  //35
}

quinta-feira, 24 de agosto de 2023

Controle Liga/Desliga para CAPS, NUM e SCROLL

- A ideia é usar uma placa de teclado USB como interface alternativa para se criar 3 chaves liga/desliga controladas via computador.

- Segue abaixo um tutorial de produção do programa e o código fonte.

- Passo a passo para implementar e testar o código que permite ligar e desligar os LEDs Caps Lock, Num Lock e Scroll Lock usando um teclado padrão no Linux.

Passo 1: Instalar Dependências

Garanta que as dependências corretas estejam instaladas. O pacote libevdev-dev é necessário para acessar os LEDs via sysfs.

Para instalar o pacote libevdev-dev no Ubuntu, você pode usar o seguinte comando:

bash
sudo apt update sudo apt install libevdev-dev

Passo 2: Criar o Código

Crie um novo arquivo de código-fonte chamado ligadesliga_leds.c e cole o código C fornecido anteriormente no arquivo.

Passo 3: Compilar o Código

Abra um terminal e navegue até o diretório onde você criou o arquivo ligadesliga_leds.c. Em seguida, execute o seguinte comando para compilar o código:

bash
sudo gcc -o ligadesliga_leds ligadesliga_leds.c -levdev

Isso compilará o código e gerará um executável chamado ligadesliga_leds.

Passo 4: Executar o Programa

Agora, você pode executar o programa usando o comando sudo para garantir que tenha as permissões necessárias para acessar os LEDs:

bash
sudo ./ligadesliga_leds

Passo 5: Testar o Programa

Após executar o programa, ele exibirá instruções no terminal. Pressione as teclas 'c', 'n' ou 's' para alternar o brilho dos LEDs Caps Lock, Num Lock e Scroll Lock, respectivamente. Pressione 'x' para sair do programa.

Lembre-se de que a capacidade de controlar os LEDs Caps Lock, Num Lock e Scroll Lock depende do seu hardware e do suporte do sistema operacional. Pode haver variações entre sistemas e distribuições Linux.

 

CÓDIGO FONTE DO PROGRAMA

#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>

#define CAPSLOCK_PATH "/sys/class/leds/input4::capslock/brightness"
#define NUMLOCK_PATH "/sys/class/leds/input4::numlock/brightness"
#define SCROLLLOCK_PATH "/sys/class/leds/input4::scrolllock/brightness"

int main() {
    struct termios old_settings, new_settings;
    char input;

    tcgetattr(STDIN_FILENO, &old_settings);
    new_settings = old_settings;
    new_settings.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &new_settings);

    printf("Pressione 'c' para alternar o LED Caps Lock.\n");
    printf("Pressione 'n' para alternar o LED Num Lock.\n");
    printf("Pressione 's' para alternar o LED Scroll Lock.\n");
    printf("Pressione 'x' para sair.\n");

    while (1) {
        input = getchar();
        if (input == 'x') {
            break;
        } else if (input == 'c') {
            FILE* capslock_file = fopen(CAPSLOCK_PATH, "r+");
            if (capslock_file) {
                char value;
                fscanf(capslock_file, "%c", &value);
                fseek(capslock_file, 0, SEEK_SET);
                fprintf(capslock_file, "%c", (value == '0') ? '1' : '0');
                fclose(capslock_file);
            }
        } else if (input == 'n') {
            FILE* numlock_file = fopen(NUMLOCK_PATH, "r+");
            if (numlock_file) {
                char value;
                fscanf(numlock_file, "%c", &value);
                fseek(numlock_file, 0, SEEK_SET);
                fprintf(numlock_file, "%c", (value == '0') ? '1' : '0');
                fclose(numlock_file);
            }
        } else if (input == 's') {
            FILE* scrolllock_file = fopen(SCROLLLOCK_PATH, "r+");
            if (scrolllock_file) {
                char value;
                fscanf(scrolllock_file, "%c", &value);
                fseek(scrolllock_file, 0, SEEK_SET);
                fprintf(scrolllock_file, "%c", (value == '0') ? '1' : '0');
                fclose(scrolllock_file);
            }
        }
    }

    tcsetattr(STDIN_FILENO, TCSANOW, &old_settings);
    return 0;
}

 

terça-feira, 22 de agosto de 2023

Cercado em Cerâmica

- Ideia de cercado feito com cerâmica.

- As placas foram unidas com parafusos para madeira.



segunda-feira, 21 de agosto de 2023

Código Arduino Para Motores Trifásicos

- Este programa gera uma sequência que pode ser usada para alimentar as 3 fases de um motor trifásico a partir de uma fonte de corrente contínua.

- Implementa os seguintes controles: 

. liga e desliga a marcha;

. sentido de funcionamento;

. frequência; e

. potência (largura de pulso).


const int dirPin = 3;       // Pino de entrada para controlar a direção
const int controlPin = 2;   // Pino para controlar o estado 000
const int outputPins[] = {5, 6, 9}; // Pinos de saída para a sequência desejada
int currentState = 0;
int currentDirection = 1;   // 1 para contar para cima, -1 para contar para baixo

void setup() {
  pinMode(dirPin, INPUT);
  pinMode(controlPin, INPUT);
 
  for (int i = 0; i < 3; i++) {
    pinMode(outputPins[i], OUTPUT);
  }
}

void loop() {
  int controlState = digitalRead(controlPin);
  int direction = digitalRead(dirPin);
 
  int sequence[] = {5, 4, 6, 2, 3, 1}; // Sequência de estados: 101, 100, 110, 010, 011, 001

  if (controlState == LOW) {
    sequence[0] = 0;
    digitalWrite(outputPins[0], LOW);
    digitalWrite(outputPins[1], LOW);
    digitalWrite(outputPins[2], LOW);
    while (digitalRead(controlPin) == LOW) {
      // Aguarda o pino de controle ficar alto para continuar
    }
  }

  if (direction == HIGH) {
    currentDirection = 1;
  } else {
    currentDirection = -1;
  }

  int frequency = map(analogRead(A0), 0, 1023, 0, 300); // Mapeia a leitura analógica para a faixa de frequência
 
  int pulseWidth = map(analogRead(A1), 0, 1023, 0, 255); // Mapeia a leitura analógica para a faixa de largura de pulsos
 
  int delayTime = 1000 / frequency; // Calcula o tempo de atraso com base na frequência
 
  currentState = (currentState + currentDirection + 6) % 6; // Calcula o próximo estado
 
  int currentOutput = sequence[currentState];
 
  digitalWrite(outputPins[0], bitRead(currentOutput, 2));
  digitalWrite(outputPins[1], bitRead(currentOutput, 1));
  digitalWrite(outputPins[2], bitRead(currentOutput, 0));
 
  delayMicroseconds(pulseWidth); // Mantém o pulso ativo de acordo com a largura de pulsos
 
  digitalWrite(outputPins[0], LOW);
  digitalWrite(outputPins[1], LOW);
  digitalWrite(outputPins[2], LOW);
 
  delay(delayTime); // Atraso entre os estados
}
 

sábado, 19 de agosto de 2023

Gerador de Legendas - 7.0

- Esta versão fornece legenda melhor sincronizada à fala.

- A qualidade do reconhecimento da fala está ligada à qualidade do modelo de idioma usado.

import os
import subprocess
import vosk
import pysrt
import json
from flask import Flask, render_template, request
from werkzeug.utils import secure_filename
from moviepy.editor import VideoFileClip

app = Flask(__name__)

UPLOAD_FOLDER = 'uploads'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

def segundos_para_subrip_time(segundos):
    minutos, segundos = divmod(segundos, 60)
    horas, minutos = divmod(minutos, 60)
    return pysrt.SubRipTime(hours=int(horas), minutes=int(minutos), seconds=segundos)

def recognize_speech(file_path, language):
    if language == "en":
        model_path = "vosk-model-small-en-us-0.15"
    elif language == "pt":
        model_path = "vosk-model-small-pt-0.3" #model_path = "vosk-model-pt-fb-v0.1.1-20220516_2113" #Para melhor reconhecimento da fala.
    elif language == "es":
        model_path = "vosk-model-small-es-0.42"
    else:
        raise ValueError("Idioma não suportado.")

    if not os.path.isfile(file_path):
        raise FileNotFoundError("O arquivo de vídeo não existe.")

    sample_rate = 16000
    model = vosk.Model(model_path)
    rec = vosk.KaldiRecognizer(model, sample_rate)
    rec.SetWords(True)
    audio_duration = VideoFileClip(file_path).duration
    ffmpeg_command = f"ffmpeg -y -i {file_path} -vn -acodec pcm_s16le -ar {sample_rate} -ac 1 -f wav -"
    ffmpeg_process = subprocess.Popen(ffmpeg_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)

    subtitles = []
    current_subtitle = None
    subtitle_index = 1

    while True:
        audio_data = ffmpeg_process.stdout.read(sample_rate * 2)
        if not audio_data:
            break
        rec.AcceptWaveform(audio_data)
        result = json.loads(rec.Result())

        if "result" in result:
            words = result["result"]
            if not words:
                break

            start_time = words[0]["start"]
            end_time = words[-1]["end"]
            transcript = " ".join([word["word"] for word in words])

            if current_subtitle:
                current_subtitle.text += " " + transcript
                current_subtitle.end = segundos_para_subrip_time(end_time)
            else:
                current_subtitle = pysrt.SubRipItem(
                    index=subtitle_index, start=segundos_para_subrip_time(start_time), end=segundos_para_subrip_time(end_time), text=transcript
                )
                subtitle_index += 1

            # Se a legenda tiver mais de 9 palavras, finalizamos a legenda
            if len(current_subtitle.text.split()) >= 9:
                subtitles.append(current_subtitle)
                current_subtitle = None

        else:
            if current_subtitle:
                subtitles.append(current_subtitle)
                current_subtitle = None

    if current_subtitle:
        subtitles.append(current_subtitle)

    ffmpeg_process.stdout.close()
    ffmpeg_process.wait()

    return subtitles

@app.route("/", methods=["GET", "POST"])
def index():
    if request.method == "POST":
        file = request.files["video_file"]
        language = request.form["language_choice"]

        if file and file.filename.endswith(".mp4"):
            if not os.path.exists(app.config['UPLOAD_FOLDER']):
                os.makedirs(app.config['UPLOAD_FOLDER'])

            file_path = os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(file.filename))
            file.save(file_path)

            try:
                subtitles = recognize_speech(file_path, language)
                output_file = os.path.splitext(file_path)[0]

                if language == "en":
                    output_file += "_ing.srt"
                elif language == "pt":
                    output_file += "_por.srt"
                elif language == "es":
                    output_file += "_esp.srt"

                with open(output_file, "w", encoding="utf-8") as f:
                    for subtitle in subtitles:
                        f.write(str(subtitle))
                        f.write("\n")

                message = f"Processo concluído. Legenda gerada em {output_file}"
            except Exception as e:
                message = f"Erro durante o reconhecimento: {str(e)}"
        else:
            message = "Selecione um arquivo de vídeo no formato .mp4."

        return render_template("index.html", message=message)

    return render_template("index.html")

if __name__ == "__main__":
    app.run(debug=True)
 

domingo, 13 de agosto de 2023

TV como Lâmpada LED

- Uso de uma TV de 50 polegadas como lâmpada LED.



quarta-feira, 9 de agosto de 2023

Motor de Alta Tensão

 - Réplica e modificações.