2 puntos por GN⁺ 2023-11-28 | 1 comentarios | Compartir por WhatsApp
  • Después de que su hija de dos años se obsesionara con los aviones, creó en algunas noches, como proyecto paralelo, Aviator, una app para iOS que muestra las aeronaves cercanas como si fuera un radar en el teléfono
  • FlightRadar24 muestra la ubicación de las aeronaves en un mapa, pero había que determinar aparte hacia qué dirección mirar en el cielo real y qué avión sería más fácil de encontrar para una niña
  • La app combina la información de orientación de Core Location, la API REST no comercial de OpenSky Network, anotaciones de MapKit y una UI en SwiftUI para mostrar las aeronaves alineadas con la dirección del dispositivo
  • Tras comprobar en una prueba MVP que los aviones reales coincidían con lo que mostraba la app, agregó ocultamiento del mapa, ampliación de aeronaves a baja altitud, animación de radar, efecto CRT, sonido y háptica, y configuración de colores
  • La app final se publicó en App Store, y quedaron como posibles mejoras posteriores el nivel de zoom, la API avanzada de OpenSky, mostrar países de salida y llegada, mejoras del shader de Metal, filtros de distancia y altitud, y un “zany mode”

De mirar aviones a requisitos de una app

  • Durante un viaje al extranjero en verano, su hija esperaba con entusiasmo un vuelo de 3 horas y, después de abordar, una azafata le permitió conocer la cabina de pilotos, lo que la hizo engancharse aún más con los aviones
  • Desde entonces pedía con frecuencia que le ayudaran a encontrar aviones en el cielo, al punto de pasar una hora en el jardín, llevándola en hombros, buscando aviones en el cielo del atardecer
  • FlightRadar24 mostraba la ubicación de las aeronaves sobre un mapa, pero el usuario tenía que alinear por su cuenta hacia qué dirección mirar en el cielo real
  • En un mapa 2D, un Learjet a 40,000 pies y un AirBus que acaba de despegar de London City Airport pueden verse parecidos, pero en el cielo real es más fácil encontrar una aeronave grande a baja altitud
  • Lo que necesitaba una niña de dos años no era interpretar un mapa, sino simplemente encontrar aviones
  • El problema inicial se resumió en tres puntos
    • Alinear la dirección: según la orientación del dispositivo, la ubicación de las aeronaves debe corresponderse con la dirección real en el cielo
    • Representar el tamaño: el tamaño en pantalla debe variar según la altitud de la aeronave
    • Usabilidad: no debe ser una app profesional de seguimiento de vuelos, sino una app con sensación de juguete retro

Diseño inicial de Aviator

  • La idea de la app era “mostrar vuelos cercanos en un radar”, y el proyecto se llamó Aviator
  • Los requisitos principales eran tres
    • Cuando el dispositivo gira, la pantalla también gira para que las aeronaves aparezcan en la dirección correcta
    • El tamaño en pantalla varía según la altitud de la aeronave
    • Tiene una sensación divertida de juguete retro, adecuada para una niña
  • Para manejar la orientación usó actualizaciones de heading de la API Core Location de iOS
    • En didUpdateHeading de CLLocationManagerDelegate recibe la orientación del dispositivo
    • Con CurrentValueSubject de Combine transmite el valor de orientación a las vistas SwiftUI
  • Para los datos de aeronaves usó OpenSky Network
    • Proporciona datos de aeronaves en tiempo real dentro de un rango específico de latitud y longitud mediante una API REST simple
    • El uso no comercial es gratuito
    • La idea era llamar al endpoint cada pocos segundos para un barrido de radar realista
  • Los datos de ubicación se obtienen con Core Location, y se consulta un rango de latitud y longitud alrededor de la ubicación del usuario
    • En el planteamiento inicial buscaba difuminar suficientemente la ubicación del usuario usando latitud ±1 grado y una precisión de ubicación de 0.1 grados, alrededor de 10 km
    • En el código de ejemplo real de la API usó un rango de 0.5 grados de latitud y 1 grado de longitud para que en la latitud del Reino Unido quedara aproximadamente cuadrado
  • Como la API de OpenSky Network está restringida a uso no comercial y la app tampoco era un servicio comercial, en SwiftUI usó una estructura MV simple y separó solo servicios centrales como API y Location

