[{"content":"","date":"29 de julio de 2026","externalUrl":null,"permalink":"/es/tags/ai/","section":"Tags","summary":"","title":"Ai","type":"tags"},{"content":"","date":"29 de julio de 2026","externalUrl":null,"permalink":"/es/tags/discord/","section":"Tags","summary":"","title":"Discord","type":"tags"},{"content":"","date":"29 de julio de 2026","externalUrl":null,"permalink":"/es/tags/discord.py/","section":"Tags","summary":"","title":"Discord.py","type":"tags"},{"content":"","date":"29 de julio de 2026","externalUrl":null,"permalink":"/es/tags/docker/","section":"Tags","summary":"","title":"Docker","type":"tags"},{"content":"Diseño hardware digital y escribo sobre lo que voy construyendo. Actualmente curso una maestría en ingeniería de computación en USC, enfocada en arquitecturas de procesadores y aceleración por hardware para machine learning.\nAquí vas a encontrar proyectos y guías sobre IA self-hosted, domótica, impresión 3D, tecnología para la salud o prácticamente cualquier proyecto en el que esté trabajando.\nProyectos Sobre mí Contacto ","date":"29 de julio de 2026","externalUrl":null,"permalink":"/es/","section":"Emiliano Fernández Cervantes","summary":"Diseño hardware digital y escribo sobre lo que voy construyendo. Actualmente curso una maestría en ingeniería de computación en USC, enfocada en arquitecturas de procesadores y aceleración por hardware para machine learning.\n","title":"Emiliano Fernández Cervantes","type":"page"},{"content":"","date":"29 de julio de 2026","externalUrl":null,"permalink":"/es/series/ia-privada-en-casa/","section":"Series","summary":"","title":"IA Privada en Casa","type":"series"},{"content":"","date":"29 de julio de 2026","externalUrl":null,"permalink":"/es/tags/ollama/","section":"Tags","summary":"","title":"Ollama","type":"tags"},{"content":"","date":"29 de julio de 2026","externalUrl":null,"permalink":"/es/tags/open-webui/","section":"Tags","summary":"","title":"Open-Webui","type":"tags"},{"content":"Montaste un asistente de IA privado en tu propia computadora, le cargaste el manual de tu casa, y responde de maravilla. ¿Entonces por qué nadie en tu casa lo usa?\nSi esto te suena familiar, el problema casi nunca es el modelo: es la puerta de entrada. Pedirle a alguien de tu familia que recuerde una URL, abra el navegador, inicie sesión y elija el modelo correcto de una lista es pedirle que cambie sus hábitos, y los hábitos casi nunca pierden. En lugar de esperar a que ellos vayan al asistente, pon el asistente donde ya están: en una app de chat que ya tienen abierta en el celular.\nEn mi casa esa app es Discord, y esta guía te lleva por el puente que construí para lograrlo. Al terminar vas a tener un bot pequeño de Discord que toma mensajes !ask de un servidor familiar, los reenvía a una instancia propia de Open WebUI respaldada por Ollama, y publica la respuesta de vuelta en el canal.\nAdemás, el camino vale la pena por sí solo. En el trayecto vas a trabajar con integración de APIs REST, networking de Docker, presupuesto de memoria de GPU y generación aumentada por recuperación, un conjunto de habilidades muy transferible para un proyecto que puedes terminar en un fin de semana.\nUn supuesto antes de empezar: esta guía arranca donde termina la IA privada. Esta es la parte dos de la serie, así que si todavía no tienes un asistente corriendo, la parte uno sobre cómo desplegar tu IA privada con Ollama construye esa mitad del stack, y todo lo que sigue aquí es la capa que finalmente la vuelve útil para todos los demás en la casa.\nSin app nueva, sin login, sin menú desplegable que equivocarle. El modelo nunca fue la parte difícil de este proyecto, la puerta de entrada sí. El stack: un puente deliberadamente aburrido # El principio de diseño detrás de todo esto es que el bot debe ser aburrido. No hace nada de IA: no procesa documentos, no administra prompts, y no le habla a Ollama. Solo lee mensajes de Discord y hace llamadas HTTP. Eso deja las partes interesantes (el system prompt, la base de conocimiento, la elección del modelo) en un solo lugar, donde las puedes cambiar sin tocar ni una línea de Python.\nServidor de Discord familiar la interfaz que todos ya tienen │ !ask ¿Dónde está la llave de paso del agua? ▼ Bot de Discord (Python, Docker) un puente delgado, sin lógica de IA │ POST /api/chat/completions Authorization: Bearer \u0026lt;key\u0026gt; ▼ Open WebUI (Docker) system prompt + manual de la casa (KB) │ OLLAMA_BASE_URL ▼ Ollama (servicio nativo, GPU) el runtime del modelo Todo excepto Discord corre en WSL2 en mi computadora de escritorio, que es donde está la GPU: una NVIDIA GeForce RTX 3070 Ti con 8 GB de VRAM, la misma tarjeta de la PC que armé yo mismo. Acuérdate de esos 8 GB, porque más adelante son los que deciden en silencio qué modelo puedes correr. Open WebUI y el bot están deliberadamente juntos en la misma instancia de WSL con network_mode: host, así se alcanzan entre ellos y alcanzan a Ollama por localhost, sin networking entre máquinas que debuggear. Mi servidor de casa era el candidato obvio para hospedar el bot, aunque tiene alrededor de 1.8 GB de RAM y ya está ocupado, así que mantener las tres piezas juntas en la máquina con GPU resultó más simple y más rápido.\nHay una propiedad que vale la pena señalar, porque define toda la parte de seguridad: el bot es solo de salida. Él marca hacia Discord y hacia Open WebUI, y nada en internet se conecta jamás hacia adentro de mi casa para alcanzarlo. Ese fue el factor decisivo cuando comparé Discord contra WhatsApp, cuya Cloud API oficial espera un webhook entrante, mientras que las librerías no oficiales cargan tanto riesgo de baneo como una segunda dependencia que mantener.\nPaso 1: Crear el bot de Discord # Entra al Discord Developer Portal, crea una nueva aplicación y abre la pestaña Bot.\nAquí importan tres cosas:\nCopia el token y guárdalo en un lugar seguro. Es la contraseña de tu bot, y va en un archivo .env que nunca se sube al repositorio. Activa el Message Content Intent en Privileged Gateway Intents. Sin esto tu bot se conecta sin problemas, se queda en el canal, e ignora silenciosamente cada mensaje, porque Discord simplemente no le manda el texto. Es la forma más fácil de perder una tarde en este proyecto, así que hazlo desde ahorita. Invita al bot a tu servidor con Send Messages, Read Message History y Embed Links. No necesita más, y darle los menos permisos posibles a un bot que vive en tu casa siempre es el instinto correcto. Paso 2: El conocimiento va en Open WebUI, no en el bot # Esta es la decisión que mantiene el proyecto pequeño, así que vale la pena tomarla antes de escribir código.\nDentro de Open WebUI, ve a Workspace → Models y crea un modelo personalizado. El mío se llama Family1, y carga dos cosas: un system prompt en español que le dice al modelo que es un asistente del hogar, y una colección de conocimiento con el manual de la casa. Ese manual es simplemente un documento en Markdown que describe la configuración del Wi-Fi, los dispositivos del hogar inteligente, el centro de carga, los electrodomésticos, y todos esos pedacitos de conocimiento que normalmente viven en la cabeza de una sola persona.\nOpen WebUI se encarga de la recuperación por su cuenta. Cuando llega una pregunta, extrae los fragmentos relevantes del manual y los entrega al modelo como contexto, y eso es lo que hace que las respuestas sean específicas de tu casa y no genéricamente plausibles. La consecuencia importante es arquitectónica: el prompt y el conocimiento viven en el volumen de datos de Open WebUI, no en Ollama ni en el bot. Eso significa que puedes reescribir la personalidad del asistente o subir una versión nueva del manual sin reconstruir ni reiniciar nada.\nEse mismo hecho es también una advertencia. Todo lo que hace que el asistente sea tuyo está en un solo volumen de Docker, así que respáldalo antes de cualquier cambio grande:\ndocker run --rm -v open-webui:/data -v $PWD:/backup alpine \\ tar czf /backup/owui-data.tgz -C /data . Por último, genera la credencial que va a usar el bot: Settings → Account → API Keys → Generate new key. Cópiala en ese momento, porque después ya no se puede ver.\nPaso 3: El puente entre Discord y la API de Open WebUI # Ahora el código. Todo el bot es un solo archivo de Python con dos comandos, y eso no es casualidad. Cada función que me dieron ganas de agregar resultó pertenecer más arriba, en Open WebUI.\nLas dependencias son mínimas:\ndiscord.py\u0026gt;=2.3,\u0026lt;3 requests\u0026gt;=2.31,\u0026lt;3 python-dotenv\u0026gt;=1.0,\u0026lt;2 El corazón es una sola función que manda la pregunta y saca la respuesta del JSON. El código va tal cual está en el repositorio, con sus comentarios en inglés incluidos, para que puedas copiarlo y compararlo línea por línea sin sorpresas; la explicación corre por cuenta del texto de aquí abajo:\n# OpenWebUI uses the OpenAI-compatible chat completions endpoint. # Previously this was /api/chat (wrong) — the correct path is /api/chat/completions. ASK_ENDPOINT = f\u0026#34;{OPENWEBUI_URL}/api/chat/completions\u0026#34; def ask_openwebui(question: str) -\u0026gt; str: \u0026#34;\u0026#34;\u0026#34;Send a question to OpenWebUI and return the model answer.\u0026#34;\u0026#34;\u0026#34; headers = {\u0026#34;Content-Type\u0026#34;: \u0026#34;application/json\u0026#34;} if OPENWEBUI_API_KEY: headers[\u0026#34;Authorization\u0026#34;] = f\u0026#34;Bearer {OPENWEBUI_API_KEY}\u0026#34; # No system message here on purpose: the OpenWebUI model \u0026#34;Family1\u0026#34; already # carries its own (Spanish) system prompt + the \u0026#34;Manual Casa\u0026#34; knowledge base. # Sending a second system message here competes with / overrides that prompt. payload = { \u0026#34;model\u0026#34;: OPENWEBUI_MODEL, \u0026#34;messages\u0026#34;: [ {\u0026#34;role\u0026#34;: \u0026#34;user\u0026#34;, \u0026#34;content\u0026#34;: question}, ], \u0026#34;stream\u0026#34;: False, } log.info(\u0026#34;POST %s model=%s\u0026#34;, ASK_ENDPOINT, OPENWEBUI_MODEL) response = requests.post(ASK_ENDPOINT, json=payload, headers=headers, timeout=180) if not response.ok: log.error( \u0026#34;OpenWebUI returned HTTP %d: %s\u0026#34;, response.status_code, response.text[:400], ) response.raise_for_status() data = response.json() # Try a few common response shapes so the script is easier to adapt. # OpenWebUI\u0026#39;s /api/chat/completions returns the standard OpenAI shape: # {\u0026#34;choices\u0026#34;: [{\u0026#34;message\u0026#34;: {\u0026#34;content\u0026#34;: \u0026#34;...\u0026#34;}}]} if isinstance(data, dict): if \u0026#34;choices\u0026#34; in data and data[\u0026#34;choices\u0026#34;]: return data[\u0026#34;choices\u0026#34;][0][\u0026#34;message\u0026#34;][\u0026#34;content\u0026#34;].strip() if \u0026#34;message\u0026#34; in data and isinstance(data[\u0026#34;message\u0026#34;], dict): content = data[\u0026#34;message\u0026#34;].get(\u0026#34;content\u0026#34;) if content: return str(content).strip() if \u0026#34;content\u0026#34; in data and isinstance(data[\u0026#34;content\u0026#34;], str): return data[\u0026#34;content\u0026#34;].strip() return str(data) Varios detalles ahí son críticos, y a cada uno llegué después de equivocarme.\nUsa la ruta compatible con OpenAI. Open WebUI expone /api/chat/completions, no /api/chat. Mi primera versión usaba la segunda y solo obtuve errores que parecían un problema de autenticación.\nOPENWEBUI_URL debe ser la URL base pelona. El script agrega la ruta él mismo, así que poner una ruta en la variable la duplica y produce un 404 muy confuso.\nNo mandes un system message. Se siente natural definir la personalidad del asistente en el código, pero al hacerlo compites con el prompt que ya está pegado al modelo personalizado, y el resultado es un asistente con dos juegos de instrucciones que se contradicen.\nParsea a la defensiva. Open WebUI devuelve el formato estándar de OpenAI, pero verificar un par de formatos alternativos cuesta un puñado de líneas y deja el script listo para apuntar a otro backend. Loggear el status code y los primeros cientos de caracteres de una respuesta fallida cuesta más o menos lo mismo, y es la diferencia entre debuggear con evidencia y debuggear a ciegas.\nEl lado de Discord es igual de pequeño. !ask corre dentro de un indicador de \u0026ldquo;escribiendo\u0026rdquo;, para que la familia vea que el bot está trabajando en lugar de asumir que está roto, cada camino de error termina en una frase que un humano puede leer, y la respuesta se parte en pedazos antes de enviarse porque Discord rechaza mensajes de más de 2000 caracteres:\n@bot.command(name=\u0026#34;ask\u0026#34;) async def ask(ctx: commands.Context, *, question: str) -\u0026gt; None: \u0026#34;\u0026#34;\u0026#34;Ask the family assistant a question. Usage: !ask How do I turn on movie mode? \u0026#34;\u0026#34;\u0026#34; async with ctx.typing(): try: answer = ask_openwebui(question) except requests.RequestException as exc: status = getattr(getattr(exc, \u0026#34;response\u0026#34;, None), \u0026#34;status_code\u0026#34;, None) detail = f\u0026#34; (HTTP {status})\u0026#34; if status else \u0026#34;\u0026#34; await ctx.send(f\u0026#34;Sorry, I could not reach OpenWebUI{detail}: {exc}\u0026#34;) return except Exception as exc: # noqa: BLE001 - show a friendly error message await ctx.send(f\u0026#34;Something went wrong: {exc}\u0026#34;) return if not answer: await ctx.send(\u0026#34;I did not get an answer back.\u0026#34;) return # Discord message limit is 2000 characters. if len(answer) \u0026lt;= 2000: await ctx.send(answer) return # If the answer is long, split it into chunks. chunk_size = 1900 for start in range(0, len(answer), chunk_size): await ctx.send(answer[start : start + chunk_size]) Los mensajes de error salen en inglés porque así están en el repositorio; si tu familia prefiere leerlos en español, ese es el primer cambio obvio que puedes hacerle al script.\nUn comando !ping que contesta pong lo completa. Suena trivial, pero responde la pregunta más común de la casa (\u0026quot;¿está caído o nada más está lento?\u0026quot;) sin que nadie tenga que leer un log.\nPaso 4: Empaquetar en un container y correrlo # La imagen es prácticamente lo más simple que puede ser una imagen de Python, con la capa de dependencias cacheada aparte del código para que los cambios se reconstruyan en segundos:\nFROM python:3.12-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY family_discord_openwebui_bot.py . CMD [\u0026#34;python3\u0026#34;, \u0026#34;family_discord_openwebui_bot.py\u0026#34;] Y el archivo de Compose:\nservices: bot: build: . container_name: family-assistant-bot restart: unless-stopped env_file: .env network_mode: host network_mode: host es lo que permite al container alcanzar Open WebUI en un simple localhost:8080, ya que ambos viven en la misma instancia de WSL. restart: unless-stopped significa que el bot regresa solo después de un reinicio, lo cual importa cuando se supone que la casa puede depender de él.\nTu .env guarda cuatro valores:\nDISCORD_TOKEN=tu_token_de_discord OPENWEBUI_URL=http://localhost:8080 OPENWEBUI_MODEL=ollama-family1:latest OPENWEBUI_API_KEY=sk-... OPENWEBUI_MODEL merece una segunda mirada, porque es la trampa más sutil de todo el proyecto. Tiene que ser el id del modelo personalizado que creaste en el Paso 2, el que tiene el manual de la casa adjunto. Si lo apuntas al motor pelón, todo parece funcionar: el bot se conecta, las preguntas reciben respuesta, las respuestas suenan fluidas. También están completamente desconectadas de tu casa, porque te brincaste el system prompt y la recuperación de documentos. Confirma el id exacto en Workspace → Models en lugar de adivinarlo, y no lo copies del .env.example de mi repositorio, que ahí todavía trae el id del motor y es exactamente el error del que te está advirtiendo este párrafo.\nLuego lo levantas:\ndocker compose up -d docker compose logs -f bot Los logs deben mostrar Logged in as ... y Bot is ready. En Discord, !ping debe devolver pong, y !ask debe devolver algo que solo tu propio manual pudo haberle dicho.\nLas partes difíciles: cuatro obstáculos que conviene conocer # El puente me tomó una tarde. Todo lo que está debajo es donde estuvo la ingeniería de verdad, y las cuatro lecciones de abajo sirven mucho más allá de este proyecto, así que es la sección que yo leería primero si estuviera en tu lugar.\nLa GPU que no se estaba usando # Durante un tiempo el asistente respondía bien pero dolorosamente lento, y los logs explicaban por qué: Ollama seguía cayendo a library=cpu, reportando failure during GPU discovery ... failed to finish discovery before timeout después de unos treinta segundos, tanto para CUDA 12 como para CUDA 13. Al mismo tiempo, nvidia-smi dentro de WSL listaba la tarjeta sin ningún problema. CUDA se veía sano y la GPU se veía presente, y aun así la inferencia corría en CPU.\nRastrear el proceso reveló el mecanismo real. Ollama descubre GPUs lanzando un subproceso runner que escucha en 127.0.0.1 en un puerto aleatorio, y luego se conecta a él por loopback para preguntarle qué hardware existe. Mi WSL estaba configurado con networkingMode=mirrored, y en modo mirrored esas conexiones locales de proceso a proceso se enrutan por el stack de red de Windows y se quedan colgadas. El connect() del proceso padre se quedaba sin resolver hasta que expiraba el timeout, el runner era terminado, el descubrimiento \u0026ldquo;fallaba\u0026rdquo;, y Ollama concluía que no había GPU.\nDos experimentos rápidos lo confirmaron. Un script de cinco líneas en Python que escuchaba y se conectaba en 127.0.0.1 se colgaba exactamente igual, y una multiplicación de matrices en PyTorch terminó en 0.4 segundos en la GPU, lo que ubicaba la falla en el loopback y no en CUDA ni en Ollama.\nLa solución fue una línea en C:\\Users\\fdeze\\.wslconfig:\n[wsl2] networkingMode=NAT localhostForwarding=true Después de un wsl --shutdown, Ollama cargó el modelo al 100% en GPU. De pasada, NAT también me devolvió la VPN de la universidad, que el modo mirrored había roto sin avisar. La lección a la que sigo regresando: cuando el síntoma apunta a la capa exótica (drivers, CUDA, la GPU), verifica primero la capa aburrida. Era networking.\nElegir un modelo que de verdad quepa # Mi primer motor fue qwen3.5-tuned, un Qwen3.5 de 9.7B cuantizado a Q4_K_M con un contexto de 8192 tokens. En papel cabía, y ollama ps estaba muy de acuerdo: PROCESSOR decía 100% GPU. La aritmética es la que cuenta la historia real. Ese motor ocupa 6.6 GB, el escritorio de Windows ya trae apartados alrededor de 1.3 GB de la tarjeta antes de que Ollama pida algo, y 6.6 más 1.3 aterrizan en unos 7.9 GB de los 8.2 GB de la RTX 3070 Ti. Eso son unos 250 MB de margen en una tarjeta que está al 97 por ciento.\nVivir al 97 por ciento no es un lugar estable. En reposo el modelo era perfectamente reproducible, generando alrededor de 70 tokens por segundo corrida tras corrida. Pero mientras hacía las mediciones, ese mismo modelo con ese mismo prompt se desplomaba de manera intermitente a unos 20 tokens por segundo, con el procesamiento del prompt cayendo de unos 800 tokens por segundo a unos 133, justo cuando el escritorio de Windows pedía VRAM y esos últimos 250 MB simplemente ya no estaban. Ese es el derrame: el KV cache y los buffers de cómputo se van a la memoria del sistema y el trabajo deja de ser trabajo de GPU sin avisarle a nadie. Una lentitud ocasional e impredecible es peor para un servicio familiar que una lentitud permanente, porque nadie puede saber si está descompuesto o nada más está teniendo un mal minuto. Que fuera un modelo de razonamiento lo empeoraba todavía más, porque la parte que corría a velocidad de CPU era justamente la larga traza de razonamiento.\nLa respuesta no era una tarjeta más grande, era dimensionar bien. Construí un motor más chico a partir de una base de 4B con contexto de 4096 tokens:\nFROM qwen3.5:4b PARAMETER num_ctx 4096 PARAMETER num_gpu 99 PARAMETER temperature 0.7 PARAMETER top_k 20 PARAMETER top_p 0.9 PARAMETER presence_penalty 1.5 PARAMETER repeat_penalty 1.1 ollama create qwen3.5-4b-tuned -f qwen-family-4b.Modelfile ollama ps # la prueba de aceptación: PROCESSOR debe decir 100% GPU El motor de 4B ocupa 5.5 GB, lo que deja 2.7 GB de la tarjeta sin reclamar por el modelo y todavía cerca de 1.4 GB realmente libres una vez que el escritorio toma su parte. Ese margen es todo el punto, y los números lo siguieron: el 4B sostiene alrededor de 103 tokens por segundo contra los 70 del 9.7B en su mejor momento, y los sostiene de manera consistente en lugar de a ratos. Dimensionar bien no me costó velocidad, me compró velocidad.\nAsí que la verdadera prueba de aceptación no es que PROCESSOR diga 100% GPU, porque el motor grandote también pasaba esa prueba. Es que diga 100% GPU con todavía cerca de un gigabyte de VRAM libre, y ese gigabyte libre es la diferencia entre un asistente en el que la familia confía y uno que abandonan. Aunque bajar de 9.7B a 4B suena a retroceso, el costo en calidad resultó pequeño, precisamente porque las respuestas se apoyan en el manual de la casa y no en el conocimiento memorizado del modelo. La recuperación de documentos me dejó gastar mi VRAM en velocidad en lugar de en datos de cultura general.\nEso sí, ese argumento carga un supuesto que yo no había probado: solo se sostiene mientras la recuperación de verdad encuentre el pasaje correcto. Regreso a eso más abajo, porque cuando por fin lo medí resultó ser el eslabón más débil de todo el stack.\nApagar el razonamiento # El último obstáculo fue el más raro. Mi motor razona por defecto, emitiendo cientos de tokens internos hasta para un saludo, y combinado con un system prompt grande y los fragmentos recuperados del manual dentro de un presupuesto de 4096 tokens, esa traza de razonamiento se comía la respuesta. No quise quedarme con la impresión, así que lo reproduje: la misma pregunta, la misma semilla, el contexto llenado a propósito hasta los 4096 tokens completos del modelo para igualar los 1,547 a 2,284 tokens que carga una pregunta real después de la recuperación, una corrida con el razonamiento apagado y dos con él encendido.\nthink tiempo real tokens de salida razonamiento respuesta devuelta false 3.7 s 114 ninguno 420 caracteres, limpia true 92.9 s 8,190 29,254 caracteres vacía, 0 caracteres true 51.0 s 4,561 16,993 caracteres 464 caracteres Esa tabla es la falla completa en un solo lugar. Con el razonamiento encendido, la traza consumía el presupuesto de salida antes de que la respuesta siquiera empezara: la mejor de las dos corridas todavía tardó 51 segundos en entregar 464 caracteres, y la otra se gastó 92.9 segundos emitiendo 29,254 caracteres de razonamiento para al final no devolver nada. Un mensaje en blanco después de minuto y medio no es un asistente lento, es uno descompuesto, y cualquiera en la casa concluiría justamente eso.\nVale la pena señalar un matiz, porque explica por qué esto es específicamente un problema de RAG: el razonamiento solo es catastrófico cuando el contexto está lleno. Con un prompt corto y sin restricciones, ese mismo motor nada más se va de unos 10 a 14 segundos a unos 27 a 30. Es la combinación de un system prompt grande, los fragmentos recuperados y un techo de 4096 tokens la que convierte una lentitud en una respuesta vacía. Por eso apagarlo es obligatorio en una ruta con RAG y no una optimización opcional.\nLa solución que todo mundo sugiere, poner /no_think en el prompt, no hizo absolutamente nada en este build: medí 479 tokens de razonamiento con el flag puesto. Lo que sí funcionó fue poner think: false como parámetro del modelo personalizado en Open WebUI, en Workspace → Models → Params. Tiene que vivir en la definición del modelo, porque el endpoint de chat completions de Open WebUI no reenvía un campo think que venga a nivel de request desde el bot.\nOpen WebUI, Workspace → Models → Family1 → Params. Es la única pantalla donde el ajuste se queda guardado, así que vale la pena ubicarla antes de ponerte a editar cualquier otra cosa. Con eso resuelto, las respuestas llegan en unos cuatro segundos. Regresé a medirlo en serio en lugar de quedarme con la impresión: nueve preguntas enviadas de punta a punta a través de Open WebUI contra el modelo Family1 con el manual de la casa adjunto, cada una cargando entre 1,547 y 2,284 tokens de prompt después de la recuperación y produciendo entre 75 y 601 tokens de respuesta. La más rápida regresó en 2.3 segundos, la típica entre tres y seis, y la más lenta, que fue la primera de la corrida, en 8.4 segundos. Para una pregunta doméstica hecha desde el celular, eso es indistinguible de instantáneo.\nLos arranques en frío eran la parte que daba miedo. Cuando el modelo todavía tenía que cargarse y hacer su primera recuperación, la primera pregunta del día tardaba de 100 a 134 segundos, que es exactamente la razón por la que el timeout HTTP del bot es de 180 segundos y no los 90 con los que empecé: se me caían por timeout peticiones que sí iban a funcionar. Esos números ya no se reproducen. Descargué el motor de Ollama y reinicié el container de open-webui para limpiar sus caches, luego cronometré cuatro preguntas seguidas, y la genuinamente fría regresó en 9.8 segundos, seguida de 6.2, 6.2 y 5.4 en caliente.\nAun así dejé el timeout generoso, porque un timeout al que nunca llegas no cuesta nada, mientras que uno un poquito corto te cuesta justo la petición que más querías que funcionara. Todas las mediciones de este post, junto con los scripts de benchmark que las producen, están en BENCHMARKS.md en el repositorio del bot, el que está enlazado al final, para que puedas volver a correrlas en tu propio hardware en lugar de creerme nada más porque sí.\nSobrevivir un reinicio # NAT le dio a WSL una IP privada que cambia en cada arranque, lo cual rompería el acceso a Open WebUI desde la red local. Una regla netsh portproxy en Windows reenvía los puertos 8080 y 11434 del host hacia la dirección actual de WSL, y como esa dirección se mueve, un pequeño script de PowerShell refresca las reglas y abre las entradas correspondientes del firewall, ejecutado por una tarea programada al iniciar sesión. La IP del host de Windows nunca cambia, así que la configuración de mi reverse proxy y mi dominio público nunca se tienen que tocar.\nEl eslabón más débil: medir si la recuperación de verdad recupera # Todo lo anterior descansa en una afirmación que nunca había puesto a prueba: que apoyar las respuestas en el manual de la casa es lo que le permite a un modelo de 4B hacer este trabajo. Si eso es cierto, la recuperación es el componente más importante del stack, y eso significa que merece su propia medición. Por fin se la hice, y el resultado honesto es que también es la parte más débil de lo que construí.\nEl truco está en calificar la recuperación con el modelo fuera de la jugada. Para cada una de dieciséis preguntas le pedí a Open WebUI los primeros k fragmentos y revisé si la respuesta correcta aparecía tal cual en lo que regresaba. Sin generación, sin juzgar la redacción, nada más un sí o un no sobre si el dato llegó siquiera a la ventana de contexto. Esa separación importa, porque una respuesta equivocada en un sistema RAG tiene dos causas completamente distintas, y no puedes arreglar la que no identificaste.\nmanual k=3 k=5 k=8 producción 11/16 12/16 12/16 sin las imágenes embebidas 12/16 12/16 12/16 En producción corro con TOP_K = 3, así que el número que describe mi casa es 11 de 16. Como una tercera parte de las veces, la respuesta nunca le llega al modelo. Cuando eso pasa el asistente no está equivocado, está desinformado, y desde afuera esas dos fallas se ven idénticas.\nLo que me sorprendió fue lo poco que movieron las perillas obvias. Subir la k compró una pregunta cuando mucho, y limpiar el manual compró otra cuando mucho. La razón es una división sorprendentemente limpia en los rankings: cada pregunta que el retriever acierta la acierta dentro de los primeros cuatro fragmentos, y cada pregunta que falla se va al lugar 10 o peor, en 15, 17, 19 y 24 con el manual de producción. No hay nada intermedio. Ninguna k realista rescata esas fallas sin arrastrar primero diez fragmentos de ruido a un presupuesto de 4096 tokens, que es la misma presión de contexto que hacía tan destructiva la traza de razonamiento más arriba.\nLas fallas además tienen una forma, y eso es lo que señala la solución. Las cuatro persistentes son nombres propios que viven dentro de tablas de markdown: búsquedas de redes Wi-Fi, un número de modelo de hardware, ese tipo de pregunta. Es justamente la consulta que la búsqueda por palabra clave maneja bien y que los embeddings vectoriales densos manejan mal, porque una coincidencia exacta de token casi no suma puntos en un espacio construido para representar significado. Entonces la palanca no es traer más fragmentos, es ordenarlos mejor: un reranker de tipo cross-encoder sobre una lista de candidatos más amplia. Prender la búsqueda híbrida por sí sola no hace nada en mi instancia, porque sin un modelo de reranking configurado los candidatos combinados terminan recalificados por la misma métrica de similitud que ya los había ordenado.\nHay un hallazgo más que vale la pena llevarte a tu propia base de conocimiento, porque es gratis. Mi manual de producción pesa 836 KB, de los cuales solo unos 17 KB son texto. Todo lo demás son capturas de pantalla embebidas en base64, y por eso 698 de sus 744 fragmentos son ruido de imágenes en lugar de prosa. Quitarlas mejoró los rankings de manera general incluso donde el veredicto final no cambió. Una base de conocimiento no es una carpeta donde avientas documentos, es un documento que mantienes.\nAsí que la misma reflexión de siempre aplica también aquí: la recuperación es lo que le permitió a un modelo chico hacer el trabajo de uno grande, y la recuperación es también donde queda más margen de mejora. Vale la pena saberlo antes de suponer que adjuntar un documento es el final del trabajo. Los números están en la sección 6 de ese mismo BENCHMARKS.md, y el script que califica es bench/bench_rag.py, así que puedes apuntarlo a tu propia base de conocimiento y averiguar qué alcanza a ver tu asistente.\nLo que ganas con este setup # El resultado del día a día es poco glamoroso, y justo por eso funciona. Alguien escribe !ask en un canal de Discord que ya tenía abierto, y entre tres y seis segundos después sabe dónde está la llave de paso del agua, cómo regresar el proyector a la entrada correcta, o cuál es la contraseña del Wi-Fi. En mi casa nadie tuvo que aprender una herramienta nueva, y nadie tuvo que esperar a que yo contestara, que es lo más cercano al éxito que puede tener un proyecto casero.\nEl resultado de ingeniería es un stack con costuras limpias. El bot es sin estado a propósito: cada !ask manda solo esa pregunta, así que los seguimientos tipo \u0026ldquo;¿y cómo la cambio?\u0026rdquo; no funcionan. Eso es un intercambio deliberado, no un descuido. No guardar estado deja el contexto completo de 4096 tokens disponible para el system prompt y los fragmentos del manual, y un FAQ del hogar está hecho abrumadoramente de preguntas independientes. Agregaré historial por canal el día que alguien de verdad lo pida, y no antes.\nAdemás, las habilidades que te llevas de aquí sirven en todas partes: integración de APIs REST y parseo defensivo de respuestas, networking de Docker y ciclo de vida de containers, presupuesto de memoria de GPU, y ese tipo de debugging metódico que separa un síntoma de una causa. Cada obstáculo del camino (el intent que olvidé activar, el endpoint equivocado, el loopback colgado, el modelo que no cabía) se convirtió en un pedazo de entendimiento que todavía me llevo conmigo. Cada tropiezo es simplemente otra oportunidad de aprender de los errores pasados y seguir mejorando, y en un home lab esas lecciones se acumulan más rápido que casi en cualquier otro lado.\n¿Qué sigue? # Algunos caminos que me parecen valiosos de aquí en adelante:\nUn reranker delante de la recuperación. Las fallas que medí son fallas de orden, no de presupuesto, así que el cambio que les corresponde es un rerank con cross-encoder sobre una lista de candidatos más amplia, no una k más grande. Es el punto de esta lista que espero que mueva más la aguja del asistente. Seguimiento conversacional. Un historial corto por canal en el arreglo de messages permitiría una ida y vuelta natural, a costa del presupuesto de contexto. Vale la pena solo junto con una ventana de contexto más grande. Slash commands. Los comandos nativos / de Discord con autocompletado serían más amigables que un prefijo ! para los miembros de la familia que nunca aprendieron la convención del prefijo. Permiso de escritura, con cuidado. Ahora el asistente solo responde. Dejarlo actuar sobre el hogar inteligente sería el siguiente paso natural, y es el paso que más necesita barreras de seguridad: una lista explícita de acciones permitidas, y confirmación antes de cualquier cosa con consecuencias físicas. Respaldos que de verdad corran. El system prompt y el manual de la casa viven en un solo volumen de Docker. Un snapshot programado de ese volumen es el punto menos glamoroso y más valioso de esta lista. El bot completo está en GitHub, en EmilianFC20/family-assistant. Si construyes tu propia versión, me encantaría saber qué preguntas termina haciéndole tu casa con más frecuencia.\n","date":"29 de julio de 2026","externalUrl":null,"permalink":"/es/posts/bot-de-discord-para-tu-ia-privada/","section":"Posts","summary":"Montaste un asistente de IA privado en tu propia computadora, le cargaste el manual de tu casa, y responde de maravilla. ¿Entonces por qué nadie en tu casa lo usa?\n","title":"Ponle un bot de Discord a tu IA privada para que tu familia sí la use","type":"posts"},{"content":"","date":"29 de julio de 2026","externalUrl":null,"permalink":"/es/posts/","section":"Posts","summary":"","title":"Posts","type":"posts"},{"content":"","date":"29 julio 2026","externalUrl":null,"permalink":"/series/private-ai-at-home/","section":"Series","summary":"","title":"Private AI at Home","type":"series"},{"content":"Things I have built and documented end to end. Each one covers how I put it together, what I used, and what I got wrong along the way.\n","date":"29 julio 2026","externalUrl":null,"permalink":"/tags/project/","section":"Tags","summary":"Things I have built and documented end to end. Each one covers how I put it together, what I used, and what I got wrong along the way.\n","title":"Projects","type":"tags"},{"content":"Cosas que he construido y documenté de principio a fin. Cada una incluye cómo la armé, con qué, y en qué me equivoqué en el camino.\n","date":"29 de julio de 2026","externalUrl":null,"permalink":"/es/tags/proyecto/","section":"Tags","summary":"Cosas que he construido y documenté de principio a fin. Cada una incluye cómo la armé, con qué, y en qué me equivoqué en el camino.\n","title":"Proyectos","type":"tags"},{"content":"","date":"29 de julio de 2026","externalUrl":null,"permalink":"/es/tags/rag/","section":"Tags","summary":"","title":"Rag","type":"tags"},{"content":"","date":"29 de julio de 2026","externalUrl":null,"permalink":"/es/tags/self-hosted/","section":"Tags","summary":"","title":"Self-Hosted","type":"tags"},{"content":"","date":"29 de julio de 2026","externalUrl":null,"permalink":"/es/series/","section":"Series","summary":"","title":"Series","type":"series"},{"content":"","date":"29 de julio de 2026","externalUrl":null,"permalink":"/es/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"","date":"29 de julio de 2026","externalUrl":null,"permalink":"/es/tags/wsl/","section":"Tags","summary":"","title":"Wsl","type":"tags"},{"content":"","date":"1 de febrero de 2026","externalUrl":null,"permalink":"/es/tags/c/","section":"Tags","summary":"","title":"C","type":"tags"},{"content":"¿Qué pasaría si pudieras describir un videojuego en lenguaje natural, presionar enter, y ver a un agente de IA escribir y depurar código en C hasta que algo jugable apareciera en tu terminal?\nSí se puede, y te alcanza con una tarde. Con una CLI de IA, un compilador de C y la librería ncurses, puedes construir un juego de bloques cayentes inspirado en Tetris que corre directamente en tu terminal, en una sola sesión. No necesitas ser programador de C para empezar, y yo tampoco lo era: mi propio tetris.c, escrito a mano, nunca pasó del compilador, y justo ahí empieza de verdad este proyecto. Al final te quedas con tres cosas que vale la pena tener: un binario que compilaste tú, un código en C legible que puedes desarmar línea por línea, y un flujo de trabajo que puedes reutilizar en la siguiente idea que se te ocurra.\nEso es exactamente lo que esta guía te enseña a hacer.\nEl juego a media partida: el tablero de 10 por 20 con bordes de | y -, las celdas vacías como puntos, las piezas colocadas como corchetes de colores y el puntaje a un lado, todo dibujado por ncurses. Actualización, agosto de 2026. Este post documenta una sesión que corrí en febrero de 2026 con Gemini CLI. En el Google I/O del 19 de mayo de 2026, Google anunció que está consolidando sus herramientas de desarrollo bajo la marca Antigravity y retirando Gemini CLI, y el 18 de junio de 2026 Gemini CLI dejó de responder peticiones para usuarios gratuitos y para suscriptores de Google AI Pro y Ultra. Las organizaciones con licencia de Gemini Code Assist Standard o Enterprise no se ven afectadas. El sucesor es Antigravity CLI, y el Paso 1 te da su comando de instalación actual. Dejé el resto del post tal como ocurrió, porque lo que se transfiere a la herramienta nueva es el flujo de trabajo, no el binario específico.\nUn juego que cambió la historia # En 1984, un científico soviético llamado Alexey Pajitnov se sentó frente a una Electronika 60 y escribió un programa en Pascal. La idea era elegante: siete piezas geométricas caen desde arriba de la pantalla, las rotas y las acomodas para completar filas, y las filas completas desaparecen. Lo llamó Tetris.\nEse programa se convirtió en uno de los juegos más jugados de la historia, distribuido en prácticamente todas las plataformas imaginables durante cuatro décadas. Aunque la idea se describe en una frase, construir siquiera un clon funcional en aquella época implicaba dominar ciclos de tiempo, renderizado en terminal, matemáticas de rotación y horas de debugging paciente. Era trabajo de ingeniería real, con todo lo que eso implica.\nHoy puedes pedirle a un agente de IA que produzca el código C equivalente en una sola sesión. Ese contraste es el verdadero tema de este proyecto: cuarenta años de avance tecnológico, comprimidos en una conversación con un agente.\nSí puedes construir esto. Las mecánicas de los juegos de bloques cayentes (las formas de las piezas, la gravedad, la lógica de limpieza de filas) no tienen protección de derechos de autor. Lo que hace que Tetris sea Tetris como marca (el nombre registrado, el logo, la música Korobeiniki) pertenece a The Tetris Company. Lo que construyes aquí es un clon independiente con fines educativos, y el valor de ingeniería es exactamente el mismo.\nDónde empezó realmente este proyecto # Antes de ser una guía, esto fue un archivo que no compilaba.\nEn ese momento estaba aprendiendo C, así que escribí mi propio tetris.c a mano. No compiló, y después de un rato viendo los errores seguía sin entender por qué. Mi primer impulso no fue borrarlo y dejar que un agente empezara de cero, fue pedir un diagnóstico, así que abrí Gemini CLI en esa carpeta y escribí exactamente esto:\nhi, I was trying to do the tetris game but coul not compile it. Could you please check the code for any errors? @tetris.c Tal cual, con todo y errores de dedo. En español sería algo como \u0026ldquo;hola, estaba intentando hacer el juego de tetris pero no pude compilarlo. ¿Puedes revisar el código por si tiene errores?\u0026rdquo;. El @tetris.c del final es la forma en que Gemini CLI carga un archivo a la conversación, así que el agente leyó mi código real y no una descripción de él.\nLa revisión fue honesta, y no fue la respuesta que esperaba: el archivo era un desastre. Yo mismo lo acepté en mi siguiente mensaje. Catorce minutos después de pedir una revisión de código, borré mi intento y le pedí al agente que empezara desde cero.\nVale la pena nombrar esa decisión, porque es un criterio que los ingenieros usamos todo el tiempo y del que casi no hablamos: saber cuándo seguir reparando un borrador y cuándo una reescritura limpia es simplemente el camino más rápido. Si vas a empezar este proyecto con un intento fallido propio, no estás atrasado. Estás justo donde yo estaba.\nLo que necesitas # Una terminal de Linux o WSL2 en Windows 11 GCC (el compilador de C): sudo apt install gcc La librería de desarrollo de ncurses: sudo apt install libncurses-dev Un agente de IA en la terminal: hoy Antigravity CLI, y Gemini CLI en la sesión que describe este post Una cuenta para autenticar el agente en el primer arranque (Gemini CLI pedía una cuenta de Google gratuita; sigue el flujo de inicio de sesión que te pida tu herramienta) ncurses es lo que hace que una terminal se comporte como una pantalla y no como un log que se desplaza. Te da posicionamiento del cursor, lectura del teclado sin esperar a que se presione enter, y pares de color, que es justo lo que necesita un juego de bloques cayentes y nada más.\nSi es la primera vez que configuras WSL2, los primeros pasos de mi post sobre cómo desplegar una IA privada con Ollama cubren todo el proceso de instalación.\nPaso 1: Instala un agente de IA en la terminal # La herramienta actual es Antigravity CLI, el sucesor de Gemini CLI. Está reescrito en Go y puede correr varios agentes en paralelo en segundo plano. Se instala con un solo script.\nEn macOS, Linux o WSL:\ncurl -fsSL https://antigravity.google/cli/install.sh | bash En Windows, desde PowerShell:\nirm https://antigravity.google/cli/install.ps1 | iex Después sigue las instrucciones de primer arranque de la propia herramienta para autenticarte.\nPara dejarlo asentado, y no como un paso a seguir, el agente que usé en febrero de 2026 fue Gemini CLI, corriendo sobre Gemini 2.5 Pro. El log de esa sesión no guarda el modelo, pero todas las sesiones de Gemini CLI de esa época en mi máquina corrieron con Gemini 2.5, y otras cuatro sesiones de ese mismo día quedaron registradas con 2.5 Pro. En aquel entonces la CLI a veces caía en Gemini 2.5 Flash, así que tómalo como el modelo que la herramienta me estaba sirviendo en ese momento y no como un dato que pueda señalar en el registro.\nGemini CLI se distribuía como un paquete npm y necesitaba Node.js 18 o posterior:\nnpm install -g @google/gemini-cli # retirado el 18 de junio de 2026 gemini En aquel momento bastaba con iniciar sesión con una cuenta de Google gratuita. Ese es justo el camino que dejó de funcionar, así que si tienes abierto un tutorial más viejo en otra pestaña, esta es la razón por la que no te responde nada.\nEn cualquiera de los dos casos, terminas en una sesión interactiva con el agente dentro de la terminal. Funciona como un chat con manos: describes lo que quieres, y el agente razona, escribe el código y ejecuta comandos en tu nombre.\nPaso 2: Pide el juego # Este es el prompt que produjo el juego completo. Es una sola frase, y la cito tal como la escribí:\nthank you but you are right, this code was a mess. Could you create the tetris game in c instead? I deleted the previous file so please start over En español: \u0026ldquo;gracias, pero tienes razón, este código era un desastre. ¿Podrías crear el juego de tetris en C mejor? Borré el archivo anterior, así que empieza desde cero\u0026rdquo;.\nEsa es toda la especificación. No mencioné ninguna librería, ni el tamaño del tablero, ni el esquema de controles, ni la regla de puntaje, ni el comando de compilación. Lo que regresó fue un solo archivo de C de 234 líneas, escrito y compilado por el propio agente, y cada decisión de diseño de esta lista es suya, no mía:\nncurses como capa de renderizado, un solo archivo con #include \u0026lt;ncurses.h\u0026gt;, enlazado con -lncurses. Un tablero de 10 por 20 (BOARD_WIDTH 10, BOARD_HEIGHT 20) con bordes dibujados con | y -. Las siete piezas con sus cuatro estados de rotación, guardadas en una sola tabla const int PIECES[7][4][4][4] en lugar de calcular las rotaciones. Controles con flechas: izquierda y derecha para mover, arriba para rotar en sentido horario con (rotation + 1) % 4, abajo para caída suave, y q o Q para salir. Siete pares de color con init_pair(), uno por pieza: cian, amarillo, magenta, verde, rojo, azul y blanco. Gravedad de intervalo fijo: el ciclo principal duerme 20 ms por vuelta y baja la pieza cuando su contador pasa de 20, o sea alrededor de 400 ms por fila, y nunca acelera. Puntaje cuadrático: score += lines_cleared * lines_cleared * 100, así que limpiar cuatro filas de un solo golpe vale 4 × 4 × 100 = 1,600 puntos, contra los 4 × 100 = 400 que juntarías limpiándolas de una en una. Son buenos valores por defecto, y ahí está lo verdaderamente interesante. ncurses es la opción natural para un juego de terminal, 10 por 20 es el tablero estándar, las flechas son lo primero que va a apretar cualquier jugador, y premiar las limpiezas múltiples es lo que le da al juego su tensión de riesgo y recompensa. Una petición de una línea aterrizó en convenciones que a mí me habría tomado un rato investigar.\nAun así, el trade-off existe y va en una sola dirección: todo lo que no especifiques lo decide el agente por ti, y lo decide en silencio. Mi propio juego es la prueba. La gravedad nunca acelera, así que no hay curva de dificultad, y tampoco hay panel de siguiente pieza ni mecánica de hold. Nada de eso es un error. Simplemente son cosas que nunca pedí.\nEntonces la regla práctica no es \u0026ldquo;sé específico o va a fallar\u0026rdquo;, porque aquí la vaguedad claramente no falló. Es esta otra: sé específico en lo que de verdad te importa. Si quieres un tablero más ancho, controles WASD, wall kicks al rotar o una velocidad que suba con el puntaje, nómbralos en el prompt. Agregar el comando de compilación y una línea como \u0026ldquo;asegúrate de que compile y corra\u0026rdquo; también ayuda, porque convierte una tarea de generación de texto en una tarea verificable. Todo lo demás lo puedes delegar con tranquilidad.\nSea lo que sea que decidas especificar, envía el prompt y deja que el agente trabaje.\nPaso 3: Observa el ciclo de depuración # Esta es la parte que vale la pena ver con atención. Gemini CLI no te entrega un bloque de texto para que tú lo pegues en algún lado. Escribió tetris.c directamente en la carpeta del proyecto y ahí mismo lo compiló, y cuando terminó la sesión el binario ya estaba junto al código fuente. La unidad de trabajo es un programa que corre, no un fragmento que todavía tienes que armar.\nEl ciclo que sí puedo documentar a detalle es el primero, el que corrió sobre mi archivo roto. Le di al agente código que no compilaba, leyó el archivo real, me explicó qué estaba mal, y la conclusión a la que llegamos fue que reescribir me iba a dejar con un juego funcional más rápido que reparar. Ese es el mismo ciclo que hace cualquier desarrollador: leer la falla, razonar la causa, comparar el arreglo contra el rediseño, y actuar. La diferencia es que todo eso ocurrió en minutos, no a lo largo de una noche entera.\nCuántos intentos necesitó el agente en su propia reescritura, honestamente no te lo puedo decir, porque mi log solo guarda mi lado de la conversación. Lo que sí te puedo decir es lo que quedó en disco: un archivo de C autocontenido que compila limpio con gcc tetris.c -o tetris -lncurses y un juego que se puede jugar.\nLo que sí puedo medir con precisión es el reloj, que además es el número que casi todos quieren cuando preguntan para qué sirve un agente. Desde mi primer prompt hasta tener un binario compilado y jugable pasaron 24 minutos con 44 segundos. La reescritura por sí sola, desde el mensaje de \u0026ldquo;empieza desde cero\u0026rdquo; hasta un programa que corría, tomó 11 minutos con 19 segundos, y el binario apareció quince segundos después que el archivo fuente. Esas cifras salen de evidencia y no de mi memoria: las dos marcas de tiempo de los prompts están en el log de Gemini CLI, en ~/.gemini/tmp/\u0026lt;hash\u0026gt;/logs.json (06:35:59 y 06:49:24 UTC), y las otras dos son las fechas de modificación de tetris.c (07:00:28) y del binario que quedó junto a él (07:00:43). El log trabaja en UTC y mi máquina iba ocho horas atrás, y por eso el log dice 2 de febrero mientras que este post está fechado la noche del 1 de febrero. Así que te puedo decir exactamente cuánto tardó sin poder decirte cuántos intentos le costó, y las dos mitades de esa frase vale la pena decirlas en voz alta.\nAdemás, leer el código que regresa es una de las formas más directas de aprender C y ncurses. Seguir cómo is_valid_position() valida cada movimiento, cómo place_piece() recorre las filas hacia abajo después de una limpieza, y cómo los pares de color se amarran al tipo de pieza enseña más que un capítulo de sintaxis, y el aprendizaje ocurre como consecuencia natural de construir el proyecto. Si quieres leer el archivo completo antes de escribir una sola línea propia, lo que salió de esa sesión es público en EmilianFC20/tetris-in-c con licencia MIT, subido tal cual lo produjo el agente y sin pulir a propósito. El binario compilado no está ahí, y es a propósito también: compilarlo te toca a ti.\nLíneas 7 a 31 del tetris.c generado: los defines BOARD_WIDTH, BOARD_HEIGHT y PIECE_SIZE, y el arranque de la tabla PIECES con las piezas I, O, T y S, cada una con sus cuatro estados de rotación. Aunque el ciclo sea rápido, el ingeniero del cuarto sigues siendo tú. El trabajo del agente es producir un candidato. El tuyo es leerlo, correrlo y decidir si realmente hace lo que pediste.\nPaso 4: Compila y juega # En mi sesión el agente ya había escrito tetris.c y lo había compilado antes de regresarme el trabajo, así que no quedaba nada por construir. Si tu agente se detiene en el archivo fuente, o si estás haciendo esto a mano, este es el comando:\ngcc tetris.c -o tetris -lncurses El flag -lncurses es el que siempre se olvida. Le indica al linker que enlace tu programa contra la librería de ncurses, y sin él el código compila sin problema y luego truena en la etapa de enlazado con referencias indefinidas a funciones como initscr.\nSi el compilador no encuentra ncurses.h, instala primero los headers de desarrollo:\nsudo apt install libncurses-dev Luego corre el juego:\n./tetris El ciclo completo de compilar y jugar: gcc regresa sin salida, ls -l muestra el binario tetris de 17320 bytes junto al tetris.c de 7089 bytes, y ./tetris termina imprimiendo el puntaje final. Controles:\nTecla Acción ← / → Mover pieza a la izquierda o derecha ↑ Rotar pieza en sentido horario ↓ Caída suave (descenso más rápido) q Salir El puntaje se calcula por filas eliminadas en cada colocación. Limpiar varias filas en un solo movimiento vale mucho más que limpiarlas de una en una, así que conviene armar el tablero a propósito para hacer limpiezas múltiples en lugar de soltar las piezas donde vayan cayendo.\nLo que ganas al construirlo # Cuando ese juego aparece en tu terminal por primera vez, hay un momento de satisfacción genuina. Describiste algo, y apareció software funcionando.\nDebajo de ese momento te quedan tres cosas concretas. La primera, un programa que armaste y compilaste tú, que se siente muy distinto a descargar el binario de alguien más. La segunda, un código en C completo y autocontenido que puedes leer como material de estudio: el estado del juego, el ciclo de entrada, el manejo del tiempo, la lógica de rotación y el renderizado en terminal, todo en un archivo lo bastante chico como para tenerlo entero en la cabeza. La tercera, un flujo de trabajo repetible, porque nada del proceso fue exclusivo de Tetris.\nEl mío está publicado en EmilianFC20/tetris-in-c por si quieres algo contra qué comparar el tuyo, o nada más leer las 234 líneas y ver hasta dónde llegó una sola frase en inglés.\nEse último punto es lo que convierte a los agentes de IA en la terminal en un multiplicador de capacidad real. No necesitas dominar la gestión de memoria en C, las APIs de renderizado en terminal ni las matrices de rotación antes de poder construir algo que funcione. En lugar de estudiar durante meses y después construir, puedes empezar por el resultado que quieres, leer el código generado para entender qué hace, y construir tu modelo mental del lenguaje de adentro hacia afuera. La distancia entre \u0026ldquo;tengo una idea\u0026rdquo; y \u0026ldquo;tengo un programa corriendo\u0026rdquo; nunca había sido tan corta.\nEso fue exactamente lo que encontré cuando construí este proyecto. Estaba aprendiendo C y explorando Gemini CLI al mismo tiempo, y la intersección resultó buena: una meta concreta, un lenguaje que apenas estaba aprendiendo, y un agente que podía hacer el primer borrador de la implementación mientras yo me enfocaba en entender lo que producía. Aunque el juego terminado es la parte que se puede jugar, del intento fallido fue de donde más aprendí. Escribir un archivo que no compilaba, escuchar una evaluación honesta de por qué, y elegir una reescritura limpia en lugar de un rescate me dijo mucho más sobre dónde estaba realmente mi C que cualquier programa funcionando. Cada tropiezo fue simplemente otra capa por entender, y otra oportunidad para seguir mejorando.\nEso sí, el contraste con 1984 vale la pena tenerlo presente. El trabajo de Pajitnov representa un nivel de dedicación y oficio que merece respeto genuino, y lo que ofrecen los agentes de IA no es un reemplazo para esa profundidad. Es una rampa de entrada más rápida al punto donde puedes empezar a construir comprensión propia y real.\n¿Qué sigue? # Una vez que tu juego esté corriendo, hay varios caminos que vale la pena explorar:\nDificultad progresiva: aumentar la velocidad de caída conforme sube el puntaje, para que el juego rete al jugador a seguir mejorando. Panel de siguiente pieza: mostrar un panel lateral con la pieza que viene para que el jugador pueda planear con anticipación. Mecánica de hold: dejar que el jugador guarde una pieza y la intercambie más adelante. Puntaje máximo persistente: guardar el mejor puntaje en un archivo y mostrarlo al iniciar. Renderizado gráfico con SDL2: reemplazar ncurses con SDL2 para un juego en ventana con gráficos reales y sonido. Cada una de estas ideas es también un buen segundo ejercicio del mismo flujo: describe el cambio con precisión, deja que el agente lo redacte, y lee lo que regresó antes de aceptarlo.\nSi construyes tu propia versión de esto, me encantaría saber qué extendiste o cambiaste.\nTetris® es una marca registrada de The Tetris Company, LLC. Este proyecto es una reimplementación educativa e independiente de la mecánica de bloques cayentes y no tiene afiliación ni respaldo de The Tetris Company.\n","date":"1 de febrero de 2026","externalUrl":null,"permalink":"/es/posts/videojuego-en-c-con-ia/","section":"Posts","summary":"¿Qué pasaría si pudieras describir un videojuego en lenguaje natural, presionar enter, y ver a un agente de IA escribir y depurar código en C hasta que algo jugable apareciera en tu terminal?\n","title":"Crea un videojuego estilo Tetris en C con Gemini CLI","type":"posts"},{"content":"","date":"1 de febrero de 2026","externalUrl":null,"permalink":"/es/tags/desarrollo-de-videojuegos/","section":"Tags","summary":"","title":"Desarrollo-De-Videojuegos","type":"tags"},{"content":"","date":"1 febrero 2026","externalUrl":null,"permalink":"/tags/gamedev/","section":"Tags","summary":"","title":"Gamedev","type":"tags"},{"content":"","date":"1 de febrero de 2026","externalUrl":null,"permalink":"/es/tags/gemini-cli/","section":"Tags","summary":"","title":"Gemini-Cli","type":"tags"},{"content":"","date":"1 de febrero de 2026","externalUrl":null,"permalink":"/es/tags/ncurses/","section":"Tags","summary":"","title":"Ncurses","type":"tags"},{"content":"","date":"1 de febrero de 2026","externalUrl":null,"permalink":"/es/tags/programacion/","section":"Tags","summary":"","title":"Programacion","type":"tags"},{"content":"","date":"1 febrero 2026","externalUrl":null,"permalink":"/tags/programming/","section":"Tags","summary":"","title":"Programming","type":"tags"},{"content":"¿Qué pasaría si el asistente de IA que usa toda tu familia corriera en tu propia computadora, respondiera en segundos y nunca enviara ni una sola palabra de tus conversaciones a la nube?\nPuedes construirlo. Con herramientas gratuitas y de código abierto, y una PC con una GPU decente, una IA privada corre completamente en hardware que ya tienes: sin cuota mensual, sin cuenta con ningún proveedor, sin datos saliendo de tu red. Además, este es uno de los proyectos de home lab más gratificantes que puedes hacer. Al terminar habrás trabajado con Linux, Docker, drivers de GPU y networking en red local, y entenderás cómo encajan entre sí esas cuatro capas.\nEsta guía te lleva paso a paso por todo el proyecto: un chatbot privado al estilo ChatGPT, impulsado por Ollama y Open WebUI, acelerado por tu GPU NVIDIA y accesible desde cualquier teléfono, laptop o tablet de la casa.\nLo tengo corriendo en mi casa, y lo más difícil nunca fue la IA. Fueron tres detalles pequeños de red que ningún tutorial me advirtió, así que dejé anotado cada uno justo en el punto donde te los vas a encontrar.\nA esto le vamos a llegar: una ventana de chat como cualquier otra, salvo que el modelo que responde vive en una GPU de mi propia casa. Lo que necesitas antes de empezar # Una PC con Windows 11 y una GPU NVIDIA. La GPU es lo que hace que las respuestas se sientan inmediatas y no lentas. La mía es una RTX 3070 Ti de 8 GB de VRAM, la misma tarjeta de mi guía para armar tu propia PC, y servir este asistente terminó siendo justo el uso al que le apunté ese build. Todos los números de esta guía se midieron ahí, así que puedes calibrar tus expectativas contra una tarjeta de gama media y no contra una workstation. El driver NVIDIA de Windows en versión 471.11 o posterior. No hay que instalar nada dentro de Linux. Espacio libre en disco para los pesos del modelo, que ocupan varios gigabytes cada uno. Acceso de administrador en Windows, porque algunos pasos tocan el firewall y la tabla de reenvío de puertos. El stack # En 2024, Ollama todavía no tenía instalador nativo para Windows, así que la única forma de correrlo en una máquina Windows era a través de WSL2 (Windows Subsystem for Linux). Lejos de ser una limitación, WSL2 es genuinamente la mejor forma de hacerlo: obtienes un entorno Linux real con acceso completo a la GPU, corriendo junto a Windows en hardware que ya tienes.\nEl stack completo:\nWSL2 en Windows 11: un entorno Linux real corriendo junto a Windows, con acceso directo a la GPU NVIDIA. Ollama: se encarga de descargar, administrar y servir modelos de lenguaje open-weight de forma local. Open WebUI: una interfaz web limpia, al estilo ChatGPT, que se comunica con Ollama por HTTP. Docker: corre Open WebUI como un container dentro de WSL, lo que mantiene el setup portátil y ordenado. Portainer (opcional): un dashboard visual para administrar containers Docker sin necesidad de la línea de comandos. WSL2 con un port proxy automatizado: la configuración que hace que el chatbot sea accesible desde otros dispositivos en la red local, con una pequeña tarea programada que evita que las reglas de reenvío se rompan en cada reinicio. Puesto todo junto, una pregunta desde tu celular viaja así:\nCelular, laptop o tablet en la LAN los dispositivos que todos ya traen │ http://\u0026lt;IP-LAN-DE-LA-PC\u0026gt;:8080 ▼ Host Windows (netsh portproxy) reapuntado en cada inicio de sesión │ 0.0.0.0:8080 -\u0026gt; \u0026lt;IP-DE-WSL\u0026gt;:8080 ▼ Open WebUI (Docker, --network=host) la interfaz al estilo ChatGPT │ OLLAMA_BASE_URL=http://127.0.0.1:11434 ▼ Ollama (servicio nativo, GPU NVIDIA) descarga, administra y sirve el modelo No te espantes por WSL. Es una herramienta increíblemente poderosa: tienes la línea de comandos de Linux completa (gestores de paquetes, scripts, Docker, todo) sin salir del entorno Windows que ya conoces. Si nunca lo has usado, este proyecto es una excelente primera experiencia.\nPaso 1: Activar WSL2 e instalar Ubuntu # Abre PowerShell como administrador y ejecuta:\nwsl --install Esto activa WSL2 e instala Ubuntu por defecto. Después de reiniciar, abre Ubuntu desde el menú de inicio y completa la configuración inicial (nombre de usuario y contraseña).\nSi ya tienes WSL instalado y quieres confirmar que usas la versión 2:\nwsl --list --verbose Busca VERSION 2 junto al nombre de tu distribución. Si aparece versión 1, actualízala con wsl --set-version Ubuntu 2.\nPaso 2: Verificar tu GPU NVIDIA en WSL # WSL2 en Windows 11 expone tu GPU automáticamente, así que no necesitas instalar un driver NVIDIA separado dentro de Linux. El driver vive en el host de Windows; WSL lo conecta. El único requisito es tener el driver NVIDIA de Windows en versión 471.11 o posterior (cualquier driver lanzado después de mediados de 2021 debería funcionar).\nDentro de la terminal de WSL, ejecuta:\nnvidia-smi Deberías ver una tabla con el nombre de tu GPU, la versión del driver y la versión de CUDA.\nDos datos deciden si el resto de la guía va a funcionar: la versión del driver en el renglón superior, que debe ser 471.11 o posterior, y que aparezca una versión de CUDA. Si los dos están ahí, Ollama encuentra la GPU sin que le digas nada. Si el comando no se encuentra o arroja un error, abre GeForce Experience (o descarga el driver más reciente desde nvidia.com) y actualiza tu driver de Windows, luego vuelve a intentarlo.\nEste paso importa: Ollama usará la GPU automáticamente si CUDA es visible, lo que hace las respuestas notablemente más rápidas.\nPaso 3: Instalar Ollama y descargar tu primer modelo # Dentro de tu terminal de WSL, ejecuta el script oficial de instalación:\ncurl -fsSL https://ollama.com/install.sh | sh El script detecta CUDA y configura Ollama para usar la GPU. Una vez que termine, descarga y corre un modelo. Yo usé llama3.1, que era el modelo open-weight más capaz disponible en ese momento:\nollama run llama3.1 La primera ejecución descarga los pesos del modelo (varios gigabytes, según el modelo). Después de eso, quedarás en un chat interactivo directo en la terminal. Haz una pregunta para confirmar que todo funciona y sal con /bye.\nOllama también levanta un servidor HTTP en segundo plano en http://127.0.0.1:11434. Esta es la API que usará Open WebUI.\nQué corro hoy (agosto de 2026): llama3.1 era la elección correcta en 2024, pero los modelos abiertos avanzan rapidísimo y hoy ya ni siquiera está instalado en esta máquina. El motor que atiende a la casa ahora es Qwen3.5 4B (qwen3.5:4b, 4.7B de parámetros, cuantización Q4_K_M, 3.4 GB en disco), y se descarga igualito con ollama run qwen3.5:4b. Nada más de esta guía depende del modelo que elijas, así que empieza con el que esté vigente cuando leas esto. Los resultados medidos más abajo explican por qué un 4B terminó ganándole a un modelo mucho más grande en una tarjeta de 8 GB.\nPaso 4: Desplegar Open WebUI con Docker # Instala Docker Engine dentro de WSL. La forma más rápida es usar el script de conveniencia oficial:\ncurl -fsSL https://get.docker.com | sh sudo usermod -aG docker $USER Cierra y vuelve a abrir tu sesión de WSL para que el cambio de grupo surta efecto, luego inicia el daemon de Docker:\nsudo service docker start Ahora levanta el container de Open WebUI:\nsudo docker run -d \\ --network=host \\ -v open-webui:/app/backend/data \\ -e OLLAMA_BASE_URL=http://127.0.0.1:11434 \\ --name open-webui \\ --restart always \\ ghcr.io/open-webui/open-webui:main Una nota sobre OLLAMA_BASE_URL: el valor http://127.0.0.1:11434 le indica al container cómo conectarse a Ollama, y es el que te recomiendo escribir. 0.0.0.0 es en realidad una dirección de escucha, que significa \u0026ldquo;acepta conexiones en todas las interfaces\u0026rdquo;, más que un destino. Linux sí la acepta como destino y la enruta a localhost, así que OLLAMA_BASE_URL=http://0.0.0.0:11434 también funciona (mi propio compose lleva mucho tiempo corriendo así), pero funciona por un comportamiento específico de la plataforma y no porque la dirección signifique lo que quieres decir. Escribir 127.0.0.1 dice exactamente lo que buscas y se traslada sin cambios a cualquier otra plataforma. Como el container corre con --network=host, comparte el namespace de red de WSL con Ollama, por lo que 127.0.0.1 resuelve correctamente.\nAbre un navegador en tu computadora con Windows y ve a http://localhost:8080. Deberías ver la página de login de Open WebUI. Crea una cuenta (es local, no necesitas verificación de correo) y empieza a chatear.\nPaso 5: Llegar a tu IA privada desde cualquier dispositivo de la casa # En este punto el chatbot solo es accesible desde la PC donde lo instalaste. Para abrirlo al resto de la casa, reenvías los puertos correspondientes desde el host de Windows hacia WSL con netsh portproxy. Este enfoque tiene una pega conocida: WSL2 recibe una IP interna distinta cada vez que reinicias Windows, por lo que una regla de reenvío fija se rompe silenciosamente después de cada reinicio. La solución no es abandonar el port forwarding, sino automatizarlo: un pequeño script vuelve a apuntar el reenvío a la IP actual de WSL, ejecutado automáticamente por una tarea programada en cada inicio de sesión.\n¿Por qué no el modo \u0026ldquo;espejo\u0026rdquo;? Windows 11 también ofrece networkingMode=mirrored, que le da a WSL la IP del host directamente y elimina la necesidad de cualquier reenvío. Es tentador, pero enruta las conexiones a 127.0.0.1 a través del stack de red de Windows, lo que rompe el descubrimiento de GPU de Ollama (la sonda de loopback se cuelga y Ollama cae silenciosamente a CPU) y, en mi caso, interfirió con una VPN. El modo NAT más un port proxy automatizado mantiene la GPU funcionando y es igual de confiable una vez que el refresco está en un script.\nMantener WSL en modo NAT # NAT es el modo por defecto de WSL2, pero conviene dejarlo explícito. Crea o edita el archivo C:\\Users\\\u0026lt;tu-usuario\u0026gt;\\.wslconfig en Windows (vive en tu carpeta de usuario de Windows, no dentro de WSL):\n[wsl2] networkingMode=NAT localhostForwarding=true Luego apaga WSL desde PowerShell para que el cambio surta efecto:\nwsl --shutdown Abrir los puertos en el firewall de WSL # sudo ufw allow 8080/tcp sudo ufw allow 11434/tcp El puerto 8080 es Open WebUI. El 11434 es la API de Ollama; lo necesitarás accesible en la red si más adelante quieres conectar otras herramientas (o un bot de Discord) directamente al servidor de modelos.\nHacer que Ollama escuche en la red # Por defecto, Ollama solo escucha en 127.0.0.1. Para que sea accesible desde otros dispositivos, sobreescribe la configuración de su servicio:\nsudo systemctl edit ollama En el editor que se abre, agrega:\n[Service] Environment=\u0026#34;OLLAMA_HOST=0.0.0.0:11434\u0026#34; Guarda y reinicia:\nsudo systemctl restart ollama El formato importa: El valor debe ser 0.0.0.0:11434 sin el prefijo http://. Agregar el prefijo hace que Ollama lo interprete como una URL y se enlace a IPv6 [::] en lugar de IPv4, que no recibe de forma confiable el tráfico IPv4 de la LAN. Déjalo como un host:puerto simple.\nReenviar los puertos desde Windows hacia WSL # La IP interna de WSL cambia en cada arranque, así que escribirla a mano se rompería tras el siguiente reinicio. En su lugar, escribe un pequeño script de PowerShell que consulte la IP actual de WSL y reconstruya las reglas de reenvío. Guárdalo como C:\\Users\\\u0026lt;tu-usuario\u0026gt;\\wsl-portproxy.ps1:\n# Vuelve a apuntar el reenvío de Windows a la IP interna actual de WSL para que # los dispositivos de la LAN alcancen los servicios dentro de WSL en la IP del host. # Ejecutar como Administrador. $ports = @(8080, 11434) # Obtener la IPv4 interna actual de WSL (la primera de `hostname -I`) $wslIp = (wsl hostname -I).Trim().Split(\u0026#34; \u0026#34;)[0] if (-not $wslIp) { Write-Error \u0026#34;No se pudo determinar la IP de WSL. ¿Está WSL corriendo?\u0026#34;; exit 1 } Write-Host \u0026#34;IP de WSL: $wslIp\u0026#34; foreach ($p in $ports) { # Limpiar la regla vieja de este puerto y agregar una nueva netsh interface portproxy delete v4tov4 listenport=$p listenaddress=0.0.0.0 2\u0026gt;$null | Out-Null netsh interface portproxy add v4tov4 listenport=$p listenaddress=0.0.0.0 connectport=$p connectaddress=$wslIp | Out-Null Write-Host \u0026#34;portproxy: 0.0.0.0:$p -\u0026gt; ${wslIp}:$p\u0026#34; # Asegurar que el firewall de Windows permita la entrada en este puerto (se agrega una sola vez) $ruleName = \u0026#34;WSL portproxy $p\u0026#34; if (-not (Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue)) { New-NetFirewallRule -DisplayName $ruleName -Direction Inbound -Action Allow ` -Protocol TCP -LocalPort $p | Out-Null Write-Host \u0026#34;firewall: entrada TCP $p permitida\u0026#34; } } Write-Host \u0026#34;`nListo. Tabla portproxy actual:\u0026#34; netsh interface portproxy show v4tov4 Ejecútalo una vez desde una PowerShell como Administrador para aplicar los reenvíos de inmediato. Las reglas de firewall que crea aceptan tráfico entrante en esos puertos desde cualquier origen; si prefieres restringirlas a tu red de casa, agrega -RemoteAddress 192.168.1.0/24 a la llamada New-NetFirewallRule, sustituyendo tu propio rango de LAN (el subnet que te reporta ipconfig para tu adaptador Wi-Fi o Ethernet, que muchas veces es 192.168.0.0/24 o 10.0.0.0/24).\nRefrescar el reenvío automáticamente en cada reinicio # Para no tener que correr el script a mano, regístralo como una tarea programada que se dispare al iniciar sesión. Desde una PowerShell como Administrador:\n$action = New-ScheduledTaskAction -Execute \u0026#34;powershell.exe\u0026#34; -Argument \u0026#34;-WindowStyle Hidden -ExecutionPolicy Bypass -File C:\\Users\\\u0026lt;tu-usuario\u0026gt;\\wsl-portproxy.ps1\u0026#34; $trigger = New-ScheduledTaskTrigger -AtLogOn Register-ScheduledTask -TaskName \u0026#34;WSL portproxy\u0026#34; -Action $action -Trigger $trigger -RunLevel Highest Ahora obtén la IP local de tu PC (ipconfig en PowerShell, busca la dirección IPv4 de tu adaptador Wi-Fi o Ethernet) y accede a http://\u0026lt;IP-de-la-PC\u0026gt;:8080 desde cualquier otro dispositivo en la misma red. Tras un reinicio, la tarea vuelve a apuntar el reenvío a la nueva IP interna de WSL automáticamente, así que la dirección en la LAN no cambia.\nAdvertencia headless: la tarea se dispara al iniciar sesión. Si llegas a la máquina sin iniciar sesión (por ejemplo vía \\\\wsl$ o una herramienta remota), corre wsl-portproxy.ps1 una vez a mano para levantar el reenvío.\nPaso 6: Portainer (opcional) # Si prefieres una interfaz visual para administrar tus containers Docker en lugar de usar la línea de comandos, Portainer es una opción ligera. Levántalo junto a Open WebUI:\nsudo docker run -d \\ --network=host \\ -v /var/run/docker.sock:/var/run/docker.sock \\ -v portainer_data:/data \\ --name portainer \\ --restart always \\ portainer/portainer-ce La interfaz web de Portainer quedará disponible en http://localhost:9000, que es el puerto HTTP por defecto de Portainer CE (9443 sirve la misma interfaz por HTTPS). Como el container corre con --network=host, no publica ningún puerto propio: simplemente escucha en los puertos de WSL, así que alcanzarlo desde otro dispositivo requeriría el mismo tratamiento de portproxy del Paso 5. Te permite iniciar, detener e inspeccionar containers con unos clics, lo cual es muy útil cuando quieres actualizar Open WebUI sin tener que recordar los flags exactos de docker run.\nCuando el stack ya tiene más de un container, un dashboard resuelve más rápido que docker ps la única pregunta que suele importar: ¿todo sigue arriba? Lo que de verdad corro, y por qué se salta el Paso 5 por completo. En mi máquina no hay ningún servidor de Portainer dentro de WSL. Lo que corre ahí es un Edge agent de Portainer (portainer/agent:latest con EDGE=1 más el edge ID y la key que emite el servidor), mientras que el servidor de Portainer vive en el NAS de la casa. El agente marca hacia afuera y mantiene el túnel abierto, así que no publica ni un solo puerto y nunca hay que encontrarlo en la dirección de WSL. Es una inversión elegante del problema que tanto trabajo cuesta resolver en el Paso 5: en vez de enseñarle a la red cómo llegar a un blanco móvil, el blanco móvil mantiene una conexión abierta hacia algo que no se mueve, lo que lo vuelve inmune a la IP cambiante de WSL y a los reinicios. Si ya tienes un servidor de Portainer en tu red, esta es la forma más robusta de administrar los containers que viven dentro de WSL.\n¿Qué tan rápido va en realidad? Números medidos en una GPU de 8 GB # La razón entera de poner una GPU detrás de este stack es la velocidad, así que aquí van cifras reales en lugar de adjetivos. Las medí en agosto de 2026 en la RTX 3070 Ti (8 GB) con Ollama 0.24.0, llamando directo al endpoint /api/generate y leyendo los propios contadores de Ollama (eval_count / eval_duration), con think: false, tres tamaños distintos de prompt y la mediana de tres corridas en cada punto.\nModelo Generación Procesamiento de prompt Tiempo al primer token VRAM ocupada, de 8,192 MiB llama3.2, 3.2B, Q4_K_M 195 tok/s 7,370 tok/s 0.10 s 3,017 MiB qwen3.5:4b, 4.7B, Q4_K_M 102 tok/s 513 tok/s 0.22 s 5,949 MiB Qwen3.5 9.7B, Q4_K_M (mi versión tuneada) 70 tok/s 780 tok/s 0.20 s 7,921 MiB Esa última columna es una lectura absoluta de nvidia-smi tomada en una sesión tranquila, así que cuenta todo lo que hay en la tarjeta: el modelo y lo que el escritorio de Windows traía ocupado en ese momento (434 MiB). El dato de memoria del 4B se midió con mi versión tuneada, que carga los mismos pesos que qwen3.5:4b y ocupa lo mismo.\nDe esa tabla vale la pena leer tres cosas. Primero, unos 100 tokens por segundo en un modelo de 4.7B con 0.2 s al primer token significa que la respuesta empieza a aparecer en cuanto dejas de escribir y luego llega mucho más rápido de lo que cualquiera alcanza a leer, que es la vara práctica para un asistente familiar. Segundo, la tasa se mantiene plana con la longitud: el 4B sostuvo entre 101 y 105 tok/s lo mismo cuando generó 34 tokens que cuando generó 534. Tercero, cargar un modelo desde disco cuesta entre 3.4 y 6.4 segundos, y solo se paga en la primera petición después de que Ollama lo descarga de memoria.\nLa \u0026ldquo;versión tuneada\u0026rdquo; del último renglón es un Modelfile sobre los pesos originales, no un reentrenamiento, y por eso mi 4B tuneado midió 103 tok/s contra los 102 tok/s del 4B de fábrica: a un punto de distancia. El tuneo cambia el comportamiento del asistente, no su velocidad. Esa personalización es justo el tema de la parte 2 de esta serie.\nDimensiona el modelo a la tarjeta, no al disco # Este es el hallazgo que no esperaba y el que probablemente te ahorre una tarde entera.\nUn modelo de 6.6 GB en una tarjeta de 8 GB se ve como un ajuste cómodo en papel. No lo es, porque el modelo nunca es el único inquilino, y el otro inquilino no se queda quieto: el escritorio de Windows ocupó 434 MiB de VRAM en una sesión tranquila y entre 1,295 y 1,326 MiB mientras la máquina estaba en uso. Carga el modelo de 9.7B con num_ctx 8192 y la tarjeta se llena hasta 7,921 MiB de sus 8,192 MiB en el caso tranquilo, y hasta 7,883 a 7,939 MiB en el ocupado: entre 250 y 270 MiB de margen en ambos casos, cerca del 97 % de ocupación. El total cae en el mismo lugar bajo las dos condiciones porque Ollama dimensiona su reserva según lo que haya libre, en vez de tomar una cantidad fija. Por fuera nada se veía mal, y ollama ps seguía reportando 100% GPU.\nEn reposo se portaba bien y de forma reproducible: seis generaciones largas seguidas cayeron todas entre 69 y 72 tok/s, que es la cifra honesta de estado estable para ese modelo en esta tarjeta. Sin embargo, durante una de las corridas de benchmark el mismo modelo respondiendo el mismo prompt se desplomó a 19 a 21 tok/s, con el procesamiento de prompt cayendo de unos 800 tok/s a 133. Eso es lo que compra un cuarto de gigabyte de margen: el margen no solo es chico, además se mueve con lo que Windows esté dibujando, así que en cuanto el escritorio pide más VRAM, parte del trabajo se sale de la GPU. La caída es intermitente y no permanente, y precisamente por eso es una base mala para un servicio del que dependen otras personas. Va rápido todas las veces que lo pruebas y lento la única vez que alguien más lo necesita.\nEl modelo de 4B resuelve esto no por ser más listo, sino por dejar espacio. Su footprint es fijo, 5,515 MiB, así que lo que varía es el espacio libre y no el modelo: alrededor de 2.2 GB libres cuando el escritorio está en reposo y unos 1.4 GB cuando está ocupado. Un margen que absorbe con holgura ese vaivén del escritorio es justo lo que mantiene estable la velocidad. Mover el asistente familiar del 9.7B al 4B es exactamente la decisión que desarrollo en la parte 2, y el razonamiento se generaliza: cuando elijas modelo, revisa la VRAM libre después de cargarlo, no el tamaño del archivo antes de bajarlo.\nLo que obtienes cuando todo está corriendo # Terminas con un asistente de IA rápido, siempre disponible y completamente privado: sin suscripción, sin cuenta, sin datos saliendo de tu casa. Cualquier dispositivo de tu red lo alcanza en http://\u0026lt;IP-de-tu-PC\u0026gt;:8080, y sigue respondiendo esté o no alguien frente a la PC.\nLos casos de uso son más prácticos de lo que parecen. En mi casa, la familia lo usa para preguntar la contraseña del Wi-Fi, qué servicio de streaming tiene cierta serie, o cómo volver a conectar un dispositivo del hogar inteligente que se cayó de la red. Son el tipo de preguntas que antes requerían una búsqueda en internet o gritar por toda la casa. Tu hogar encontrará sus propios usos cotidianos rápidamente.\nLo que te enseña el proyecto # Más allá del asistente en sí, este es uno de los mejores proyectos de home lab que puedes hacer como ingeniero, porque te obliga a cruzar cuatro fronteras en un solo build: GPU passthrough hacia un entorno Linux virtualizado, networking de containers, un firewall de Linux y el puente entre el host Windows y WSL. Cada una de esas habilidades se transfiere directo a lo siguiente que construyas.\nLos obstáculos son el plan de estudios, y cuatro de ellos fueron los que más me enseñaron:\nEl atajo tentador no siempre es el correcto. El modo espejo habría eliminado por completo el port forwarding, pero rompió el descubrimiento de GPU de Ollama e interfirió con mi VPN. NAT más un script fue la opción menos elegante y la que sí funcionó. Los formatos de configuración no son sugerencias. Un prefijo http:// en OLLAMA_HOST bastó para que el servidor se enlazara a IPv6 y quedara invisible para el resto de la LAN. Leer cómo un programa interpreta su propia configuración cuesta mucho menos tiempo que adivinarlo. Un arreglo que tienes que recordar no es un arreglo. Reapuntar el reenvío a mano después de cada reinicio no es algo que nadie sostenga por mucho tiempo. Convertirlo en un script y una tarea programada fue lo que volvió a un demo funcional algo en lo que la familia confía. Que quepa no es lo mismo que que corra bien. El modelo de 9.7B cupo en 8 GB con 250 MiB de sobra, y Ollama reportaba felizmente 100% GPU. También perdía la mayor parte de su velocidad cada vez que el escritorio quería su VRAM de vuelta. Medir el margen libre después de cargar, en lugar de confiar en el tamaño del archivo, es un hábito que conviene adoptar temprano. Aunque ninguno de esos problemas aparecía en las guías con las que empecé, cada uno me dejó entendiendo el stack mejor de lo que lo habría entendido con un primer intento sin tropiezos. Ese es el patrón que sigo encontrando en el home lab: cada contratiempo es simplemente otra oportunidad de aprender de errores pasados y seguir mejorando.\n¿Qué sigue? # Una vez que tu IA privada esté corriendo, el stack se vuelve una base y no un producto terminado. Estos son los caminos que vale la pena explorar después:\nProbar diferentes modelos: Ollama hace trivial descargar y cambiar entre modelos; comparar tu elección inicial con otras opciones open-weight es el siguiente paso natural, y la tabla de arriba te sirve de plantilla para medirlos con honestidad en tu propia tarjeta. Agregar un system prompt personalizado: darle al asistente una personalidad y contexto específico del hogar para hacerlo aún más útil en el día a día. Acceder desde fuera de tu red: poner Open WebUI detrás de un reverse proxy (Nginx Proxy Manager es un buen punto de partida) y apuntarle un dominio, para que el chatbot sea accesible desde tu teléfono aunque no estés en casa. Conectarlo a Discord: un pequeño bot que reenvíe los mensajes a la API de Open WebUI y publique las respuestas de vuelta en un canal, para que la familia lo use desde una app que ya tienen abierta sin necesidad de navegar a una URL. Justo eso construí, y la parte 2 de esta serie documenta el puente completo: Ponle un bot de Discord a tu IA privada para que tu familia sí la use. Tomes el camino que tomes, lo importante es que el asistente es tuyo: tu hardware, tus datos, tus reglas. Si construyes tu propia versión de esto, me gustaría mucho saber cómo te fue.\n","date":"1 de agosto de 2024","externalUrl":null,"permalink":"/es/posts/despliega-ia-privada-con-ollama/","section":"Posts","summary":"¿Qué pasaría si el asistente de IA que usa toda tu familia corriera en tu propia computadora, respondiera en segundos y nunca enviara ni una sola palabra de tus conversaciones a la nube?\n","title":"Despliega tu IA privada con Ollama y Open WebUI en WSL2","type":"posts"},{"content":"","date":"1 de agosto de 2024","externalUrl":null,"permalink":"/es/tags/nvidia/","section":"Tags","summary":"","title":"Nvidia","type":"tags"},{"content":"","date":"13 enero 2023","externalUrl":null,"permalink":"/tags/3d-printing/","section":"Tags","summary":"","title":"3d-Printing","type":"tags"},{"content":"","date":"13 de enero de 2023","externalUrl":null,"permalink":"/es/tags/bigtreetech/","section":"Tags","summary":"","title":"Bigtreetech","type":"tags"},{"content":"","date":"13 de enero de 2023","externalUrl":null,"permalink":"/es/tags/bltouch/","section":"Tags","summary":"","title":"Bltouch","type":"tags"},{"content":"¿Ya te pasaste una tarde entera persiguiendo la primera capa perfecta, solo para dejar bien una esquina y perder la otra? Nivelar a mano la cama en una Ender 3 de fábrica es un ritual: cuatro perillas, una hoja de papel, y una primera capa que queda preciosa del lado izquierdo de la cama y translúcida del derecho. El problema no es que seas malo girando perillas. Es que la cama no está plana, y por más que ajustes cuatro esquinas no vas a corregir una superficie que se pandea en el centro.\nUn BLTouch resuelve esto de otra manera. En lugar de pedirte que dejes la cama plana, mide qué tan chueca está y le dice a la impresora que siga esa forma. Este post trata de instalarle uno a una Ender 3 que ya trae una BIGTREETECH SKR Mini E3 V2.0: imprimir un soporte, cablear el sensor y (la parte que de verdad decide si funciona) medir los offsets entre el sensor y la boquilla.\nEsto no lo saqué de cero. El procedimiento que sigue está basado en la guía de Teaching Tech BLtouch for any 3D printer - Comprehensive step by step guide, que es el video que tuve abierto en la segunda pantalla mientras instalaba el mío. Lo que yo agrego aquí es todo lo específico de esta máquina: el cableado de la SKR Mini E3 V2.0, los offsets que medí en mi propio soporte, y los números que solo aparecen cuando haces la aritmética para tu propia geometría.\nEsta es la parte 3 de cinco. La parte 2 fue el cambio de placa que hace fácil todo esto, y la parte 4 compila el firmware que amarra todo el conjunto.\nEl BLTouch montado junto al hotend en un soporte impreso, con el pin desplegado. Qué es realmente un BLTouch # El nombre suena a algo exótico, pero el mecanismo es simple e ingenioso. Dentro de la carcasa hay un pin retráctil y un solenoide, además de un sensor de efecto Hall que detecta magnéticamente la posición del pin.\nPara tomar una medición, el firmware energiza el solenoide y el pin cae. La impresora baja el eje Z hasta que el pin toca la cama y es empujado de vuelta hacia adentro del cuerpo; el sensor Hall detecta ese movimiento y el sensor manda una señal de disparo, exactamente igual que si se cerrara un final de carrera. El firmware registra la altura Z en ese instante, retrae el pin y se mueve al siguiente punto.\nHaz eso en una cuadrícula de puntos por toda la cama y tienes una malla: un mapa de qué tan alta o baja está la cama en cada posición. Durante la impresión, Marlin ajusta Z continuamente contra esa malla, así que la boquilla sigue la superficie real en lugar de un plano imaginario perfectamente horizontal.\nVale la pena tener claras dos consecuencias prácticas del mecanismo antes de instalar uno:\nToca la cama con un pin de plástico, no con la boquilla. Así que mide sobre cualquier superficie que le pongas debajo, y si le toca un clip de la cama te va a dar felizmente una lectura sin sentido. Hace un autotest al encender. Cuando prendes la impresora, el pin debe desplegarse y retraerse un par de veces y terminar retraído, con la luz roja fija. Ese bailecito es tu primer y mejor diagnóstico: si no ocurre, o el pin se queda afuera parpadeando, el sensor tiene un problema de cableado o de alimentación, y no tiene caso avanzar al firmware. Imprimir el soporte # El BLTouch no trae ninguna forma de sujetarse a una Ender 3. Te la imprimes.\nYo usé (Yet Another) Ender 3 BLTouch Mount, del usuario de Thingiverse StevenMLawson (con licencia Creative Commons). Reemplaza la tapa frontal del shroud del ventilador del hotend y sostiene el sensor hacia la izquierda de la boquilla, que es la razón por la que más adelante el offset en X sale tan grande.\nLa descarga trae dos modelos:\nBLTouchMount.STL: la versión normal, que es la que yo imprimí. BLTouchMount-Laser.STL: una variante preparada para un módulo láser, que solo quieres si de verdad vas a montar uno. Imprímelo en PETG si puedes. Esta pieza queda pegada al bloque calefactor. El PLA aguanta un rato, pero después de una impresión larga en un día caluroso tu sensor termina inclinándose en silencio una fracción de milímetro fuera de posición, y eso aparece como una primera capa fea que vas a pasar toda una tarde persiguiendo. Con PETG o ABS te ahorras el tema completo.\nEn cuanto a parámetros, nada exótico: capas de 0.2 mm, 4 perímetros, 30–40 % de relleno. Esta pieza sostiene la alineación de tu instrumento de medición, así que vale la pena imprimirla sólida y revisar que haya salido sin deformaciones antes de atornillarle un sensor.\nMóntalo con los tornillos del ventilador del hotend, usando tornillería M3. La regla general es dejar el sensor lo más cerca posible de la boquilla, pero no tan cerca como para que falle por la exposición al calor, y atornillarlo bien firme, porque cualquier juego o bamboleo en el soporte arruina la exactitud de todas las lecturas que tome. Tres cosas que hay que verificar una vez puesto:\nQue el cuerpo del sensor quede a escuadra con la cama y sin juego. Un sensor inclinado mide una malla inclinada, y uno flojo mide una cama distinta cada vez. Que el pin retraído quede entre 2.3 mm y 4.3 mm por encima de la punta de la boquilla. Ese es el rango que marca Antclabs, y tiene dos límites porque el recorrido del pin es fijo, así que el sensor falla distinto en cada extremo. Si lo montas muy arriba, el pin desplegado ya no baja lo suficiente por debajo de la boquilla como para tocar la cama primero: llega antes la boquilla, el sensor nunca dispara y Marlin sigue bajando Z porque, hasta donde él sabe, la cama todavía está lejos. Ese es el extremo peligroso, y termina con la boquilla enterrada en tu superficie de impresión. Si lo montas muy abajo, el palpado en sí funciona bien, pero el pin retraído queda colgando dentro de la zona de trabajo durante todo el resto de la impresión. Ajustar la altura es más fácil de lo que suena. Con la impresora apagada, baja el cabezal a mano hasta que la boquilla descanse sobre la cama, y usa una llave allen de 3 mm como separador para fijar contra ella la altura del sensor. Si el soporte no deja deslizar el sensor, usa rondanas para calzarlo hasta que caiga dentro del rango. Que no haya nada en la cama con lo que el pin retraído se pueda atorar. Este es el extremo bajo de esa misma preocupación, pero verificado contra tu máquina real y no contra un número: despliega el pin a mano en distintas posiciones y confirma que nunca cae sobre un clip cuando la impresora palpa cerca de una orilla, y que no tiene de dónde engancharse cuando el cabezal pasa sobre una pieza alta. El soporte impreso del BLTouch recién salido de la cama, antes de montarlo. El cableado # Un BLTouch viene con cinco cables, normalmente repartidos en dos conectores:\nUn conector de 3 pines: café (GND), rojo (5 V) y naranja/amarillo (la señal de control, que se comporta como una señal de servo y le dice al pin que se despliegue o se guarde). Un conector de 2 pines: negro (GND) y blanco (la señal de disparo, que se comporta como un final de carrera). En la mayoría de las placas tienes que llevar esos dos conectores a dos lugares distintos, que es justamente la incomodidad que hacía molesto agregar un sensor a la placa Creality de fábrica. La SKR Mini E3 V2.0 trae un header de probe dedicado que acepta ambos, así que aquí es un solo conector.\nEn términos de firmware, ese header corresponde a dos pines del STM32: la señal de disparo cae en PC14 y el control del servo en PA1. Vas a ver PC14 aparecer explícitamente en la configuración de la parte 4, así:\n#define Z_MIN_PROBE_PIN PC14 Cuidado con la polaridad del conector. El header de probe tiene guía, pero el cable que viene con el BLTouch no siempre está crimpado en el orden que esperas, y meterle 5 V al pin de señal arruina la tarde. Compara los colores de los cables contra las etiquetas serigrafiadas junto al header antes de empujarlo hasta el fondo.\n¿Y el final de carrera Z original? Déjalo conectado. El sensor tiene su propio pin dedicado, así que el switch mecánico del eje Z no le estorba, y conservarlo no cuesta nada. El firmware va a usar el sensor para hacer home en Z (esa es la opción USE_PROBE_FOR_Z_HOMING) mientras el switch se queda cableado como el final de carrera Z-min de siempre.\nLleva el cable junto al arnés existente hacia el hotend, con suficiente holgura para que un recorrido completo en X y Y no lo jale, y suficiente sujeción para que nunca se meta en el camino del pórtico. Los cinchos y la malla original son tus aliados aquí.\nEl conector de 5 pines del BLTouch conectado al header de probe dedicado de la SKR Mini E3 V2.0. Probar el sensor antes de confiar en él # Antes de nivelar nada, confirma que el sensor responde a los comandos. Conéctate por USB y manda estos uno por uno:\nM280 P0 S10 ; desplegar el pin M280 P0 S90 ; guardar el pin M280 P0 S120 ; correr el autotest (el pin cicla repetidamente) M280 P0 S160 ; reset / liberar estado de alarma Si S10 y S90 funcionan, tu señal de servo está bien cableada y el firmware está hablando con el sensor. Manda S120, déjalo ciclar unas cuantas veces y luego S160 para detenerlo.\nDespués confirma la señal de disparo, que es un cable aparte y puede estar mal aunque desplegar y guardar funcionen perfecto. Despliega el pin y manda:\nM119 Busca la línea z_probe, o z_min si tu configuración no tiene un pin de probe aparte. En cuanto configuras un sensor de nivelado automático, Marlin le da su propia línea de estado, y esta instalación tiene un Z_MIN_PROBE_PIN dedicado, así que z_probe es la línea que importa aquí.\nEmpuja el pin hacia arriba con la mano y vuelve a mandar M119: el estado debe cambiar. Aquí está el detalle que hace que mucha gente persiga fallas imaginarias: el BLTouch reporta lo contrario de lo que esperarías de un final de carrera. Con el pin retraído y en reposo marca TRIGGERED, y con el pin desplegado esperando la cama marca open. Si lees esa polaridad de la forma intuitiva, vas a concluir que un sensor perfectamente sano está descompuesto. Lo que estás confirmando es simplemente que los dos estados cambian cuando el pin se mueve. Un sensor que despliega precioso pero que nunca cambia de estado va a clavar la boquilla contra la cama en el primer G28, así que no te saltes esta prueba.\nLa parte que sí importa: los offsets del sensor # El BLTouch no está donde está la boquilla. Cuelga hacia un lado, a una altura distinta. Cada medición que toma la toma entonces en otro lugar, y el firmware necesita saber exactamente dónde para convertir lecturas del sensor en alturas de la boquilla.\nEso es un solo ajuste, tres números:\n#define NOZZLE_TO_PROBE_OFFSET { -41, -12, -1.925 } Esos son los números con los que terminé para este soporte. No los copies a ciegas: X e Y dependen de tu soporte, y Z depende de tu sensor específico, de tu soporte y de cómo quedó atornillado. Así los sacas tú.\nX e Y: dónde está el sensor respecto a la boquilla # Los valores se miden de la boquilla hacia el sensor, en coordenadas de la impresora. X negativa significa que el sensor está a la izquierda de la boquilla; Y negativa, que está adelante.\nEl método confiable de baja tecnología:\nPega una hoja de papel a la cama y haz home. Baja la boquilla hasta que apenas toque el papel y marca el punto exacto que queda bajo la punta. Sube Z, mueve el carro con los controles de la propia impresora hasta que el pin del sensor quede sobre esa marca, y despliega el pin para que toque el papel. Marca ese punto también. Mide con calibrador las distancias en X y en Y entre las dos marcas, y deduce los signos según hacia dónde tuviste que mover el carro. Medir directo sobre el hardware con un calibrador también funciona si la geometría es accesible: la distancia horizontal entre el centro de la boquilla y el centro del pin, en cada eje. Para mi soporte eso dio 41 mm a la izquierda y 12 mm hacia el frente, de ahí -41 y -12.\nAdemás, esos números tienen un costo real, y vale más hacer la cuenta que andar adivinando. El carro solo se mueve hasta cierto punto, así que un sensor que cuelga 41 mm hacia un lado simplemente no alcanza la franja más lejana de la cama. Súmale los 10 mm de PROBING_MARGIN que mantienen los puntos de palpado alejados de las orillas (ambos valores se definen en la parte 4) y, sobre una cama de 235 × 235 mm, Marlin recorta la zona palpable a esto:\nX: de 10 mm a 194 mm, o sea 184 mm de los 235 mm disponibles. El extremo lejano sale directo del offset (235 − 41 = 194) y el cercano, del margen. Y: de 10 mm a 223 mm, o sea 213 mm. Aquí el offset de 12 mm cuesta mucho menos (235 − 12 = 223), y otra vez el margen define la orilla cercana. Así que el sensor toca en realidad unos 184 × 213 mm de los 235 × 235 mm, lo que deja casi 30 % del área de la cama sin medir directamente. Haz esa misma resta con tus propios offsets y tu margen y vas a conocer tu número antes de imprimir nada.\nEsa franja sin medir es justamente la razón por la que en la parte 4 se activa EXTRAPOLATE_BEYOND_GRID, que extiende la malla más allá de los puntos palpados más externos para que las orillas y las esquinas sigan recibiendo corrección en lugar de quedarse fuera del mapa.\nZ: qué tan abajo del punto de disparo queda la boquilla # Este es el número que decide si tu primera capa es perfecta o una embarrada, y a diferencia de X e Y no lo sacas con una regla.\nEl procedimiento clásico:\nHaz home con G28, luego manda M851 Z0 y M500 para poner en cero cualquier offset guardado y partir de un estado conocido. Muévete al centro de la cama y baja Z en pasos pequeños con una hoja de papel debajo de la boquilla, hasta que el papel se arrastre apenas. Anota el valor de Z de la pantalla. Ese número negativo es tu offset. Guárdalo: M851 Z-1.925 M500 Marlin también trae una versión guiada de exactamente esto, el asistente de offset del probe, que te lleva de la mano desde la pantalla y guarda el resultado por ti. Viene activado en el firmware que compilamos en la parte 4, precisamente porque hacerlo a mano es latoso y vas a querer repetirlo cada vez que cambies de boquilla o vuelvas a montar el sensor. Un detalle que le cuesta a mucha gente una tarde de búsqueda: PROBE_OFFSET_WIZARD no está en Configuration.h, donde vive cada uno de los ajustes que esta serie va citando, sino en Configuration_adv.h, el segundo archivo de configuración y bastante más largo. Marlin hasta deja una nota al respecto en el primer archivo, señalando hacia el otro: \u0026ldquo;PROBE_OFFSET_WIZARD (configuration_adv.h) can be used for setting the Z offset.\u0026rdquo;\nLa otra herramienta que vale la pena activar para esto es el babystepping con BABYSTEP_ZPROBE_OFFSET, que también vive en Configuration_adv.h. Eso te deja ajustar Z en vivo, durante la primera capa de una impresión, y que el ajuste se escriba de vuelta en el offset del sensor en lugar de perderse al terminar. Empieza una primera capa grande y obsérvala; en esta configuración llegas al ajuste con doble clic sobre la pantalla de estado (eso es DOUBLECLICK_FOR_Z_BABYSTEPPING, también activado), y de ahí ajustas hasta que la extrusión se vea bien y guardas con M500. Es de lejos la forma más rápida de converger a un buen número.\nNivelar y que se quede # Con los offsets puestos, el flujo real de nivelación es corto:\nG28 ; home de todos los ejes (Z ahora hace home con el sensor) G29 ; palpar la cuadrícula y construir la malla M500 ; guardar la malla en la EEPROM El G28 primero no es opcional, y la razón es más específica que \u0026ldquo;primero haz home y luego mide\u0026rdquo;. El propio Configuration.h de Marlin lo dice sin rodeos: \u0026ldquo;Normally G28 leaves leveling disabled on completion.\u0026rdquo; Hacer home no es que simplemente deje de activar la compensación, es que la apaga. Por eso el M420 S1 tiene que ir después, para volver a prenderla, y por esa misma razón la variante de volver a palpar que viene más abajo pone el G29 después del G28 y nunca antes. Con un sensor instalado, Marlin además exige hacer home de Z en un punto seguro y no en la esquina (la opción Z_SAFE_HOMING), porque en la esquina extrema el sensor quedaría colgando fuera de la cama, sin nada debajo.\nY luego viene el paso que todo el mundo olvida. Guardar la malla no significa que la impresora la use. La malla tiene que cargarse y activarse al inicio de cada impresión, que es una línea en el start G-code de tu slicer:\nM420 S1 Ponla después del G28 en la secuencia de inicio. Sin ella, la impresora guarda obedientemente un mapa perfecto de tu cama y luego lo ignora, y tú concluyes que el nivelado automático no sirve.\nSi prefieres volver a palpar antes de cada impresión en lugar de confiar en una malla guardada, cambia el M420 S1 por un G29 en el start G-code, siempre después del G28. Cuesta un minuto o dos por impresión y es más robusto si mueves la impresora de lugar o cambias de superficie seguido.\nLa malla de la cama después de un G29, mostrando qué tan lejos de plana está en realidad. Por qué las piezas altas dejan de seguir la cama # Hay un comportamiento que sorprende a casi todos la primera vez que lo notan: la corrección se desvanece con la altura. ENABLE_LEVELING_FADE_HEIGHT viene activado de fábrica en Marlin, con DEFAULT_LEVELING_FADE_HEIGHT 10.0, y los dos están tal cual en el firmware que corre en mi máquina. Ese valor no lo elegí yo, lo heredé, y después de compilar el firmware con mis propias manos prefiero saber qué está haciendo a que me tome por sorpresa más adelante. El comentario de Configuration.h lo describe con precisión: \u0026ldquo;Gradually reduce leveling correction until a set height is reached, at which point movement will be level to the machine\u0026rsquo;s XY plane.\u0026rdquo;\nDicho de otro modo, mi impresora hace todo el trabajo de la malla en los primeros 10 mm de la impresión y de ahí en adelante lo va difuminando, y por encima de esa altura se mueve en su propio plano horizontal en lugar de seguir la forma de la cama. Eso es intencional y es el comportamiento que quieres: la compensación existe para rescatar las primeras capas, no para inclinar una pieza de 200 mm de alto siguiendo el pandeo del vidrio. Si en algún momento quieres cambiarla, M420 Z\u0026lt;altura\u0026gt; ajusta la altura de desvanecimiento en caliente.\nCuando no funciona # El pin parpadea en rojo y se queda abajo. Eso es un estado de alarma, normalmente porque el pin está obstruido, porque le pegaron al sensor, o por una mala conexión. Manda M280 P0 S160 para resetearlo. Si vuelve a alarmar de inmediato, revisa que el pin se mueva libremente.\nNo hay autotest al encender. Sin autotest no hay 5 V o no hay tierra: es problema de cableado, no de firmware.\nDespliega y guarda, pero la impresora se clava en la cama. La señal de control está bien y la de disparo no. Regresa a la prueba de M119 de arriba.\nLa malla parece cordillera. Valores que varían más de unas cuantas décimas de milímetro casi siempre apuntan a algo mecánico: soporte del sensor flojo, un resorte de la cama sin tensión, o un sensor que no está a escuadra. Eso se arregla ahí, no en software.\nLa primera capa queda pareja pero demasiado alta o demasiado baja. Eso es puramente el offset de Z. Ajústalo con babystepping durante una impresión hasta que se vea bien y guarda con M500.\nQué ganas con esto, y qué sigue # Con el sensor montado, cableado y sus offsets medidos, tu Ender 3 ya no necesita el ritual de las cuatro perillas. Mide su propia cama y Marlin corrige por eso automáticamente, impresión tras impresión. La mía pasó de una primera capa que dependía de qué esquina estuviera cuidando yo, a una que sale pareja de orilla a orilla, que es justo el tipo de resultado poco vistoso pero repetible que de verdad importa en el día a día.\nLlegar ahí, eso sí, dio por hecho un firmware que ya sabe del sensor: que BLTOUCH está activado, que el probe está en PC14, que el nivelado bilineal está encendido, que los offsets están guardados. Ese firmware no aparece por arte de magia.\nLa parte 4 lo construye: VS Code, PlatformIO, Auto Build Marlin, y el conjunto específico de cambios de configuración que convierten una descarga genérica de Marlin en firmware para esta máquina en particular.\n","date":"13 de enero de 2023","externalUrl":null,"permalink":"/es/posts/instalar-bltouch-ender-3/","section":"Posts","summary":"¿Ya te pasaste una tarde entera persiguiendo la primera capa perfecta, solo para dejar bien una esquina y perder la otra? Nivelar a mano la cama en una Ender 3 de fábrica es un ritual: cuatro perillas, una hoja de papel, y una primera capa que queda preciosa del lado izquierdo de la cama y translúcida del derecho. El problema no es que seas malo girando perillas. Es que la cama no está plana, y por más que ajustes cuatro esquinas no vas a corregir una superficie que se pandea en el centro.\n","title":"Cómo instalar un BLTouch en una Ender 3: soporte, cableado y offsets","type":"posts"},{"content":"","date":"13 enero 2023","externalUrl":null,"permalink":"/series/ender-3-upgrade/","section":"Series","summary":"","title":"Ender 3 Upgrade","type":"series"},{"content":"","date":"13 de enero de 2023","externalUrl":null,"permalink":"/es/tags/ender-3/","section":"Tags","summary":"","title":"Ender-3","type":"tags"},{"content":"","date":"13 de enero de 2023","externalUrl":null,"permalink":"/es/tags/hardware/","section":"Tags","summary":"","title":"Hardware","type":"tags"},{"content":"","date":"13 de enero de 2023","externalUrl":null,"permalink":"/es/tags/impresion-3d/","section":"Tags","summary":"","title":"Impresion-3d","type":"tags"},{"content":"","date":"13 de enero de 2023","externalUrl":null,"permalink":"/es/series/mejorando-la-ender-3/","section":"Series","summary":"","title":"Mejorando La Ender 3","type":"series"},{"content":"¿Tu Ender 3 de las primeras versiones es lo más ruidoso del cuarto cada vez que arranca una capa, o ya te topaste con pared tratando de meterle funciones que el firmware de fábrica simplemente no aguanta? Los dos problemas vienen de la misma pieza: la placa con la que Creality mandó la impresora. Ese chillido no es un defecto genérico de las impresoras baratas. Es una consecuencia muy concreta de los drivers que vienen soldados en esa placa, y es apenas una de varias cosas que limitan en silencio lo que la máquina puede hacer.\nLa solución es un cambio directo, de esos que se resuelven en una tarde aunque nunca hayas abierto la impresora. Este post recorre el cambio de la placa de fábrica por una BIGTREETECH SKR Mini E3 V2.0: qué te está costando realmente la placa original, por qué este reemplazo en particular es la respuesta fácil para una Ender 3, y cómo hacer el cambio sin sacarle el humito mágico a nada. Es la parte 2 de cinco. La parte 1 imprimió las piezas que le arreglaron a esta máquina todo lo mecánico, la parte 3 le agrega un sensor BLTouch, y la parte 4 compila firmware de Marlin a la medida para todo el conjunto usando VS Code.\nLa BIGTREETECH SKR Mini E3 V2.0 junto a la placa Creality de fábrica que reemplazó. Qué te está costando de verdad la placa de fábrica # La placa de una Ender 3 de las primeras es un diseño de Creality derivado de la familia Melzi. Está construida alrededor de un ATmega1284P: un microcontrolador AVR de 8 bits a 16 MHz, con 128 KB de flash y 16 KB de RAM. Es la misma familia de chip que un Arduino, y sí funciona. La impresora imprime. Pero trae cuatro límites de fábrica.\nLos drivers de los motores vienen soldados. Son drivers de la clase A4988 y no están en zócalos, así que no puedes cambiarlos por unos más silenciosos. Cada movimiento de la impresora se escucha por cómo esos drivers recortan la corriente en las bobinas del motor. De ahí viene el ruido del que todo el mundo se queja.\nLa mayoría de estas placas viene sin bootloader. En un Arduino normal, el bootloader es el programita que permite que el chip acepte firmware nuevo por USB. Creality lo omitió, lo que significa que para meterle tu propio firmware primero tienes que grabarle un bootloader al chip usando otro dispositivo como programador ISP, cableando un Arduino Uno o un USBasp al header ICSP de la placa. Aunque no es difícil, sí es un proyecto entero atravesado entre tú y un simple cambio de firmware.\n128 KB de flash no dan para mucho. Un Marlin moderno con las funciones que de verdad quieres (nivelado automático de cama, malla de nivelación, babystepping, linear advance, asistente de offset del probe) no entra cómodamente. Terminas sacrificando unas funciones por otras y peleándote con errores de compilación por falta de espacio.\nNo hay dónde conectar un sensor de nivelación. La placa de fábrica no tiene header dedicado de probe ni de servo, así que agregar un BLTouch implica repartir sus cinco cables entre una señal de servo improvisada y la entrada del final de carrera Z.\nO sea: ruidosa, difícil de flashear, sin espacio y complicada de ampliar. Cambiar la placa resuelve las cuatro de una sola vez.\nPor qué la SKR Mini E3 V2.0 en particular # BIGTREETECH diseñó esta placa como un reemplazo directo de la motherboard de la Ender 3, y lo de \u0026ldquo;directo\u0026rdquo; es literal. Los barrenos coinciden con los postes de la placa original, los conectores son de los mismos tipos y están más o menos en los mismos lugares, y la pantalla de fábrica se conecta tal cual. No hay cable adaptador, no hay que barrenar nada, no hay que recablear el display.\nLo que ganas a cambio:\nUn STM32F103RC de 32 bits a 72 MHz con 256 KB de flash. El doble de espacio y muchísimo más margen, tanto para funciones como para la planificación de movimiento. Drivers TMC2209, soldados pero en modo UART. Que vengan soldados aquí da igual, porque son justamente los silenciosos. En modo StealthChop los motores quedan prácticamente mudos, y el control por UART significa que el firmware ajusta corriente, microstepping y modos por software, en lugar de que tú andes moviendo potenciómetros diminutos con un desarmador. Flasheo de firmware desde la microSD. En lugar de grabar un bootloader con un programador ISP, copias un archivo firmware.bin a una tarjeta, la metes en la placa y enciendes. Ese es todo el proceso. Un header de probe de 5 pines dedicado, así que el BLTouch se conecta con su propio conector en vez de andar repartido entre dos puertos. En eso se apoya la parte 3. Compatibilidad con la pantalla giratoria de fábrica, que en Marlin corresponde a la opción CR10_STOCKDISPLAY. Una cosa que hay que verificar antes de comprar: la versión importa. El repositorio de BIGTREETECH cubre la V1.0, la V1.2 y la V2.0 de esta placa, y no son la misma placa. La versión viene impresa en el propio PCB. Todo en esta serie es la V2.0, y más adelante, en el firmware, eso se traduce en la línea #define MOTHERBOARD BOARD_BTT_SKR_MINI_E3_V2_0. Si te equivocas en ese define, el firmware compila sin problema y luego se comporta como poseído, porque va a estar manejando los pines equivocados.\nAntes de desconectar nada # Dos costumbres que te van a ahorrar una mala noche.\nFotografía el cableado primero. Quita la tapa de la base y, antes de tocar un solo conector, toma fotos claras y bien iluminadas de toda la placa desde arriba, y luego acercamientos de cada esquina. Cuando estés reconectando una hora después y dos conectores negro-con-rojo de dos cables se vean idénticos, esas fotos van a ser tu única fuente de verdad.\nEtiqueta los conectores. Cinta masking y pluma. Resistencia del hotend, termistor del hotend, ventilador de capa, ventilador del disipador, resistencia de la cama, termistor de la cama, motores X/Y/Z/E, finales de carrera X/Y/Z, pantalla. Toma cinco minutos y elimina toda una categoría de errores, esos donde acabas metiendo el termistor de la cama en la entrada del termistor del hotend.\nAdemás, desconecta la impresora de la pared y dale un minuto a la fuente para descargarse antes de empezar. Ya que estás ahí adentro, no toques el switch selector de voltaje de la fuente si el tuyo lo trae; está puesto para el voltaje de tu país y nada de esta modificación requiere cambiarlo.\nLa placa Creality de fábrica todavía en su lugar, fotografiada antes de desconectar nada. Esta es la foto de referencia que vas a querer después. El cambio, paso a paso # 1. Abrir la base # La motherboard vive en la caja debajo de la impresora. Acuesta la máquina de lado, quita los tornillos de la tapa y levántala. Todo lo que sigue se hace con la impresora desconectada.\n2. Desconectar todo de la placa vieja # Recorre la placa de forma metódica, en lugar de ir jalando conectores al azar:\nMotores: X, Y, Z y E. En una Ender 3 son cuatro conectores JST de cuatro pines idénticos, que es exactamente la razón por la que los etiquetaste. Finales de carrera: X, Y y Z, tres conectores de dos pines. Hotend: el cartucho calefactor (dos cables más gruesos) y el termistor (dos cables delgados). Ventiladores: el de capa y el del disipador del hotend. Cama: los cables de la resistencia (gruesos, normalmente en terminal de tornillo) y el termistor de la cama. Pantalla: el cable listón que va al LCD. Alimentación: la entrada de 24 V desde la fuente. Anota la polaridad ahora mismo, viene impresa en la placa junto a la terminal. Algunos conectores tienen una pestañita de retención; jala del cuerpo de plástico, nunca de los cables.\n3. Desatornillar y sacar la placa vieja # Cuatro tornillos hacia los postes y ya sale. Guarda los tornillos, los vas a reutilizar.\n4. Montar la SKR Mini E3 # Va sobre los mismos postes con los mismos tornillos. Si no coincide, detente y verifica que tengas la variante para Ender 3 y no otro modelo de SKR.\n5. Reconectar guiándote por la serigrafía # Cada puerto de la SKR Mini E3 viene etiquetado en el PCB. Recorre la misma lista de antes, pero fijándote en la etiqueta y no en la posición: XM, YM, ZM, EM para los motores; X-STOP, Y-STOP, Z-STOP para los finales de carrera; HE0 y TH0 para la resistencia y el termistor del hotend; FAN0 y FAN1 para el ventilador de capa y el del disipador; HB y TB para la cama; EXP1 para la pantalla.\nDeja la entrada de 24 V para el final y verifica dos veces la polaridad contra lo que anotaste en el paso 2. Este es el único conector que puede destruir la placa si va al revés.\nUn apunte sobre el motor del extrusor. En esta placa el conector del extrusor queda eléctricamente invertido respecto al cableado original de Creality. No lo arregles recrimpando el conector ni volteando cables. Se corrige en el firmware con una sola línea, #define INVERT_E0_DIR true, que forma parte de la configuración de la parte 4. Si flasheas el firmware precompilado de BIGTREETECH y el extrusor gira al revés, esta es la razón.\nLa SKR Mini E3 V2.0 montada sobre los postes originales, con todo reconectado, antes de poner la tapa. Cómo meterle firmware # Una SKR Mini E3 nueva no llega sabiendo que está montada en una Ender 3. Necesita firmware, y el proceso de flasheo es refrescantemente simple:\nFormatea una microSD en FAT32. Las tarjetas de 32 GB o menos son la apuesta segura; algunas placas son quisquillosas con las más grandes. El tamaño de unidad de asignación de 4096 bytes es la recomendación habitual. Copia un archivo llamado exactamente firmware.bin a la raíz de la tarjeta. No dentro de una carpeta. Con la impresora apagada, mete la tarjeta en la ranura microSD de la placa. Enciende y espera. La placa lee el archivo, lo escribe en su memoria flash y lo renombra en la tarjeta como FIRMWARE.CUR para marcarlo como ya usado. La pantalla enciende cuando termina. Ese renombrado es tu señal de éxito. Si después de un ciclo de encendido el archivo sigue llamándose firmware.bin, la placa nunca lo leyó: formato equivocado, nombre equivocado, tarjeta incompatible, o el archivo estaba dentro de una subcarpeta.\nBIGTREETECH incluye binarios precompilados en su repositorio, en firmware/V2.0/, entre ellos firmware.bin, firmware-bltouch.bin y firmware-bltouch-for-z-homing.bin. Son una forma perfectamente razonable de confirmar que la placa funciona la primera vez que la enciendes, y un buen plan B si una compilación tuya se porta mal. Pero son genéricos, y no van a conocer los offsets de tu probe, el tamaño de tu cama ni tus temperaturas de precalentamiento. Compilar el tuyo es justo de lo que trata la parte 4.\nPrimer encendido: revisa antes de imprimir # Aunque dan ganas de cargar filamento y lanzar un Benchy de inmediato, aguántate. Haz esto primero, con la tapa todavía quitada para poder alcanzar rápido el switch de encendido:\nEnciende sin calentar nada. La pantalla debe prender y mostrar la pantalla de estado normal de Marlin. Si se queda oscura, apaga de inmediato y revisa el listón de la pantalla y el conector de 24 V.\nMueve cada eje desde el menú. Movimientos cortos, de 10 mm. Cada eje debe moverse en la dirección que le pediste. Si un eje va al revés, eso es un ajuste de dirección en el firmware, no una falla de cableado.\nPrueba los finales de carrera. Conéctate por USB con una terminal (Pronterface, OctoPrint, o el monitor serial de VS Code) y manda:\nM119 Te devuelve el estado de todos los finales de carrera. Actívalos con la mano uno por uno y vuelve a mandar M119; la línea correspondiente debe cambiar entre open y TRIGGERED. Si alguno reporta TRIGGERED sin que nada lo esté tocando, revisa ese conector antes de mandar la impresora a home.\nDespués sí, haz home. G28, mirando la máquina con el dedo sobre el apagador. El homing es justo el momento en el que un final de carrera mal conectado o una dirección invertida se convierte en un eje estrellado.\nRevisa los termistores antes que las resistencias. Con todo frío, la temperatura del hotend y la de la cama deben marcar algo parecido a la temperatura ambiente. Si alguna marca un número absurdo, tienes los termistores cambiados o una mala conexión, y no quieres enterarte de eso encendiendo una resistencia.\nSolo cuando todo eso salga limpio, pon la tapa de vuelta e imprime algo pequeño.\nQué ganas con esto y qué sigue # Justo después del cambio, dos cosas se transforman: tu impresora se vuelve dramáticamente más silenciosa, y flashear firmware pasa de ser un proyecto con cautín a ser arrastrar un archivo. Lo segundo es lo que de verdad importa, porque convierte al firmware de algo fijo en algo sobre lo que puedes seguir iterando. A mí ese cambio fue justo lo que me abrió la puerta a las siguientes dos mejoras de esta serie.\nAdemás, terminas con una placa que te da un margen que antes no tenías: el doble de flash, un header de probe dedicado, y drivers que controlas desde software en vez de con un desarmador. Ese margen es justo lo que aprovecha el resto de esta serie. La parte 3 instala un sensor BLTouch en el hotend con un soporte impreso, lo conecta al header de probe dedicado que trae esta placa, y calcula los offsets del sensor. La parte 4 arma el entorno en VS Code con PlatformIO y Auto Build Marlin, y recorre cada cambio de configuración necesario para compilar un firmware que sepa de todo lo anterior.\n","date":"12 de enero de 2023","externalUrl":null,"permalink":"/es/posts/cambiar-motherboard-ender-3-skr-mini-e3/","section":"Posts","summary":"¿Tu Ender 3 de las primeras versiones es lo más ruidoso del cuarto cada vez que arranca una capa, o ya te topaste con pared tratando de meterle funciones que el firmware de fábrica simplemente no aguanta? Los dos problemas vienen de la misma pieza: la placa con la que Creality mandó la impresora. Ese chillido no es un defecto genérico de las impresoras baratas. Es una consecuencia muy concreta de los drivers que vienen soldados en esa placa, y es apenas una de varias cosas que limitan en silencio lo que la máquina puede hacer.\n","title":"Cómo cambiar la motherboard de tu Ender 3 por una BIGTREETECH SKR Mini E3 V2.0","type":"posts"},{"content":"","date":"12 de enero de 2023","externalUrl":null,"permalink":"/es/tags/electronica/","section":"Tags","summary":"","title":"Electronica","type":"tags"},{"content":"","date":"12 enero 2023","externalUrl":null,"permalink":"/tags/electronics/","section":"Tags","summary":"","title":"Electronics","type":"tags"},{"content":"","date":"23 de abril de 2022","externalUrl":null,"permalink":"/es/tags/armado-de-pc/","section":"Tags","summary":"","title":"Armado-De-Pc","type":"tags"},{"content":"¿Estás pensando en armar tu propia PC en lugar de comprar una prearmada? Si algo te detiene, seguramente no es usar el desarmador. Es pararte frente a una pared de componentes sin saber cuáles funcionan juntos.\nY ahí está la buena noticia, porque la compatibilidad no es cuestión de suerte, de intuición ni de años de experiencia. Cada fabricante publica exactamente con qué funciona su producto, así que todo ese problema se resuelve en papel antes de que gastes un solo peso. Un procesador, una motherboard, la memoria, la tarjeta de video, el almacenamiento, la fuente de poder y el gabinete tienen que coincidir entre sí en socket, chipset, tamaño y potencia. Si logras que coincidan, el ensamble físico resulta ser la parte fácil.\nEsta guía es el checklist de componentes que usé para planear y armar mi propia máquina, un Intel Core i5-12600K acompañado de una RTX 3070 Ti. Va en el mismo orden en el que conviene comprar, y uso ese build a lo largo del texto como ejemplo concreto de cada regla en acción. Al final no solo vas a tener una lista de partes, vas a entender por qué cada parte está ahí.\nPor dentro del build terminado: la motherboard AORUS Z690, la torre de aire Hyper 212, la memoria Vengeance RGB Pro y la RTX 3070 Ti, todo iluminado. Por qué la compatibilidad, y no el ensamble, es el verdadero reto # Cada componente de una PC tiene que cumplir con lo que le exigen sus vecinos. El procesador determina qué socket y qué chipset necesita la motherboard. La motherboard determina qué tipo de memoria es siquiera posible usar. La tarjeta de video determina cuánta potencia tiene que entregar la fuente de poder. El gabinete determina qué tan grande puede ser todo lo demás.\nNada de esto es adivinar. Los fabricantes publican exactamente qué es compatible con qué, y en cuanto sabes dónde buscar, elegir componentes se vuelve una serie de decisiones pequeñas y verificables en lugar de un salto de fe. Ese es el enfoque de esta guía: revisar la especificación, confirmar que coincide, pasar al siguiente componente.\nComo cada decisión acota la siguiente, hay un orden natural para tomarlas:\nEl procesador, que fija el socket y la generación del chipset. La motherboard, que fija el tipo de memoria y el tamaño físico. La tarjeta de video, que fija cuánta potencia debe entregar la fuente. El gabinete y el enfriamiento, que fijan qué cabe físicamente y qué tan bien respira todo. Aunque es tentador empezar por la tarjeta de video, porque es de la que todo mundo habla, empezar por el procesador es lo que evita que tengas que regresarte después. Si sigues la cadena en orden, cada componente que agregas ya viene acotado por los anteriores.\nCómo elegir cada componente (y por qué importa) # Procesador: deja que él te diga el chipset # Empieza por el procesador, porque de él depende casi todo lo demás. Cada fabricante indica, directamente en las especificaciones del producto, con qué generación de chipset es compatible. En los procesadores Intel Core, esa compatibilidad sigue el socket y un patrón de nombres para el chipset: sockets como LGA 1151, LGA 1200 y LGA 1700 (12ª generación), junto con chipsets que siguen el patrón H_x_10 / B_x_60 / Z_x_90, donde x marca la generación. En AMD Ryzen, el patrón equivalente es A_x_20 / B_x_50 / X_x_70 sobre el socket PGA AM4, con la salvedad de que la serie Ryzen 7000 pasó a un socket LGA y ya no es compatible con AM4.\nEn mi build: elegí el Intel Core i5-12600K, un chip de 12ª generación, con multiplicador desbloqueado, sobre socket LGA 1700. Siguiendo el patrón anterior, eso significaba que la motherboard tenía que ser de la serie 600, en mi caso una Z690, la gama más alta de esa generación (la letra Z del propio patrón Z_x_90 de Intel).\nMotherboard: socket, chipset y tamaño físico tienen que coincidir los tres # Una motherboard tiene que pasar tres filtros al mismo tiempo: el socket tiene que coincidir con el procesador, el chipset tiene que ser compatible con la generación del procesador, y el tamaño físico tiene que caber dentro del gabinete. Los tamaños van de mayor a menor: EATX, ATX, mini-ATX, mini-ITX.\nEn mi build: elegí la Gigabyte Z690 AORUS ELITE AX DDR4, una motherboard ATX construida sobre el chipset Z690 para LGA 1700. Hay un detalle en ese nombre que vale la pena ver con calma: esta motherboard existe en versión DDR4 y en versión DDR5, y no son intercambiables, lo cual nos lleva directo al siguiente componente.\nLa Z690 AORUS ELITE AX DDR4 junto al i5-12600K: un socket LGA 1700 con su chipset de la serie 600 correspondiente. RAM: DDR4 o DDR5, la decide la motherboard # El procesador no decide tu tipo de memoria, lo decide la motherboard, y actualmente ninguna motherboard soporta DDR4 y DDR5 al mismo tiempo. Esa decisión se toma en el momento en que eliges la motherboard, no cuando compras la memoria. Además, las especificaciones de la motherboard indican hasta qué velocidades puedes llegar en realidad, incluyendo perfiles con overclock (OC), así que conviene leerlas antes de pagar por una velocidad que la motherboard no va a poder usar.\nEn mi build: como elegí la versión DDR4 de la Z690 AORUS ELITE AX, mi memoria también tenía que ser DDR4: Corsair Vengeance RGB Pro DDR4, 2 x 8 GB para 16 GB en total, a 3600 MHz, y certificada Intel XMP para que la motherboard alcance esa velocidad sin necesidad de ajustarla manualmente.\n16 GB (2x8) de Corsair Vengeance RGB Pro DDR4 a 3600 MHz, elegidos según el tipo de memoria que soporta la motherboard. Almacenamiento: M.2 NVMe o SATA # El almacenamiento moderno se reduce casi siempre a SSD M.2, que pueden ser SATA o NVMe (Non-Volatile Memory Express), además del formato más antiguo SATA 3. Todas las M.2 son físicamente compatibles con cualquier generación de PCIe, pero revisa exactamente qué generación soporta tu motherboard, porque de eso depende si de verdad obtienes el rendimiento completo de la unidad o solo su piso de velocidad.\nEn mi build: usé una WD_BLACK SN850, un SSD NVMe de 1 TB en PCIe Gen4, con velocidad de lectura de hasta 7000 MB/s. Emparejar una unidad Gen4 con una motherboard que soporte M.2 Gen4, y no con un slot Gen3 más viejo, es justo el tipo de verificación que decide si esa velocidad es real o nada más teórica. Más adelante, en los resultados medidos, pongo a prueba esa cifra nominal sobre esta misma unidad.\nEl WD_BLACK SN850, un SSD NVMe de 1 TB en PCIe Gen4. Tarjeta de video: deja que ella defina tu fuente de poder # La tarjeta de video se conecta mediante un puerto PCI Express (3.0, 4.0, y así sucesivamente), y aquí hay un detalle que te ahorra muchos dolores de cabeza: todas las generaciones de PCIe son retrocompatibles, así que una tarjeta más nueva funciona sin problema en un puerto más viejo. Lo que sí importa de verdad para tu build es la potencia. En cuanto sepas la potencia pico de la tarjeta, la regla que yo sigo es simple: la fuente de poder debe tener una capacidad de al menos el doble de esa potencia pico. Una tarjeta con 200 W de pico, por ejemplo, necesita una fuente de al menos 400 W.\nEn mi build: elegí una ZOTAC GAMING GeForce RTX 3070 Ti Trinity OC, con 8 GB de memoria GDDR6X. Esa tarjeta fue la que definió el tamaño de la fuente de poder para todo lo demás.\nLa ZOTAC RTX 3070 Ti Trinity OC, el componente que definió el requerimiento de fuente de poder para todo el build. Fuente de poder: deja espacio para crecer # Una buena fuente de poder es modular en la medida de lo posible, porque eso significa cables individuales que solo conectas si los necesitas, lo cual reduce el desorden dentro del gabinete. Por dentro, conviene buscar PCBs separados para mejor eficiencia, y decidir entre un diseño monorriel o multirriel. Además, piensa más allá del build actual: dejar margen de expansión es lo que evita que una futura actualización te obligue a comprar otra fuente completa.\nEn mi build: elegí una Corsair RM750x, 750 W, certificada 80 PLUS Gold, y totalmente modular. Siguiendo mi propia regla de duplicar la potencia pico, eso deja un margen cómodo para la RTX 3070 Ti y todavía espacio real para crecer.\nLa Corsair RM750x: 750 W, totalmente modular, 80 PLUS Gold. Enfriamiento: aire o líquido # Todo build termina haciéndote la misma pregunta: ¿enfriamiento por aire o por líquido? Las dos son respuestas válidas, y la correcta depende del gabinete, del procesador y de qué tanto quieras meterte a armar un loop.\nEn mi build: usé un Cooler Master Hyper 212 RGB Black Edition, una torre de aire que viene con su propio controlador de ventilador RGB. Es el único disipador de CPU en esta máquina, sin ningún loop líquido de por medio.\nEl Cooler Master Hyper 212 RGB Black Edition, la torre de aire que enfría al i5-12600K. Gabinete: que quepa todo, buen flujo de aire y los detalles que suman # Un gabinete tiene que cumplir con más que solo verse bien: tamaño, disipación de calor y espacio para expansión futura importan igual. Como mínimo, busca 2 ventiladores, de preferencia 3 o 4. Antes de comprar, confirma que la tarjeta de video y la motherboard caben físicamente, y piensa desde antes en las temperaturas una vez que todo esté instalado. Además de eso, hay varios extras que vale la pena priorizar: slots removibles para la tarjeta de video, buena protección y organización de cables, un panel de vidrio templado, filtros de polvo, y un formato mid tower si buscas el mejor equilibrio entre espacio interior y lugar sobre el escritorio.\nEn mi build: todo quedó dentro de un Corsair iCUE 4000X RGB Tempered Glass Mid-Tower ATX, que aloja la motherboard ATX con espacio de sobra y cumple prácticamente todos los puntos de esa lista.\nEl Corsair iCUE 4000X recién salido de la caja, panel de vidrio templado todavía con el plástico protector. Ventiladores y RGB: flujo de aire, presión estática y equilibrados # No todos los ventiladores son intercambiables. Más allá de lo obvio, el tamaño (comúnmente 120 mm o 140 mm), los ventiladores están diseñados para uno de tres trabajos: flujo de aire, que mueven un volumen general de aire; presión estática, diseñados para empujar aire a través de una restricción como un radiador o un filtro denso; y equilibrados, que combinan ambas cosas.\nEn mi build: el iCUE 4000X viene con tres ventiladores frontales Corsair SP120 RGB ELITE Performance PWM, y yo agregué un par de controladores Corsair iCUE Lighting Node CORE para tener toda la iluminación RGB (los ventiladores, la memoria y el disipador) bajo un mismo sistema controlado por software.\nLos tres ventiladores frontales RGB que trae de fábrica el iCUE 4000X, visibles a través del vidrio. Guía rápida de conectores # Antes de empezar a conectar cualquier cosa, ayuda saber reconocer qué tienes enfrente:\nEPS de 8 pines: alimenta al procesador, aparte de la alimentación principal de la motherboard. Conectores CPU Fan / CPU Optional: pueden ser de 4 pines PWM (controlados por señal) o de 3 pines (regulados por voltaje). Conector RGB: blanco, de 4 pines a 12 V o de 3 pines a 5 V, y no son intercambiables entre sí. Conector de 24 pines: la alimentación principal de la motherboard. USB-C y USB 3.0: el USB 3.0 usa un conector físico distinto al del USB 2.0, así que revisa el cable del panel frontal de tu gabinete antes de dar por hecho que va a entrar. Conector SATA: para unidades SATA y algunos periféricos ópticos o de generaciones anteriores. Puerto PCIe de 16x o 1x: el de 16x para la tarjeta de video, el de 1x para tarjetas de expansión más pequeñas. Conector M.2: para tu SSD M.2, ya sea NVMe o SATA, montado directamente en la motherboard. La lista final de componentes: un build con i5-12600K y RTX 3070 Ti # Juntando todas las decisiones anteriores, esta es la lista completa de componentes de este build, fechado el 23 de abril de 2022:\nComponente Lo que elegí Gabinete Corsair iCUE 4000X RGB Tempered Glass Mid-Tower ATX (negro) CPU Intel Core i5-12600K (12ª gen, LGA 1700, desbloqueado) Motherboard Gigabyte Z690 AORUS ELITE AX DDR4 (rev. 1.0) Tarjeta de video ZOTAC GAMING GeForce RTX 3070 Ti Trinity OC, 8 GB GDDR6X RAM Corsair Vengeance RGB Pro DDR4, 2 x 8 GB (16 GB en total), 3600 MHz, Intel XMP Almacenamiento WD_BLACK SN850 NVMe SSD, 1 TB, PCIe Gen4 Fuente de poder Corsair RM750x, 750 W, 80 PLUS Gold, totalmente modular Disipador de CPU Cooler Master Hyper 212 RGB Black Edition (aire) Ventiladores del gabinete Corsair SP120 RGB ELITE Performance PWM, 120 mm Controlador RGB Corsair iCUE Lighting Node CORE (x2) Todos los componentes desempacados y acomodados antes de empezar el ensamble. Cada renglón de esa tabla se puede rastrear hasta una regla del checklist de arriba. El socket LGA 1700 del i5-12600K obligó a un chipset de la serie 600, por eso la motherboard es una Z690. Elegir la versión DDR4 de esa motherboard es la razón por la que la memoria es DDR4 y no DDR5. La motherboard ATX cabe en un gabinete mid tower ATX. Y los 750 W de la RM750x cumplen de sobra la regla de \u0026ldquo;al menos el doble de la potencia pico\u0026rdquo; para la RTX 3070 Ti. Nada de eso fue casualidad, es el mismo checklist de compatibilidad aplicado componente por componente.\nEnsamble y primer arranque: qué hacer si la PC enciende pero no da video # Cuando ya verificaste cada componente en papel, el ensamble es sobre todo trabajo paciente de desarmador. El momento que de verdad te pone a prueba llega después, cuando presionas el botón de encendido por primera vez y la pantalla se queda negra. A mí me pasó, y saber de antemano cómo salir de ahí probablemente te sirva más que cualquier otra sección de esta guía.\nActualiza el BIOS antes de confiar en la motherboard # Antes que cualquier otra cosa, actualicé el BIOS de la motherboard. Una actualización de firmware es el único paso que, en principio, puede dejarte con un ladrillo carísimo, así que merece una decisión pensada y no un acto reflejo. En mi caso el riesgo era bajo, y por razones que pude verificar en las especificaciones de la propia motherboard: la Z690 AORUS ELITE AX tiene Q-Flash Plus, que graba el firmware directamente desde una USB sin procesador, sin memoria y sin tarjeta de video instalados, y además trae DualBIOS, un segundo chip físico de BIOS que puede tomar el relevo si el principal se daña. Una motherboard que se puede recuperar de una actualización fallida sin siquiera tener un CPU funcionando convierte un paso intimidante en uno rutinario.\nRevisa si tu motherboard tiene esas dos funciones antes de empezar. Si las tiene, actualizar primero es el orden más limpio, porque arrancas desde un firmware que ya conoce tu procesador en lugar de descubrir un hueco de compatibilidad cuando ya está todo atornillado.\nEl primer encendido: sin señal de video # Y entonces llegó el momento que todo el que arma su primera PC reconoce. Presioné el botón de encendido, la máquina cobró vida, y el monitor respondió con absolutamente nada: sin imagen, nada más su foquito rojo. Sin señal de video.\nMi primera sospecha fue la tarjeta de video. Es el reflejo natural, porque la GPU es la pieza más grande, más cara y más llamativa dentro del gabinete, y es donde va conectado el cable del monitor. También resultó ser, como se ve, la sospecha equivocada.\nAísla una variable a la vez # En lugar de desarmar toda la máquina de un jalón, cambié una sola variable. Saqué la RTX 3070 Ti y arranqué con los gráficos integrados del i5-12600K, lo cual eliminó por completo de la ecuación al componente más complejo. Después reasenté los dos módulos de memoria en los mismos slots.\nArrancó. Ya con imagen en pantalla y con la causa identificada, volví a instalar la tarjeta de video y el build quedó terminado.\nHasta entonces, ya con una máquina que sabía estable, entré al BIOS y habilité XMP, el perfil de memoria que permite que los módulos corran a la velocidad para la que están calificados y no a la velocidad conservadora que la motherboard usa por default. Ese es el paso que convierte los 3600 MHz impresos en la caja de la memoria en un número que el sistema realmente usa. Dejarlo para el final es un buen hábito en general: primero haz que la máquina arranque de forma confiable y afínala después, para que si una configuración llega a dar problemas ya sepas que todo lo que está por debajo estaba bien.\nEse es todo el método, y vale la pena interiorizarlo: cambia una cosa, prueba, y solo entonces cambia la siguiente. Un primer arranque fallido no es una sentencia sobre tu build, es un sistema con una incógnita adentro, y cada componente que puedas quitar o volver a probar reduce la búsqueda.\nDos lecciones que te puedes llevar a tu propio build # Cuando una PC recién armada no da POST, sospecha de la memoria antes que de la tarjeta de video. Un módulo puede verse perfectamente instalado y aun así no estar asentado hasta el fondo, y esta es por mucho la causa más común de una pantalla negra en un primer armado. Reasentarla te cuesta cinco minutos, lo cual la vuelve la hipótesis más barata de descartar. Fíjate además en que la solución fueron los mismos slots, no unos distintos: el problema era el asentamiento, no la elección de slot. Una decisión de compatibilidad me dio una herramienta de diagnóstico que no había planeado. Elegí la versión \u0026ldquo;K\u0026rdquo; del i5-12600K por su multiplicador desbloqueado. Intel también vende una variante \u0026ldquo;KF\u0026rdquo;, el mismo procesador pero sin gráficos integrados, y si hubiera comprado esa no habría tenido forma alguna de sacar imagen en pantalla sin la mismísima tarjeta que estaba tratando de descartar. La GPU integrada se convirtió en mi segundo camino, independiente, para obtener video, que es justo lo que me permitió aislar el problema en un solo paso. Aunque el beneficio fue accidental, el hábito detrás no lo es: elegir la pieza que deja más puertas abiertas suele pagarte en situaciones que no anticipaste. Resultados medidos: temperaturas, consumo y rendimiento real # Una cosa es planear el build en papel y otra muy distinta es vivir con él. Así que si te preguntas qué entrega en realidad una máquina armada de esta forma, aquí están mediciones reales tomadas sobre esta misma computadora, años después de haberla ensamblado y con el mismo disipador de aire con el que salió al mundo. Cada cifra viene de la instrumentación del propio hardware bajo una carga controlada, y en cada caso digo con qué herramienta se tomó, porque nombrar el método de medición es justo lo que separa una medición de una afirmación.\nVale la pena saber algo más antes de leer los números: esta es una máquina de fábrica. El BIOS que le grabé el día que la armé en 2022 es el mismo firmware con el que ha corrido desde entonces, y más allá de activar el XMP no le moví nada. Sin overclock, sin afinaciones, solo cuatro años de uso normal. Eso es justamente lo que vuelve útiles estas cifras si estás planeando un build parecido, porque son lo que te entrega una máquina comparable tal como sale, no el premio de una sesión de tuneo.\nEl CPU: cómo se lleva el Hyper 212 con el i5-12600K # La prueba fue una carga sostenida que mantuvo los 16 hilos del i5-12600K al 100 %, con los sensores de la motherboard leídos por HWiNFO en modo sensors-only con logging a CSV, muestreada durante una ventana de estado estable de cinco minutos (150 muestras).\nEn reposo Bajo carga sostenida Temperatura promedio de núcleos 31.0 °C 54.6 °C Potencia del paquete 23 W 98.8 W Alrededor de esos dos números hay cuatro resultados que importan más que las temperaturas en sí:\nEl núcleo más caliente llegó a 62.8 °C en promedio, con un pico de 64 °C. El TjMAX del i5-12600K, la temperatura a la que el procesador empieza a protegerse, es de 100 °C. Con los núcleos promediando 54.6 °C, quedan alrededor de 45 °C de margen térmico (100 − 54.6 ≈ 45). Cero throttling térmico y cero eventos de límite de potencia en las 150 muestras. El procesador nunca fue obligado a bajar el ritmo. Los P-cores sostuvieron 4500 MHz durante toda la ventana, sin caídas. Los relojes sostenidos son la verdadera prueba de que un disipador va al paso, porque uno que no puede se delata como frecuencia que baja mucho antes que como una temperatura alarmante. Vuelve a la temperatura de reposo en menos de un minuto en cuanto se quita la carga. Dicho de otro modo, una buena torre de aire, y no un loop líquido, alcanzó y sobró para este procesador bajo una carga real pesada. Es un dato útil si estás sopesando ese mismo trade-off y te preguntas si enfriar por aire es un sacrificio.\nUna aclaración honesta sobre esa carga. El trabajo fue openssl speed rsa2048, forkeado una vez por hilo: carga pesada, realista y completamente entera. Pidió alrededor de 99 W, por debajo de los 125 W nominales del chip, así que un Prime95 con small FFT o un torture test con AVX-512 sin duda calentarían más. Lee estos números como carga real sostenida, no como el peor caso, y trata igual cualquier cifra que encuentres en internet: una temperatura sin la carga que la produjo no significa gran cosa.\nY otra aclaración honesta, ahora sobre la motherboard. HWiNFO reportó los dos límites de potencia, PL1 y PL2, en 4095 W, que es su manera de decir que no hay ningún límite: la motherboard Gigabyte viene de fábrica con los límites de potencia de Intel quitados, aunque la especificación del propio i5-12600K sea de 125 W PBP y 150 W MTP. Bajo esta carga no cambió nada, porque el procesador nunca pidió más de unos 99 W, pero con una carga pesada de tipo AVX sí cambiaría, y también es parte de por qué el renglón de \u0026ldquo;cero eventos de límite de potencia\u0026rdquo; de arriba se lee como se lee: no había límite que alcanzar. Si armas sobre una motherboard parecida, vale la pena abrir una herramienta de monitoreo una vez y revisar si el techo contra el que corre tu procesador lo decidió Intel o tu motherboard.\nLa GPU: la RTX 3070 Ti bajo inferencia de IA # Para la tarjeta de video usé una carga que hoy corre de forma habitual: servir modelos de lenguaje locales con Ollama, y leí la telemetría de la propia tarjeta con nvidia-smi muestreando durante inferencia sostenida.\nEn reposo Sirviendo un modelo Temperatura 41 °C 60 °C Consumo 12.6 W ~248 W (límite de 310 W) Bajo esa carga la tarjeta se mantuvo entre 1920 y 1935 MHz. Además, 60 °C en una GPU trabajando de forma constante es un lugar cómodo, y eso habla tanto del flujo de aire del gabinete, con tres ventiladores frontales alimentando a la tarjeta, como del disipador propio de la GPU.\n¿Fue acertada la fuente de 750 W? # Aquí es donde las mediciones le pagan a la planeación, porque esos 248 W son justo el dato que le faltaba a la regla de dimensionamiento sobre la que está construida toda esta guía. Sumando:\n248 W medidos en la tarjeta de video bajo carga sostenida 150 W de potencia máxima en turbo del i5-12600K ~50 W para todo lo demás: la unidad de almacenamiento, los ventiladores, la memoria y la propia motherboard Eso da aproximadamente 450 W de pico estimado contra una fuente de 750 W, es decir, la máquina opera cerca del 60 % de la capacidad de la fuente en su momento más exigente. Tómalo como una estimación y nada más, porque medí los componentes por separado y no el sistema completo en la toma de corriente; el número real necesitaría un medidor de enchufe. Aun así, confirma la regla: duplicar la potencia pico de la tarjeta de video dio una fuente con margen de verdad, suficiente para una futura actualización de GPU sin tener que comprar otra fuente.\nQué produce en realidad ese hardware # Los números de calor y watts solo son interesantes por el trabajo que hay debajo de ellos. Generando 200 tokens con temperature 0 en Ollama sobre esa RTX 3070 Ti, con la velocidad tomada de los propios campos de tiempo que devuelve el endpoint /api/generate de Ollama (eval_count entre eval_duration) y no de un cronómetro ni de un benchmark de terceros:\nModelo Velocidad de generación llama3.2 194.9 tok/s qwen3.5:4b 97.1 tok/s qwen3.5 (6.6 GB) 22.9 tok/s La caída del último es el renglón más instructivo de la tabla. Un modelo de 6.6 GB contra 8 GB de VRAM deja casi nada de margen, y la velocidad se desploma en consecuencia. Es la misma lección de todas las demás secciones de esta guía, llegando una vez más: la especificación que elegiste al comprar, en este caso 8 GB de GDDR6X, es el techo con el que te terminas topando en la práctica.\nEl almacenamiento: qué entrega en realidad el SN850 # La caja promete hasta 7000 MB/s de lectura, y poner a prueba una cifra así exige una precaución. Con 32 GB de RAM en la máquina, una lectura normal la habría atendido la caché de archivos de Windows, y habría terminado midiendo mi memoria en lugar de mi disco. Así que escribí y leí un archivo de 4 GiB en C:, que es el propio SN850, saltándome la caché (FILE_FLAG_NO_BUFFERING) para obligar a que cada petición llegara al dispositivo. El método es lo que vuelve real a la cifra, y es la diferencia entre una prueba seria y un número que nada más te hace sentir bien.\nOperación Buffer Medido Nominal WD Escritura secuencial 4 MiB 5,031 MB/s 5,300 MB/s Lectura secuencial 1 MiB 4,098 MB/s n/d Lectura secuencial 4 MiB 5,391 MB/s n/d Lectura secuencial 16 MiB 5,841 MB/s 7,000 MB/s Hay dos resultados en esa tabla que valen más que la velocidad de portada:\nEl tamaño del buffer mueve la lectura un 43%. Pasar de un buffer de 1 MiB a uno de 16 MiB lleva a la unidad de 4,098 a 5,841 MB/s (5,841 ÷ 4,098 ≈ 1.43). Con peticiones chicas el cuello de botella no es el disco, es la latencia de cada petición individual, así que una prueba que reporta un NVMe \u0026ldquo;lento\u0026rdquo; quizá nada más le está pidiendo los datos en pedazos demasiado pequeños para mantenerlo ocupado. La escritura llega prácticamente a especificación y la lectura no. La escritura queda en 95% de su valor nominal (5,031 ÷ 5,300 ≈ 0.95), mientras que la mejor lectura alcanza 83% de los 7,000 MB/s de la caja (5,841 ÷ 7,000 ≈ 0.83). La explicación más probable no es la edad de la unidad: estaba al 97.3% de su capacidad, con 25.5 GB libres de 930.5 GB. Un SSD tan lleno se queda sin espacio para su caché SLC y sin bloques libres donde trabaje el recolector de basura, y esas dos cosas son justo las que el número nominal da por hechas. Si te llevas un solo hábito práctico de esta sección, que sea ese: un SSD lleno es un SSD lento, así que déjale espacio libre de verdad. Sobre el estado de la unidad después de cuatro años de uso diario, sus propios contadores de salud reportan 0% de desgaste, 41 °C al momento de la prueba y 84 °C como la temperatura más alta que ha registrado en su vida. La resistencia del disco, al menos con este uso, no ha resultado ser el factor limitante.\nCuánto tarda en arrancar, y en qué se va realmente ese tiempo # El tiempo de arranque es la cifra que todo mundo presume y casi nadie mide bien, normalmente porque de por medio hay un cronómetro y algo de optimismo. Windows, en cambio, lleva el registro solito: el log Microsoft-Windows-Diagnostics-Performance/Operational escribe un evento 100 en cada arranque, con las fases ya separadas. Al leerlo salieron 12 arranques reales entre el 18 de julio y el 11 de agosto de 2026, sin cronómetro por ningún lado.\nFase Mediana Ruta principal (del botón de encendido a un escritorio usable) 19.7 s Post-arranque (los programas de inicio cargando después) ~36 s Total 56.2 s En esos 12 arranques la ruta principal fue de 17.3 a 38.4 s y el total de 44.1 a 76.5 s, con cero eventos de degradación registrados.\nLo interesante no es el total, es el reparto. El tramo que de verdad depende de los componentes de los que trata esta guía, el NVMe y el procesador, son unos 20 segundos. Los otros 36 son programas que yo instalé cargando después de que el escritorio ya apareció. Dicho de otro modo, esta máquina no tarda en arrancar por el hardware que elegí con tanto cuidado, tarda por lo que le puse encima. Vale la pena recordarlo la próxima vez que una computadora se sienta lenta al encender: la lista de componentes casi nunca es la culpable, y la lista de programas de inicio casi siempre sí.\nLo que ganas al armarla tú mismo # La máquina terminada es solo la mitad de la recompensa. La otra mitad es que sales de ahí entendiendo de verdad tu propia computadora, de primera mano y no por haberlo leído en una ficha técnica: por qué un socket tiene que coincidir con un chipset, por qué el tipo de memoria es una decisión de la motherboard y no una preferencia, y por qué los watts de una fuente de poder son una restricción de ingeniería real y no un número que se calcula al ojo.\nEn concreto, recorrer este checklist te deja cuatro cosas que una PC prearmada rara vez te da:\nUna computadora hecha a la medida de lo que realmente haces, porque elegiste cada parte contra tu propio uso y no contra un paquete armado por marketing. Conocimiento que se transfiere, porque leer una hoja de especificaciones y verificar una afirmación es la misma habilidad, se trate de una motherboard, de un microcontrolador o de un sensor. Una ruta de actualización diseñada a propósito, desde los watts de sobra en la fuente hasta los slots libres en la motherboard. La confianza para volver a abrirla, porque una máquina que tú armaste es una máquina que puedes diagnosticar, limpiar y reparar. En mi caso, aplicar mi propio checklist a una compra real (un i5-12600K, una motherboard Z690, memoria DDR4 y una fuente dimensionada correctamente para la RTX 3070 Ti) fue la prueba de que el método funciona de principio a fin y no solo en el papel. Cada componente llegó ya verificado contra sus vecinos, así que nada de lo que estaba en esa caja fue una apuesta.\nLos trade-offs que vale la pena nombrar # Ningún build es una suma de decisiones perfectas, y ser honesto sobre los trade-offs también es parte de la ingeniería:\nDDR4 en lugar de DDR5. La misma Z690 AORUS ELITE AX existe en versión DDR5. Elegir la versión DDR4 significó construir sobre el estándar de memoria maduro y disponible en ese momento, a cambio de no estar en la plataforma más nueva. Enfriamiento por aire en lugar de un loop líquido. El Hyper 212 es una torre sencilla y de bajo mantenimiento, sin bomba ni refrigerante de qué preocuparse, y es un punto de diseño distinto al de un loop líquido. Una fuente dimensionada para el futuro, no solo para hoy. Duplicar la potencia pico implica pagar por watts que el build actual no usa, y ese margen es justo lo que convierte una futura actualización en un cambio de componente en vez de en una segunda compra. Un mid tower en lugar de un gabinete compacto. Ocupa más espacio en el escritorio que un build mini-ITX, y a cambio da lugar para la motherboard ATX, la torre de aire, los ventiladores frontales y lo que venga después. Lo que me dejó este proyecto # Lo que se me quedó no es la lista de partes, es el hábito detrás de ella: ir a la fuente original, verificar el dato y solo entonces comprometerse. Además, este build fue un buen recordatorio de que una computadora es un sistema y no un montón de piezas, y de que las restricciones interesantes siempre viven en las interfaces entre componentes: el socket, el estándar de memoria, el presupuesto de potencia y el volumen físico del gabinete. Es el mismo instinto que aplico en sistemas embebidos y en cualquier proyecto donde la curiosidad, la paciencia, la lectura cuidadosa y la disposición a equivocarme en papel antes de equivocarme con dinero terminan pagando. Cada error que atrapas en la etapa de planeación es un error que nunca vas a tener que pagar en hardware.\nLa máquina terminada, ensamblada y funcionando: los tres ventiladores frontales de entrada, la torre Hyper 212 y la memoria RGB, todo visible a través del vidrio. Qué exploraría después # Hacer overclock al i5-12600K, ya que es un chip de la serie K con multiplicador desbloqueado y la Z690 AORUS ELITE AX lo soporta. Una plataforma DDR5 en un próximo build, ahora que las motherboards y memorias DDR5 ya maduraron desde entonces. Mejorar la organización de cables, aprovechando los canales del iCUE 4000X para que el interior quede tan limpio como merece la iluminación RGB. Afinar la curva de ventiladores y la iluminación RGB desde el software iCUE de Corsair, ahora que ya están instalados los controladores Lighting Node CORE. Regresar la memoria a su velocidad nominal. Después le agregué un segundo par de módulos de otro kit, y la motherboard acomodó los cuatro al perfil del kit más lento en lugar de los 3600 MHz a los que está calificado el par Corsair. Mezclar kits te cuesta la velocidad del más rápido, y esa es una regla de compatibilidad que aprendí después de este build y no durante. La solución limpia es un solo kit parejo, no dos que apenas conviven. Una vez armada la máquina, la pregunta más interesante es a qué la vas a poner a trabajar. Esta misma máquina es la que corre mi asistente de IA privado: la misma RTX 3070 Ti alrededor de la cual dimensioné la fuente de poder también sirve modelos de lenguaje locales, completamente en mi propio hardware y sin mandarle un solo prompt al servidor de alguien más. Documenté todo ese proceso en Despliega tu IA privada con Ollama.\nSi estás planeando tu propio build, me encantaría saber qué componentes estás comparando entre sí, y por qué.\n","date":"23 de abril de 2022","externalUrl":null,"permalink":"/es/posts/como-armar-tu-propia-pc/","section":"Posts","summary":"¿Estás pensando en armar tu propia PC en lugar de comprar una prearmada? Si algo te detiene, seguramente no es usar el desarmador. Es pararte frente a una pared de componentes sin saber cuáles funcionan juntos.\n","title":"Cómo armar tu propia PC: guía para elegir componentes compatibles","type":"posts"},{"content":"","date":"23 abril 2022","externalUrl":null,"permalink":"/tags/gaming-pc/","section":"Tags","summary":"","title":"Gaming-Pc","type":"tags"},{"content":"","date":"23 abril 2022","externalUrl":null,"permalink":"/tags/pc-building/","section":"Tags","summary":"","title":"Pc-Building","type":"tags"},{"content":"","date":"23 de abril de 2022","externalUrl":null,"permalink":"/es/tags/pc-gamer/","section":"Tags","summary":"","title":"Pc-Gamer","type":"tags"},{"content":"","date":"29 de noviembre de 2020","externalUrl":null,"permalink":"/es/tags/arduino/","section":"Tags","summary":"","title":"Arduino","type":"tags"},{"content":"","date":"29 noviembre 2020","externalUrl":null,"permalink":"/tags/biomedical-engineering/","section":"Tags","summary":"","title":"Biomedical-Engineering","type":"tags"},{"content":"¿Alguna vez te has preguntado qué pasa realmente dentro del monitor que cuelga sobre una cama de hospital, ese que dibuja una línea verde con cada latido mientras un número parpadea en la esquina?\nDetrás de esa pantalla hay una cadena de sensores, amplificadores, filtros y decisiones de diseño muy deliberadas. Puedes construir tú mismo una versión simplificada de esa cadena, y al terminar vas a entender cómo funciona un monitor de cabecera de una forma que ninguna clase ni ninguna hoja de datos te puede enseñar.\nPara eso es esta guía. Vas a adquirir tres señales fisiológicas al mismo tiempo (electrocardiograma, fotopletismografía y temperatura), acondicionar cada una en el dominio analógico y dibujar las tres en vivo en una sola pantalla TFT-LCD, tal como lo hace un monitor real. Muchos proyectos de salud con Arduino se apoyan en módulos ya armados que esconden todo el trabajo analógico. Este no: la etapa frontal está hecha con componentes discretos, así que cada ganancia, cada frecuencia de corte y cada offset son decisiones que tú tomas y que puedes defender.\nYo construí esta versión para BI3014.1, el Laboratorio de Tecnologías Biomédicas del Tecnológico de Monterrey, Campus Ciudad de México. Todo lo que sigue es el diseño que terminó funcionando, incluyendo los obstáculos que lo fueron moldeando.\nUna aclaración importa más que cualquier circuito de este post: esto es un prototipo didáctico construido para una práctica universitaria, no un dispositivo médico. Nunca se diseñó, probó ni certificó para diagnosticar o monitorear pacientes, y no debe usarse con ese fin. Para lo que sí sirve, y muy bien, es para entender de forma práctica cómo está construido un monitor de signos vitales.\nLas tres señales corriendo al mismo tiempo en la pantalla TFT-LCD: temperatura en amarillo, fotopletismografía (PLETH) en cian y electrocardiograma (ECG) en verde. Qué hace en realidad un monitor de signos vitales # Antes de diseñar cualquier cosa, conviene saber qué estás imitando.\nEl CENETEC (Centro Nacional de Excelencia Tecnológica en Salud) define un monitor de signos vitales como un dispositivo que permite detectar, procesar y desplegar de forma continua los parámetros fisiológicos de un paciente. En la práctica, un monitor adquiere una señal del cuerpo, la amplifica, la acondiciona y la despliega en pantalla.\nLa mayoría de los monitores clínicos son modulares, para que el médico elija qué variables seguir: ECG, frecuencia respiratoria, presión arterial no invasiva o invasiva, temperatura, saturación de oxígeno (SpO2), saturación venosa de oxígeno, gasto cardiaco, dióxido de carbono, presión intracraneal o presión de gases en la vía aérea durante anestesia. Según su movilidad se dividen en monitores fijos (anestesia, adultos, neonatales) y monitores de transporte, ya sea intrahospitalario, interhospitalario o en ambulancia.\nEn su estructura, sin embargo, todos se reducen a cuatro piezas: una fuente de alimentación, una unidad de procesamiento de información, una pantalla y un módulo de adquisición por cada parámetro. Esa estructura es justo el plano que vas a escalar a algo que un Arduino pueda manejar.\nLa arquitectura: cinco bloques, no un solo circuito enredado # Organiza el proyecto en cinco bloques: tres bloques de adquisición de señal (ECG, PLETH y temperatura), un bloque de integración construido alrededor de un Arduino MEGA 2560 y un bloque de visualización, una pantalla TFT-LCD.\nLos bloques de ECG y PLETH pasan por tres etapas cada uno: adquisición de la señal, filtrado y acondicionamiento analógico, y conversión analógico-digital. La temperatura se salta la etapa intermedia por completo y va directo del sensor al ADC, porque el LM35 ya entrega una señal limpia y lineal que no necesita acondicionamiento.\nPensar en bloques, y no en un solo diagrama enredado, fue la decisión de ingeniería más útil que tomé, y es la que más te recomiendo. Te permite diseñar, construir y depurar cada cadena de adquisición por separado antes de preocuparte por cómo van a compartir un mismo Arduino y una misma pantalla.\nLos bloques tampoco pasaron directo al protoboard. Primero simulé los circuitos en Proteus y Tinkercad, y una vez armados los verifiqué en la mesa de trabajo con osciloscopio y multímetro. Simular antes de armar y medir después de armar es una costumbre que vale la pena conservar en cualquier proyecto analógico: la simulación es barata de iterar, y los instrumentos son los que te dicen qué está haciendo de verdad tu circuito y no lo que supusiste que haría.\nLa arquitectura de cinco bloques: tres cadenas de adquisición alimentando al Arduino MEGA 2560, que a su vez controla la pantalla TFT-LCD. Qué necesitas # Arduino MEGA 2560, el bloque de integración que lee todos los canales y controla la pantalla. Una pantalla TFT-LCD con controlador HX8357, para el bloque de visualización. Electrodos de Ag/AgCl con sus latiguillos, para el ECG. Un amplificador de instrumentación AD620, para la etapa frontal del ECG. Un LED infrarrojo IR333C y un fototransistor PT333-3B, para la etapa frontal de PLETH. Un amplificador operacional TL081, para la etapa de acondicionamiento de PLETH. Un sensor de temperatura LM35. Dos baterías de 9 V, para la fuente bipolar que necesita la etapa de instrumentación. Un segundo Arduino UNO, usado únicamente como fuente de 5 V (más abajo explico por qué). Las tres cadenas de señal de un vistazo # Señal Transductor Amplificación Filtrado Pin del Arduino ECG Electrodos de Ag/AgCl, derivación II de Einthoven AD620, ganancia 1000 V/V, offset de 2.5 V Pasabanda, 1.2 a 150 Hz A12 PLETH LED IR333C y fototransistor PT333-3B Etapa con TL081, ganancia 180 (ajustada experimentalmente) Pasabanda, 1.2 a 150 Hz A8 Temperatura LM35 Ninguna, la salida del sensor ya es usable Ninguno A10 La cadena de ECG: convertir milivolts en algo que el ADC pueda ver # La electrocardiografía mide la actividad eléctrica del corazón, y todo empieza con el transductor: un par de electrodos de Ag/AgCl (plata / cloruro de plata) que convierten la señal fisiológica en una señal eléctrica. Usé la configuración de la derivación II de Einthoven para la adquisición.\nEste es el problema que tienes que resolver. Un ECG típico de un adulto tiene una amplitud de apenas 0.5 a 4 mV, en un rango de frecuencia de 0.05 a 150 Hz. Si metes eso directo a un Arduino no vas a ver más que ruido, porque la señal es miles de veces más pequeña que el paso del ADC.\nLa amplificación la aporta un amplificador de instrumentación AD620, que lee la señal de forma diferencial directamente desde los electrodos. Que sea diferencial importa: es lo que rechaza la interferencia que ambos electrodos captan en modo común, que en un cuarto lleno de cableado eléctrico es casi todo lo que captan. Configuré la ganancia en 1000 V/V con un offset de 2.5 V, de modo que la señal amplificada queda cómodamente entre 0 y 5 V, centrada dentro del rango de entrada del Arduino en lugar de recortarse contra tierra.\nDespués de la amplificación, la señal pasa por un filtro pasabanda de 1.2 a 150 Hz para quitar la deriva de la línea base y el ruido de alta frecuencia, y la señal acondicionada se lee en el pin analógico A12.\nEl circuito de adquisición de ECG: amplificador de instrumentación AD620, electrodos y latiguillos sobre el protoboard. La cadena de PLETH: leer el pulso con luz # La fotopletismografía mide los cambios pulsátiles en el volumen de sangre, lo cual te permite recuperar el ritmo cardiaco de forma óptica en lugar de eléctrica. El transductor es un LED infrarrojo IR333C que ilumina un lecho capilar (la yema de un dedo, en este caso), junto con un fototransistor PT333-3B del otro lado que detecta la luz transmitida y la convierte en señal eléctrica. Con cada latido, las pulsaciones arteriales cambian cuánta luz se absorbe, y esa variación es la señal que buscas.\nUsé el fototransistor en configuración de emisor común, alimentando una etapa de acondicionamiento construida con un amplificador operacional TL081. La ganancia, 180, se determinó de forma experimental, ajustada para que el trazo se viera claro en pantalla y no derivada analíticamente.\nVale la pena nombrar dos compromisos honestos, porque son el tipo de decisión que distingue un prototipo que funciona de uno equivocado:\nAquí la PLETH es cualitativa, por decisión propia. Son tantos los factores externos que afectan la absorción de luz que resulta una herramienta poco confiable para medir el volumen absoluto de sangre. La traté estrictamente como un indicador cualitativo de flujo sanguíneo, que es exactamente lo suficiente para visualizar una onda de pulso y nada más de lo que el montaje puede sostener con honestidad.\nEl filtro es compartido, no óptimo. La PLETH normalmente se filtra entre 0.5 y 5 Hz. Por simplicidad la filtré en la misma banda de 1.2 a 150 Hz que usé para el ECG, reutilizando un solo diseño de filtro en ambas cadenas de adquisición. Eso cuesta algo de rechazo de ruido y compra un montaje mucho más simple, que era la decisión correcta para un prototipo de laboratorio. La señal se lee en el pin analógico A8.\nEl circuito de PLETH: un LED IR333C y un fototransistor PT333-3B montados en un clip para dedo, conectados a la etapa de acondicionamiento con el TL081. La cadena de temperatura: la que se mantiene simple # La temperatura es, por diseño, la cadena más sencilla de las tres, y eso es una ventaja. Usé un sensor LM35, elegido por su precisión, su rango de trabajo y su respuesta lineal, que elimina la necesidad de cualquier curva de calibración. Su exactitud ronda los 0.25 °C, que en realidad es más fina que lo que alcanza a resolver el Arduino: con la referencia por defecto de 5 V, un paso del ADC de 10 bits equivale a unos 4.88 mV, y con los 10 mV/°C que entrega el LM35 ese paso se traduce en cerca de 0.49 °C. Dicho de otro modo, quien fija la resolución de la medición es la conversión y no el sensor, y esa resolución se lee directo en el código: la constante 500.0 / 1023 del sketch de abajo es justamente el tamaño del paso, 0.489 °C por cuenta. Ese es el resultado buscado y no un compromiso, porque medio grado por paso sobra para la temperatura corporal humana, que es justo lo que este monitor existe para desplegar, y una lectura con un solo decimal dentro del rango clínicamente interesante no pide nada más fino. Más bits en el ADC solo habrían resuelto dígitos que la exactitud del propio sensor no respalda, es decir, precisión falsa: números que se ven más certeros de lo que realmente es la medición.\nComo el LM35 ya entrega un voltaje analógico limpio y proporcional a la temperatura, se salta por completo el filtrado y el acondicionamiento, y se lee directamente en el pin analógico A10. La conversión de cuentas del ADC a grados Celsius es la línea que vas a encontrar en el sketch de abajo:\nT = LM35 * (500.0 / 1023) donde LM35 guarda el número de pasos medidos por el ADC de 10 bits. El 500 tampoco es un número mágico: con la referencia analógica de 5 V, la escala completa corresponde a 5000 mV y, como el LM35 entrega 10 mV/°C, esa escala completa abarca 500 °C. Dividir esos 500 °C entre las 1023 cuentas del ADC es lo que convierte las cuentas crudas en grados Celsius, y es la misma aritmética del tamaño de paso de arriba vista desde el otro lado: el voltaje de referencia y la escala de salida del sensor resumidos en una sola cifra.\nUn pequeño refinamiento hace que la lectura sea agradable a la vista. La variación natural entre muestras hace que el número en pantalla brinque todo el tiempo, así que el valor que se despliega es el promedio de las últimas cinco mediciones de temperatura, escrito con un decimal. Ese promedio se actualiza cinco veces por cada ciclo del programa: en el sketch, la rama de la temperatura se ejecuta cada vez que el contador de columnas x1 es múltiplo de 63, es decir en 0, 63, 126, 189 y 252 conforme el trazo recorre la pantalla. Son dos cincos distintos y conviene no confundirlos: uno es cuántas muestras entran al promedio y el otro es cada cuánto se vuelve a dibujar el resultado.\nEl LM35, conectado directamente al Arduino MEGA sin ninguna etapa intermedia de acondicionamiento. La alimentación: el problema que no vi venir # Alimentar tres cadenas de adquisición tan distintas desde una sola tarjeta resultó más complicado que cualquiera de los diseños de filtro, y ahí se fue la mayor parte de mi tiempo de laboratorio.\nLa etapa de instrumentación con el AD620 necesitaba una fuente bipolar, así que la alimenté con dos baterías de 9 V conectadas como un riel dividido de -9 V a +9 V. El LM35, el LED infrarrojo, el fototransistor y la etapa sumadora de 2.5 V del circuito de ECG necesitaban un 5 V estable, pero un solo Arduino no podía entregar suficiente corriente para todos a la vez. La solución fue agregar un segundo Arduino UNO dedicado exclusivamente a suministrar ese riel de 5 V, lo cual resolvió el problema de forma limpia, aunque no elegante. Por último, el shield de la pantalla TFT-LCD funciona con el riel de 3.3 V del propio Arduino MEGA.\nAl inicio también intenté alimentar todo desde una sola fuente de banco con varios voltajes. No funcionó. El ruido de la línea eléctrica se filtraba a las señales de una forma que las baterías nunca provocaron, probablemente por los filtros Notch: sí formaban parte del diseño desde el principio, pero nunca quedaron bien calibrados, porque no tenía a la mano el equipo necesario para caracterizarlos. Volver a alimentar con baterías las etapas analógicas sensibles lo resolvió de inmediato.\nSi vas a construir tu propia etapa frontal, tómalo como un atajo más que como una advertencia. Por algo tanta instrumentación biomédica sigue dependiendo de fuentes aisladas y con respaldo de batería en la entrada, y vas a sentir ese motivo la primera vez que veas 60 Hz montados encima de un complejo QRS.\nDibujar tres señales al mismo tiempo en una pantalla TFT-LCD # El bloque de visualización es una pantalla TFT-LCD basada en un controlador HX8357, manejada con las librerías Adafruit_GFX y Adafruit_TFTLCD. Llegar hasta ahí fue todo un proyecto aparte.\nNo existe una sola librería bien documentada que funcione con todas las variantes de esta pantalla, y el controlador que más se menciona en internet es el ILI9341, no el HX8357 que en realidad tenía. Identificar qué controlador traía mi pantalla, antes de que algo se dibujara correctamente, fue una de las sesiones de depuración más difíciles de todo el proyecto. Si tu pantalla solo se ve en blanco, sospecha del controlador antes que del cableado.\nUna vez que la pantalla ya se comunica con el Arduino, la lógica de dibujo es sorprendentemente simple. La PLETH y el ECG se dibujan como gráficas que se desplazan en vivo: por cada muestra nueva, el programa traza una línea recta desde la posición de la muestra anterior hasta la actual. Cuando el trazo llega al borde derecho de la pantalla, ambas gráficas se borran y el dibujo vuelve a empezar desde el borde izquierdo, lo cual marca el final de un ciclo del programa. La temperatura, al ser un número y no una forma de onda, simplemente se imprime como texto.\nEn pantalla, la temperatura aparece en amarillo en la esquina superior derecha, la PLETH en cian en la mitad superior y el ECG en verde en la mitad inferior. Ese esquema de colores no es decoración: es lo que permite leer el arreglo de un vistazo, igual que en un monitor real.\nAquí está el sketch completo de Arduino, TFTLCDemi.ino. Los comentarios dentro del código están en español, tal como los escribí originalmente, y dejé el código funcionando sin tocar en lugar de ordenarlo después:\n#include \u0026lt;Adafruit_GFX.h\u0026gt; // Core graphics library #include \u0026lt;Adafruit_TFTLCD.h\u0026gt; // Hardware-specific library #define LCD_CS A3 // Chip Select goes to Analog 3 #define LCD_CD A2 // Command/Data goes to Analog 2 #define LCD_WR A1 // LCD Write goes to Analog 1 #define LCD_RD A0 // LCD Read goes to Analog 0 #define LCD_RESET A4 // Can alternately just connect to Arduino\u0026#39;s reset pin // For the Arduino Mega, use digital pins 22 through 29 // (on the 2-row header at the end of the board). // D0 connects to digital pin 22 // D1 connects to digital pin 23 // D2 connects to digital pin 24 // D3 connects to digital pin 25 // D4 connects to digital pin 26 // D5 connects to digital pin 27 // D6 connects to digital pin 28 // D7 connects to digital pin 29 //Variables int Ox[316]; int ECG[316]; int x1 = 0; //Contador //Temperatura int LM35; float TEMPERATURA; float T1 = 0; float T2 = 0; float T3 = 0; float T4 = 0; #define BLACK 0x0000 #define BLUE 0x001F #define RED 0xF800 #define GREEN 0x07E0 #define CYAN 0x07FF #define MAGENTA 0xF81F #define YELLOW 0xFFE0 #define WHITE 0xFFFF Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET); void setup() { // put your setup code here, to run once: Serial.begin(9600); tft.reset(); tft.begin(0x8357); tft.setRotation(1); // establece posicion vertical tft.fillScreen(BLACK); // fondo de pantalla de color negro tft.setTextColor(YELLOW, BLACK); // texto en color amarillo tft.setTextSize(3); // escala de texto en 3 tft.setCursor(270, 30); // ubica cursor tft.print((char)247); tft.setTextSize(4); // escala de texto en 4 tft.setCursor(290, 30); // ubica cursor tft.print(\u0026#39;C\u0026#39;); // tft.fillRect(0, 0, tft.width(), 20, CYAN); // rectangulo azul naval a modo de fondo de titulo // tft.setTextColor(WHITE); // color de texto en blanco // tft.setTextSize(2); // escala de texto en 2 // tft.setCursor(25, 6); // ubica cursor // tft.print(\u0026#34;Panel de control\u0026#34;); // imprime texto // tft.setCursor(0, 35); // ubica cursor // tft.print(\u0026#34;Zona: 1\u0026#34;); // imprime texto // tft.setCursor(0, 55); // ubica cursor // tft.print(\u0026#34;Temperatura Humedad\u0026#34;); // imprime texto // tft.drawLine(0, 170, 240, 170, RED); // linea horizontal de color rojo // tft.setCursor(0, 185); // ubica cursor // tft.print(\u0026#34;Zona: 2\u0026#34;); // imprime texto // tft.setCursor(0, 205); // ubica cursor // tft.print(\u0026#34;Temperatura Humedad\u0026#34;); // imprime texto } void loop() { tft.fillRect(0, 70, tft.width(), tft.height() - 60, BLACK); // Se borra el display tft.setTextColor(CYAN, BLACK); // texto en color amarillo tft.setTextSize(1); // escala de texto en 3 tft.setCursor(10, 60); // ubica cursor tft.print(\u0026#34;PLETH\u0026#34;); tft.setTextColor(GREEN, BLACK); // texto en color amarillo tft.setTextSize(1); // escala de texto en 3 tft.setCursor(10, 170); // ubica cursor tft.print(\u0026#34;ECG\u0026#34;); while ( x1 \u0026lt; 315 ) { // Leer temperatura if (x1 % 63 != 0) { LM35 = analogRead(10); TEMPERATURA = (LM35 * 500.0) / 1023; //Fórmula para calcular la temperatura // SUMA = TEMPERATURA + SUMA; T4 = T3; T3 = T2; T2 = T1; T1 = TEMPERATURA; delay(1); } else { LM35 = analogRead(10); TEMPERATURA = (LM35 * 500.0) / 1023; //Fórmula para calcular la temperatura // SUMA = TEMPERATURA + SUMA; TEMPERATURA = (TEMPERATURA + T1 + T2 + T3 + T4) / 5; //Escribir en TFTLCD tft.setTextColor(YELLOW, BLACK); // texto en color amarillo tft.setTextSize(4); // escala de texto en 4 tft.setCursor(170, 30); // ubica cursor tft.print(TEMPERATURA, 1); //Temperatura con 1 decimal delay(2); // SUMA = 0; //Se borra la suma de las temperaturas } //Leer ECG ECG[x1 + 1] = analogRead(12); ECG[x1 + 1] = map(ECG[x1 + 1], 0, 1023, 0, 50); tft.drawLine( x1 + 4, 230 - ECG[x1], x1 + 5, 230 - ECG[x1 + 1], GREEN); delay(10); //Leer Pulsímetro Ox[x1 + 1] = analogRead(8); Ox[x1 + 1] = Ox[x1 + 1] * 6; if (Ox[x1 + 1] \u0026gt; 1023) { Ox[x1 + 1] = Ox[x1]; } else { Ox[x1 + 1] = map(Ox[x1 + 1], 0, 1023, 0, 50); tft.drawLine( x1 + 4, 120 - Ox[x1], x1 + 5, 120 - Ox[x1 + 1], CYAN); } // Ox[x1 + 1] = analogRead(8); // Ox[x1 + 1] = Ox[x1 + 1] * 6; // Ox[x1 + 1] = map(Ox[x1 + 1], 0, 1023, 0, 50); // tft.drawLine( x1 + 4, 120 - Ox[x1], x1 + 5, 120 - Ox[x1 + 1], CYAN); x1++; delay(10); // demora de 10 mseg. } ECG[0] = ECG[x1]; //Se guarda el último valor medido Ox[0] = Ox[x1]; x1 = 0; } Un detalle de tiempos que te va a ahorrar horas # El ADC del Arduino tiene un tiempo de conversión de 13 ciclos de reloj, y cada llamada a analogRead() necesita ese tiempo para estabilizarse antes de cambiar al siguiente canal. Si te saltas esa espera, o lees canales más rápido de lo que el ADC puede multiplexar entre ellos, obtienes lecturas incorrectas o crosstalk entre canales, donde una señal se filtra visiblemente hacia otra. Por eso el ciclo de adquisición de arriba está lleno de llamadas a delay(), y es lo primero que debes revisar si tu trazo de ECG empieza a pulsar al ritmo de la PLETH.\nCon qué te quedas al final # La recompensa es una pantalla que se comporta como aquello que querías imitar: tres variables fisiológicas, actualizándose en vivo y legibles de un vistazo.\nEn mi montaje, las tres señales aparecieron al mismo tiempo en la pantalla TFT-LCD, que era todo el punto. Las lecturas de temperatura ambiente del LM35 se movieron entre 23.9 °C y 25.8 °C, coincidiendo con lo que medí de forma independiente en el monitor serial. El trazo de ECG mostró complejos QRS limpios y reconocibles, y el de PLETH mostró ondas de pulso claras y sincronizadas con cada latido.\nEl montaje completo: dos Arduinos, dos protoboards, ambos rieles de batería y la pantalla TFT-LCD, todo trabajando junto para mostrar tres señales a la vez. Más allá de la pantalla, te llevas algo más portable que el prototipo: la capacidad de tomar una señal que existe en el mundo físico y llevarla de punta a punta hasta un display, tomando una decisión defendible en cada etapa.\nLecciones que vale la pena llevarte a tu siguiente proyecto # La parte difícil es la integración, no ningún circuito en particular. Con cinco bloques interdependientes, una falla en cualquiera rompe todo el sistema, así que cada conexión tiene que hacerse con cuidado y verificarse antes de avanzar. Depurar un sistema terminado que nunca ha funcionado es muchísimo más difícil que validar cada bloque conforme lo agregas.\nCuando el hardware es ambiguo, las hojas de datos le ganan a los foros. Identificar un controlador de pantalla sin documentación clara, planear un presupuesto de energía entre varios rieles y dos tarjetas, y adaptar señales para un periférico que el Arduino nunca fue pensado para manejar de forma nativa: nada de eso salió de un solo tutorial. Salió de leer con atención y resolver cada obstáculo conforme apareció, que es, honestamente, gran parte de en qué consiste la ingeniería.\nElegir la pantalla más difícil fue la decisión correcta. Un display numérico sencillo habría funcionado mucho antes. La TFT-LCD tomó bastante más tiempo, pero permitió mostrar dos formas de onda completas en distintos colores junto con una lectura numérica, así que el resultado sí se parece a un monitor de signos vitales y no a una fila de números. Cuando el objetivo del proyecto es enseñarte cómo se siente un sistema real, escoge el componente que más te acerque a ese sistema real.\nCada tropiezo aquí, la fuente de banco ruidosa, la pantalla en blanco, el Arduino que no daba suficiente corriente, terminó enseñando más que las partes que funcionaron al primer intento.\nHacia dónde llevarlo después # Un filtro Notch bien calibrado, caracterizado con el equipo adecuado, para que una fuente de banco sea viable y la etapa analógica frontal deje de depender de baterías. Estimación de SpO2, extendiendo la cadena de PLETH con un LED de una segunda longitud de onda para pasar de un trazo de pulso cualitativo a una medición real de saturación de oxígeno. Registro de datos, enviando las señales adquiridas por puerto serial a una computadora para guardarlas y analizarlas después, además de mostrarlas en tiempo real. Un solo riel de 5 V diseñado desde el inicio con suficiente margen de corriente, para eliminar la necesidad de un segundo Arduino usado únicamente como fuente. Si estás trabajando en un proyecto de instrumentación biomédica, me encantaría saber qué construiste y con qué te tropezaste en el camino.\n","date":"29 de noviembre de 2020","externalUrl":null,"permalink":"/es/posts/monitor-signos-vitales-arduino/","section":"Posts","summary":"¿Alguna vez te has preguntado qué pasa realmente dentro del monitor que cuelga sobre una cama de hospital, ese que dibuja una línea verde con cada latido mientras un número parpadea en la esquina?\n","title":"Cómo construir un monitor de signos vitales con Arduino: ECG, PLETH y temperatura","type":"posts"},{"content":"","date":"29 noviembre 2020","externalUrl":null,"permalink":"/tags/embedded-systems/","section":"Tags","summary":"","title":"Embedded-Systems","type":"tags"},{"content":"","date":"29 de noviembre de 2020","externalUrl":null,"permalink":"/es/tags/ingenieria-biomedica/","section":"Tags","summary":"","title":"Ingenieria-Biomedica","type":"tags"},{"content":"","date":"29 de noviembre de 2020","externalUrl":null,"permalink":"/es/tags/procesamiento-de-senales/","section":"Tags","summary":"","title":"Procesamiento-De-Senales","type":"tags"},{"content":"","date":"29 noviembre 2020","externalUrl":null,"permalink":"/tags/signal-processing/","section":"Tags","summary":"","title":"Signal-Processing","type":"tags"},{"content":"","date":"29 de noviembre de 2020","externalUrl":null,"permalink":"/es/tags/sistemas-embebidos/","section":"Tags","summary":"","title":"Sistemas-Embebidos","type":"tags"},{"content":"¿Cuántas veces has laminado un modelo, copiado el archivo a una microSD, cruzado el cuarto, metido la tarjeta en la impresora y regresado a la computadora porque se te olvidó revisar la temperatura? Ese pequeño ciclo es invisible hasta que alguien te lo señala, y después ya no lo puedes dejar de ver. OctoPrint en una Raspberry Pi lo elimina: el trabajo va del laminador a la máquina por la red, y la impresora se convierte en algo que puedes ver, controlar y detener desde el cuarto de al lado o desde el otro lado de la ciudad.\nEsta es la parte 5 de cinco, y es la que cambia cómo usas la impresora en lugar de cambiar lo que la impresora es. La parte 1 imprimió las mejoras que la máquina se puede hacer sola. La parte 2 cambió la motherboard por una BIGTREETECH SKR Mini E3 V2.0. La parte 3 le puso un sensor BLTouch, y la parte 4 compiló el firmware que amarra a esos dos. Todo lo anterior mejora lo que la impresora hace con un archivo. Esta parte mejora cómo llega el archivo hasta ahí.\nUna confesión sobre el orden, porque cambia cómo conviene leer esto: OctoPrint fue de las primeras cosas que le agregué a mi Ender 3, mucho antes de abrir la caja de electrónica. Está al final de la serie por tema, no por fecha. Lo bueno es que no necesitas ninguna de las cuatro partes anteriores para hacer esta. Una Ender 3 completamente de fábrica recibe exactamente el mismo beneficio.\nLa interfaz web de OctoPrint durante una impresión, con la gráfica de temperatura y la vista de la cámara. Qué cambia de verdad cuando la impresora entra a la red # La microSD no es nada más una incomodidad. Es una desconexión. Mientras el archivo viaje en una tarjeta, la impresora no tiene idea de lo que sabe tu computadora, y tu computadora no tiene idea de lo que está haciendo la impresora. Todo lo que quieres saber (si sigue avanzando, si pegó la primera capa, cuánto le falta) te obliga a ir físicamente a ver.\nPoner una Raspberry Pi entre las dos cierra ese hueco, y cambian cuatro cosas al mismo tiempo:\nLos trabajos viajan por la red. Laminas, le das imprimir y listo. Sin tarjeta, sin caminatas y sin el clásico \u0026ldquo;¿copié la versión nueva o la vieja?\u0026rdquo;. Tienes una terminal de verdad. Mandar G-code a mano se vuelve trivial, y eso convierte cada comando de calibración de esta serie (M119, M303, M851, M500) en algo que escribes en vez de algo que peleas con la perilla del LCD. La puedes ver. Una cámara apuntando a la cama significa revisar una impresión de seis horas sin estar parado junto a ella. La puedes detener. Esta es la que paga el proyecto completo, y regreso a ella más adelante. Nada de esto mejora las impresiones por sí solo. Lo que hace es acortar el ciclo alrededor de imprimir, y un ciclo corto es justo lo que hace que te den ganas de iterar.\nQué necesitas # Una Raspberry Pi. Yo uso una Raspberry Pi 4. OctoPrint no es un software exigente y corre en placas más modestas, pero la Pi 4 deja margen cómodo para la interfaz web y el stream de la cámara al mismo tiempo. Una microSD para la Pi. La mía es de 16 GB. La imagen de OctoPi es chica, así que 16 GB sobran para el sistema y para los G-code que traes a la mano. Antes de decidir la capacidad, lee la sección de timelapse más abajo, porque esa es la función que se come una tarjeta entera, y 16 GB es justo donde a mí se me acabó el espacio. Una fuente de poder decente. Una Pi 4 pide 5 V a 3 A por USB-C. Una Pi mal alimentada lanza advertencias de bajo voltaje y se comporta raro de formas que parecen bugs de software, y eso es una manera miserable de gastar una tarde. Un cable USB de la Pi a la impresora. Revisa qué conector trae tu placa antes de comprarlo, porque cambia entre la placa Creality de fábrica y las placas de 32 bits que se venden aparte. Una webcam USB, opcional pero muy recomendable. La mía es una webcam USB genérica, de una marca que ni recuerdo, y sin ningún soporte fijo. La acomodo donde alcance a ver la cama. Aun así ha sido la parte más útil de todo este armado, lo cual te dice qué tan bajo está el requisito aquí. Resuelto el tema de red. La Pi se puede conectar por Wi-Fi o por cable Ethernet. La mía trabaja por Wi-Fi, que es lo que te deja poner la impresora donde tenga sentido tenerla y no donde está el router, y se configura antes de que la Pi arranque por primera vez. Ethernet queda como la alternativa si tu máquina vive cerca de un switch. Paso 1: Graba OctoPi en la microSD # Hay varias formas de terminar con OctoPrint corriendo. Yo tomé la más simple: OctoPi, la imagen oficial para Raspberry Pi que ya trae OctoPrint instalado y configurado, grabada directo a una microSD. Sin instalación manual de Python, sin containers y sin arqueología de dependencias.\nUsa el Raspberry Pi Imager:\nElige tu modelo de Pi. En Choose OS, entra a Other specific-purpose OS → 3D printing → OctoPi y toma la versión estable. Elige tu microSD. Ahora viene el paso que te salva de tener que conectarle teclado y monitor a la Pi. Antes de grabar la imagen, abre las opciones avanzadas del Imager (el ícono del engrane) y configura, como mínimo:\nEl hostname, que es por donde vas a llegar a la máquina. SSH activado, con una contraseña que tú hayas elegido. SSID, contraseña y país del Wi-Fi, para que la Pi entre a tu red desde el primer arranque. Ese último punto es todo el truco. Una Pi grabada así es un equipo headless: grabas la tarjeta, la metes, la enciendes y dos o tres minutos después ya está en tu red esperándote. Es la misma costumbre de trabajar headless desde el principio que hace agradable, en lugar de tedioso, administrar cualquier servidor casero.\nDespués conecta la Pi a la impresora por USB, enciende las dos y abre OctoPrint en el navegador. Hay dos maneras de encontrarla:\nhttp://octopi.local # el nombre mDNS, si tu red lo resuelve http://192.168.1.50 # o la dirección de la Pi en tu propia LAN Esa dirección es un ejemplo, no mi red. Para encontrar la tuya, entra a la página de administración de tu router y revisa la lista de clientes DHCP, o corre ipconfig (Windows) o ip addr (Linux) en una máquina ya conectada para ver qué rango usa tu red. Ya que estés ahí, considera darle a la Pi una reservación de DHCP en el router, para que su dirección nunca se mueva y tu marcador siga funcionando.\nLa primera vez que abres OctoPrint corre un asistente de configuración: creas tu cuenta, defines el perfil de la impresora (tamaño de cama, cama caliente, número de extrusores) y ya estás dentro.\nEl Raspberry Pi Imager con OctoPi seleccionado y las opciones avanzadas abiertas para Wi-Fi y SSH. Paso 2: Conecta la impresora por USB # En el panel de Connection, del lado izquierdo de la interfaz de OctoPrint, eliges un puerto serial y una velocidad. AUTO en los dos suele funcionar al primer intento, y OctoPrint se acuerda de la combinación que encontró.\nSi prefieres ponerlo explícito, el puerto aparece como un nombre de dispositivo de Linux, normalmente /dev/ttyUSB0 o /dev/ttyACM0 según el chip USB-serial de tu placa, y la velocidad para un firmware Marlin estándar es 115200, el mismo valor de BAUDRATE que se documenta en la parte 4.\nHay un ajuste de firmware que decide si el USB sirve o no en la BIGTREETECH SKR Mini E3 V2.0:\n#define SERIAL_PORT 2 En esa placa el puerto USB está cableado al segundo periférico serial del STM32, así que el puerto 2 es con el que habla tu computadora (o tu Pi). La parte 4 lo explica en su contexto, mejor que repetirlo aquí.\nVale la pena aclarar la cronología, porque es fácil suponer que estas dos mejoras van juntas: mi impresora corrió OctoPrint con la placa Creality de fábrica durante mucho tiempo antes de que esa placa se cambiara. Son completamente independientes. Cualquier placa que exponga un puerto serial por USB le habla a una Pi, y la pregunta del SERIAL_PORT solo aparece si estás compilando tu propio firmware para una placa que tiene más de uno.\nCuando la conexión se establece, la gráfica de temperatura empieza a moverse y la pestaña de control cobra vida. En ese momento tienes una terminal de G-code completa: escribes M119 y lees el estado de los finales de carrera, corres M303 para un autotune de PID, mandas M500 para guardar. Todo lo que las partes anteriores de esta serie te piden mandar por un monitor serial, ahora lo puedes mandar desde una pestaña del navegador.\nPaso 3: De Cura directo a la impresora # Esta es la parte que te quita la microSD de encima, y toma como dos minutos.\nEn Cura, abre el Marketplace e instala el plugin OctoPrint Connection (mantenido por fieldOfView). Reinicia Cura, entra a Preferences → Printers, selecciona tu Ender 3 y da clic en Connect OctoPrint.\nCura necesita un API key para hablarle a OctoPrint. Tienes dos caminos:\nPresionar el botón \u0026ldquo;Request\u0026hellip;\u0026rdquo; del plugin y aprobar la solicitud en la interfaz web de OctoPrint. Es el camino que yo recomendaría, porque genera una llave de aplicación acotada a Cura en lugar de entregarle tu llave maestra. O pegar la llave a mano, generándola en los ajustes de OctoPrint. Trata el API key como una contraseña. Le da control de tu impresora a quien la tenga. No la pegues en un foro cuando andes pidiendo ayuda, no la subas a un repositorio y recórtala de cualquier captura antes de publicarla. En este post no aparece ninguna, ni siquiera una falsa, precisamente porque una llave que se ve creíble es justo lo que la gente copia sin pensar.\nDespués de escribir o solicitar la llave, presiona Connect. Ese último clic importa: el plugin solo guarda la llave cuando te conectas con ella.\nDe ahí en adelante, el botón de imprimir de Cura se convierte en Print with OctoPrint, y el trabajo laminado se sube y arranca sin que una tarjeta entre en la ecuación.\nAun así, a veces subo el archivo a mano, y está bien. Cuando lamino en otra computadora, o cuando ya tengo un G-code que no salió de mi Cura de siempre, nada más lo arrastro a la lista de archivos de OctoPrint en la interfaz web y le doy imprimir desde ahí. El plugin es el camino cómodo, no el único, y conviene conocer los dos porque la subida manual funciona desde cualquier dispositivo con navegador, incluido el celular.\nEl plugin OctoPrint Connection en Cura, ya conectado a la impresora, con el campo del API key tapado. Paso 4: La cámara, y la función que de verdad se gana su lugar # Conecta una webcam USB a la Pi y OctoPrint toma el stream solo. La mía, otra vez, es una webcam genérica sin soporte, acomodada donde alcance a ver la cama. Nunca le imprimí un bracket ni compré una mejor, y aun así cambió mi forma de imprimir.\nAquí está el porqué, y no es la razón que la gente espera.\nEl valor no está en la novedad de ver plástico saliendo de una boquilla. Está en que una impresión que va mal se anuncia visualmente mucho antes de anunciarse de cualquier otra forma. Cuando la pieza se despega y la boquilla empieza a arrastrarla, o cuando la primera capa claramente no pegó, eso lo ves en tres segundos desde el celular. Y entonces puedes hacer lo que de verdad importa: cancelar la impresión a distancia.\nEsa combinación, vista en vivo más cancelación remota, es la justificación honesta de la cámara. Una impresión que falla en la hora uno de seis desperdicia cinco horas de filamento y de máquina, o no, y la única diferencia es si alguien pudo asomarse y darle stop. Yo lo he hecho desde fuera de la casa más de una vez, y nunca se ha sentido como un adorno.\nSobre Octolapse # OctoPrint puede grabar un timelapse de fábrica. Octolapse es el plugin que lo lleva más lejos: mueve el cabezal fuera del cuadro antes de cada foto, así que el video final muestra el modelo creciendo suavemente desde la cama, sin la boquilla cruzando la toma. Es el efecto detrás de prácticamente todos los timelapses satisfactorios de impresión 3D que has visto.\nAquí voy a ser directo contigo, porque prefiero ser útil que quedar bien: tengo la capacidad y no la uso. La razón es el almacenamiento. Un timelapse implica guardar un cuadro por cada capa y luego renderizar un video con todos ellos, y mi tarjeta de 16 GB simplemente no tiene espacio para los cuadros y los archivos terminados al mismo tiempo. Así que la función está ahí, disponible, sin usarse.\nEso no es una crítica a Octolapse. Es una decisión de dimensionamiento que tomé sin pensarla bien: 16 GB es una tarjeta cómoda para correr OctoPrint y una tarjeta apretada para filmarlo. Y es justo el tipo de cosa que conviene saber antes de comprar la microSD y no después. Si los timelapses son parte de por qué quieres hacer este proyecto, planea el almacenamiento primero.\nLa vista de la webcam en OctoPrint mostrando una impresión en curso sobre la cama. Paso 5: Verla desde fuera de la casa # Todo lo anterior funciona dentro de tu red local. En cuanto sales, se acaba, y ahí entra el acceso remoto.\nPodrías resolverlo con port forwarding y un reverse proxy, y de hecho yo corro justo ese tipo de esquema para otros servicios. Para una impresora 3D en particular lo pensaría dos veces. La propia documentación de OctoPrint es inusualmente tajante con esto, y tiene razón: exponer directo al internet abierto una máquina que le aplica calor al plástico no es un riesgo que valga la pena por comodidad. Un servicio de relay, donde la Pi abre una conexión saliente hacia un proveedor y tú llegas a través de él, evita abrir un solo puerto en tu router.\nActualización, 2026: cambié de herramienta para esto. Cuando armé esta impresora, en octubre de 2020, usé AstroPrint, siguiendo el video de CrossLink \u0026ldquo;Access OctoPrint from ANYWHERE with AstroPrint\u0026rdquo; (abril de 2020), que fue la guía con la que realmente trabajé en su momento. Hace unos meses, en 2026, me pasé a OctoEverywhere, y eso es lo que corre hoy en mi Pi. Para ser justos con AstroPrint: sigue existiendo y sigue recibiendo mantenimiento, así que esto fue un cambio de mi parte, no un escape. Los pasos de abajo describen la herramienta que uso actualmente; la ruta de AstroPrint queda registrada aquí como historia, no como instrucción.\nEl camino actual, si quieres seguir lo que de verdad tengo corriendo:\nEn OctoPrint, entra a Settings → Plugin Manager → Get More, busca OctoEverywhere e instálalo. Está en el repositorio oficial de plugins de OctoPrint. Reinicia OctoPrint cuando te lo pida. Sigue la liga del plugin para crear una cuenta y vincular tu impresora. Abre el portal desde el celular o desde cualquier navegador, donde estés. Lo que obtienes, según la descripción del propio proyecto, es acceso remoto a la interfaz completa de OctoPrint (plugins incluidos), streaming de la cámara y notificaciones de impresión, en un plan gratuito y sin nada de port forwarding. Lo que a mí me importa es que la vista remota es la misma interfaz que la local, así que el botón de cancelar está exactamente donde mi pulgar ya lo busca.\nQué no arregla esto # Quiero ser honesto con los límites de esta mejora, porque \u0026ldquo;impresora conectada a la red\u0026rdquo; suena más transformador de lo que es.\nSigues caminando hasta la impresora. Alguien tiene que despegar la pieza terminada, quitar el skirt, limpiar la superficie y arrancar el siguiente trabajo. OctoPrint elimina el viaje antes de la impresión, no el de después.\nUna impresora en red no mejora una primera capa mala. Ni un milímetro. Si tu cama no está nivelada y tu offset de Z está mal, OctoPrint le va a entregar fielmente un archivo hermoso a una máquina que lo va a imprimir mal, y ahora además lo puedes ver en alta definición. Ese problema le toca al BLTouch y al firmware, que es justamente por qué son posts aparte.\nUna cámara no es detección de fallas. Solo ayuda cuando alguien se asoma. Te compra la posibilidad de agarrar una falla, no la garantía.\nTener esas fronteras claras es, creo, el hábito de ingeniería más útil que me dejó este proyecto. Cada mejora resuelve bien un problema específico, y la tentación de esperar que una buena herramienta arregle un problema que no le corresponde es de donde salen muchos fines de semana desperdiciados.\nActualización, junio de 2026: la instalación envejeció y tuve que volver a grabarla # Lee esto antes de cortarle la corriente a tu Pi. Este post está fechado en 2020, y la instalación que describe corrió sin dar lata durante años. En junio de 2026 se murió. La historia es corta, el arreglo es reproducible, y la lección del final es lo único aquí que te puede salvar un fin de semana.\nQué pasó. Después de un apagón de la Pi, la interfaz web de OctoPrint ya nunca regresó. La causa de fondo fue corrupción del sistema de archivos EXT4 en la microSD, provocada por un apagado sucio que había interrumpido una actualización en caliente meses antes. El daño llevaba ahí todo ese tiempo, callado, esperando un reinicio que lo sacara a la luz.\nLo primero que revivió la impresora fue forzar una revisión del sistema de archivos al arrancar. Eso se hace desde otra computadora, montando la partición de boot de la tarjeta y agregándole un parámetro a /boot/cmdline.txt:\nfsck.mode=force Es un truco que de verdad vale la pena conocer, y funcionó. También es un parche y no una reparación: arregla el daño que alcanza a ver y no te dice nada de lo que aquella escritura interrumpida haya dejado atrás.\nPor qué regrabar era la decisión correcta de todos modos. Mi tarjeta original estaba construida sobre Raspberry Pi OS Buster con Python 3.7, y los dos ya habían llegado a su fin de soporte hacía rato. La imagen actual de OctoPi está construida sobre Bookworm con Python 3.11. Una instalación de OctoPi envejece por debajo de ti aunque nada salga mal, así que una tarjeta que además ya se había corrompido no valía la pena mantenerla con respiración artificial. Un detalle que te conviene a ti: este post nunca fijó una versión de OctoPi, te dice que tomes la versión estable del Imager, así que las instrucciones de arriba no se quedaron viejas. La que se quedó vieja fue mi instalación.\nQué implicó la migración de verdad. Esta es la parte que te sirve, y es la diferencia entre una tarde y un fin de semana:\nSaca primero un respaldo de OctoPrint. OctoPrint exporta su propio .zip desde la interfaz web, y yo saqué uno de la instalación enferma antes de tocar cualquier otra cosa. Si tu Pi todavía responde aunque sea a medias, haz esto antes de ponerte creativo. Regraba la misma tarjeta. No tenía otra a la mano, así que la tarjeta que falló es la que corre hoy, escrita de cero con la versión estable actual de OctoPi desde el Imager. Restaura desde el respaldo. Ajustes, archivos de G-code y plugins regresaron de ese .zip, y la restauración la hice por cable Ethernet en lugar de Wi-Fi. La lección, dicha sin rodeos: usa siempre el comando Shutdown de OctoPrint antes de cortarle la corriente a la Pi. No el switch, no el enchufe. Una tarjeta SD interrumpida a media escritura es exactamente así como empieza esta falla, y la interrupción que mató a la mía ocurrió meses antes de que apareciera el síntoma. Un respaldo y un clic en Shutdown cuestan segundos; la alternativa me costó una noche de diagnóstico y una reinstalación completa.\nPrefiero dejar esto aquí que reescribir el post en silencio como si nada hubiera pasado. Un equipo que corre casi seis años se gana su historia de mantenimiento, y tratar esa historia como una cosa más que aprender es más útil que fingir que el armado salió perfecto.\nHacia dónde sigue esto # Tengo dos cosas en la lista, y las dos apuntan hacia afuera de la impresora.\nSacar el almacenamiento del timelapse de la Pi. El límite de espacio que mantiene a Octolapse sin usar no es realmente un problema de la impresora, es un problema de \u0026ldquo;esta computadora chiquita tiene una tarjeta chiquita\u0026rdquo;, y yo ya tengo corriendo un servidor casero armado con una laptop vieja cuyo propósito entero es guardar archivos. Apuntar los cuadros y los videos renderizados a un almacenamiento en red en vez de a la tarjeta de la Pi es la solución obvia, y es un buen ejemplo de cómo un home lab se va acumulando: una máquina que armaste por una razón termina resolviendo, sin ruido, un problema que tenías en otro lado.\nHome Assistant. Meter la impresora a la misma capa de automatización que el resto de la casa es el siguiente paso natural, y es la pieza que preferiría desarrollar bien en lugar de bosquejarla aquí.\nCinco partes después, la Ender 3 que llegó en kit es más silenciosa, se nivela sola, corre un firmware que yo compilé, trae puestas piezas que ella misma se imprimió y ahora vive en la red. Ninguno de esos pasos requirió una habilidad que yo tuviera al empezar, y ese es realmente el punto. Curiosidad, un par de guías abiertas en la segunda pantalla y la disposición a tratar cada falla como lo siguiente que hay que aprender te llevan a través de todos ellos.\nEmpieza por donde tu propia impresora te moleste más. Esa siempre es la primera mejora correcta.\n","date":"15 de octubre de 2020","externalUrl":null,"permalink":"/es/posts/controlar-ender-3-con-octoprint/","section":"Posts","summary":"¿Cuántas veces has laminado un modelo, copiado el archivo a una microSD, cruzado el cuarto, metido la tarjeta en la impresora y regresado a la computadora porque se te olvidó revisar la temperatura? Ese pequeño ciclo es invisible hasta que alguien te lo señala, y después ya no lo puedes dejar de ver. OctoPrint en una Raspberry Pi lo elimina: el trabajo va del laminador a la máquina por la red, y la impresora se convierte en algo que puedes ver, controlar y detener desde el cuarto de al lado o desde el otro lado de la ciudad.\n","title":"Controla tu Ender 3 por la red con OctoPrint en una Raspberry Pi","type":"posts"},{"content":"","date":"15 de octubre de 2020","externalUrl":null,"permalink":"/es/tags/cura/","section":"Tags","summary":"","title":"Cura","type":"tags"},{"content":"","date":"15 de octubre de 2020","externalUrl":null,"permalink":"/es/tags/octoprint/","section":"Tags","summary":"","title":"Octoprint","type":"tags"},{"content":"","date":"15 de octubre de 2020","externalUrl":null,"permalink":"/es/tags/raspberry-pi/","section":"Tags","summary":"","title":"Raspberry-Pi","type":"tags"},{"content":"Ya armaste tu Ender 3, la impresión de prueba salió bien y ahora estás viendo la máquina sin saber muy bien qué hacer con ella. Mi respuesta siempre es la misma: hazle piezas a la impresora. Una impresora 3D es una de las poquísimas herramientas capaces de fabricar sus propias mejoras, y en una Ender 3 eso no es un truco simpático. Es literalmente lo que convierte un kit que imprime en una máquina que da gusto usar.\nEste post es una lista de las mejoras impresas para la Ender 3 que siguen montadas en la mía años después. Abajo vas a encontrar dieciséis piezas numeradas, cada una con su foto, una descripción corta del problema que resuelve y el link para descargar el modelo. Están agrupadas por la zona de la impresora que mejoran, para que te brinques directo a lo que hoy te está molestando y empieces por ahí.\nEsta es la parte 1 de cinco. La parte 2 cambia la motherboard por una BIGTREETECH SKR Mini E3 V2.0, la parte 3 instala un sensor BLTouch, la parte 4 compila firmware de Marlin a la medida en VS Code, y la parte 5 mete la impresora a la red con OctoPrint en una Raspberry Pi.\nLa Ender 3 después de varias rondas de mejoras impresas, casi todas hechas por la misma impresora. Lo primero útil que hace esta impresora son piezas para sí misma # Hay algo muy satisfactorio en una máquina que se mejora sola, pero el argumento práctico pesa todavía más que el poético. Una mejora impresa cuesta unos cuantos pesos de filamento en lugar de un envío y dos semanas de espera. Es reversible, porque nada de esto requirió cortar, barrenar ni soldar. Y cada pieza funciona además como ejercicio de calibración: un modelo que tiene que atornillarse a hardware real te dice muchísimo más sobre la precisión dimensional de tu impresora que cualquier figura decorativa.\nEl primer lote lo imprimí en agosto de 2020, poco después de que llegó la impresora, y la lista siguió creciendo durante los siguientes dos años conforme aparecían nuevas molestias. Todo lo que sigue está impreso en PLA y todo sigue en servicio.\nHay dos costumbres que vale la pena adoptar antes de descargar nada. La primera: lee la página del modelo y no nada más veas la miniatura, porque algunas piezas necesitan hardware que todavía no tienes, otras vienen en variantes para distintos perfiles de aluminio, y la licencia cambia de un modelo a otro. La segunda: dale crédito a quien le toca. Donde conozco al autor, lo nombro y lo enlazo aquí abajo. Donde ya no sé cuál de las muchas versiones de la comunidad fue la que descargué, lo digo tal cual, porque una atribución equivocada es peor que una atribución ausente.\nFilamento que entra sin pelearse # El portacarrete de fábrica va arriba del marco y cumple, hasta el momento en que tu carrete no es del tamaño que Creality dio por hecho. Este es el grupo que yo imprimiría primero, porque un carrete que se atora aparece después en todas tus impresiones, casi siempre disfrazado de subextrusión que te pasas la noche echándole la culpa al hotend.\n1. Soporte para carretes de 80 mm # Qué resuelve: los carretes de muestra y muchos de recarga traen un núcleo más angosto que el estándar, así que bailan o se atoran en el soporte original. Modelo: Creality (Ender 3) Filament holder 80mm spools de mjoaris (CC-BY).\nLee la página del modelo antes de mandarlo a imprimir, porque la nota del propio autor es fácil de saltarse: \u0026ldquo;To be clear, you will need two 608ZZ bearings.\u0026rdquo; Necesitas dos baleros 608ZZ, los comunes de patineta, baratos y fáciles de conseguir, pero la pieza no te sirve de nada mientras ellos vienen en camino.\nEl soporte para carretes de 80 mm con sus dos baleros 608ZZ, cargando un carrete de recarga que el soporte original no sostiene. 2. Montaje lateral de carrete # Qué resuelve: el recorrido largo, alto y tambaleante del filamento desde arriba del marco, más un carrete pesado justo donde peor le cae a las vibraciones de la máquina. Modelo: Ender-3 Side Spool Mount and other Printers with 20/40mm de DrStreet.\nPasar el carrete al costado del marco acorta el camino hasta el extrusor y baja el centro de masa. El modelo está hecho para perfil de 20/40 mm, así que se adapta a más impresoras que solo esta. Ojo: cambia la geometría de todo lo que va antes del extrusor y, como vas a ver más abajo, en mi caso jubiló otra pieza de la lista sin hacer ruido.\nEl montaje lateral de carrete, que acorta el camino del filamento hasta el extrusor y baja el centro de masa de la máquina. 3. Guía de filamento # Qué resuelve: que el filamento vaya raspando contra una orilla del marco camino al extrusor en lugar de correr por una curva suave y controlada. Modelo: Ender 3 filament guide de Jonasen.\nEs la pieza más pequeña de toda la lista y una de las que más extrañaría. Se desliza directo sobre el marco, así que instalarla toma segundos, y la abertura del anillo te deja meter el filamento de lado en vez de ensartar un carrete entero por un aro cerrado.\nLa guía de filamento, la pieza más chica de la lista, que convierte una orilla que raspa en una curva suave hacia el extrusor. Mejores impresiones justo donde sale el plástico # Estas dos mejoras son las que se ven en la pieza impresa, y por eso las pongo por encima de cualquier detalle estético de más abajo. Las dos son del mismo autor y atacan el pequeño volumen alrededor de la boquilla, que es donde en realidad se decide la calidad de impresión.\n4. Ducto de enfriamiento Mistral-E # Qué resuelve: el mal enfriamiento de la pieza, que es lo que hace que los voladizos se caigan y que las puntas delgadas queden blandas y a medio derretir. Modelo: Mistral-E Filament Cooling Duct de Leo_N, publicado en diciembre de 2018. Mi archivo es Mistral-E_v1.3_Leo_N.stl.\nSi de todo este post vas a imprimir una sola cosa, que sea esta, porque el ducto decide qué tan rápido se congela cada capa en su lugar. Su autor fue muy claro con los compromisos que buscó: usar el ventilador original de la impresora en vez de exigir hardware nuevo, soplar un volumen alto de aire sobre el filamento justo después de la boquilla, evitar que ese aire pegue en el bloque calefactor, quedar lo bastante compacto para no estorbarle a los sensores de autonivelación, y no subir ni el ruido ni el peso del extrusor. Ese punto de los sensores de autonivelación envejeció muy bien en mi máquina, porque la parte 3 de esta serie terminó poniendo un sensor BLTouch justo al lado del hotend.\nEl ducto de enfriamiento Mistral-E montado junto a la boquilla, la mejora que más le cambió la calidad a mis impresiones. 5. Inserto para el extrusor MK8 # Qué resuelve: los tapones que se forman dentro del cuerpo del extrusor, donde el filamento tiene espacio para doblarse en lugar de ir guiado en línea recta. Modelo: Creality Mk8 Extruder Insert de Leo_N. Mi archivo es Extruder_Insert_Leo_N.stl.\nEs la mejora menos visible del post y una de las más útiles, porque un tapón te cuesta una impresión perdida más la media hora que te lleva encontrar la causa. Dos notas del autor conviene llevártelas a tu propio armado: hay que cortar el tubo PTFE a la medida, así que considera un poco de trabajo manual y no solo imprimir y atornillar, y la versión 1.1 engrosó la pared entre los dos tubos PTFE específicamente por resistencia, lo cual te dice dónde vive el esfuerzo en esa pieza.\nEl inserto del extrusor MK8, con el tubo PTFE cortado a la medida, guiando el filamento derecho por el cuerpo del extrusor. Cables que dejan de tallarse # Lo que desgasta un cable es el movimiento. En una Ender 3 de fábrica, tanto el mazo que va al hotend como el que va a la cama se doblan miles de veces por impresión, y de paso se van tallando contra el marco.\n6. Cadena de cables # Qué resuelve: mazos de cable sin guía, que se doblan donde caiga y se tallan contra el marco cada vez que se mueve un eje. Modelo: Ender 3 Cable Chain de johnniewhiskey (CC-BY).\nUna cadena articulada lleva el mazo por una trayectoria controlada, para que se doble donde tú decidiste. También es por mucho la impresión más laboriosa de la lista: las instrucciones del autor piden \u0026ldquo;15 Links for Heatbed\u0026rdquo; y \u0026ldquo;10 Links (or more) for X gantry\u0026rdquo;, es decir 15 eslabones para la cama caliente y 10 o más para el eje X, entre 25 y 30 antes de que empieces siquiera con las tapas, los soportes y la esquina de la cama. Hay otra línea de ese mismo README que te ahorra volver a empezar: \u0026ldquo;Use a little higher print temp than usual for stronger part. Too low temp will cause part break while assembly.\u0026rdquo; Los eslabones se ensamblan a presión con la mano y uno impreso frío se truena justo ahí, así que imprime este juego más caliente de lo que acostumbras.\nLa cadena de cables impresa ya montada. Es la pieza más laboriosa del conjunto y la que más le cambia el aspecto a la máquina. 7. Clips para cables # Qué resuelve: cables sueltos colgando del marco y metiéndose en el camino de un eje en movimiento. Modelo: Ender 3 Cable Clips de Holspeed, un remix del clip para cable plano de jn-gr.\nEl complemento barato de la cadena: clips chiquitos que se abrazan al perfil de aluminio y dejan los cables pegados a él. El remix agregó filetes de 45 grados por dentro de los brazos y pestañas para zafar el clip con un desarmador plano, incluye una variante a 90 grados para anclar el cable plano donde cruza un perfil, y se modificó para recibir los dos cables de 3 mm que salen de la fuente. Imprime varios, los vas a usar todos.\nLos clips sujetando el cableado pegado al perfil, el complemento barato de la cadena de cables. La caja de electrónica: ruido y protección # Una parte del ruido de la Ender 3 viene de los drivers de los motores, y ahí ninguna pieza impresa te va a salvar (para eso es la parte 2). El resto es aire, y el aire sí es un problema que se resuelve imprimiendo.\n8. Silenciador para el ventilador de la fuente # Qué resuelve: el zumbido constante del ventilador de la fuente, que suena todo el tiempo que la impresora está encendida, incluso cuando no está haciendo nada. Modelo: un modelo común de la comunidad que no puedo atribuir con honestidad.\nUn ducto impreso redirige y difunde la salida de aire del ventilador, lo que le quita lo filoso al ruido sin bloquear el flujo que la fuente sí necesita. Busca específicamente la versión hecha para tu fuente, porque Creality mandó más de un modelo.\nEl ducto impreso en el ventilador de la fuente, que difunde la salida de aire y le quita lo filoso al zumbido. 9. Rejilla para el ventilador de la motherboard # Qué resuelve: que un dedo, un cable o un cincho se metan al ventilador que enfría la motherboard, allá abajo en la caja de electrónica de la impresora. Modelo: Creality Ender 3 Board Fan Guard - Slimmed de Phryxus. Mi archivo es Fan_Guard_V2.STL.\nOjo con qué protege esta pieza: el ventilador de la electrónica, no el del hotend ni el de enfriamiento de pieza, así que cuida el flujo de aire que mantiene vivos a tus drivers. Imprimí justo esta versión por dos datos de la página del modelo: el diseño slimmed usa alrededor del 60% del material y del tiempo de la versión con aletas, y su V2 abre cerca de 30% más de área transversal de paso de aire, así que la rejilla le estorba menos al enfriamiento que está protegiendo. Una rejilla que ahoga al ventilador sería peor que no poner ninguna.\nLa rejilla slimmed del ventilador de la motherboard, elegida porque usa menos material y deja pasar más aire que la versión con aletas. Perillas que de verdad puedes girar # Dos de los controles que más usas en la impresora vienen, de fábrica, sin ser realmente controles.\n10. Perilla del extrusor # Qué resuelve: cargar y descargar filamento a mano, que si no significa agarrar una palanquita metálica del extrusor y girarla con las yemas. Modelo: Ender 3 Yoda Extruder Knob de JaZzSuperman.\nUna perilla impresa se ensarta en el eje y convierte ese pellizco incómodo en un movimiento firme y agradable. Empecé con una perilla redonda de lo más común y después encontré esta, que es la misma idea pero con la cabeza de Yoda. Funciona igual de bien y es la que trae la máquina desde entonces. No todas las decisiones de ingeniería tienen que ser austeras.\nLa perilla de Yoda en el extrusor, que vuelve cómodo cargar y descargar filamento a mano. 11. Perilla para el eje Z # Qué resuelve: subir y bajar el gantry con la mano cuando estás nivelando, cuando cambias la boquilla y cada vez que necesitas la cama fuera del camino. Modelo: un modelo común de la comunidad que no puedo atribuir con honestidad.\nLa perilla entra en la parte superior del husillo Z, así que giras el tornillo directo en vez de pelearte con el copie o forzar el motor. Cuesta casi nada imprimirla y la vas a usar todo el tiempo.\nLa perilla del eje Z sobre el husillo, para subir y bajar el gantry con la mano. Mantener la máquina ordenada y protegida # Este último grupo no tiene que ver con la calidad de impresión. Tiene que ver con que la impresora sea un objeto agradable y durable de tener en tu espacio, que motiva más de lo que parece cuando la alternativa es un escritorio revuelto que terminas evitando.\n12. Cajón bajo la base # Qué resuelve: que las boquillas, los coples bowden de repuesto y las llaves allen se te desperdiguen por el cuarto en vez de vivir con la impresora. Modelo: Drawer for Ender3, Ender 3 de Jaypirnts.\nSe monta debajo de la base de la impresora y convierte espacio muerto en guardado. Es la pieza que siempre comentan las visitas.\nEl cajón impreso bajo la base, donde por fin tienen lugar las boquillas, las llaves allen y las refacciones. 13. Tapa para el PCB de la pantalla # Qué resuelve: que la pantalla de fábrica deje su tarjeta expuesta por atrás, donde junta polvo y se lleva uno que otro golpe. Modelo: Ender 3 Display LCD PCB Cover de Rocco81-92.\nFíjate en la licencia de esta, CC-BY-NC-SA, que es más estricta que las demás de aquí: uso no comercial, y las derivadas se comparten bajo la misma licencia. Si la vas a remezclar o a vender impresiones, eso importa.\nLa tapa de Rocco81-92 cerrando la parte trasera de la pantalla, donde la tarjeta quedaría expuesta al polvo y a los golpes. 14. Cubierta frontal de la pantalla # Qué resuelve: la luz de la pantalla en las impresiones nocturnas, cuando el LCD alumbra el cuarto y de todos modos no necesitas leerlo. Modelo: un modelo común de la comunidad que no puedo atribuir con honestidad. Mi archivo es Ender_3_Screen_Cover.stl.\nQue quede claro: esta es una pieza distinta de la tapa del PCB de arriba. El modelo de Rocco81-92 cierra la parte trasera de la pantalla, donde va la tarjeta; esta cubre el frente. Tapar ese resplandor es la razón por la que sigue en mi máquina, y si la impresora comparte cuarto contigo de noche lo vas a agradecer. Que además le dé una mejor cara al frente es un extra, no el motivo.\nLa cubierta frontal de la pantalla, que tapa la luz del LCD durante las impresiones nocturnas. 15. Cubierta del riel # Qué resuelve: que la basura y el polvo de las impresiones se acumulen en el riel del marco. Yo la puse solo del lado donde está el carrete. Modelo: un modelo común de la comunidad que no puedo atribuir con honestidad. Mi archivo es New_Ender_3_rail_cover.stl.\nMantener ese riel limpio es una superficie menos donde se junta polvo alrededor de una máquina en movimiento, y es una impresión de cinco minutos. También hace que la máquina se vea terminada, y reconozco que eso contó, pero la basura fue la razón de imprimirla. Buena candidata para ese pedazo de filamento que te quedó al final del carrete.\nLa cubierta del riel del lado del carrete, que evita que la basura y el polvo de las impresiones se acumulen ahí. 16. Portaespátula # Qué resuelve: que la espátula de la cama termine debajo de una pila de papeles al otro lado del cuarto. Modelo: un modelo común de la comunidad que no puedo atribuir con honestidad.\nSuena trivial y lo es, pero una herramienta que alcanzas es una herramienta que sí usas.\nEl portaespátula, para que la espátula de la cama viva con la impresora y no del otro lado del cuarto. Lo que imprimí y dejé de usar # No todo de esa lista se ganó su lugar, y creo que vale la pena decirlo en voz alta en un recorrido como este. Tres piezas salieron de la máquina.\nDos perillas de extrusor. Antes de la perilla de Yoda imprimí una redonda de lo más común, y también imprimí una variante diseñada para el extrusor de la CR-10. Las dos funcionaban. Las dos salieron de todos modos, en cuanto encontré una versión que ajustaba mejor y que simplemente me gustó más.\nUna segunda guía de filamento. Imprimí la 2020 / Ender 3 Filament Guide de Filboyt y dejé de usarla en el momento en que me cambié al montaje lateral del carrete. La pieza no tenía nada malo. Mover el carrete al costado del marco cambió tanto la trayectoria del filamento que la guía se quedó sin trabajo que hacer.\nEsa segunda historia es la más útil de las dos, y es un patrón que conviene esperar: en una máquina que vas mejorando por partes, una mejora puede volver obsoleta a otra anterior. Aunque una impresión que termina en un cajón se siente como filamento tirado, con el tiempo llegué a ver esas tres de otra forma. Costaron casi nada, me enseñaron qué medidas importaban de verdad, y son la razón por la que reconocí la mejor solución cuando la vi. Imprimir primero la versión ordinaria no es un fracaso. Es la manera en que aprendes qué significaría \u0026ldquo;mejor\u0026rdquo;.\nQué cuidar cuando imprimas estas piezas # Todo esto lo imprimí en PLA y ha aguantado, ese es el resumen honesto. Más allá del material, hay tres cosas que conviene pensar antes de mandar a imprimir:\nLa cercanía al calor. El PLA es el punto débil de esta lista donde una pieza vive junto a aire caliente, así que revisa el ducto de la fuente, la rejilla del ventilador de la motherboard y sobre todo el ducto de enfriamiento junto al hotend después de sus primeras impresiones largas. Si tienes PETG a la mano, esas son las candidatas sensatas.\nLa orientación de las capas. Los eslabones de la cadena y los clips son piezas chicas que se flexionan una y otra vez, y una pieza impresa siempre es más débil entre capas. Oriéntalas para que el esfuerzo de flexión corra a lo largo de las capas y no tratando de despegarlas.\nEl hardware no viene en la descarga. El soporte de carretes de 80 mm necesita sus dos baleros 608ZZ, el inserto del extrusor necesita tubo PTFE cortado a la medida, y varias de estas piezas piden tornillos M3 o M4 y tuercas T para sujetarse al marco. Revisa qué pide cada modelo antes de empezar, para que la pieza terminada no se quede en el estante esperando un paquete.\nHacia dónde sigue esto # Las mejoras impresas le arreglaron a esta máquina casi todo lo mecánico, y lo hicieron al precio del filamento. Lo que no pueden arreglar es lo que pasa dentro de la electrónica: el ruido de los drivers, el firmware que ya no crece, y el header que falta para conectar un sensor de nivelación. Justo ahí es donde sigue esta serie.\nLa parte 2 cambia la placa de 8 bits de fábrica por una BIGTREETECH SKR Mini E3 V2.0, que vuelve la impresora dramáticamente más silenciosa y convierte el flasheo de firmware en arrastrar un archivo. La parte 3 instala un sensor BLTouch, y vale la pena decirlo aquí: empieza con una pieza impresa más, el soporte que sostiene el sensor junto al hotend. La parte 4 compila un firmware de Marlin que sabe de todo lo anterior, y la parte 5 le entrega el control de la máquina completa a OctoPrint corriendo en una Raspberry Pi.\nSi de este post te llevas una sola cosa, que sea la costumbre y no la lista: cuando algo de tu impresora te moleste, revisa si la propia impresora puede resolverlo antes de sacar la cartera. Más seguido de lo que uno esperaría, sí puede.\n","date":"2 de agosto de 2020","externalUrl":null,"permalink":"/es/posts/mejoras-impresas-ender-3/","section":"Posts","summary":"Ya armaste tu Ender 3, la impresión de prueba salió bien y ahora estás viendo la máquina sin saber muy bien qué hacer con ella. Mi respuesta siempre es la misma: hazle piezas a la impresora. Una impresora 3D es una de las poquísimas herramientas capaces de fabricar sus propias mejoras, y en una Ender 3 eso no es un truco simpático. Es literalmente lo que convierte un kit que imprime en una máquina que da gusto usar.\n","title":"Mejoras impresas para la Ender 3: las piezas que tu impresora se hace sola","type":"posts"},{"content":"","date":"2 de agosto de 2020","externalUrl":null,"permalink":"/es/tags/piezas-impresas/","section":"Tags","summary":"","title":"Piezas-Impresas","type":"tags"},{"content":"","date":"2 agosto 2020","externalUrl":null,"permalink":"/tags/printed-parts/","section":"Tags","summary":"","title":"Printed-Parts","type":"tags"},{"content":"","externalUrl":null,"permalink":"/es/authors/","section":"Authors","summary":"","title":"Authors","type":"authors"},{"content":"","externalUrl":null,"permalink":"/es/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"Siempre me da gusto platicar sobre diseño de hardware, aceleración de machine learning, ingeniería biomédica, o algún proyecto de home lab que se salió de control. La forma más rápida de contactarme es por LinkedIn.\nActualmente busco posiciones de tiempo completo en ingeniería en diseño RTL y arquitectura de computadoras, aceleración por hardware para machine learning, o infraestructura de IA y datacenter.\nDónde encontrarme # Correo fdezemi@emilian.website LinkedIn emiliano-fernandez-cervantes GitHub EmilianFC20 Radico en Los Ángeles, California, y soy originario de la Ciudad de México. Leo mensajes en español y en inglés, así que escríbeme en el que prefieras.\nEscanea el código para guardar mis datos en tu teléfono Descargar la tarjeta de contacto (.vcf) Mándame un mensaje # Nombre Correo electrónico Mensaje Enviar mensaje ","externalUrl":null,"permalink":"/es/contact/","section":"Emiliano Fernández Cervantes","summary":"Siempre me da gusto platicar sobre diseño de hardware, aceleración de machine learning, ingeniería biomédica, o algún proyecto de home lab que se salió de control. La forma más rápida de contactarme es por LinkedIn.\n","title":"Contacto","type":"page"},{"content":"Me llamo Emiliano. Trabajo en hardware digital: diseño RTL para circuitos integrados y aceleración por hardware para machine learning. Me gusta entender cómo funcionan las cosas, y me gusta construir tecnología que tenga un impacto real en las personas que la usan.\nActualmente curso mi Maestría en Ingeniería de Computación en USC como becario Fulbright–García Robles. Mi enfoque es la arquitectura de procesadores y la aritmética que hay debajo del machine learning: diseñar datapaths eficientes en Verilog y llevar el rendimiento más lejos con CUDA. En paralelo a mis estudios trabajo en el equipo de virtualización y almacenamiento de Keck Medicine of USC, sobre una infraestructura Nutanix repartida entre un datacenter y tres hospitales.\nEstudié ingeniería biomédica en el Tecnológico de Monterrey, me gradué con honores como el promedio más alto de la carrera, y mi proyecto de titulación terminó publicado como artículo de primer autor en IEEE Transactions on Neural Systems and Rehabilitation Engineering. Después pasé cuatro años en PPD, parte de Thermo Fisher Scientific, coordinando el soporte a ensayos clínicos bajo requisitos regulatorios, donde co-construí una herramienta en Excel/VBA que redujo una conciliación manual de más de cinco horas a unos treinta minutos, y que terminó adoptándose en la mayoría de los estudios de la compañía.\nEn qué trabajo # Diseño digital y RTL. Un procesador compatible con ARM con pipeline de 5 etapas y multithreading de grano fino de 4 vías, además de una GPU SIMT, ambos desarrollados en Verilog, sintetizados y probados en una tarjeta NetFPGA. Hardware para machine learning. Una unidad MAC de 16 bits con pipeline, layout full-custom en Cadence Virtuoso y verificación DRC/LVS. Actualmente desarrollo un acelerador de atención INT8 mediante co-diseño para la Arty Z7-20, desde un modelo C++ ciclo-exacto y RTL en Verilog hasta su integración con Zynq como operador de PyTorch. Infraestructura y home lab. Un servidor OpenMediaVault basado en Debian, con servicios en contenedores administrados mediante Docker Compose y un reverse proxy NGINX con soporte para SSL y WebSockets, sobre una red mesh con múltiples subredes enrutadas con OpenWrt, además de un servidor local de inferencia con GPU NVIDIA. Formación y reconocimientos # M.S. en Ingeniería de Computación, University of Southern California (2025–2027) — beca Viterbi Endowment Beca Fulbright–García Robles, COMEXUS Ingeniería Biomédica, Tecnológico de Monterrey — titulado con honores y promedio más alto de la carrera Actualmente busco posiciones de tiempo completo en ingeniería para después de graduarme en mayo de 2027 así que escríbeme.\nVer mis proyectos ","externalUrl":null,"permalink":"/es/about/","section":"Emiliano Fernández Cervantes","summary":"Me llamo Emiliano. Trabajo en hardware digital: diseño RTL para circuitos integrados y aceleración por hardware para machine learning. Me gusta entender cómo funcionan las cosas, y me gusta construir tecnología que tenga un impacto real en las personas que la usan.\n","title":"Sobre mí","type":"page"}]