Man, how did you achieve the canvas effect on the top of the cab?!
@KepaAlonso11 күн бұрын
The canvas effect on top of the cab was achieved using a combination of washes, oil paints, and dry brushing. First, I applied a base color to the canvas. Then, I used a darker wash to enhance the folds and details, simulating shadows and grime. After that, I used oil paints to add subtle stains and blend colors for a more weathered look. Finally, I dry-brushed lighter tones onto the raised areas and edges to highlight the fabric's wear and tear, giving it a realistic, aged appearance.
@KepaAlonso29 күн бұрын
<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Generador de Onda</title> <style> body { text-align: center; font-family: Arial, sans-serif; } canvas { border: 1px solid black; display: block; margin: 20px auto; } input[type="range"] { width: 1200px; } </style> </head> <body> <h1>Generador de Onda</h1> <label for="frequency">Frecuencia: <span id="freqValue">50</span> Hz</label> <br> <input type="range" id="frequency" min="1" max="2000" step="1" value="50"> <br><br> <label for="waveType">Tipo de Onda:</label> <select id="waveType"> <option value="sine">Sinusoidal</option> <option value="square">Cuadrada</option> <option value="sawtooth">Diente de sierra</option> <option value="triangle">Triangular</option> </select> <br><br> <button id="playButton">Reproducir/Pausar</button> <canvas id="waveCanvas" width="800" height="400"></canvas> <script> // Configuración de Web Audio API const AudioContext = window.AudioContext || window.webkitAudioContext; const audioCtx = new AudioContext(); let oscillator = null; // Oscilador para generar la onda let isPlaying = false; // Estado de reproducción let isDrawing = false; // Estado de animación const frequencySlider = document.getElementById('frequency'); const freqValueDisplay = document.getElementById('freqValue'); const playButton = document.getElementById('playButton'); const waveTypeSelect = document.getElementById('waveType'); // Nuevo selector de tipo de onda // Configuración para el canvas const canvas = document.getElementById('waveCanvas'); const ctx = canvas.getContext('2d'); let frequency = 440; // Frecuencia inicial let amplitude = 100; // Amplitud de la onda let offsetX = 0; // Para animar la onda let waveType = 'sine'; // Tipo de onda inicial // Función para iniciar el oscilador function startOscillator(frequency) { oscillator = audioCtx.createOscillator(); oscillator.type = waveType; // Tipo de onda según la selección oscillator.frequency.setValueAtTime(frequency, audioCtx.currentTime); oscillator.connect(audioCtx.destination); oscillator.start(); } // Función para detener el oscilador function stopOscillator() { if (oscillator) { oscillator.stop(); oscillator.disconnect(); oscillator = null; } } // Función para dibujar la onda en el canvas function drawWave() { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.beginPath(); ctx.moveTo(0, canvas.height / 2); for (let x = 0; x < canvas.width; x++) { let y = canvas.height / 2; let t = (x + offsetX) / canvas.width; switch (waveType) { case 'sine': y += amplitude * Math.sin(2 * Math.PI * frequency * t); break; case 'square': y += amplitude * (Math.sin(2 * Math.PI * frequency * t) > 0 ? 1 : -1); break; case 'sawtooth': y += amplitude * (2 * (t * frequency - Math.floor(0.5 + t * frequency))); break; case 'triangle': y += amplitude * (2 * Math.abs(2 * (t * frequency - Math.floor(0.5 + t * frequency))) - 1); break; } ctx.lineTo(x, y); } ctx.strokeStyle = 'blue'; ctx.lineWidth = 2; ctx.stroke(); offsetX += 5; // Ajusta la velocidad de la animación if (isPlaying) { requestAnimationFrame(drawWave); // Solo continua animando si está sonando } } // Actualizar frecuencia cuando se mueve el deslizador frequencySlider.addEventListener('input', function() { frequency = parseFloat(this.value); freqValueDisplay.textContent = frequency.toFixed(0); if (oscillator) { oscillator.frequency.setValueAtTime(frequency, audioCtx.currentTime); // Actualiza la frecuencia del sonido } if (!isPlaying) { // Si el oscilador está parado, redibuja la onda para reflejar la nueva frecuencia ctx.clearRect(0, 0, canvas.width, canvas.height); drawWave(); } }); // Actualizar el tipo de onda cuando se selecciona un tipo diferente waveTypeSelect.addEventListener('change', function() { waveType = this.value; if (oscillator) { stopOscillator(); // Detener el oscilador actual startOscillator(frequency); // Iniciar un nuevo oscilador con el nuevo tipo de onda } if (!isPlaying) { // Si no está reproduciendo, redibuja la onda con el nuevo tipo ctx.clearRect(0, 0, canvas.width, canvas.height); drawWave(); } }); // Reproducir o pausar la onda playButton.addEventListener('click', function() { if (!isPlaying) { startOscillator(frequency); playButton.textContent = 'Pausar'; isPlaying = true; drawWave(); // Comienza la animación } else { stopOscillator(); playButton.textContent = 'Reproducir'; isPlaying = false; } }); // Dibuja la onda inicialmente sin animación drawWave(); </script> </body> </html>
@tommarekczАй бұрын
that is interesting
@IOSALiveАй бұрын
Kepa Alonso, great content it was really good
@KepaAlonsoАй бұрын
To understand DC motor control via PWM, watch video : studio.kzbin.infosXi1ZD4eogw/edit
@KepaAlonsoАй бұрын
You can download the code along with more resources on this website: kalonso9.wixsite.com/kalo/connectcode
@KepaAlonsoАй бұрын
You can download the code along with more resources on this website: kalonso9.wixsite.com/kalo/connectcode
@KepaAlonsoАй бұрын
You can download the code along with more resources on this website: kalonso9.wixsite.com/kalo/connectcode
@KepaAlonsoАй бұрын
You can download the code along with more resources on this website: kalonso9.wixsite.com/kalo/connectcode
@KepaAlonsoАй бұрын
You can download the code along with more resources on this website: kalonso9.wixsite.com/kalo/connectcode
@KepaAlonsoАй бұрын
You can download the code along with more resources on this website: kalonso9.wixsite.com/kalo/connectcode
@KepaAlonsoАй бұрын
You can download the code along with more resources on this website: kalonso9.wixsite.com/kalo/connectcode
@KepaAlonsoАй бұрын
You can download the code along with more resources on this website: kalonso9.wixsite.com/kalo/connectcode
@KepaAlonsoАй бұрын
You can download the code along with more resources on this website: kalonso9.wixsite.com/kalo/connectcode
@KepaAlonsoАй бұрын
You can download the code along with more resources on this website: kalonso9.wixsite.com/kalo/connectcode
@acidbubblebath77Ай бұрын
"Get this reservoir filled dam it!"
@KepaAlonsoАй бұрын
HTML code (copy in a notepad txt file and save as PWM.html): <!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>DC MOTOR CONTROL</title> <style> body { font-family: Arial, sans-serif; text-align: center; margin-top: 50px; background-color: #f4f4f4; color: #333; } .slider-container { margin: 20px; } .slider-container label { font-weight: bold; margin-right: 10px; } .slider-container input[type="range"] { width: 300px; } canvas { border: 2px solid #007BFF; border-radius: 10px; background-color: #ffffff; margin-top: 20px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); } h1 { color: #007BFF; } </style> </head> <body> <h1>DC MOTOR CONTROL</h1> <div class="slider-container"> <label for="frequencySlider">Frequency (Hz):</label> <input type="range" id="frequencySlider" min="1" max="20" value="4"> <span id="frequencyValue">4</span> Hz </div> <div class="slider-container"> <label for="dutyCycleSlider">Duty Cycle (%):</label> <input type="range" id="dutyCycleSlider" min="0" max="100" value="50"> <span id="dutyCycleValue">50</span> % </div> <div class="slider-container"> <label for="volumeSlider">Amplitude:</label> <input type="range" id="volumeSlider" min="0" max="1" step="0.01" value="0.5"> <span id="volumeValue">0.5</span> </div> <canvas id="pwmCanvas" width="600" height="300"></canvas> <script> const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); const pwmGain = audioCtx.createGain(); const frequencySlider = document.getElementById("frequencySlider"); const dutyCycleSlider = document.getElementById("dutyCycleSlider"); const volumeSlider = document.getElementById("volumeSlider"); const frequencyValue = document.getElementById("frequencyValue"); const dutyCycleValue = document.getElementById("dutyCycleValue"); const volumeValue = document.getElementById("volumeValue"); const canvas = document.getElementById("pwmCanvas"); const ctx = canvas.getContext("2d"); let pwmInterval = null; // Función para actualizar la frecuencia, el ciclo de trabajo y el volumen function updatePWM() { const frequency = parseFloat(frequencySlider.value); const dutyCycle = parseFloat(dutyCycleSlider.value) / 100; const volume = parseFloat(volumeSlider.value); frequencyValue.textContent = frequency; dutyCycleValue.textContent = Math.round(dutyCycle * 100); volumeValue.textContent = volume; // Limpiar cualquier intervalo anterior clearInterval(pwmInterval); // Controlar la señal en función del ciclo de trabajo if (dutyCycle >= 1) { // Señal siempre alta pwmGain.gain.setValueAtTime(volume, audioCtx.currentTime); } else if (dutyCycle <= 0) { // Señal siempre baja pwmGain.gain.setValueAtTime(0, audioCtx.currentTime); } else { // Modulación PWM para otros ciclos de trabajo const period = 1 / frequency; const highTime = period * dutyCycle; pwmInterval = setInterval(() => { pwmGain.gain.setValueAtTime(volume, audioCtx.currentTime); pwmGain.gain.setValueAtTime(0, audioCtx.currentTime + highTime); }, period * 1000); } drawPWMWave(frequency, dutyCycle, volume); } // Función para dibujar la señal PWM en el canvas function drawPWMWave(frequency, dutyCycle, volume) { const width = canvas.width; const height = canvas.height; ctx.clearRect(0, 0, width, height); const period = width / frequency; const highTime = period * dutyCycle; const amplitude = height * (1 - volume); // Escala la altura de la onda según el volumen ctx.beginPath(); ctx.strokeStyle = "#007BFF"; ctx.lineWidth = 2; if (dutyCycle >= 1) { ctx.moveTo(0, amplitude); ctx.lineTo(width, amplitude); } else if (dutyCycle <= 0) { ctx.moveTo(0, height); ctx.lineTo(width, height); } else { for (let x = 0; x < width; x += period) { ctx.lineTo(x, amplitude); ctx.lineTo(x + highTime, amplitude); ctx.lineTo(x + highTime, height); ctx.lineTo(x + period, height); } } ctx.stroke(); } // Inicializar el contexto de audio const pwmOscillator = audioCtx.createOscillator(); pwmOscillator.type = 'square'; pwmOscillator.frequency.value = frequencySlider.value; pwmOscillator.connect(pwmGain); pwmGain.connect(audioCtx.destination); pwmOscillator.start(); // Eventos de los deslizadores frequencySlider.addEventListener("input", updatePWM); dutyCycleSlider.addEventListener("input", updatePWM); volumeSlider.addEventListener("input", updatePWM); // Inicializar la señal PWM updatePWM(); // Activar el contexto de audio con un click del usuario document.body.addEventListener('click', () => { if (audioCtx.state === 'suspended') { audioCtx.resume(); } }); </script> </body> </html>
<!DOCTYPE html> <html> <head> <title>Medidor de RPM</title> <style> body { background-color: black; color: white; text-align: center; font-family: Arial, sans-serif; margin: 0; padding: 0; display: flex; flex-direction: column; align-items: center; height: 100vh; } input[type=range] { -webkit-appearance: none; width: 80%; margin: 10px; } input[type=range]::-webkit-slider-runnable-track { width: 100%; height: 8.4px; cursor: pointer; animate: 0.2s; background: #3071a9; border-radius: 1.3px; box-shadow: 0px 0px 0.9px #000000; } input[type=range]::-webkit-slider-thumb { border: 1px solid #000000; height: 36px; width: 16px; border-radius: 3px; background: #ffffff; cursor: pointer; -webkit-appearance: none; margin-top: -14px; } .slider-container { display: flex; flex-direction: column; align-items: center; margin-top: 20px; } canvas { border: none; margin-top: 20px; } .rpm-container { position: relative; top: -120px; transform: translateY(-50%); width: 100px; display: flex; flex-direction: column; align-items: center; background-color: gray; padding: 10px; border-radius: 5px; } .rpm-number { font-size: 24px; font-weight: bold; } .rpm-text { font-size: 16px; } </style> </head> <body> <canvas id="rpmGauge" width="600" height="600"></canvas> <div class="rpm-container"> <div class="rpm-number" id="rpm">0</div> <div class="rpm-text">RPM</div> </div> <select id="microphoneSelect"></select> <p><button onclick="startRecording()">Iniciar</button></p> <div class="slider-container"> <label for="bufferDuration">Duración del buffer (ms): </label> <input type="range" id="bufferDuration" name="bufferDuration" min="20" max="1000" value="20" oninput="updateBufferDuration(this.value)"> <span id="bufferDurationValue">20</span> <p></p> <label for="updateInterval">Intervalo de actualización (ms): </label> <input type="range" id="updateInterval" name="updateInterval" min="20" max="1000" value="20" oninput="updateUpdateInterval(this.value)"> <span id="updateIntervalValue">20</span> <p></p> <label for="fftSize">FFT Size: </label> <input type="range" id="fftSize" name="fftSize" min="32" max="32768" value="2048" step="32" oninput="updateFftSize(this.value)"> <span id="fftSizeValue">2048</span> <p></p> </div> <script> // Inicialización del contexto de audio y el analizador let audioContext = new (window.AudioContext || window.webkitAudioContext)(); let analyser = audioContext.createAnalyser(); analyser.fftSize = 2048; let bufferLength = analyser.frequencyBinCount; let dataArray = new Uint8Array(bufferLength); let mediaStreamSource; // Configuración inicial const sampleRate = audioContext.sampleRate; let updateInterval = 20; // Intervalo de actualización en milisegundos let frequencyBuffer = []; let bufferDuration = 20; // Duración inicial del buffer en milisegundos let maxBufferLength = Math.floor(bufferDuration / updateInterval); let intervalId; let rpm = 0; let targetRpm = 0; let lastRpm = 0; let lastUpdateTime = 0; let rpmStabilityThreshold = 2; // Umbral de cambio de RPM para considerar velocidad cero let stableTimeThreshold = 100; // Tiempo en ms para considerar RPM estable y poner a cero let smoothingFactor = 0.1; // Factor de suavizado para la EMA // Inicialización del canvas y su contexto var canvas = document.getElementById("rpmGauge"); var context = canvas.getContext("2d"); var centerX = canvas.width / 2; var centerY = canvas.height / 2; var radius = 250; var startAngle = -230 * Math.PI / 180; // Posición inicial del medidor var endAngle = 50 * Math.PI / 180; // Posición final del medidor // Función para dibujar el medidor function drawGauge() { context.clearRect(0, 0, canvas.width, canvas.height); context.fillStyle = "black"; context.fillRect(0, 0, canvas.width, canvas.height); context.beginPath(); context.arc(centerX, centerY, radius, startAngle, endAngle, false); context.fillStyle = "black"; context.fill(); context.lineWidth = 5; context.strokeStyle = "white"; context.stroke(); // Dibujar los números de las RPM context.fillStyle = "white"; context.font = "bold 16px Arial"; context.textAlign = "center"; context.textBaseline = "middle"; for (var i = 0; i <= 12; i++) { var angle = startAngle + (i * (endAngle - startAngle) / 12); var x = centerX + (radius - 60) * Math.cos(angle); var y = centerY + (radius - 60) * Math.sin(angle); context.fillText(i * 100, x, y); } // Dibujar las líneas de las marcas y subdivisiones context.lineWidth = 2; for (var i = 0; i <= 120; i += 10) { var angle = startAngle + (i * (endAngle - startAngle) / 120); var x1 = centerX + (radius - 20) * Math.cos(angle); var y1 = centerY + (radius - 20) * Math.sin(angle); var x2 = centerX + (radius - 30) * Math.cos(angle); var y2 = centerY + (radius - 30) * Math.sin(angle); context.beginPath(); context.moveTo(x1, y1); context.lineTo(x2, y2); context.strokeStyle = "white"; context.stroke(); } // Dibujar subdivisiones más pequeñas context.lineWidth = 1; for (var i = 0; i <= 120; i += 2) { var angle = startAngle + (i * (endAngle - startAngle) / 120); var x1 = centerX + (radius - 20) * Math.cos(angle); var y1 = centerY + (radius - 20) * Math.sin(angle); var x2 = centerX + (radius - 25) * Math.cos(angle); var y2 = centerY + (radius - 25) * Math.sin(angle); context.beginPath(); context.moveTo(x1, y1); context.lineTo(x2, y2); context.strokeStyle = "white"; context.stroke(); } } // Función para dibujar la aguja del medidor function drawNeedle() { var angle = startAngle + (rpm * (endAngle - startAngle) / 12000); var x = centerX + (radius - 50) * Math.cos(angle); var y = centerY + (radius - 50) * Math.sin(angle); context.beginPath(); context.moveTo(centerX, centerY); context.lineTo(x, y); context.strokeStyle = "red"; context.lineWidth = 5; context.stroke(); } // Función para calcular la Media Móvil Exponencial (EMA) function calculateEMA(currentValue, previousEMA, smoothingFactor) { return (currentValue * smoothingFactor) + (previousEMA * (1 - smoothingFactor)); } // Función para iniciar la grabación del audio function startRecording() { let selectedDeviceId = document.getElementById('microphoneSelect').value; let constraints = { audio: { deviceId: selectedDeviceId ? { exact: selectedDeviceId } : undefined } }; navigator.mediaDevices.getUserMedia(constraints) .then(stream => { mediaStreamSource = audioContext.createMediaStreamSource(stream); mediaStreamSource.connect(analyser); intervalId = setInterval(analyze, updateInterval); }) .catch(err => { console.error('Error accessing audio stream', err); }); }
@KepaAlonso2 ай бұрын
// Función para analizar los datos de audio function analyze() { analyser.getByteFrequencyData(dataArray); let maxVal = 0; let maxIndex = 0; for (let i = 0; i < bufferLength; i++) { if (dataArray[i] > maxVal) { maxVal = dataArray[i]; maxIndex = i; } } let frequency = maxIndex * sampleRate / analyser.fftSize; frequencyBuffer.push(frequency); // Mantener el buffer dentro de la longitud máxima if (frequencyBuffer.length > maxBufferLength) { frequencyBuffer.shift(); } // Calcular la frecuencia media let sumFrequency = frequencyBuffer.reduce((sum, freq) => sum + freq, 0); let avgFrequency = sumFrequency / frequencyBuffer.length; // Convertir la frecuencia media a RPM let newTargetRpm = avgFrequency * 10; // Aplicar la suavización mediante EMA targetRpm = calculateEMA(newTargetRpm, targetRpm, smoothingFactor); let currentTime = Date.now(); if (Math.abs(targetRpm - lastRpm) <= rpmStabilityThreshold) { if (currentTime - lastUpdateTime > stableTimeThreshold) { targetRpm = 0; } } else { lastUpdateTime = currentTime; } lastRpm = targetRpm; document.getElementById('rpm').innerText = isNaN(targetRpm) ? '0' : Math.round(targetRpm / 10); // Dibujar el medidor y la aguja drawGauge(); drawNeedle(); } // Actualizar la duración del buffer function updateBufferDuration(value) { bufferDuration = parseInt(value); maxBufferLength = Math.floor(bufferDuration / updateInterval); document.getElementById('bufferDurationValue').innerText = value; frequencyBuffer = []; // Limpiar el buffer al cambiar la duración } // Actualizar el intervalo de actualización function updateUpdateInterval(value) { updateInterval = parseInt(value); clearInterval(intervalId); intervalId = setInterval(analyze, updateInterval); maxBufferLength = Math.floor(bufferDuration / updateInterval); document.getElementById('updateIntervalValue').innerText = value; } // Actualizar el tamaño de la FFT function updateFftSize(value) { analyser.fftSize = parseInt(value); bufferLength = analyser.frequencyBinCount; dataArray = new Uint8Array(bufferLength); document.getElementById('fftSizeValue').innerText = value; } // Animar la aguja del medidor function animateNeedle() { if (Math.abs(rpm - targetRpm) > 1) { rpm += (targetRpm - rpm) * 0.05; drawGauge(); drawNeedle(); } requestAnimationFrame(animateNeedle); } // Población de la lista de micrófonos disponibles function populateMicrophoneList() { navigator.mediaDevices.enumerateDevices() .then(devices => { let microphoneSelect = document.getElementById('microphoneSelect'); devices.forEach(device => { if (device.kind === 'audioinput') { let option = document.createElement('option'); option.value = device.deviceId; option.text = device.label || `Microphone ${microphoneSelect.length + 1}`; microphoneSelect.appendChild(option); } }); }) .catch(err => { console.error('Error enumerating devices', err); }); } // Inicializar la lista de micrófonos al cargar la página populateMicrophoneList(); // Dibujar el medidor y la aguja al cargar la página drawGauge(); drawNeedle(); animateNeedle(); </script> </body> </html>
MORSE SENDER - POWERSELL USB CONTROL CODE: Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing # Crear formulario $form = New-Object System.Windows.Forms.Form $form.Text = 'USB RELAY CONTROL' $form.Size = New-Object System.Drawing.Size(400, 500) $form.StartPosition = 'CenterScreen' # Crear fuente para los cuadros de texto $fontTextBox = New-Object System.Drawing.Font("Arial", 14) # Crear etiqueta para puerto USB $label = New-Object System.Windows.Forms.Label $label.Location = New-Object System.Drawing.Point(15, 250) $label.Size = New-Object System.Drawing.Size(180, 40) $label.Text = 'NÚMERO DE PUERTO USB:' $form.Controls.Add($label) # Crear cuadro combinado para puerto USB $comboBox = New-Object System.Windows.Forms.ComboBox $comboBox.Location = New-Object System.Drawing.Point(200, 250) $comboBox.Size = New-Object System.Drawing.Size(160, 40) $ports = [System.IO.Ports.SerialPort]::getportnames() $comboBox.Items.AddRange($ports) $form.Controls.Add($comboBox) # Crear objeto para el puerto serie (se inicializará más tarde) $KEPAALONSORELAY = $null # Crear cuadro de texto para la entrada $inputBox = New-Object System.Windows.Forms.TextBox $inputBox.Location = New-Object System.Drawing.Point(15, 20) $inputBox.Size = New-Object System.Drawing.Size(360, 40) $inputBox.Font = $fontTextBox $form.Controls.Add($inputBox) # Crear botón para convertir y enviar código Morse $sendButton = New-Object System.Windows.Forms.Button $sendButton.Location = New-Object System.Drawing.Point(15, 70) $sendButton.Size = New-Object System.Drawing.Size(360, 40) $sendButton.Text = 'Enviar' $sendButton.Enabled = $true # Inicialmente habilitado $form.Controls.Add($sendButton) # Crear cuadro de texto para la salida de código Morse $outputBox = New-Object System.Windows.Forms.TextBox $outputBox.Location = New-Object System.Drawing.Point(15, 120) $outputBox.Size = New-Object System.Drawing.Size(360, 100) $outputBox.Multiline = $true $outputBox.Font = $fontTextBox $form.Controls.Add($outputBox) # Diccionario de código Morse $morseCode = @{ 'A' = '.-'; 'B' = '-...'; 'C' = '-.-.'; 'D' = '-..'; 'E' = '.'; 'F' = '..-.'; 'G' = '--.'; 'H' = '....'; 'I' = '..'; 'J' = '.---'; 'K' = '-.-'; 'L' = '.-..'; 'M' = '--'; 'N' = '-.'; 'O' = '---'; 'P' = '.--.'; 'Q' = '--.-'; 'R' = '.-.'; 'S' = '...'; 'T' = '-'; 'U' = '..-'; 'V' = '...-'; 'W' = '.--'; 'X' = '-..-'; 'Y' = '-.--'; 'Z' = '--..'; '1' = '.----'; '2' = '..---'; '3' = '...--'; '4' = '....-'; '5' = '.....'; '6' = '-....'; '7' = '--...'; '8' = '---..'; '9' = '----.'; '0' = '-----'; ' ' = ' ' # Espacio para separar palabras } # Función para enviar un solo carácter en código Morse a través del relé y pitido por altavoz function SendCharMorse { param ($char) $dotDuration = 100 # Duración del punto en milisegundos $dashDuration = $dotDuration * 3 $symbolGap = $dotDuration $char = $char.ToString().ToUpper().Trim() # Asegurarse de que el carácter esté en mayúsculas y sin espacios en blanco if ($morseCode.ContainsKey($char)) { $morse = $morseCode[$char] foreach ($symbol in $morse.ToCharArray()) { switch ($symbol) { '.' { $KEPAALONSORELAY.Write($ON, 0, $ON.Length) [System.Console]::Beep(1000, $dotDuration) # Pitido para punto Start-Sleep -Milliseconds $dotDuration $KEPAALONSORELAY.Write($OFF, 0, $OFF.Length) } '-' { $KEPAALONSORELAY.Write($ON, 0, $ON.Length) [System.Console]::Beep(1000, $dashDuration) # Pitido para raya Start-Sleep -Milliseconds $dashDuration $KEPAALONSORELAY.Write($OFF, 0, $OFF.Length) } } Start-Sleep -Milliseconds $symbolGap } Start-Sleep -Milliseconds ($symbolGap * 6) # Espacio entre letras } } $sendButton.Add_Click({ $text = $inputBox.Text.ToUpper() if ($comboBox.Text -ne "" -and $KEPAALONSORELAY -eq $null) { $KEPAALONSORELAY = New-Object System.IO.Ports.SerialPort $comboBox.Text, 9600, None, 8, One $KEPAALONSORELAY.Open() } $outputBox.Text = "" # Limpiar el cuadro de salida foreach ($char in $text.ToCharArray()) { $charString = $char.ToString().Trim() # Convertir el carácter a cadena y eliminar espacios en blanco if ($morseCode.ContainsKey($charString)) { $morse = $morseCode[$charString] $outputBox.AppendText($morse + " ") # Añadir el código Morse del carácter actual al cuadro de salida $form.Refresh() # Refrescar el formulario para actualizar la pantalla SendCharMorse -char $charString } } [System.Windows.Forms.MessageBox]::Show("MENSAJE ENVIADO") }) # Crear matrices de bytes para encender y apagar [BYTE[]] $ON = 0xA0, 0x01, 0x01, 0xA2 [BYTE[]] $OFF = 0xA0, 0x01, 0x00, 0xA1 # Crear LinkLabel para autor $LinkLabelAuthor = New-Object System.Windows.Forms.LinkLabel $LinkLabelAuthor.Location = New-Object System.Drawing.Point(75, 300) $LinkLabelAuthor.Size = New-Object System.Drawing.Size(250, 20) $LinkLabelAuthor.LinkColor = 'BLUE' $LinkLabelAuthor.ActiveLinkColor = 'RED' $LinkLabelAuthor.Text = 'KEPA ALONSO GOIKOETXEA' $LinkLabelAuthor.Add_Click({ [System.Diagnostics.Process]::Start('kalonso9.wixsite.com/kalo') }) $form.Controls.Add($LinkLabelAuthor) # Crear LinkLabel para Wikipedia $LinkLabelWiki = New-Object System.Windows.Forms.LinkLabel $LinkLabelWiki.Location = New-Object System.Drawing.Point(75, 330) $LinkLabelWiki.Size = New-Object System.Drawing.Size(250, 20) $LinkLabelWiki.LinkColor = 'BLUE' $LinkLabelWiki.ActiveLinkColor = 'RED' $LinkLabelWiki.Text = 'MORSE CODE' $LinkLabelWiki.Add_Click({ [System.Diagnostics.Process]::Start('en.wikipedia.org/wiki/Morse_code') }) $form.Controls.Add($LinkLabelWiki) # Mostrar el formulario $form.ShowDialog() # Cerrar el puerto serie si está abierto if ($KEPAALONSORELAY -ne $null -and $KEPAALONSORELAY.IsOpen) { $KEPAALONSORELAY.Write($OFF, 0, $OFF.Length) $KEPAALONSORELAY.Close() }
@RicardoTerrazav25 ай бұрын
las matematicas por sí mismas y como tales son hermosas
@KepaAlonso5 ай бұрын
Mandelbrot Set <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Conjunto de Mandelbrot</title> <style> body, html { margin: 0; padding: 0; overflow: hidden; } canvas { display: block; background-color: black; } </style> </head> <body> <canvas id="canvas"></canvas> <script> const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); const width = canvas.width = window.innerWidth; const height = canvas.height = window.innerHeight; let magnificationFactor = 300; // Factor de magnificación inicial const centerReal = -0.5; // Coordenada real del centro const centerImaginary = 0; // Coordenada imaginaria del centro const maxIterations = 1000; // Número máximo de iteraciones const animationDuration = 10000; // Duración de la animación en milisegundos (10 minutos) // Función para determinar si un punto pertenece al conjunto de Mandelbrot function mandelbrot(c_real, c_imaginary) { let real = 0; let imaginary = 0; for (let i = 0; i < maxIterations; i++) { const tempReal = real * real - imaginary * imaginary + c_real; const tempImaginary = 2 * real * imaginary + c_imaginary; real = tempReal; imaginary = tempImaginary; if (real * imaginary > 5) { return (i / maxIterations * 250); } } return 0; } // Función para dibujar el conjunto de Mandelbrot centrado en la pantalla function drawMandelbrot() { const offsetX = width / 2; const offsetY = height / 2; for (let x = 0; x < width; x++) { for (let y = 0; y < height; y++) { const c_real = (x - offsetX) / magnificationFactor + centerReal; const c_imaginary = (y - offsetY) / magnificationFactor + centerImaginary; const intensity = mandelbrot(c_real, c_imaginary); const color = intensity > 0 ? `hsl(0, 100%, ${intensity}%)` : 'black'; ctx.fillStyle = color; ctx.fillRect(x, y, 1, 1); } } } // Función para iniciar la animación function animate() { const startTime = Date.now(); function drawFrame() { const elapsedTime = Date.now() - startTime; ctx.clearRect(0, 0, width, height); const progress = Math.min(0.01, elapsedTime / animationDuration); magnificationFactor += progress * 30; // Aumentar el factor de magnificación gradualmente drawMandelbrot(); if (progress < 1) { requestAnimationFrame(drawFrame); } } drawFrame(); } // Iniciar la animación después de un breve retraso setTimeout(animate, 10); </script> </body> </html>
@KepaAlonso5 ай бұрын
Barnsley Fern <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Fractal tipo Ola</title> <style> body, html { margin: 0; padding: 0; overflow: hidden; } canvas { display: block; background-color: black; } </style> </head> <body> <canvas id="canvas"></canvas> <script> const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); const width = canvas.width = window.innerWidth+20; const height = canvas.height = window.innerHeight; const scale = height / 10; // Escala para el tamaño del helecho (ajustado para cubrir la altura de la pantalla) const initialX = width / 2; const initialY = height / 2 + 380; // Coordenada inicial Y con una separación de 50 píxeles arriba const animationDuration = 600; // Duración de la animación en milisegundos (10 minutos) // Función para dibujar el helecho function drawFern(x, y, iterations) { for (let i = 0; i < iterations; i++) { const rand = Math.random(); let newX, newY; if (rand < 0.01) { newX = 0; newY = 0.16 * y; } else if (rand < 0.86) { newX = 0.85 * x + 0.04 * y; newY = -0.04 * x + 0.85 * y + 1.6; } else if (rand < 0.93) { newX = 0.2 * x - 0.26 * y; newY = 0.23 * x + 0.22 * y + 1.6; } else { newX = -0.15 * x + 0.28 * y; newY = 0.26 * x + 0.24 * y + 0.44; } ctx.fillStyle = 'green'; ctx.fillRect(initialX + newX * scale, initialY - newY * scale, 1, 1); x = newX; y = newY; } } // Función para iniciar la animación function animate() { const startTime = Date.now(); function drawFrame() { const elapsedTime = Date.now() - startTime; ctx.clearRect(0, 0, width, height); const progress = Math.min(0.1, elapsedTime / animationDuration); drawFern(0, 0, 1000000 * progress); // Incremento en el número de iteraciones if (progress < 1) { requestAnimationFrame(drawFrame); } } drawFrame(); } // Iniciar la animación después de un breve retraso setTimeout(animate, 10); </script> </body> </html>
@KepaAlonso5 ай бұрын
Julia Fractal <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Conjunto de Julia Animado</title> <style> body, html { margin: 0; padding: 0; overflow: hidden; } canvas { display: block; background-color: black; } </style> </head> <body> <canvas id="canvas"></canvas> <script> const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); const width = canvas.width = window.innerWidth; const height = canvas.height = window.innerHeight; const maxIterations = 1000; // Número inicial de iteraciones const maxTotalIterations = 1000; // Número máximo total de iteraciones let cx = -0.7; let cy = 0.27015; let totalIterations = 0; // Función para determinar si un punto pertenece al conjunto de Julia function julia(x, y, iterations) { let zx = x / width * 3.5 - 1.8; let zy = y / height * 2 - 1; for (let i = 0; i < iterations; i++) { let temp = zx * zx - zy * zy + cx; zy = 2 * zx * zy + cy; zx = temp; if (zx * zx + zy * zy > 4) { return i / iterations * 90; } } return 0; } // Función para dibujar el conjunto de Julia progresivamente function drawJulia() { const iterationsIncrement = 5; // Incremento en el número de iteraciones por cuadro const maxFrames = maxTotalIterations / iterationsIncrement; const frameTime = 1000; // Tiempo entre cuadros en milisegundos let currentIterations = 0; function drawFrame() { ctx.clearRect(0, 0, width, height); for (let y = 0; y < height; y++) { for (let x = 0; x < width; x++) { const intensity = julia(x, y, currentIterations); const color = intensity > 0 ? intensity * 2.55 : 0; // Convertir a valor de 0 a 255 ctx.fillStyle = `rgb(0, 0, ${color})`; ctx.fillRect(x, y, 1, 1); } } currentIterations += iterationsIncrement; if (currentIterations <= maxIterations) { requestAnimationFrame(drawFrame); } } drawFrame(); } // Iniciar el dibujo progresivo del conjunto de Julia drawJulia(); </script> </body> </html>
@ahmadabosrea88655 ай бұрын
can be used to get a feedback signal from a sensor to the computer through the USB?
@KepaAlonso5 ай бұрын
No, only digital output
@georhodiumgeo98276 ай бұрын
Dam...
@KepaAlonso6 ай бұрын
goo.gl/maps/mTK97bLx3eJiQGLZ9
@kylobensolo56556 ай бұрын
Ich lade der mg-08/15 Ich höre Eindringlinge
@bill95406 ай бұрын
Great work on the weathering and shading…very nice👍
@Blackcat-do7wo6 ай бұрын
Very nice 👏
@marccxxshammer66438 ай бұрын
@selimcelik349410 ай бұрын
I'm guessing, like me, that most people were wondering if they started building in the water or if the water was diverted afterwards. I'm glad to know the answer now.
@KepaAlonso9 ай бұрын
Appreciate the observation. Initially, the flow was diverted before intercepting the channel. This unique process presented a distinctive challenge. Thanks for tuning in and showing interest.
@nazarbulatov212211 ай бұрын
Что за цвет был использован при покраске кузова?!
@KepaAlonso11 ай бұрын
Дело в том, что я использую 5 банок акриловой краски основных цветов: белого, черного, красного, желтого и синего по 500 мл каждая. Путем их смешивания я получаю все необходимые цвета для моей модели. Затем я покрываю поверхность глянцевым лаком, наношу масляные краски и в завершение использую матовый лак.
@nazarbulatov212211 ай бұрын
@@KepaAlonso спасибо за ответ! А военный автомобиль Зис5В . Покрытый только глянцевым лаком будет смотреться не очень?! И кстати салон двигатель и колеса надо покрывать лаком? И если да то по окончанию сборке? Задаю сразу все вопросы которые интересуют, так как новичок и это моя первая модель, а другие блогеры не отвечают;) Буду рад ответу!)
@nazarbulatov212211 ай бұрын
Так то у меня ещё много вопросов, но на Ютубе точных ответов найти не могу)
@KepaAlonso11 ай бұрын
Перед началом покраски тщательно очистите модель мылом и водой. Важно, чтобы поверхность была чистой от жира, так как это обеспечит хорошее сцепление краски. Наношу базовый слой серой краски с добавлением нескольких капель жидкого мыла. Важно, чтобы краска хорошо зафиксировалась; если на модели есть следы жира, например, от рук, краска может плохо держаться. Глянцевый лак используется для того, чтобы при нанесении масляных красок с растворителем, такого как агуаррас, они хорошо распределялись, создавая различные оттенки. Это можно сделать кистью и ватными тампонами, а затем убрать излишки. Обязательно наносите глянцевый лак после покрытия разноцветными слоями краски, особенно если вы собираетесь использовать наклейки. Дайте несколько дней для полного высыхания перед применением масляных красок. Будьте осторожны с избыточным использованием растворителя при нанесении масляных красок, чтобы избежать поднятия глянцевого лака. Завершающий матовый слой придаст модели более реалистичный вид, что особенно подходит для моделей военной техники, таких как танки.
@KepaAlonso11 ай бұрын
Я новичок и провожу эксперименты с моделями, и, из всего, что я пробовал, наилучший, более удовлетворительный и реалистичный результат я получил, нанося масляные краски поверх акрила, как я вам говорю. Речь идет о моделях типа танков и военной техники; для самолетов и гражданских транспортных средств ситуация отличается.
@KiKi-pn7is Жыл бұрын
👍👍👍👍
@dvdw_graphics_crafts Жыл бұрын
Love the dust effect, looking realistic! ; )
@KepaAlonso9 ай бұрын
Thank you! I'm glad you noticed and appreciate the dust effect. Achieving realism was a key goal, so I'm thrilled that it came across effectively. Your positive feedback means a lot! 😊
@dvdw_graphics_crafts9 ай бұрын
dust and mud, that's also the most fun part :D
@jimmytwizzle7836 Жыл бұрын
Hardly jaw dropping was it. In fact it was pretty uninteresting I thought. Thumbs down.