PoC: validación de orientación, datos de aeronaves y mapa

  • La PoC de orientación maneja la solicitud de permisos de ubicación, la configuración del delegate y el inicio de actualizaciones de heading con un singleton LocationManager
  • La vista SwiftUI se suscribe a rotationAngleSubject con .onReceive e implementa un efecto tipo brújula que hace rotar rectángulos colocados en círculo
  • En el dispositivo de prueba respondía bien a los cambios reales de ubicación, pero por una animación que trataba 0 y 360 grados como valores separados, aparecía un glitch visual en el que los rectángulos daban una vuelta completa al pasar por el norte verdadero
  • La API REST de OpenSky devuelve un arreglo de vuelos regionales mediante una solicitud GET con un rango de latitud y longitud
    • El endpoint de ejemplo usa states/all con parámetros lamin, lamax, lomin, lomax
    • La documentación de la REST API está bien hecha, pero como la respuesta no tiene keys, había que parsear los campos JSON en orden
    • Con UnkeyedContainer de Swift decodificó icao24, callsign, origin_country, time_position, last_contact, longitude, latitude, entre otros
  • El primer intento de dibujar aeronaves consistió en multiplicar la diferencia entre la ubicación del usuario y la latitud y longitud de la aeronave por una escala fija de pantalla, y colocar una imagen del SF Symbol airplane
    • La distancia real de 1 grado de latitud o longitud varía según la ubicación, así que no podía ser preciso
    • Aun así fue útil como punto de partida
  • Para validar la precisión, colocó un Map de SwiftUI como fondo y superpuso las aeronaves y la brújula
    • Comparado con la proyección de FlightRadar, la cantidad de aeronaves y los clusters coincidían a grandes rasgos, pero las ubicaciones estaban bastante desplazadas
    • Luego cambió a dibujar las aeronaves directamente sobre el mapa como anotaciones (annotation)

MVP: anotaciones de MapKit y prueba con usuario

  • Al apuntar a iOS 17, usó la función de anotaciones de mapas de MapKit para mostrar marcadores con forma de avión en coordenadas geográficas reales
  • FlightMapView dibuja anotaciones de aeronaves sobre Map(position:) y bloquea la interacción con el mapa mediante .allowsHitTesting(false) para ajustarlo al uso como radar
  • Al principio, el ajuste de tamaño basado en altitud aplicaba una escala logarítmica para que las aeronaves más altas se vieran más grandes
    • Combinó el true_track de la aeronave con la orientación del usuario de Core Location para alinear la dirección del ícono de avión
  • En la primera prueba de usuario del MVP encontró aviones reales junto con su hija y confirmó que las aeronaves mostradas en la app también eran visibles en el cielo real
  • Después de la prueba quedaron claras dos correcciones
    • El ajuste de tamaño estaba al revés: para mostrar las aeronaves más fáciles de encontrar a simple vista en el cielo, las de menor altitud debían verse más grandes
    • Su hija no quería un mapa, sino solo aviones, por lo que era necesario quitar el mapa para reducir el ruido visual
  • La fórmula de escala corregida es min(2, max(4.7 - log10(flight.geo_altitude + 1), 0.7))
    • En escaneos del cielo local produjo valores de 0.7 a 2.0, y la distribución en pantalla quedó bien ajustada

Construcción de la UI de radar

  • La API de OpenSky suele devolver timeouts, 502 Bad Gateway y respuestas 200 con datos null
    • Como es una API gratuita no comercial y no tiene SLA, agregó lógica básica de reintentos en el cliente
    • Al día siguiente funcionó bien durante todo el día, y en general parecía aceptable fuera de ciertas horas de mucho tráfico
  • Para ocultar el mapa real usó un overlay MapPolygon
    • Aunque originalmente es un overlay para resaltar áreas del mapa, lo aprovechó para cubrir el mapa y dejar solo las anotaciones de aeronaves
    • Los overlays de Apple se dibujan sobre el mapa y debajo de las anotaciones, así que el resultado fue el deseado
  • La pantalla de radar se implementó con líneas, círculos concéntricos y un angular gradient giratorio de 20 grados de ancho
  • Después simplificó el efecto de línea del radar a un angular gradient de 360 grados
    • Al rotar un gradient que va de verde a transparente y luego a negro, parece un barrido con estela
    • Evaluó que el enfoque “grug-brained” muchas veces encaja mejor
  • Al girar rápido el dispositivo aparecía un artefacto visual en el que se veían fragmentos del mapa en las esquinas de la pantalla, y lo resolvió con una reverse mask que cubre de negro el exterior de la vista de radar

Producto: efecto CRT, sonido, configuración y App Store

  • Para dar una sensación de juguete retro, agregó un efecto de pantalla CRT
    • Usó el soporte integrado para shaders de Metal en colorEffect de iOS 17
    • El shader aplica valores de scanline a los píxeles que no son negros
    • Añadió un parámetro time para que las scanlines se muevan rápidamente hacia arriba y den una sensación dinámica
  • Consultó a OpenSky Network para confirmar si estaba bien publicarla en App Store según su política, y recibió respuesta en menos de 20 minutos
  • Para la experiencia de radar y la accesibilidad, agregó sonido del sistema y háptica cuando se actualizan los vuelos
    • Reproduce un sonido beep-boop con AudioServicesPlaySystemSound(1052)
    • Usa sensoryFeedback(.levelChange, trigger:) de SwiftUI
  • Como el sonido podía resultar molesto, agregó configuración basada en @AppStorage
    • silent: modo silencioso
    • showMap: permite desactivar el overlay de radar y ver el mapa de abajo
    • userColor: permite elegir el color del radar con el color picker de SwiftUI
  • Como había cancelado la suscripción a Midjourney, usó el generador gratuito no comercial de Gencraft para crear una mascota de Aviator con la apariencia de su hija usando un gorro de aviador
  • Al reinscribirse en el Apple Developer Program, pagó £79 y preparó la distribución en App Store
    • Aunque apunta solo a iOS 17, tuvo que enviar capturas de pantalla de iPhone de 6.5 y 5.5 pulgadas
    • Como el iPhone de 5.5 pulgadas más reciente, el iPhone 8 Plus, llega como máximo a iOS 16, exportó capturas en ambos tamaños con AppScreens
  • La app llegó a App Store, y el enlace de descarga es Aviator — Radar on your Phone

Candidatas para próximas versiones

  • Quedó satisfecho con el resultado de este proyecto paralelo hecho durante algunas noches, y la experiencia de programar un juguete para su hija fue de las más divertidas en mucho tiempo
  • Las funciones candidatas para el próximo release son las siguientes
    • Agregar un nivel de zoom del mapa para limitar el radar solo a aeronaves más cercanas
    • Mostrar helicópteros, satélites y categorías de tamaño de aviones con la API avanzada de OpenSky Network
    • Agregar un toggle para mostrar el país de salida y llegada de las aeronaves
    • Mejorar el efecto de pantalla CRT con shaders de Metal más avanzados
    • Refactorizar los controles como un modal pull-out de progressive disclosure con tamaño ajustable
    • Implementar filtros deslizantes de distancia y altitud para ocultar, por ejemplo, aeronaves bajas y lejanas
    • Implementar un zany mode que renderice ovnis, insectos gigantes y alienígenas en el radar

1 comentarios

 
GN⁺ 2023-11-28
Opiniones en Hacker News
  • Gran trabajo y buen artículo. Es interesante lo fuerte que el diseño del indicador de radar original sostiene este proyecto.
    Es posible que el niño nunca llegue a tocar un ASR-9 con pantalla PPI, mucho menos un CRT real, pero dedicaron bastante esfuerzo a simularlo.
    Quizá sea porque les gusta el esqueumorfismo, pero también parece ser porque la pantalla de radar original condensaba muy bien la pregunta: “¿hay algo en el cielo y dónde está respecto de mí?”.
    Siento que las interfaces actuales para observar el cielo, al orientarse hacia información de contexto, enlaces a servicios externos y espacios publicitarios, perdieron la capacidad de responder fácilmente esa pregunta.

    • Me gusta que la pantalla de RADAR, aunque era producto de la tecnología que la hizo posible, es decir, el barrido, también era una representación deliberada para mostrar con claridad el objeto observado.
      La distancia del objetivo se expresaba como distancia desde el centro, y el rumbo como un ángulo sobre la circunferencia.
      Dicho eso, imitar el barrido quizá haya sido una decisión de diseño discutible, y los colores brillantes junto con un fondo sin mapa no parecen un problema en absoluto, porque concentran la atención en la intención de la pantalla.
      También se veía que, al girar con el teléfono en la mano, el seguimiento de la brújula rompía la ilusión del barrido.
    • No todas las UI para observar el cielo fueron en esa dirección. SkyMap también vale la pena.
      https://github.com/sky-map-team/stardroid
    • Un servicio que todavía captura bien “¿hay algo en el cielo y dónde está respecto de mí?” es el modo AR de FlightRadar24.
      Entiendo todos los componentes técnicos involucrados e incluso opero mi propia estación ADSB, pero sigue siendo sorprendente apuntar la cámara al cielo y ver los metadatos de los aviones dentro del campo de visión.
    • Creo que me gustó porque el punto de partida era muy puro. Empezó con “¿hacia qué dirección tengo que mirar para encontrar el avión?” y desde ahí fueron construyendo todo.
  • Excelente. Lo agregué a mi lista de cosas para hacer algún día.
    En una línea similar, le hice a mi hijo de 5 años un logbook de vuelos, y empezamos desde que era bebé. Cada vez que volamos, le hago preguntar a la tripulación si el capitán podría escribir algo.
    Registramos la ruta, el tipo de avión y lo que pasó, y a la tripulación le encanta este tipo de cosas. También hemos visto la cabina y las áreas de descanso de la tripulación, y los mensajes que escribieron siempre fueron muy amables.
    Cada vez que se lo devuelven, mi hijo sonríe de oreja a oreja, así que lo recomiendo mucho para pequeños fanáticos de los aviones.

    • Mi padre me empezó un logbook cuando era bebé, y ahora, en mis 30, todavía lo sigo actualizando. Incluye todos los vuelos que he tomado hasta ahora, así que es una idea realmente genial.
    • Otro voto por el logbook. Cuando mi hija tenía unas 8 semanas volamos de London a New York, y hasta nos quedó una foto espectacular de ella en la cabina con la gorra del capitán.
    • Genial. Incluso siendo un adulto hecho y derecho, una invitación a la cabina fue algo tremendamente cool, así que definitivamente pienso empezar en mi próximo vuelo.
  • Me gusta que una función imprescindible del lanzamiento inicial haya sido cambiar el color de la pantalla. Eso demuestra una comprensión muy sólida de las necesidades del público objetivo.
    A cualquier niño de 3 años le encanta cualquier juguete que tenga selector de color.

    • A mí, un hombre adulto, también me emociona que haya un selector de color.
      Basta imaginar la emoción irracional de pasar los 250 de karma en HN.
    • Es uno de los componentes más subestimados de SwiftUI.
      Incluso si se lo muestro hoy, lo primero que le importa a mi hijo es elegir el color, y además es bueno para el desarrollo de la motricidad fina.
  • La parte de “habíamos exagerado tanto la emoción de viajar en avión que al niño le sorprendió enterarse de que había que tomar un taxi hasta el aeropuerto. Pensaba que podía salir de casa caminando y subirse directo al avión” es realmente adorable, graciosa y entendible.

  • Sobre la parte de que, cuando la tripulación ve a un pequeño fanático adorable de los aviones, le muestran la cabina: vestirse con jumpsuits naranjas de NASA a juego es un pasaporte para entrar a cualquier cabina.
    La tripulación se emociona más que los niños, y además es muy fácil encontrar al niño en el aeropuerto.

    • Genial. Entonces solo falta que mi esposa o yo entremos a NASA. ¿Harán falta muchos desarrolladores iOS en el espacio?
  • También está relacionado An app can be a home cooked meal, un artículo sobre clonar para uso familiar una fallida app de red social llamada Tapstack.
    https://www.robinsloan.com/notes/home-cooked-app/

    • Lo marqué como favorito porque es un artículo lovely. Coincido en que, aunque tuviera 0 descargas, el proceso en sí habría valido la pena.
      Claro que volverse viral tampoco está nada mal.
  • Tengo dos pequeñas objeciones.
    Que los puntos de los aviones se muevan después de ser dibujados rompe un poco la inmersión. Se sentiría más realista si los puntos fueran “pintados” por el barrido y quedaran fijos hasta el siguiente barrido.
    Para hacerlo aún más realista, también podrían extrapolar desde los puntos de datos anteriores para que cada avión se mueva de forma consistente en cada barrido.

    • Ambos son puntos válidos. Si se ajustan bien el timing y el ángulo, lo primero parece perfectamente posible.
      Lo segundo incluso podría ser más simple. Como la API devuelve la velocidad del vuelo, se puede calcular con un solo punto de datos.
  • Una buena actividad para hacer con tu hija es ir a una calle, estacionamiento o parque que esté en el extremo de la dirección de aterrizaje de la pista del aeropuerto internacional más cercano.
    Normalmente cambia según la dirección del viento, así que conviene coordinarlo; estacionas el auto y ves cómo entran los aviones para aterrizar.
    La niña puede ver en su radar qué avión viene, y nosotros usamos flightradar24.
    Los niños quedaron completamente fascinados al ver lo cerca del suelo que bajaban los jets grandes durante la aproximación, y se entretienen fácilmente durante horas. Tuvimos que negociar para irnos porque no querían, querían ver si el siguiente avión era más grande o pasaba más cerca.

    • Si fuera el autor, creo que sería London City Airport (LCY), donde el ángulo de aproximación es muy pronunciado.
      Solo pueden operar aeronaves multimotor de ala fija de tamaño igual o inferior a un Airbus A318 que cuenten con certificación especial de aeronave y tripulación para realizar una aproximación de 5,5°.
      https://www.youtube.com/watch?v=yZIDFgpT0-o
      https://en.wikipedia.org/wiki/London_City_Airport
    • Si estás cerca de D.C., Gravely Point es exactamente ese lugar. Ya sea despegando o aterrizando, sientes que podrías contar hasta los remaches de los aviones.
    • Conviene llevar tapones para los oídos.
    • Cuando estaba en la secundaria había un terreno baldío de grava justo afuera de la reja del aeropuerto, al final de la pista. Cuando el viento estaba en la dirección correcta y los aviones despegaban sobre ese terreno, era un buen lugar para estacionar el auto y tener una cita.
    • No es exactamente lo mismo que la sugerencia, pero en SFO hay una Sky Terrace antes del control de seguridad desde donde se pueden ver aviones.
  • Esta app tiene un problema. La página de la app dice claramente 4 años o más, pero el usuario objetivo tiene 2 años.
    Muy bien hecha.

    • Espero que logren mantenerse fuera del radar de la policía de la App Store.
  • Excelente.
    Una pequeña pregunta de detalle: ¿los visores de radar CRT realmente tenían líneas de barrido? Yo pensaba que habrían sido pantallas vectoriales.
    En relación con la lista de funciones adicionales, como es una app para observar aviones, estaría bueno que al tocar un punto mostrara el modelo del avión durante unos segundos.

    • Correcto. Las pantallas de radar antiguas básicamente eran como osciloscopios, donde la posición X/Y se controlaba por el ángulo del radar y la distancia actual del eco de radar. Es una especie de gráfico en coordenadas polares.
      Gracias a la persistencia del fósforo, los ecos de radar fuertes quedaban en la pantalla por un momento. Si en ese tiempo el radar daba una vuelta o más, el mismo avión aparecía como un nuevo punto ligeramente desplazado, es decir, un “plot”.
      También se podían marcar los plots en la pantalla con un plumón para convertirlos en un “track”.
      Había además pantallas especiales en las que se apuntaba una cámara de cine hacia la pantalla de radar para grabar horas de ecos y reproducirlos después.
      Por ejemplo, hay una grabación reproducida en cámara rápida de aeronaves del Pacto de Varsovia durante la revolución checoslovaca de 1968: https://youtu.be/rAUodXI4LPw?t=622
    • Sí era una pantalla vectorial, pero quizá de una forma un poco distinta a la que estás imaginando.
      Las pantallas de radar originales escaneaban desde el centro hacia afuera en dirección radial. El tiempo del barrido estaba predeterminado para escalar la distancia, y la señal de intensidad del haz era directamente la señal amplificada del eco de radar.
      Por eso, una señal de eco más fuerte aparecía como un “blip” más visible en una pantalla de larga persistencia.
      Lo interesante es que, para hacer que el haz del radar barriera alrededor de la pantalla CRT, todo el conjunto emisor del tubo de rayos catódicos se movía con un motor sincronizado con el plato de radar giratorio.
      Esa rotación siempre tenía que coincidir con la velocidad y la dirección del plato de radar; de lo contrario, los blips aparecían en lugares incorrectos.
      Las líneas radiales y de distancia fijas estaban impresas en el propio tubo CRT o en una cubierta transparente. Estas pantallas se usaron durante décadas, probablemente incluso hasta los años 80 o principios de los 90.
      Las versiones más modernas podían escanear independientemente en las direcciones X/Y con circuitos electrónicos simples para evitar el complejo conjunto emisor giratorio del haz.
      Más detalles: https://en.wikipedia.org/wiki/Radar_display#Plan_position_in...
    • Ampliando un poco lo que señalaron otras respuestas, el haz efectivamente barre radialmente desde el centro hacia afuera.
      El ángulo puede generarse ya sea haciendo girar físicamente las placas de deflexión, o calculando electrónicamente sen/cos y aplicándolos a las placas de deflexión X/Y.
      Como la amplitud de la señal de retorno impulsa directamente la corriente del haz, los objetivos con ecos más grandes se ven más brillantes.
      A esto se suma el efecto de tubo de almacenamiento, que no funciona como el modo biestable de las pantallas vectoriales X-Y de tubo de almacenamiento de las primeras computadoras, sino más bien como el modo de persistencia variable de algunos osciloscopios.
      Esta característica también produjo consecuencias relacionadas con intentos tempranos de diseño de aeronaves furtivas como el SR-71 o el XB-70.
      En el tubo de radar, la corriente del haz se ajusta para que el “blip” se acumule a lo largo de varios barridos, y normalmente el blip se mueve menos que su propio diámetro entre barridos.
      Pero si la sección transversal de radar del avión es inherentemente baja y se mueve tan rápido que el blip recorre una distancia mayor entre barridos, el operador de radar puede interpretar esos pequeños blips fantasma como ruido, especialmente en una situación caótica con muchos objetivos.