Documento Completo - pdf-PDFA
Documento Completo - pdf-PDFA
Documento Completo - pdf-PDFA
En las ciencias astronómicas, el uso de cámaras digitales han revolucionado el estudio del Universo. Dado su bajo costo
y su rendimiento, muy superior al de la fotografía química, cada vez son más los astrónomos amateurs que las utilizan
para retratar los objetos del firmamento.
La cámara QHY5T, diseñada y fabricada por la empresa QhyCCD, es una cámara específica para realizar fotografía
lunar, solar y planetaria y para guiado. Cuenta con un puerto de guiado opto acoplado que protege al dispositivo de
posibles corrientes parásitas que puedan provenir de los motores de la montura.
Este trabajo trata sobre el desarrollo de un controlador para la cámara QhyCCD QHY5T para el sistema operativo
GNU/Linux y de un programa visor (qhy5tviewer) que permite utilizar la cámara desde dicho sistema operativo. Tanto el
controlador como el visor se basaron en el driver abierto para GNU/Linux para la cámara QHY5 del mismo fabricante.
Ambos controladores fueron desarrollados utilizando la librería libusb y son controladores ``en espacio de usuario'', esto
quiere decir que en ningún momento el kernel Linux se modifica para que soporte el dispositivo. Muchos de las rutinas de
configuración de la cámara de bajo nivel están tomadas del código de controlador para Windows de la cámara QHY5T.
GNU/Linux, Driver, Controlador, Cámara QHY5T, A comienzos del año 2012 se comprobó que a pesar que
Astrofotografía, Fotografía Lunar, Fotografía Planetaria, existía el soporte para el sensor en el Kernel Linux, la
Fotografía Solar, QhyCCD, qhy5tviewer. cámara no funcionaba en este sistema operativo. Durante
los dos años siguientes se trabajó en el desarrollo de un
controlador para GNU/Linux y un programa visor que
permitiera grabar imágenes astronómicas, mediante
ingeniería inversa, análisis de tráfico y estudio de los
controladores de referencia.
Las imágenes presentadas en el capítulo “Conclusiones”
fueron obtenidas utilizando exclusivamente GNU/Linux.
1) Desarrollo de un controlador para GNU/Linux para la 1) Agregar soporte para imágenes de 16 bits.
cámara QHY5T. Este se basó en el controlador de la 2) Agregar soporte para binning 2x2
cámara QHY5 para GNU/Linux, en el driver para Windows 3) Migrar el controlador a libusb-1.0
de la cámara QHY5T y en técnicas de ingeniería inversa y 4) Crear el instalador para Debian GNU/Linux
análisis de tráfico USB. 5) Agregar soporte para cambiar parámetros de
2) Desarrollo de un programa de captura o visor para configuración durante la sesión en curso
GNU/Linux llamado qhy5tviewer, el cual hace uso del 6) Mejorar la función write_fits() para incluir metadata
driver comentado en el punto anterior para configurar la
cámara, mostrar el flujo de imágenes capturadas y
grabarlas en archivos, entre otras funciones.
Abril/2014
Driver para GNU/Linux en espacio de usuario para la cámara
QHY5T
Joaquin Bogado
22 de abril de 2014
2
1. Introducción 9
2. El hardware 13
2.1. El sensor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2. El procesador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.3. El puerto de guiado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3. El firmware 21
3.1. Las primeras capturas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.2. Extracción de datos de la captura de tráfico USB . . . . . . . . . . . . . . . . . . . . . 22
3.3. El formato IHEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.4. udev y fxload para la carga del firmware . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.5. Publicación del firmware del fabricante . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4. El driver 27
4.1. Detalles de la implementación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.2. El tipo qhy5t driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.3. Las funciones exportadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.4. La función ctrl msg() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.5. open y close . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.6. set params() y program camera() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.7. La función main() del driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.8. El proceso de adquisición . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.9. La función set gain() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
4.10. La función write pgm() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
4.11. Los comandos de guiado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
5. El viewer 41
5.1. La estructura general . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
5.2. Las opciones de configuración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.3. El ambiente SDL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
5.4. Los comandos de teclado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.5. La debayerización . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.5.1. La debayerización por interpolación bilineal . . . . . . . . . . . . . . . . . . . . 50
5.6. El crossair . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
5.7. Los archivos FITS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
6. Conclusiones 57
6.1. Comparaciones de rendimiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
6.1.1. Impacto del debayerizado en el framerate . . . . . . . . . . . . . . . . . . . . . 57
6.1.2. Comparación frente al controlador de referencia . . . . . . . . . . . . . . . . . . 57
6.2. Ventajas y desventajas de un controlador en espacio de usuario . . . . . . . . . . . . . 58
6.3. Avances logrados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.3.1. Resultados en fotografı́a solar . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.3.2. Resultados en fotografı́a planetaria (Júpiter) . . . . . . . . . . . . . . . . . . . 60
3
4 ÍNDICE GENERAL
7. Trabajo a futuro 67
7.1. El soporte para imágenes de 16 bits . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
7.2. El soporte para binning 2x2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
7.3. Migración a libusb-1.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
7.4. Compatibilidad con herramientas preexistentes . . . . . . . . . . . . . . . . . . . . . . 67
7.5. Substracción de dark frames automática . . . . . . . . . . . . . . . . . . . . . . . . . . 68
7.6. Modificación de parámetros de captura durante la sesión . . . . . . . . . . . . . . . . . 68
7.7. Mejoras a la función write fits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
7.8. El instalador para Debian . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
7.9. Obtención del código . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
7.10. Compilación del controlador y el visor . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
8. Apendice A 71
8.1. Sobre las técnicas de guiado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
8.2. Sobre las técnicas de procesado para fotografı́a lunar y planetaria . . . . . . . . . . . . 72
Índice de tablas
5
6 ÍNDICE DE TABLAS
Índice de figuras
7
8 ÍNDICE DE FIGURAS
5.11. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.12. Fragmento de la función debayer data() . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.13. Declaración de las macros para acceder a los ocho vecinos de un pixel. . . . . . . . . . 52
5.14. Un ocular reticulado iluminado. La iluminación activa permite ver el retı́culo contra el
fondo negro del cielo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
5.15. La función load crossair(). Notar la invocación a IMG Load(). . . . . . . . . . . . . 53
5.16. Fragmento de main() donde se carga el crossair y se combina con la surface que contiene
el frame. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
5.17. Captura de pantalla de qhy5tviewer utilizando el crossair. . . . . . . . . . . . . . . . . 54
5.18. Encabezado de un archivo FITS generado con qhy5tviewer. . . . . . . . . . . . . . . . 55
5.19. Implementación de la función write fits() en qhy5tviewer. . . . . . . . . . . . . . . . 56
6.1. La imagen RAW obtenida con la cámara QHY5T desde una computadora corriendo
Lihuen GNU/Linux. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
6.2. Imagen obtenida a partir de 2000 cuadros similares a los de la figura 6.1. . . . . . . . . 60
6.3. Imagen cruda de Júpiter tomada con la cámara QHY5T. . . . . . . . . . . . . . . . . . 61
6.4. La imagen de la figura 6.3 debayerizada con debayer.py. . . . . . . . . . . . . . . . . . 61
6.5. Imagen obtenida a partir de 1200 cuadros obtenidos con la QHY5T y el programa
qhy5tviewer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
6.6. Imagen cruda de los montes Apeninos tomada con la cámara QHY5T. . . . . . . . . . 63
6.7. Post procesado de unas 400 imágenes utilizando debayer.py y Registax 6 . . . . . . . . 63
6.8. Una de las primeras imágenes capturadas utilizando la cámara QHY5T en GNU/Linux. 64
6.9. Imagen cruda de Saturno tomada con la cámara QHY5T. . . . . . . . . . . . . . . . . 64
6.10. La imagen de la figura 6.9 debayerizada y recortada con debayer.py. . . . . . . . . . . 65
6.11. Imagen obtenida a partir de 820 cuadros obtenidos con la QHY5T y el programa
qhy5tviewer, procesados con Registax 6. . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Introducción
En las ciencias astronómicas, el uso de cámaras digitales han revolucionado el estudio del Universo.
Dado su bajo costo y su rendimiento, muy superior al de la fotografı́a quı́mica, cada vez son más
los astrónomos amateurs que las utilizan para retratar los objetos del firmamento, a veces incluso
haciendo visible lo que a simple vista no lo es. La astrofotografı́a, como se conoce a dicha actividad
entre los entusiastas, se diferencia de la fotografı́a tradicional (quı́mica o digital) en que las técnicas
aplicadas son sustancialmente diferentes y la etapa del procesado puede jugar un papel tan importante
como el de la adquisición de los datos. Incluso pueden diferenciarse dentro de la astrofotografı́a, dos
técnicas totalmente distintas, cuyas diferencias debido a que el brillo de los objetos a fotografiar es
muy diferente.
Para la fotografı́a de objetos de espacio profundo, como galaxias y nebulosas, generalmente se
realizan algunas decenas de tomas con cierto tiempo de exposición. Estos tiempos pueden variar de
segundos a minutos u horas, dependiendo del brillo del objeto y los filtros utilizados, permitiendo que
la luz se acumule en el sensor para revelar objetos que no son visibles a simple vista. Esto se debe no
solo a que el ojo humano es incapaz de acumular luz como los sensores, sino que tampoco es sensible a
muchas longitudes de onda como el infrarrojo o el ultravioleta, en muchas de las cuales emiten algunos
objetos.
Cuanto mayor es el tiempo de exposición, mayor es el movimiento aparente del cielo nocturno.
Para contrarrestar este movimiento y evitar que las estrellas dejen trazos en las capturas en lugar
de aparecer como objetos puntuales, los aficionados utilizan monturas ecuatoriales motorizadas, las
cuales una vez puestas en funcionamiento permiten realizar tomas de entre 1 y 3 minutos, dependiendo
de la precisión de la puesta en estación1 . Para tiempos de exposición mayores a los 3 minutos, suele
ser necesaria la técnica de “fotografı́a con guiado” ya que no solo la puesta en estación influye en la
calidad del seguimiento celeste, sino también el error periódico introducido por los engranajes de la
montura pueden producir variaciones respecto al seguimiento celeste. En esta técnica se utilizan dos
telescopios y dos cámaras, una de las cuales debe soportar el protocolo de guiado de la montura que
se esté utilizando.
Por otra parte, para la fotografı́a de objetos brillantes como la Luna, el Sol y los planetas Mer-
curio, Venus, Marte, Júpiter y Saturno se utiliza otra técnica completamente diferente en la cual se
realizan cientos o miles de exposiciones cortas del orden de los milisegundos. En esta técnica, también
conocida como Lucky Imaging[1], se descartan aquellas tomas donde la imagen del objeto se encuentra
degradada por efecto de la turbulencia atmosférica, procesándose luego solamente aquellos cuadros de
“buena calidad”.
Existen varios fabricantes de cámaras especı́ficas para estas aplicaciones como SBIG2 , QhyCCD3 y
Orion4 , entre otras. Sin embargo, muy pocas de estas marcas incluyen para sus productos destinados
a aficionados, SDKs (Software Development Kits) o drivers para GNU/Linux. SBIG y Apogge5 , solo
1 La puesta en estación permite contrarrestar el movimiento aparente del cielo realizando un solo movimiento en el
9
10 CAPÍTULO 1. INTRODUCCIÓN
distribuyen drivers y SDKs para GNU/Linux en su lı́nea de cámaras profesionales, las cuales pueden
llegar a costar varios miles de dólares, mucho más de lo que los aficionados promedio argentinos pueden
costear.
QhyCCD es una empresa china que desarrolla cámaras para astronomı́a. Cuenta con varios mo-
delos para los diferentes perfiles de usuario. Las cámaras de guiado son más económicas debido a que
generalmente se basan en sensores CMOS (Complementary metal-oxide-semiconductor) en lugar de
CCD (Charge-coupled Devices), no poseen buffers de memoria interna y no están refrigeradas. Todos
los modelos que ofrece esta empresa cuentan con drivers para las diferentes versiones del sistema ope-
rativo Windows. Sin embargo, menos de la mitad de los modelos cuenta con drivers para GNU/Linux,
aunque en el último año y medio se ha observado un incremento en interés por parte del fabricante
para dar soporte a este sistema operativo. Los primeros drivers para GNU/Linux para las cámaras
QhyCCD no fueron distribuidos de manera oficial por la empresa, sino que fueron desarrollados por
terceros, con o sin ayuda del fabricante y basándose en técnicas de ingenierı́a inversa sobre los drivers
para Windows de dichas cámaras. Durante el transcurso del 2013 y con la llegada de los nuevos mo-
delos como la QHY5-II, la QHY5L-II y otros, es que el fabricante comenzó a desarrollar un SDK para
Linux el cual al momento de escribir este trabajo aun se encuentra en desarrollo y está disponible y
en etapa de pruebas6 . Dicho SDK soporta parcialmente las funciones de los modelos nuevos pero no
se tienen noticias acerca de si se agregará soporte para los modelos anteriores a 2013.
Existen tres modelos de cámaras de guiado QhyCCD de la serie QHY5
El modelo QHY5 se basa en el sensor MT9M001[2] fabricado por Aptina (antes Micron) y tiene
dos versiones, color y mono. Es la única cámara de la serie que cuenta con un controlador para
GNU/Linux desarrollado en 2009 por Geoffrey Hausheer. Este driver es distribuido con una
licencia GPL27 .
El modelo QHY5V está basado en otro sensor del mismo fabricante. No se conocen drivers para
GNU/Linux para este modelo al momento de escribir este trabajo.
El modelo QHY5T basado en el sensor MT9T001[3] también fabricado por Aptina, tiene un
sensor más grande que los modelos anteriores y solo está disponible en formato color.
El driver desarrollado para este trabajo es para el modelo QHY5T y se basó en el driver abierto
para el modelo QHY5. A pesar de que los tres modelos son muy similares en cuanto a funciones, las tres
cámaras son radicalmente diferentes internamente (solo el tamaño del sensor, diferente en cada modelo,
cambia radicalmente el funcionamiento de ambas cámaras), por lo que las modificaciones realizadas al
driver existente para el modelo QHY5 fueron sustanciales. Ambos controladores fueron desarrollados
utilizando la librerı́a libusb y son controladores “en espacio de usuario”, esto es, en ningún momento
el kernel Linux se modifica para que soporte el dispositivo. Esto tiene algunas ventajas y desventajas
que se discuten en el capı́tulo 6.
El trabajo realizado para esta tesina consistió en:
La extracción del firmware de la cámara mediante técnicas de análisis de tráfico USB.
El desarrollo de un controlador para GNU/Linux para el modelo de cámara QHY5T, el cual se
baso en parte en el trabajo realizado por Hausheer para el controlador de la cámara QHY5, en
el driver para Windows de la cámara QHY5T desarrollado por Tom Van den Eede y en técnicas
de ingenierı́a inversa y análisis de tráfico USB.
El desarrollo de un programa de captura o visor para GNU/Linux llamado qhy5tviewer, el cual
hace uso del driver comentado en el punto anterior para configurar la cámara, mostrar el flujo
de imágenes capturadas y grabarlas en archivos, entre otras funciones.
En el capı́tulo 2 se describe el hardware de manera detallada, haciendo énfasis en las caracterı́sticas
principales del sensor de la cámara. En el capı́tulo 3 se describe el proceso por el cual se obtuvo una
de las versiones del firmware mediante técnicas de ingenierı́a inversa. En el capı́tulo 4 se describen
detalladamente las rutinas implementadas que permiten acceder a las funciones de la cámara y las
6 La última versión de dicho SDK se puede descargar de https://github.com/qhyccd-lzr/QHYCCD Linux. El autor
cuales forman parte de la API del driver, además de las rutinas internas de comunicación y sincroni-
zación privadas del driver. En el capı́tulo 5 se describe la aplicación desarrollada para la captura de
imágenes utilizando el dispositivo, la cual hace uso intensivo de la API descripta en 4. En el capı́tulo 6
se detallan los objetivos alcanzados, se muestran algunos resultados obtenidos y se presentan algunas
conclusiones. Por último capı́tulo 7 se discuten posibles mejoras tanto al driver como al visor. Además
se proveen instrucciones precisas sobre como obtener el código del controlador y del visor, además de
instrucciones para la compilación y puesta en funcionamiento.
12 CAPÍTULO 1. INTRODUCCIÓN
Capı́tulo 2
El hardware
La QHY5T, diseñada y fabricada por Hongyun Qiu para su empresa QhyCCD, es una cámara para
realizar fotografı́a lunar y planetaria y para guiado. Cuenta con un puerto de guiado opto acoplado
que protege al dispositivo de posibles corrientes parásitas que puedan provenir de los motores de
la montura. Tiene un sensor CMOS de 3 Megapixels (Mpx) color, fabricado por Aptina modelo
MT9T001[3]. El procesador de la cámara está basado en la arquitectura 8051 de Intel y es fabricado
por Cypress[4]. La cámara no cuenta con memoria interna para almacenar las fotografı́as. Estas se
transmiten a la computadora a través del puerto USB de manera inmediata.
En Windows, cuando la cámara se conecta, el driver se encarga de copiar el firmware a la cámara.
Este firmware no queda residente en la cámara y debe cargarse nuevamente cada vez que la cámara
se desconecta y se vuelve a conectar al puerto USB de la computadora. Una vez cargado el firmware,
el driver envı́a los parámetros de configuración a la cámara a través de la conexión USB. Entre los
parámetros de configuración, se pueden destacar la resolución, la ganancia del sensor (gain), el tiempo
de exposición, el binning y la cantidad de bits por pixel de la imagen devuelta por la cámara. Luego
el firmware procesa los requerimientos de nuevos frames1 del driver. El procesador de la cámara hace
de interfaz entre el sensor y la computadora.
2.1. El sensor
El sensor de imagen es el elemento de una cámara fotográfica digital que capta la luz que compone
la fotografı́a. Se trata de un chip formado por millones de componentes sensibles a la luz que al ser
expuestos capturan la imagen. Cada uno de los elementos fotosensibles del sensor se denomina pixel
(picture element). El número de pı́xeles del sensor se suele medir en millones de pı́xeles (o megapı́xeles,
Mpx). Dependiendo de la tecnologı́a utilizada en su fabricación pueden dividirse a grandes rasgos en
sensores CCD o CMOS, siendo los últimos más económicos y eficientes en cuanto a consumo de energı́a,
entre otras ventajas.
Una caracterı́stica importante a mencionar es que dado que los foto-receptores de silicio son inca-
paces de determinar la longitud de onda de los fotones recibidos, son inherentemente monocromáticos.
Los sensores color utilizan un Color Filter Array (CFA), es decir una matriz de filtros rojos, verdes y
azules con un patrón conocido como Bayer matrix o Bayer pattern[5]. La imagen en color es calculada
mediante un proceso de interpolación conocido como interpolación cromática, debayerización2 o bayer
demosaicing[6].
La QHY5T tiene un sensor CMOS color de 3Mpx modelo MT9T001 fabricado por Aptina. Este
sensor cuenta con una matriz de pixels de 2112 columnas por 1568 filas como se muestra en la figura
2.1. Las columnas 0 a 27 y 2085 a 2111 y las filas 0 a 15 y 1561 a 1567 devuelven información del
negro óptico, es decir, no están expuestas a la luz. Esta información se utiliza de manera interna por la
lógica del sensor para calibrar el nivel de negro (black level en la jerga) de la imagen, aunque también
pueden ser leı́dos configurando dos registros a través de la interfaz I 2 C 3 . Además, hay 2057 columnas
1 En este trabajo, se utilizará frame, cuadro o fotograma de manera indistinta, para hacer referencia a una matriz de
13
14 CAPÍTULO 2. EL HARDWARE
y 1545 filas de pixels activos que proveen un borde de 4+ pixels alrededor de la imagen de 2048x1536,
lo que deja espacio para el tratamiento de bordes durante la interpolación para generar la imagen en
color.
El sensor MT9T001 tiene un patrón de Bayer como se muestra en la figura 2.2. Las filas pares
tienen pixels rojos y verdes, mientras que las impares tienen pixels verdes y azules.
4 Analog-to-Digital Converter
2.1. EL SENSOR 15
Este sensor tiene una interfaz nativa I 2 C. Todas las configuraciones posibles para el sensor se
logran escribiendo los valores adecuados en registros como los detallados en la tabla. Sin embargo,
el firmware de la cámara no expone esta interfaz sino que implementa una capa de abstracción que
impide acceder a las funciones nativas I 2 C del sensor.
La tabla 2.1 resume algunos de los registros más importantes. La lista completa puede consultarse
en la tabla 3 de la página 12 de la hoja de datos del sensor[3].
Tabla 2.1: Resumen de los registros más importantes del sensor y sus valores por defecto.
NOTA: 0 = bit siempre en cero; 1 = bit siempre en uno; d = bit programable
Utilizando los cuatro registros antes mencionados es posible declarar regiones de interés (ROIs) de
manera arbitraria en múltiplos de a 4 pixels. Una ROI queda definida mediante la especificación de
una resolución y un desplazamiento respecto al origen en los ejes x e y. Para este sensor, es posible
definir ROIs por hardware, es decir que una vez configurada una ROI, el sensor solo devuelve los
datos para esa zona y no es necesario recortar los datos luego. Este comportamiento trae aparejado
un aumento en la eficiencia, ya que no consume el mismo tiempo enviar los datos correspondientes
a una imagen de 640x480 pixels a través de la interfaz USB, que enviar los datos de una imagen
de 2048x1536 pixels para luego recortar la región de interés por software. Debido a esto, se pueden
lograr un frame rate mayor a resoluciones bajas. Cabe resaltar que el uso de salteos de lectura (Row
Skip y Column Skip) y el uso de binning 5 pueden determinar algunos lı́mites para los valores de estos
registros.
Figura 2.5: Utilización de salteo de lectura 2x2 (row skip 2x, column skip 2x)
Tabla 2.2: Valores óptimos para los niveles de ganancia en relación al ruido.
También es posible configurar la ganancia global utilizando Reg0x35. Sin embargo este compor-
tamiento no es abstraı́do por el firmware con lo que queda inaccesible desde las funciones del driver.
Notar que el rango de 1 a 128 no es lineal. En el driver este rango es de 1 a 167 como consecuencia de
transformar la función de ganancia en una función lineal a pasos enteros. Se discute más al respecto
en la sección 4.9.
2.2. El procesador
La cámara cuenta con un procesador modelo CY7C68013A fabricado por Cypress Semiconductor
Corporation. Dicho procesador cuenta con una serie de caracterı́sticas que se enumeran a continuación:
Reloj del sistema de 24 MHz.
Set de instrucciones basado en la arquitectura Intel 8051, con algunas instrucciones y registros
añadidos.
Cuatro Endpoints USB programables para transferencias BULK, INTERRUPT o ISOCHRO-
NOUS 7 con capacidades de doble, triple y cuádruple buffer.
Transceptor8 USB 2.0 de alta velocidad integrado.
Soporte de compatibilidad con EZ-USB FX29 .
En el caso de la cámara QHY5T, el código del firmware en el lenguaje de la arquitectura 8051
corre desde la memoria RAM interna del procesador, la cual es cargada por USB (mediante el
protocolo FX2) al momento en que la cámara es conectada a la computadora.
Memoria RAM integrada de 16 KB para datos y/o instrucciones.
Interfaz de datos de 8 o 16 bits con conversión automática.
Interfaz I 2 C (solo en modo Master) a 100/400 KHz.
Este procesador ejecuta un firmware que atiende los requerimientos del driver. Los requerimientos
(que pueden ser mensajes de control o requerimiento de datos del sensor) son recibidos por la interfaz
USB. Estos requerimientos son luego transformados en mensajes para el sensor o en pulsos para el
puerto de guiado según corresponda.
Debido a esto, la interfaz I 2 C del sensor queda oculta e inaccesible al controlador y no es posible
comunicarse con el primero sino a través de las funciones implementadas en el firmware.
7 Estos tipos de transferencia son los soportados por el protocolo USB. Más en
http://www.beyondlogic.org/usbnutshell/usb4.shtml
8 Dispositivo transmisor y receptor.
9 Un protocolo diseñado por AnchorChips que permite cargar el firmware al procesador por USB, ya que el protocolo
Pin 1: No conectado
Dado que este puerto se conecta directamente a la lógica de la montura y que la especificación del
protocolo ST-4 no indica como se implementa esta conexión, los circuitos de la cámara se encuentran
aislados mediante opto acopladores. Esto protege a la cámara de monturas que conectan dicho puerto
directamente al circuito de potencia de los motores, los cuales por su naturaleza pueden producir
corrientes parásitas de varias veces el voltaje soportado por la electrónica de la cámara y que la
pueden dañar permanentemente.
El protocolo ST-4 es un estándar de facto, introducido en el mercado por el fabricante SBIG
para su cámara guı́a ST-4 Star Tracker Imaging Camera [7]. Esta cámara ha sido la referencia tanto
para fabricantes de otras cámaras de guiado como también para fabricantes de monturas, los cuales
dan soporte por lo menos a este protocolo o alguna modificación compatible. Sin embargo no existe
una especificación oficial que describa por ejemplo que voltajes debe manejar cada lı́nea (aunque
generalmente es el voltaje manejado por la cámara internamente) y los pulsos de guiado se activan
por flancos.
A diferencia de la cámara de SBIG, la QHY5T no dispone de hardware especializado para el análisis
de las imágenes en pos de determinar el desplazamiento de las estrellas. Esta tarea debe hacerse por
software en la computadora, mediante algún programa especializado.
Figura 2.9: Interfaz de conexión de una montura HEQ5 marca SkyWatcher. A la derecha, el puerto
de guiado compatible con el protocolo ST-4.
Capı́tulo 3
El firmware
Durante el transcurso de este trabajo se obtuvieron dos versiones del firmware por medios to-
talmente diferentes. La primera versión fue obtenida por medio de ingenierı́a inversa y análisis de
capturas de tráfico USB de la comunicación entre el driver y el dispositivo en un entorno con sistema
operativo Windows, mientras que la segunda versión fue provista por el fabricante en una etapa bas-
tante avanzada del presente trabajo. Dados los buenos resultados obtenidos mediante la aplicación de
la primer técnica es que se describe su obtención por esta vı́a.
A pesar de los buenos resultados, el proceso es sumamente largo y en algunas partes, tedioso.
Requirió mucho tiempo, esfuerzo, lectura, análisis y sobre todo, paciencia.
21
22 CAPÍTULO 3. EL FIRMWARE
estos paquetes de los paquetes de datos de los frames capturados por el sensor. Se presumı́a que una vez
enviado el tráfico de configuración, la cámara tomarı́a todos los frames con esa misma configuración
y no se volverı́a a enviar información de control hasta que se realice un cambio en la configuración a
través del programa de captura de video. Esto se pudo constatar simplemente cubriendo el sensor de
manera que no entre luz a la cámara, lo que resultó difı́cil ya que por más que la cámara estuviera
cubierta la imagen del video no era negra, sino gris, lo que indicaba que los bytes leı́dos del sensor no
eran 0x00 y podı́an confundirse con datos de control. Por el contrario, exponiendo el sensor a plena
luz, todos los bytes leı́dos del sensor eran 0xFF, es decir pixels totalmente blancos.
Se pudo constatar de esta manera lo que se presumı́a en una primera instancia, es decir, no se
transfiere información de control entre el controlador y la cámara a menos que alguna configuración
cambie. Sin embargo se notó un comportamiento no esperado cuando se iniciaba la captura antes de
conectar la cámara al puerto USB. Al momento de capturar antes de conectar la cámara, se podı́a
apreciar un flujo de tráfico el cual no se podı́a asociar ni a datos del sensor ni a parámetros de
configuración. Este flujo de datos duraba solo uno o dos segundos, luego de los cuales la conexión se
cortaba y la captura se detenı́a. Era necesario reiniciar la captura con la cámara conectada el puerto
USB para poder capturar el tráfico de configuración o de datos.
Compartiendo información del proyecto con un colega, se pudo determinar que en la mayorı́a de
las cámaras web o similares es responsabilidad del driver subir el firmware al dispositivo, dado que en
general no tienen una memoria EEPROM o similar para almacenamiento no volátil y se comenzó a
sospechar que dicho flujo de datos anormal podı́a contener dicho firmware.
Con esto en mente se comenzó a trabajar en separar el código del firmware de los reportes de
captura provistos por el USBlyzer.
Como se pudo determinar luego, otras cámaras del mismo fabricante se comportaban de manera
similar, es decir, el controlador graba el firmware del dispositivo al momento de la conexión en una
memoria volátil, por lo que es necesario realizar esta tarea cada vez que el dispositivo se conecta.
Además la versión para GNU/Linux del driver para la cámara QHY5 solucionaba esta tarea utilizando
el mecanismo udev para detección de dispositivos de GNU/Linux y fxload, el cual permite cargar el
firmware en formato IHEX a la memoria del microcontrolador de la cámara. Es decir, el firmware no
formaba parte del código fuente del driver sino que estaba separado y por ello no fue advertido en un
primer análisis de dicho código fuente.
Dicho esto, ahora habı́a pues que convertir el reporte obtenido de la captura con flujo anormal a
un archivo IHEX compatible con fxload.
De estas columnas la más importante es la columna Raw Data la cual contiene los datos crudos de
la transferencia de datos. Utilizando expresiones regulares se obtuvieron los datos de dicha columna
3.3. EL FORMATO IHEX 23
los cuales están formados por 8 dı́gitos hexadecimales para dirección, dos espacios en blanco, 16 bytes
hexadecimales separados por espacios en blanco, dos espacios en blanco y la representación ASCII de
los 16 bytes precedentes. Por ejemplo:
00000000 12 01 00 02 FF FF FF 40 18 16 10 09 00 00 00 00 .......@........
00000010 00 01
00000000 12 01 00 02 FF FF FF 40 18 16 10 09 00 00 00 00 .......@........
00000010 00 01 ..
00000000 12 01 00 02 FF FF FF 40 18 16 10 09 00 00 00 00 .......@........
00000010 00 01 ..
00000000 01 .
00000000 01 .
00000000 01 .
00000000 02 02 EE 32 ...2
..
.
Debido a una incorrecta configuración de los filtros del programa de captura de tráfico, los datos
crudos aparecı́an triplicados y el campo wvalue de los paquetes USB no figuraba en los reportes. Los
datos triplicados fueron borrados a mano con un editor de texto y la información del campo wvalue
fue copiada a mano usando lápiz y papel, para su posterior tratamiento. Además se eliminaron la
primer lı́nea del archivo generado debido a que correspondı́a a una transferencia de datos de entrada,
las direcciones y la representación ASCII.
El archivo generado se adjunta en forma separada con el nombre de q.hex, el cual a pesar de tener
extensión .hex no es un archivo IHEX bien formado.
2. Data lenght: 1 par de dı́gitos hexadecimales que indican la longitud del campo de datos del
registro.
3. Load offset: 2 pares de dı́gitos hexadecimales en big endian que indican la dirección donde se
cargarán los datos. Solo tiene sentido si es un registro de datos. Si no debe ser “0000”
4. Record type: 1 par de dı́gitos hexadecimales que indican el tipo de registro. Pueden ser desde
00 hasta 05.
6. Checksum: 1 par de dı́gitos hexadecimales con el byte menos significativo del complemento a
dos de la suma de todos los dı́gitos hexadecimales de los campos 2 al 5.
Para este trabajo solo fueron necesarios los registros de tipo 00 y 01.
De las capturas de tráfico USB se contaba con el campo de datos para armar el archivo en formato
IHEX pero no con las direcciones. Estas direcciones fueron documentadas en lápiz y papel inspeccio-
nando el campo wvalue de los paquetes de datos USB con la herramienta USBlyzer. La mayorı́a de
las direcciones correspondı́an a escrituras secuenciales donde los datos eran escritos en registros con-
secutivos. Además, era necesario calcular los checksums para cada uno de los registros. Fue necesario
entonces escribir un programa que transforme el archivo q.hex en un archivo IHEX bien formado.
Dicho programa se adjunta con el nombre qtohex.c cuya entrada es el archivo q.hex y la salida el
archivo qhy5t.hex. Cuenta con tres funciones, readline(), checksum() y write record(), además
de main(), por supuesto. La función readline() devuelve un arreglo de caracteres con una lı́nea
del archivo q.hex sin espacios, además de la longitud de dicho arreglo. La función write record()
(figura 3.2) recibe como parámetros un puntero al archivo de salida, la longitud del arreglo de datos,
la dirección de los datos, el tipo de registro (siempre 00, indicando que es un registro de datos salvo
el último registro del archivo, cuyo tipo es 01) y el arreglo de datos y escribe el registro en el archivo
de salida incluyendo el carácter de comienzo de registro : y el checksum, el cual se obtiene invocando
a la función (figura checksum()3.3) con el arreglo de datos y su longitud.
Dado que los desplazamientos del registro wvalue no habı́an sido extraı́dos en forma programática,
en main se hicieron los llamados a write record() hardcodeando las direcciones en cada llamada,
excepto cuando las escrituras eran a direcciones consecutivas.
El siguiente fragmento de código3.1 muestra como se realizan las llamadas a write record().
Notar el while, el cual se repite 23 veces y en el cual se escriben registros en direcciones consecutivas.
En main hay unos 11 bloques de direcciones como este y unos 10 donde las direcciones son aleatorias
y fue necesario especificarlas una a una.
int main () {
...
len = readline ( cmd , fin ) ;
write_record ( fout , len , 0 xE600 , 0 , cmd ) ;
len = readline ( cmd , fin ) ;
write_record ( fout , len , 0 x0200 , 0 , cmd ) ;
wvalue =0 x020B ;
while ( wvalue <= 0 x02EB ) {
len = readline ( cmd , fin ) ;
write_record ( fout , len , wvalue , 0 , cmd ) ;
wvalue +=8;
}
...
El resultado de este proceso es el archivo qhy5t.hex el cual se adjunta a este trabajo, el que
además de ser un IHEX bien formado, contiene la primer versión del firmware para la cámara QHY5T
obtenida mediante el análisis de tráfico USB. Como se pudo determinar luego, esta versión del firmware
solo difiere de la liberada por el fabricante en el primer registro, el cual está de más en la versión
presentada en este trabajo y corresponde a una señal de reset que se envı́a al microprocesador de la
cámara para indicar que a continuación se cargará el firmware. A pesar de esto, es posible cargar el
firmware obtenido por análisis de tráfico USB a la cámara mediante la utilización del programa fxload
y el funcionamiento del dispositivo es exactamente el mismo con cualquiera de las dos versiones del
firmware.
3.4. UDEV Y FXLOAD PARA LA CARGA DEL FIRMWARE 25
write_record ( FILE * fout , int len , int offset , int type , char * cmd ) {
char b [256];
sprintf (b , " : " ) ;
sprintf ( b +1 , " %02 X " , len ) ;
sprintf ( b +3 , " %04 X " , offset ) ;
sprintf ( b +7 , " %02 X " , type ) ;
int i = 0;
while ( i < len *2) {
sprintf ( b +9+ i , " %c " , cmd [ i ]) ;
i ++;
}
sprintf ( b +9+ i , " %02 X \ n " , ( unsigned char ) checksum ( len , b ) ) ;
fprintf ( fout , b ) ;
}
Esta configuración permite que el dispositivo sea usado por los usuarios del grupo video y no
exclusivamente por el usuario root. Posteriormente esta configuración se hizo estándar para todos los
demás dispositivos soportados por el fabricante y es un aporte más de este trabajo a la comunidad.
Figura 3.4: Identificación de los parámetros de configuración enviados a la cámara mediante análisis
de tráfico USB.
Hasta el momento en que el fabricante hizo disponible el código fuente del driver para Windows y
durante dos meses, todo avance respecto al controlador para GNU/Linux estuvo parado y si bien el
fabricante respondı́a las consultas, lo hacı́a en tiempos dilatados y las respuestas carecı́an de detalles
suficientes para salir adelante.
Además del firmware, el fabricante hizo disponible para este trabajo el código fuente de los con-
troladores para Windows, con la condición que no fueran hechos públicos.
Capı́tulo 4
El driver
El controlador desarrollado para este proyecto esta basado en primer lugar en el código del con-
trolador para una cámara de la misma familia, la QHY5. El controlador para esta cámara fue escrito
en 2009 por Geoffrey Hausheer y publicado con una licencia GPL2. Este driver cuenta con algu-
nas funciones interesantes, por ejemplo la relacionada con manejadores (handles) USB que permiten
buscar dispositivos conectados, abrir y cerrar manejadores para un dispositivo en particular, leer y
escribir datos en conexiones USB establecidas y guardar archivos a disco en formato .pgm, entre otras.
Además se incluye un main rudimentario a modo de pruebas que permitı́a testear todas las funciones
del driver. El estudio de este controlador fue el primer contacto del autor con la librerı́a libusb.
El presente trabajo también está basado en el controlador para Windows para la cámara QHY5T,
el cual fue desarrollado entre 2007 y 2009 por Tom Van den Eede para la empresa QHYCCD. Dicho
controlador fue cedido para este trabajo por el fabricante, con la condición que dicho código no se
haga público, debido a la responsabilidad adquirida por dicha empresa con el fabricante Orion, con el
cual tenı́a acuerdos en relación al modelo de la cámara en cuestión.
El hecho de que el fabricante hiciera disponible el código fuente del driver manifiesta el interés por
su parte de dar soporte al sistema operativo GNU/Linux. Además gracias a esto y a las consultas
realizadas a Tom por correo electrónico y chat es que fue posible tener un driver para GNU/Linux en
pocos meses y aceleró el proceso de desarrollo respecto a las técnicas de ingenierı́a reversa las cuales
habı́an dado buenos resultados pero en un tiempo considerablemente mayor.
Se detallan a continuación las funciones más importantes del driver. En muchos casos se hablarán
de cambios realizados en relación a las primeras versiones, cuando esto sea relevante.
Cabe resaltar que si bien el driver permite controlar las principales funciones de la cámara, el autor
considera este trabajo como “trabajo en progreso”. Algunas de las caracterı́sticas soportadas en el
controlador para Windows no están contempladas en el driver para GNU/Linux, a saber el soporte para
imágenes de 16 bits y el soporte de binning 2x2. Además, un proceso de refactorización permitirı́a
incluir soporte para múltiples dispositivos conectados a la misma computadora y compatibilizar la
API con la del driver para GNU/Linux de la cámara QHY5, además de las caracterı́sticas antes
mencionadas.
27
28 CAPÍTULO 4. EL DRIVER
typedef struct {
usb_dev_handle * handle ;
uint16_t width ;
uint16_t height ;
uint16_t offw ;
uint16_t offh ;
uint8_t binmode ;
uint16_t gg1 ;
uint16_t gb ;
uint16_t gr ;
uint16_t gg2 ;
uint16_t vblank ;
uint16_t hblank ;
uint8_t bpp ;
uint16_t etime ;
void * image ;
size_t framesize ;
} qhy5t_driver ;
En esta estructura, el puntero handle es el punto de comunicación con el dispositivo USB asociado
con la cámara. Su valor se asigna si la función qhy5t open() tiene éxito. Todas las funciones de
transferencia de datos entre la computadora y el dispositivo se realizan mediante la librerı́a libusb,
las cuales utilizan un puntero a usb dev handle. Este último es uno de los tipos principales de dicha
librerı́a.
Los miembros width, height, offw y offh determinan el tamaño y la posición del frame. Los
rangos para width y height son (4, 2048) y (4, 1536) respectivamente. Los rangos para offw y offh
son entre (0, 2048-width) y (0, 1536-height).
El campo binmode indica el binning. Por defecto es 1, representa binning 1x1 y es el único modo
soportado hasta el momento de escribir este trabajo.
Los miembros gg1, gb, gr y gg2 representan la ganancia de los diferentes colores de pixels del
sensor. Dado que este valor no es lineal, se debe configurar invocando a la función set gain(), la cual
es detallada más adelante. El rango de valores para la ganancia es de (1, 167) y se puede configurar
independientemente para cada color.
vblank y hblank representan los tiempos para calcular el vertical blank y el horizontal blank en la
función program camera(). Por defecto, vblank toma el valor 25 y hblank, el valor 0. Estos valores
son los mismos utilizados en el controlador para Windows y este trabajo no provee una forma de
modificar estos valores garantizando la integridad de los frames.
El campo bpp hace referencia a los bits por pixel. Por defecto es 8, indicando que cada pixel de la
imagen es de 1 byte. Es el único modo soportado hasta el momento de escribir este trabajo.
El miembro etime es el que representa el tiempo de exposición en milisegundos. El rango es de 1
a 60000, es decir que se permiten tomas de 1 milisegundo a 60 segundos de exposición. El problema
de hacer exposiciones de más de varios segundos es que el ruido tiende a igualar y en algunos casos a
superar a la señal capturada.
Por último, el miembro image es un puntero a un buffer de tamaño framesize bytes.
Casi todas las funciones implementadas para el controlador reciben un puntero a qhy5t driver,
con excepción de qhy5t open(), la cual devuelve un puntero de este tipo y de write pgm().
4.3. LAS FUNCIONES EXPORTADAS 29
qhy5t open(): Esta función no recibe argumentos y devuelve un puntero a qhy5t driver, que
es NULL si no hay un dispositivo QHY5T conectado al bus USB de la computadora. Se debe
invocar antes que las demás funciones.
qhy5t set params(): Esta función recibe los parámetros de configuración para la cámara y los
guarda en la estructura qhy5t driver.
qhy5t program camera(): Esta función escribe efectivamente los parámetros para las capturas
en los registros de la cámara, además de realizar algunos cálculos relacionados con los tiempos
del sensor. Esta función se invoca una vez, luego de invocar a qhy5t set params().
qhy5t start capture(): Esta función se encarga de iniciar el thread de exposición, una vez
que la cámara a sido programada con los parámetros de captura deseados. El thread estará ac-
tivo hasta que se invoque a la función qhy5t stop capture(), adquiriendo frames con dichos
parámetros.
qhy5t read exposure(): Esta función se invoca cada vez que el usuario del driver requiera un
frame. Se comunica a través de semáforos con el thread de exposición para acceder de manera
exclusiva al buffer desde el cual son copiados los datos.
write pgm(): Esta función escribe los datos de la imagen en un archivo. Para esto recibe como
parámetros el buffer que contiene la imagen y sus dimensiones, además de el nombre del archivo
a crear.
qhy5 timed move(): Esta función envı́a comandos de guiado al puerto ST-4. Recibe como
parámetros las direcciones del movimiento y su duración en milisegundos.
qhy5t close(): Esta función cierra la conexión con el dispositivo y libera la memoria alocada
para las estructuras.
A continuación se detallan las funciones implementadas, tanto las que pertenecen a la API de
programación como las funciones internas de comunicación y sincronización del controlador.
La información de depuración incluida en esta función fue de suma importancia durante las pri-
meras etapas del desarrollo y durante el proceso de ingenierı́a inversa, donde era posible comparar
la información enviada y recibida respecto a las capturas de tráfico obtenidas usando USBlyzer. El
modelo de esta función fue tomado del driver para la cámara QHY5, la cual fue modificada para
incluir dicha salida de depuración.
La macro dprintf expande a printf si debug es mayor que cero. Está definida de la siguiente manera:
# define dprintf if ( debug > 0) printf
donde debug es una variable global que se inicializa a 1 si el programa se compila con la opción
-DDEBUG y a cero en caso contrario.
Durante la etapa de estudio del driver para Windows, se detectaron varias funciones para realizar
comunicaciones con el dispositivo a través del puerto USB. Estas comunicaciones pueden dividirse en
dos grandes grupos, aquellas donde se transmiten datos en modo BULK 1 , ya sea hacia o desde el
dispositivo y aquellas en las que se envı́an o reciben mensajes de control.
En este trabajo se utilizaron directamente las funciones usb bulk write y usb bulk read provistas
por la librerı́a libusb, para cubrir las necesidades del primer tipo de tráfico. Esto además es consistente
con la implementación del driver para GNU/Linux de la cámara QHY5.
Para el segundo tipo de tráfico se utilizó la función ctrl msg() la cual recibe como parámetro un
puntero a usb dev handle cuyo nombre es handle, un tipo de requerimiento (generalmente, read o
write), un número que indica el requerimiento, el valor de mensaje de control, el ı́ndice, un buffer
para enviar o recibir y la longitud.
Una cosa que parecı́a sencilla pero que resultó bastante molesta fue que en el controlador de
referencia para el sistema operativo Windows se utilizaba comúnmente una función que realizaba la
misma tarea pero cuyos argumentos estaban en distinto orden. Mientras que en dicha función los
argumentos son type, request, buffer, size, index y value, en la función ctrl msg() dichos
argumentos son type, request, value, index, buffer y size. Llevó mucho tiempo y esfuerzo
traducir los llamados y fueron necesarias varias horas de revisión de código, ya que type, request,
value, index y size son números y muchas veces aparecen hardcodeados en la versión del driver
para Windows.
1 El modo BULK se utiliza en transferencias de datos grandes (de hasta 512 bytes), en ráfagas . Está garantizada la
usb_find_busses () ;
usb_find_devices () ;
for ( bus = usb_busses ; bus ; bus = bus - > next )
{
for ( dev = bus - > devices ; dev ; dev = dev - > next ) {
if ( dev - > descriptor . idVendor == vid && dev - > descriptor . idProduct
== pid ) {
located ++;
device_handle = usb_open ( dev ) ;
}
}
}
if ( device_handle == NULL ) {
return NULL ;
}
u s b _ s e t _ c o n f i g u r a t i o n ( device_handle , 1) ;
u sb _ c la i m _ in t e rf a c e ( device_handle , 0) ;
u s b _ s e t_ a l t i n t e r f a c e ( device_handle , 0) ;
return device_handle ;
}
Figura 4.3: Esta función es invocada desde qhy5t open de esta manera mostrada en 4.4
La función qhy5t open debe ser invocada en primer lugar ya que todas las demás funciones utilizan
de alguna manera el puntero devuelto por ésta. Por otra parte, la función qhy5t close es la responsable
de cerrar las conexiones y liberar los recursos reservados por las funciones anteriores. La figura 4.5
muestra la implementación de dicha función.
32 CAPÍTULO 4. EL DRIVER
Figura 4.6: Implementación de la función qhy5t set params. Esta función controla que los parámetros
configurados sean seguros.
Figura 4.7: Macros utilizadas para llenar el vector de 64 bytes con los valores de configuración en
formato big endian.
34 CAPÍTULO 4. EL DRIVER
La función además recibe un parámetro que permite reprogramar la cámara con los últimos valores
utilizados. Esto es porque el buffer con los valores calculados es copiado a un arreglo estático interno
de la rutina qhy5t program camera(). Además este arreglo permite programar la cámara solamente
si los valores calculados han cambiado.
Si bien la función adolece de varios vicios de programación, carece de estilo y necesita una seria
refactorización, como caja negra cumple su tarea diligentemente. La función puede verse en los archivos
de código entregados.
ello, ambas funciones deben lograr el acceso exclusivo a dicha sección. Para esto y como es la manera
más sencilla de hacerlo en pthreads, se utilizan semáforos (mutex ).
Los mutex en pthreads tienen dos funciones principales, pthread mutex lock() la cual detiene
la ejecución del thread hasta que pueda bloquear el semáforo4 y pthreads mutex unlock() la cual
libera el semáforo. De esta manera se puede lograr exclusión mutua en una sección crı́tica utilizando
dos variables mutex que en el driver reciben el nombre de reading y writing.
El thread de exposición es creado cuando se invoca a la función qhy5t start capture(), la que
además aloca memoria para el buffer global e invoca a pthread mutex lock() sobre el semáforo
reading. Esto garantiza que de las funciones qhy5t exposure thread() y qhy5t read exposure(),
es la primera la que logra el acceso antes a la sección crı́tica. Esto tiene sentido ya que de no ser ası́,
se corre el riesgo de tratar de leer un frame que todavı́a no fue capturado.
La función qhy5t exposure thread() toma el control de la sección crı́tica invocando a la fun-
ción pthread mutex lock() sobre el semáforo writing. Luego copia el buffer local que contiene la
información de la última exposición en el buffer global. Esta copia no es directa si no que requiere
que la información del buffer leı́do con USB BULK READ() se mapee a un frame de las dimensiones
correctas descartando el overscan. Por último, el thread de exposición devuelve el control de la sección
crı́tica invocando a pthreads mutex unlock() sobre el semáforo reading.
Como consecuencia, la función qhy5t read exposure() ahora puede acceder a la sección crı́tica
invocando a pthread mutex lock() sobre el semáforo reading. Una vez conseguido el acceso, la
función copia la información del buffer global al miembro de la estructura del driver qhy5t->image y
libera el acceso a la sección crı́tica invocando a pthread mutex unlock() sobre el semáforo writing.
La estructura del proceso de captura en pseudocódigo es la siguiente
start_capture(){
lock(reading);
//creación del thread de exposición (llamada a exposure_thread())
}
read_exposure(qhy5t){
lock(reading);
//comprobación de los datos
//copia del buffer global a qhy5t->image
unlock(writing);
}
}
exposure_thread(){
while (true){
//adquisición de los datos del sensor al buffer local
lock(writing);
//comprobación de los datos
//mapeo del frame del buffer local al global
unlock(reading);
}
}
stop_capture(){
//se~
nal de fin de la captura
//liberación de recursos
}
La última función relacionada con el proceso de adquisición de datos es qhy5t stop capture() la
cual detiene la captura en forma limpia, es decir, cancela el thread de exposición.
Esta función es muy diferente a las encontradas en los drivers de referencia. En el driver para
Windows para la QHY5T el valor de la ganancia es pasado al registro de la cámara como viene, con lo
que probablemente sea responsabilidad del programa de captura elegir los valores apropiados para la
configuración. Tampoco se especifica el rango de la ganancia pero por consultas con el desarrollador
se habı́a determinado que un rango de 0 a 1000 era apropiado.
En la versión para GNU/Linux para la QHY5, la ganancia se configura utilizando el parámetro
como un ı́ndice de desplazamiento en un arreglo que contiene todos los posibles valores de configuración
de la ganancia para el sensor de dicha cámara, que recordemos, es diferente de la QHY5T dado que
ambas cámaras utilizan sensores de modelos diferentes.
Las primeras versiones de la función qhy5t set gain() utilizaron ambas aproximaciones a la
solución. Sin embargo los resultados obtenidos fueron no satisfactorios, ya que el control de la ganancia
carecı́a de linealidad y por ejemplo, valores por debajo de 500 producı́an frames con más ganancia
que los valores por arriba de 500. Solo recientemente y a través del estudio detallado del datasheet fue
posible escribir una función que no solo devolviera valores lineales para la ganancia en pasos enteros,
sino que fueran óptimos en cuanto a la relación señal ruido.
El conjunto de formatos Netpbm incluye los formatos pbm, pgm, ppm y recientemente, pam. Los
tres primeros son muy similares y muy sencillos en cuanto a su especificación, la cual puede encontrarse
en [10], [11] y [12] respectivamente. Por su importancia para este trabajo, sin embargo, se describe
brevemente el formato pgm, utilizado por esta función.
El formato pgm
Pgm es un formato para representación de imágenes en escala de grises sumamente sencillo. Tiene
dos especificaciones, una binaria (o RAW) y la otra en formato ASCII. Una imagen pgm esta formada
por:
Dos bytes para el magic number que indican que se trata de un archivo pgm. Para el formato
binario se corresponde con la cadena de caracteres “P5”.
Un espacio en blanco (se aceptan como espacios en blanco uno o varios espacios, tabulaciones o
caracteres de fin de linea “CR” o “LF”).
Un espacio en blanco.
Un espacio en blanco.
Un número en formato decimal codificado en ASCII indicando el mayor valor posible para el
nivel de gris de la imagen. Este número se conoce como maxval y debe ser menor que 65536 y
mayor que 0.
Una matriz (raster ) de height filas, en orden de arriba hacia abajo. Cada fila consiste de width
valores de gris, en orden de izquierda a derecha. Cada valor de gris representa un pixel cuadrado
de la imagen, en la cual los pixels están contiguos, y es un número entre 0 y maxval con 0
representando el color negro y maxval el valor blanco. Cada valor de gris se representa en
formato binario, en un byte si maxval es menor que 256 y en dos bytes en caso contrario, con el
byte más significativo primero.
Una variación de este formato es el pgm plano, el cual tiene un magic number “P2” y en el el valor
de gris para cada pixel es un número decimal entre 0 y maxval representado en formato ASCII. Cada
pixel a su vez está separado por un espacio en blanco. Esto permite que una imagen en este formato
pueda modificarse utilizando un simple editor de texto. Sin embargo una imagen en este formato
utiliza al menos el doble de espacio que la misma imagen en formato pgm binario.
void write_pgm ( void * data , int width , int height , char * filename ) {
FILE * h = fopen ( filename , " w " ) ;
fprintf (h , " P5 \ n " ) ; // ppm header
fprintf (h , " %d %d \ n " , width , height ) ; // ppm header
fprintf (h , " 255\ n " ) ; // ppm header
fwrite ( data , width * height , 1 , h ) ;
fclose ( h ) ;
}
Notar el uso de la función qhy5 get row() en la función original de la figura 4.10. En este controla-
dor, es esta función la que se encarga de mapear el frame eliminando los datos de overscan. Dado que
en el presente trabajo, esta operación se realiza directamente en el thread de exposición, la función
simplemente puede escribir todo el buffer a la vez sin necesidad de recurrir a un for para escribirlo
fila por fila.
Una modificación interesante a realizar en el futuro es hacer el chequeo de que el archivo se pudo
abrir con éxito, para evitar una posible violación de segmento si la apertura falla. Esta modificación
parece muy sencilla pero podemos ver fácilmente que no lo es. La opción de poner un if y una llamada
a exit() puede no funcionar dado el uso de threads. Para que esta aproximación funcione es necesario
registrar también las funciones que cierran apropiadamente el thread de captura utilizando la función
at exit(). Otra posibilidad puede ser devolver un valor si la función tuvo éxito. Esta opción es
todavı́a peor ya que la responsabilidad de cerrar el thread de exposición si la función falla, recaerı́a
en el usuario del driver que nada debe saber de él.
Sureste, direction debe ser igual a QHY SOUTH|QHY EAST. El parámetro duration (ver figura 4.12)
expresa el tiempo del pulso de guiado en milisegundos.
if ( duration_msec > 0) {
switch ( direction ) {
case QHY_NORTH :
case QHY_SOUTH :
duration [1] = duration_msec ;
break ;
case QHY_WEST :
case QHY_EAST :
duration [0] = duration_msec ;
break ;
}
}
cmd &= direction ;
return ctrl_msg ( qhy5t - > handle , WRITE , 0 x10 , 0 , cmd , ( char *) &
duration , sizeof ( duration ) ) ;
}
La función anterior puede iniciar un pulso de guiado de varios segundos en alguna dirección, el
cual puede ser cancelado invocando la la función qhy5t cancel move(), la cual está implementada
como se muestra en la figura 4.13.
El viewer
Si bien el controlador para la cámara incluye una opción para compilar un programa de lı́nea de
comandos que permite configurarla y posteriormente grabar los frames en archivos en algún medio
de almacenamiento, este programa no provee ningún mecanismo de visualización por ejemplo, para
la etapa de enfoque. Es decir que si bien es posible indicar los parámetros de captura para una
determinada secuencia de cuadros, no es posible visualizarlos hasta que el programa termine y no es
sino a través de alguna herramienta externa que permita la visualización de archivos pgm.
Para mejorar la usabilidad se diseñó una herramienta que permitiera visualizar los frames antes de
guardarlos, haciendo uso del driver desarrollado en este proyecto, además de la librerı́a SDL (Simple
DirectMedia Layer).
Dicha herramienta recibe el nombre de qhy5tviewer y constituye el segundo desarrollo más impor-
tante de este trabajo, además del driver para la cámara propiamente dicho. Este programa de lı́nea de
comandos permite visualizar el buffer capturado mediante el uso surfaces SDL. A grandes rasgos, el
programa permite configurar un determinado modo de captura fijando los parámetros para la sesión.
Luego se configura una superficie SDL que permite mostrar los cuadros, dada la configuración de
dicha sesión, en la cual se irán mostrando de a uno los frames capturados. Al ser un entorno SDL, es
posible capturar eventos de teclado e iniciar acciones como guardar los frames capturados en archivos,
mostrar un retı́culo, incrementar la ganancia o enviar comandos de guiado a la montura.
Se detallan a continuación las secciones más importantes del programa qhy5tviewer.
El programa qhy5tviewer está escrito en lenguaje C89 al igual que el driver para la cámara QHY5T
y está basado en parte de la implementación de la función main() del driver para GNU/Linux para
la cámara QHY5 escrito por Geoffrey Hausheer. Al ser un programa de lı́nea de comandos, cobra
muchı́sima importancia los parámetros pasados a main(), ya que una vez definidos estos es que se
pueden crear las estructuras relacionadas con la librerı́a SDL entre otras. Muchas de estas configura-
ciones iniciales no serán cambiadas hasta que el programa haya terminado y definen para este trabajo,
una sesión.
La función main() declara un conjunto de variables, muchas de las cuales tienen asociados valores
por defecto. Por ejemplo, el tamaño del frame por defecto es 800x600, por ello tanto a la variable
width como height se les asignan valores al momento de su declaración como puede verse en la figura
5.1.
41
42 CAPÍTULO 5. EL VIEWER
Figura 5.1: Valores por defecto al declarar las variables en main() de qhy5tviewer.c
Algunos de estos valores pueden ser cambiados luego por medio de argumentos a main(), los cuales
son procesados utilizando la librerı́a getopt. Las opciones de configuración que admite el programa
qhy5tviewer se describen en la sección 5.2 de éste capı́tulo.
Luego de procesados los argumentos se inicializan las estructuras de SDL de acuerdo a las opciones
configuradas. Por ejemplo, si se configura un tamaño de frame de 1024x768, es necesario crear una
surface SDL donde estas imágenes quepan para que puedan ser mostradas de forma correcta durante
la ejecución del programa.
Desde main(), posteriormente se invocan a las funciones de configuración del hardware de la
cámara exportadas por el driver y se inicia el thread de captura.
Luego se entra a un bucle cerrado (el cual finaliza por un evento SDL) en el cual en primer lugar
se procesan todos los eventos de teclado de SDL, mediante los cuales es posible por ejemplo, mostrar
u ocultar el crossair (ver la sección 5.6), iniciar o detener la escritura de frames a archivos, enviar
comandos de guiado a la montura o salir del programa.
Posteriormente se hace un requerimiento al driver para obtener el último frame capturado, el cual
es guardado en un buffer. Los datos de este buffer son debayerizados (ver la sección 5.5) luego, para
permitir mostrarlos en la surface SDL en color. Si bien el bayerizado no es óptimo en cuanto a calidad
de imagen, si es lo suficientemente rápido para procesar un frame a máxima resolución entre dos
capturas consecutivas de la cámara.
Luego que el frame debayerizado es mostrado en la surface SDL, se escribe en un archivo el
frame sin debayerizar (si la escritura en archivos está activada). Dado que se guardan los frames
RAW en lugar de los frames debayerizados, es posible utilizar mejores algoritmos de debayerización
que el implementado en este trabajo a partir de los archivos guardados, en una etapa posterior de
procesamiento de las imágenes.
En resumen, el esqueleto de la aplicación puede verse con el siguiente esquema.
El nombre largo de la opción, el cual es equivalente al nombre corto pero que se invoca con
dos guiones en lugar de uno. Por ejemplo, invocar al programa con -h o con --help tiene
exactamente el mismo resultado.
Un flag que indica como se devuelven los valores para las opciones largas.
A través de esta librerı́a el programa qhy5tviewer acepta una serie de argumentos a main() que
permiten variar el comportamiento del programa y modificar los parámetros de captura de la cámara.
Las opciones soportadas son:
en Windows.
44 CAPÍTULO 5. EL VIEWER
-g o --gain: configura la ganancia del sensor. Por defecto es 1 y puede variar entre 1 y 167. A
mayor ganancia, también es mayor el ruido de la imagen obtenida.
-b o --binning: configura el binning. Dado que el driver solamente soporta binning 1x1 esta
opción se procesa pero finalmente se ignora.
-k o --vblank: configura el tiempo de vertical blank y se expresa en tiempos de pixel. Por
defecto es 142 y no se realizaron pruebas cambiando este valor.
-x y -y o --width y --height : configuran el ancho y alto del frame, respectivamente. Por
defecto la resolución es de 800x600 pixels. El offset es calculado para utilizar el centro del
sensor.
-o o --file: permite indicar el nombre base de los archivos a escribir. Por defecto es image y los
archivos guardados serán image00000.ppm, image00001.ppm y ası́ sucesivamente. El programa
no controla que dichos archivos ya existan y los sobreescribe si ası́ ocurre.
-F o --fits: guarda los archivos utilizando el formato FITS en lugar de netpbm. El soporte
para FITS hace uso de la librerı́a cfitsio. En cualquier caso, las imágenes guardadas provienen
del buffer leı́do desde el sensor y no se modifican de ninguna manera.
-X o --crossair: Muestra el crossair sobre las imágenes visualizadas. Por defecto está deshabi-
litado. También puede habilitarse o deshabilitarse mediante comandos de teclado.
-d o --debug: habilita la salida de depuración.
-h o --help: muestra la ayuda del programa.
Es posible entonces invocar al programa qhy5tviewer, por ejemplo como se muestra en la figura
5.3. De esta manera el programa configurará la cámara para realizar exposiciones de 55 milisegun-
dos con una ganancia de 24 a una resolución de 640x480 pixels. Además, si se habilita la escritura
de archivos mediante comandos de teclado, estos se guardarán con los nombres jupiter00000.ppm,
jupiter00001.ppm y ası́ sucesivamente.
Si bien todas estas opciones no cubren todas las posibilidades de configuración que la cámara
ofrece, son más que suficientes para utilizarla para fotografı́a lunar, solar o planetaria haciendo foco
primero y capturando las imágenes luego, como cámara de guiado (manual) o como ocular reticulado
para poner la montura en estación.
resolución y profundidad de color, además de una máscara que indica que propiedades de la surface
se utilizarán. Por ejemplo es posible que la surface utilice aceleración gráfica mediante la máscara
SDL HDSURFACE, pero si esta no está soportada, la inicialización falla. Para máxima compatibilidad,
la aplicación utiliza una surface del tamaño del frame, a una profundidad de color de 24 bits RGB.
Las operaciones sobre esta surface se realizan en el procesador de la máquina y no mediante el uso de
hardware gráfico dedicado (SDL SWSURFACE) y además se obliga a inicializar la surface con cualquier
opción de las soportadas por el dispositivo de video (SDL ANYFORMAT). Los datos de un buffer son
escritos en la surface y luego combinados con el fondo haciendo bliting 2 para formar la imagen final.
Notar también como se ve en la figura anterior, que los datos son debayerizados antes de ser
mostrados. Esto permite tener una visualización en colores de los datos RAW.
2 El blitting o bit blit, es una primitiva básica de los sistemas gráficos de dos dimensiones, que permite combinar dos
En la figura 5.6 se ve el flujo de control utilizado para combinar las diferentes capas que forman
la previsualización final provista por la aplicación.
Estos comandos se procesan en un bucle que obliga a tratar todos los eventos antes de continuar.
La figura 5.7 muestra la estructura del bucle. El tratamiento del evento consiste muchas veces en
activar o desactivar un flag, mientras que el tratamiento efectivo del evento se realiza posteriormente
como en el caso del crossair. Otras veces se realiza el tratamiento efectivo en el bucle como en el caso
de los comandos de guiado.
5.4. LOS COMANDOS DE TECLADO 47
5.5. La debayerización
Se conoce como interpolación cromática3 o debayerización al proceso por el cual una imagen RAW
que proviene de un sensor con una matriz bayesiana o CFA (por las siglas Color Filter Array) se
convierte en una imagen color. Una imagen RAW tiene un solo canal (se ve en escala de grises), pero
tiene información incompleta para la imagen color de 3 canales. Cada pixel de la imagen representa el
nivel de intensidad de un color (rojo, verde o azul, dependiendo de la posición del pixel) en la imagen
final.
Cabe destacar que este problema es inherente a la construcción del sensor. Este problema no existe
si el sensor es monocromático (es decir, si solo capta la intensidad de la luz y esta no es filtrada de
ninguna manera) o en sensores que utilizan la tecnologı́a Foveon X34 donde por su construcción, cada
pixel es capaz de capturar información de los tres canales (rojo, verde y azul) a la vez.
Figura 5.8: Respuesta a la luz en diferentes longitudes de onda en un sensor Foveon X3 (izq) en
comparación con un sensor estándar con un CFA con patrón de Bayer (der).
es O(n). Sin embargo, como no se realizan operaciones aritméticas sobre los pixels, este método es mucho más rápido
que VNG a pesar que el orden de ejecución de este último también es O(n).
5.5. LA DEBAYERIZACIÓN 49
(PSNR por las siglas en inglés para Peak Signal to Noise Ratio).
Figura 5.9: Una imagen color compuesta por 3 canales, rojo, verde y azul
Figura 5.10: La imagen raw en escala de grises (arriba), el patrón de bayer (medio) y la imagen
debayerizada por interpolación bilineal (abajo).
50 CAPÍTULO 5. EL VIEWER
Dada la variedad de métodos, fue necesario elegir uno teniendo en cuenta lo siguiente:
Las imágenes que el programa qhy5tviewer guarda en archivos pgm o FITS no se guardan
debayerizadas. Esto permite que en una etapa de post procesado se elija el mejor algoritmo sin
tener en cuenta el tiempo de ejecución.
Es necesario mostrar imágenes claras y en color de los objetos a fotografiar, ya que el objetivo
principal de mostrar lo que la cámara está fotografiando es permitir que el usuario haga foco.
Es necesario que el tiempo de ejecución del algoritmo elegido permita mostrar imágenes en color
a medida que la cámara las va entregando, en una computadora modesta.
La sencillez a la hora de implementar el algoritmo era deseable pero no requerida.
Dados los algoritmos estudiados, las dos opciones más potables eran la interpolación bilineal y la
SHTI. Para este trabajo se optó por la primera básicamente debido a que es levemente más sencilla
de implementar.
Figura 5.11
La figura 5.12 muestra un fragmento de la función debayer data(). Esta función recibe un puntero
a los datos de la imagen a debayerizar y obtiene las dimensiones de dicha imagen desde un puntero a
una estructura qhy5t driver. Las precondiciones que deben cumplirse para que esta función devuelva
un puntero a una imagen debayerizada es que la imagen a debayerizar sea de 8 bits por pixel y que el
patrón de Bayer sea RGGB. Esto se cumple si las imágenes a debayerizar tienen dimensiones pares.
El uso de las macros SRCT, SRCTR, SRCR, SRCBR, SRCB, SRCBL, SRCL y SRCTL permite un acceso
sencillo a cualquiera de los ocho vecinos de un pixel. Dado un puntero a un pixel SRCT retorna el
vecino superior, SRCTR el superior derecho, SRCBL el inferior izquierdo y ası́. La figura 5.13 muestra la
52 CAPÍTULO 5. EL VIEWER
declaración de estas macros. La variable w debe estar declarada e inicializada con el valor del ancho de
la imagen. Acceder a alguno de los ocho vecinos de un pixel situado en un borde de la imagen puede
devolver un pixel incorrecto (en el caso de los bordes laterales) o producir una violación de segmento
(en el caso de los bordes superior o inferior). Por ello los ı́ndices de ambas sentencias for en la figura
5.12 evitan dichos bordes, los cuales se dejan sin tratamiento.
Figura 5.13: Declaración de las macros para acceder a los ocho vecinos de un pixel.
Fue una decisión de diseño incluir la función de interpolación cromática fuera del driver. Esta
decisión es discutible. Indudablemente, la función de debayerizado depende de la disposición de los
pixels en el sensor y del tamaño de la imagen a debayerizar. En la implementación para Windows del
driver para esta cámara se incluyen de hecho dos funciones para debayerizar imágenes en 8 y 16 bits por
pixel utilizando el algoritmo Neares Neighbor Interpolation6 . En una posterior etapa de refactorización,
las funciones de interpolación cromática deberı́an incluirse en el driver, implementándolas en un archivo
separado para cubrir tanto los casos de 8 y 16 bits por pixel, como los casos donde las imágenes tengan
dimensiones no pares.
5.6. El crossair
Durante la etapa de puesta en estación de la montura, suele ser necesario determinar la deriva de
una estrella. Esto permite conocer la exactitud de la puesta en estación y da una aproximación del
tiempo máximo de exposición sin guiado. Centrar una estrella en el campo de visión puede ser un
proceso engañoso, ya que ni la cámara ni los oculares comunes poseen referencia alguna acerca del
centro de campo de visión. Para centrar una estrella de manera efectiva es necesario utilizar un ocular
reticulado7 , es decir un ocular especial que cuenta con un retı́culo (generalmente en forma de cruz) el
cual permite conocer el centro del campo de visión con exactitud. Dichos oculares pueden conseguirse
en el mercado local y si bien no son muy costosos en relación a otras piezas de equipamiento, agregan
efectivamente un costo.
El programa qhy5tviewer permite utilizar la cámara como ocular reticulado, dibujando un retı́culo
artificial sobre el flujo de imágenes proveniente de ésta. Otra caracterı́stica que ofrece el programa es
la de rotar el crossair por software, lo que permite alinearlo con los puntos cardinales sin necesidad
de rotar la cámara en el portaocular del telescopio.
6 En el driver para GNU/Linux de la cámara QHY5 no se incluyen funciones de debayerizado ya que el driver es para
la versión monocromática.
7 Un ocular es una lente intercambiable que permite variar los aumentos con los que un telescopio muestra un objeto.
Generalmente, la cámara se utiliza en lugar de un ocular aunque existen configuraciones en los que el tren óptico incluye
ambos, una cámara y un ocular.
5.6. EL CROSSAIR 53
Figura 5.14: Un ocular reticulado iluminado. La iluminación activa permite ver el retı́culo contra el
fondo negro del cielo.
Cuando se activa el crossair ya sea mediante un argumento al programa principal al inicio o median-
te comandos de teclado una vez que la sesión a comenzado, se ejecuta la función load crossair(), la
cual devuelve una surface SDL en el cual se encuentra cargada la imagen del retı́culo. Esta surface lue-
go es combinada con la última imagen obtenida de la cámara utilizando la función SDL BlitSurface()
de la librerı́a SDL. La función load crossair() recibe como parámetro un desplazamiento que por
defecto es cero y carga la imagen cuyo path es images/crossair0.png. El desplazamiento puede
variar entre 0 y 255 e indica cual es la imagen que será cargada para el retı́culo. Existen por lo tanto
256 imágenes en el directorio images/, cada una de las cuales presenta una rotación de 1.40625 grados
respecto a la anterior. Estas imágenes fueron generadas utilizando el programa de manipulación de
imágenes GIMP8 . La única particularidad respecto a estas imágenes es que tienen el fondo transpa-
rente. La función load crossair() utiliza a su vez la función IMG Load() que permite cargar archivos
inmediatamente en surfaces SDL abstrayendo el formato de los mismos. Recibe un solo parámetro que
indica la ruta relativa o absoluta al archivo a cargar. Para utilizar esta última función es necesario
incluir los encabezados de la extensión de imágenes de SDL llamada SDL image.
La figura 5.15 muestra la implementación de la función load crossair(), mientras que la figura
5.16 muestra el fragmento de la función main() en el cual se carga el crossair si es necesario.
8 http://gimp.org
54 CAPÍTULO 5. EL VIEWER
if ( crossair ) {
xair = load_crossair ( angle ) ;
if ( xair != NULL ) {
SDL_Rect recdst = {( width /2) -150 , ( height /2) -150 , 0 , 0};
if ( SDL_BlitSurface ( xair , NULL , screen , & recdst ) ) {
printf ( " %s \ n " , SDL_GetError () ) ;
}
}
else {
printf ( " Can ’t load the crossair \ n " ) ;
crossair = 0;
}
}
Figura 5.16: Fragmento de main() donde se carga el crossair y se combina con la surface que contiene
el frame.
El programa qhy5tviewer permite guardar las imágenes en archivos FITS gracias a una función
escrita por Giampiero Spezzano y modificada para que cumpla las necesidades de este trabajo. Sin
embargo estas caracterı́sticas son sumamente básicas y solo permiten escribir un archivo por imagen
y no agrega metadata excepto la estrictamente necesaria para que el archivo tenga un formato FITS
válido.
Dado que el formato FITS guarda los encabezados en formato ASCII, una simple inspección con
un editor de texto revela estos campos. La figura 5.18 muestra un encabezado de datos generado por
el programa qhy5tviewer.
Recientemente se agregaron los campos PROGRAM e INSTRUMEN que indican que el archivo
fue creado utilizando el programa qhy5tviewer y que la cámara utilizada es en efecto una QHY5T.
Para generar las imágenes en formato FITS, la función write fits() hace uso de la librerı́a
cfitsio, la cual cuenta con funciones especificas para leer y escribir archivos en dicho formato, además
de modificar todas las propiedades. Esta librerı́a es desarrollada por el Goddard Space Flight Center
(GSFC) dependiente de la agencia espacial estadounidense NASA.
La librerı́a refleja la complejidad del formato, pero para este trabajo solo fueron necesarias algunas
funciones básicas para crear el archivo de imagen, configurar los parámetros adecuados y copiar los
datos de la imagen dentro del archivo FITS.
La figura 5.19 muestra la implementación de la función write fits().
56 CAPÍTULO 5. EL VIEWER
Conclusiones
Estas pruebas fueron realizadas en una Netbook Lenovo Ideapad S100 (Equipo 1) con procesador
Intel Atom N570 (1.66 GHz) con 2 GB de RAM. Si bien la taza de frames por segundo es menor
cuando se realiza el debayerizado, las imágenes mostradas en la sección 6.3 se realizaron utilizando
este equipo, con lo que las capacidades para fotografı́a solar, lunar y planetaria tanto del driver como
del programa qhy5tviewer queda demostrada, aún utilizando equipos modestos como el mencionado.
57
58 CAPÍTULO 6. CONCLUSIONES
Estas pruebas fueron realizadas corriendo en una computadora Lenovo Thinkpad Edge E430 (Equi-
po 2) con 8 GiB de RAM y un disco de 500 GB a 3200 RPM. En el caso de Windows, se utilizó Windows
8 con la última versión disponible del controlador para este sistema operativo, además de la última
versión disponible de QGVideo5T.
Notar que las tasas de escritura a disco en la versión para GNU/Linux corriendo sobre la E430
superan en todos los casos ampliamente las tasas obtenidas con los mismos parámetros pero en la S100.
Incluso en las pruebas sin debayerización se puede apreciar una mejora aunque en este caso, más leve.
Esto indica que si bien el rendimiento en una computadora promedio es aceptable, el beneficio es
importante en una computadora con un procesador más potente.
comparables, por lo que al menos este controlador esta a la altura de rendimiento del controlador de
referencia.
Por otra parte, los controladores en espacio de kernel exportan dispositivos al sistema de archivos,
por lo que es posible que los programas de espacio de usuario accedan a las funciones exportadas por
el controlador del dispositivo en cuestión por medio de dicho archivo (en general, los archivos que
representan dispositivos se encuentran en el directorio /dev). Dado que esta interfaz es uniforme, los
programas pueden utilizar los dispositivos a través del uso de alguna librerı́a en espacio de usuario
que enlaza las funciones en espacio de kernel con las de espacio de usuario. Debido a esto es que
existe una amplia gama de programas que haciendo uso de la API v4l2 permiten visualizar streams
de video y grabar dicho stream en archivos, como mplayer, cheese y motion, entre otros. Dado que
el controlador en espacio de usuario no exporta una API v4l2, la cámara QHY5T no puede utilizarse
con estas aplicaciones. Esta es una de las principales desventajas de tener un controlador en espacio
de usuario ya que mucho software preexistente, de gran calidad y madurez, no puede utilizarse con
esta cámara y es necesario adaptar dicho software o escribir nuevo para que esto último sea posible.
A comienzos del año 2012, cuando la cámara fue adquirida, pudo comprobarse que a pesar que
existı́a el soporte para el sensor en el Kernel Linux, la cámara no funcionaba en este sistema operativo.
Esto se debı́a principalmente a que la interfaz I 2 C del sensor no es expuesta por la cámara si no que la
comunicación entre la computadora y el sensor se realiza a través del firmware cargado en el procesador
del dispositivo.
Durante los dos años siguientes se trabajó, mediante ingenierı́a inversa, análisis de tráfico y estudio
de los controladores de referencia, en el desarrollo de un controlador para GNU/Linux y un programa
visor que permitiera grabar imágenes astronómicas, los cuales se describen en la presente tesina. El
trabajo en la mejora del driver todavı́a continúa.
Utilizando programa qhy5tviewer fue posible obtener los siguientes resultados. Cabe destacar que
todas las imágenes aquı́ presentadas fueron realizadas exclusivamente utilizando el sistema operativo
GNU/Linux (en el Equipo 1, salvo que se especifique lo contrario), no solo durante la captura sino
también en el post procesado de las imágenes capturadas para llegar a la versión final de cada una.
A continuación se muestra en la figura 6.1 una imagen cruda en formato pgm obtenida durante
el mes de enero de 2014. Dicha imagen fue capturada con la cámara QHY5T utilizando el programa
qhy5tviewer desde Lihuen GNU/Linux. La cámara estaba adosada a un telescopio newtoniano Sky-
Watcher de 200 mm de apertura y 1000 mm de distancia focal (SW 200/1000), con un filtro solar
Baader + un filtro Astrodon Photometrics (Johnson/Cousins) en banda V. La figura 6.2 es el resultado
de procesar más de 2000 imágenes como la de la figura 6.1. Las imágenes fueron debayerizadas indi-
vidualmente utilizando el script debayer.py, el cual utiliza la función de debayerización de la librerı́a
OpenCV. Las etapas de alineación, apilado y aplicación de wavelets fue realizada utilizando el pro-
grama Registax 6. Finalmente se utilizó el programa GIMP para aplicar una máscara de desenfoque
y convertir el archivo .tiff resultante del procesado con Registax a formato .jpg. La cantidad efectiva
de imágenes apiladas en este caso fue de alrededor de 400, mientras que el resto fueron descartadas.
Dadas las condiciones de seeing al momento de la captura, es posible que los resultados no sean
los mejores posibles y que puedan resolverse más detalles con la atmósfera más clara.
Las imágenes corresponden a la mancha AR-1967, considerada una de las manchas más grandes
del último ciclo solar hasta el momento de escribir este trabajo.
60 CAPÍTULO 6. CONCLUSIONES
Figura 6.1: La imagen RAW obtenida con la cámara QHY5T desde una computadora corriendo Lihuen
GNU/Linux.
Figura 6.2: Imagen obtenida a partir de 2000 cuadros similares a los de la figura 6.1.
lente TeleVue PowerMate x2.53 pero no se utilizó ningún otro implemento. La figura 6.4 muestra el
resultado de utilizar el programa debayer.py para debayerizar la imagen de la figura anterior.
La imagen de la figura 6.5 es el resultado de procesar unos 1200 cuadros crudos utilizando deba-
yer.py, Registax 6 y GIMP. En ella puede apreciarse con claridad los cinturones ecuatoriales, festones
oscuros en el cinturón norte, las bandas tropicales, la tormenta conocida como la Gran Mancha Ro-
ja (GRS, por sus siglas en inglés) y varias tormentas menores sobre la superficie del planeta. A la
izquierda se ve la luna galileana Ío con su caracterı́stico color rojizo.
3 El TV PowerMate es una lente negativa similar a una lente barlow, diseñado por Al Nagler, que al alargar la distancia
focal del telescopio (en este caso en 2,5 veces) permite imágenes con más aumento, aunque no con más resolución.
62 CAPÍTULO 6. CONCLUSIONES
Figura 6.5: Imagen obtenida a partir de 1200 cuadros obtenidos con la QHY5T y el programa
qhy5tviewer.
El mes lunar tiene una duración de 29.53 dı́as solares. En este tiempo la Luna pasa por todas sus
fases. Durante la fase de Luna llena o casi llena es muy difı́cil hacer buenas tomas ya que al recibir
luz directa del sol en un ángulo de casi 90º, ninguno de los cráteres, valles o montañas tienen sombra
y la falta de contraste genera imágenes lavadas sin muchos relieves aparentes. Sin embargo esta es
una oportunidad de fotografiar el disco lunar completo, además de eventos asociados como el transito
de satélites, aviones o aves. Sin embargo esto no fue posible dado que el sensor de la cámara no es
lo suficientemente grande para que el disco quepa completo, al menos en los equipos con los que se
contaba para realizar las pruebas.
Durante las fases de cuarto creciente y cuarto menguante, ası́ como dos dı́as antes y dos dı́as
después, la zona del terminador (el amanecer o el atardecer lunar) presenta relieves y sombras de una
belleza incomparable que solo alcanzan a comprender aquellos que han puesto un ojo en el ocular.
Durante la fase de cuarto creciente, se pueden fotografiar dichos relieves entre las 18 y las 22 horas,
horario bastante cómodo para cualquier aficionado con necesidad de trabajar durante la semana. En
la fase de cuarto menguante en cambio, solo es posible fotografiar la luna entre las 2 y las 6 de
la madrugada lo que hace la tarea bastante más inconveniente en las mencionadas condiciones. Por
supuesto es posible fotografiar la Luna en dicha fase durante el dı́a, pero el contraste ofrecido por el
cielo diurno es muy inferior al del cielo nocturno. Lo que deja una ventana de unos cinco dı́as por
mes en los cuales, si las condiciones del clima son apropiadas, es posible tomar algunas fotografı́as del
los cráteres más prominentes. Demás está decir que las pruebas aquı́ expuestas no fueron exhaustivas
dado que los dı́as que fueron realizadas no fueron óptimos en cuanto a calidad de cielo.
En la figura 6.6 puede verse una imagen cruda de los Montes Apeninos tomada en enero de 2014.
La fotografı́a fue adquirida utilizando un telescopio newtoniano de 150 mm de diámetro y 750 mm de
distancia focal, sin seguimiento motorizado, durante una noche de buen seeing y transparencia pobre
(nubes intermitentes).
6.3. AVANCES LOGRADOS 63
Figura 6.6: Imagen cruda de los montes Apeninos tomada con la cámara QHY5T.
La figura 6.7 muestra el resultado de alinear y apilar solamente unas 400 imágenes utilizando el
programa Registax 6. Notar que tanto la imagen procesada como el crudo presentan zonas sobreex-
puestas. En este caso debió haberse utilizado un filtro de densidad neutra para reducir el brillo o una
ganancia o tiempo de exposición más reducido.
Figura 6.7: Post procesado de unas 400 imágenes utilizando debayer.py y Registax 6
La siguiente foto es una de las primeras capturas obtenidas con la cámara. Se trata del cráter
Gassendi, ubicado al centro sud este de la superficie lunar. Dicha imagen fue publicada en el sub
foro de Linux del fabricante QhyCCD4 por el autor de este trabajo y constituye una de las primeras
pruebas exitosas tanto del driver como de las etapas tempranas de desarrollo visor.
4 http://qhyccd.com/ccdbbs/index.php?topic=4021.0
64 CAPÍTULO 6. CONCLUSIONES
Figura 6.8: Una de las primeras imágenes capturadas utilizando la cámara QHY5T en GNU/Linux.
En la figura 6.9 se puede ver una imagen cruda de Saturno tomada en febrero de 2014. La fotografı́a
fue adquirida utilizando un telescopio newtoniano de 200 mm de diámetro y 1000 mm de distancia
focal durante una noche de buen seeing y transparencia. Además de la cámara se utilizó una lente
TeleVue PowerMate x2.5. La figura 6.10 muestra el resultado de utilizar el programa debayer.py para
debayerizar la imagen de la figura anterior. Además en este caso se utilizó la función de crop incluida
en el programa. Si bien los frames originales son de 800x600, el programa debayer.py centra el planeta
y recorta esa sección luego de debayerizar, produciendo cuadros mucho más chicos, donde el planeta
se encuentra casi en el centro. Esto mejora el alineado en Registax y reduce enormemente el tiempo
de procesado.
La imagen de la figura 6.11 es el resultado de procesar 820 cuadros. Además del recorte con deba-
yer.py, se utilizó Registax 6 para alinear y apilar los cuadros. En la etapa de apilado es posible duplicar
la resolución de la cada imagen, por lo tanto el resultado es una imagen más grande. Posteriormente
también se utilizó Gimp 2.8 para realzar las zonas de frecuencias altas utilizando una máscara de
desenfoque. En la fotografı́a pueden verse claramente los anillos del gigante gaseoso, incluso el anillo
C (el más interno) aunque mucho más tenue que el resto. La División de Cassini se encuentra bien
resuelta en toda la circunferencia del los anillos e incluso puede apreciarse el disco planetario a través
de la División. También pueden verse los diferentes colores de las franjas gaseosas del planeta. Una
más clara en la zona ecuatorial, una más oscura en la zona tropical y por último el Vórtice Hexagonal
Polar Norte, aunque este último no se halla bien resuelto5 .
Figura 6.11: Imagen obtenida a partir de 820 cuadros obtenidos con la QHY5T y el programa
qhy5tviewer, procesados con Registax 6.
5 A mayores aperturas, es posible ver claramente que este vórtice tiene una extraña forma hexagonal. Fue observado
por primera vez por la sonda Voyager en 1981. Más en http://en.wikipedia.org/wiki/Saturn %27s hexagon
66 CAPÍTULO 6. CONCLUSIONES
Capı́tulo 7
Trabajo a futuro
A pesar que el trabajo cumple con los objetivos propuestos, muchas son las mejoras que se pueden
practicar a lo aquı́ presentado. Aquı́ se exponen algunas sugerencias para trabajos futuros pero esta
lista no es ni por mucho exhaustiva. La astronomı́a amateur es un campo de juegos para los estudiantes
de informática, lleno de desafı́os atrapantes.
67
68 CAPÍTULO 7. TRABAJO A FUTURO
QHY21, QHY23 y QHY5-II, entre otras. Sin embargo, al momento de escribir este trabajo, dicho
SDK no soporta el modelo QHY5T. Dado que el SDK está liberado utilizando una licencia GPL2, es
posible desarrollar una capa de abstracción entre la API del SDK y las funciones implementadas en el
driver que cubre este trabajo. Esto permitirı́a que la cámara QHY5T funcione con herramientas que
ya están siendo desarrolladas utilizando dicho SDK como OpenSkyImager desarrollado por Giampiero
Spezzano.
Otra herramienta interesante parece ser lin guider. Esta herramienta ha sido especialmente di-
señada para realizar guiado, es decir que una vez calibrado puede detectar la dirección de la deriva de
una estrella usando información de el cuadro actual y los anteriores y enviar comandos de guiado a la
montura para mantenerla apuntando siempre al mismo lugar. Este programa actualmente soporta una
variedad de cámaras de la empresa QhyCCD además de cámaras de otros fabricantes. Sin embargo al
momento de escribir este trabajo, la cámara QHY5T no está soportada.
Para esta integración puede ser necesario reescribir y modificar la API del driver desarrollado en
este trabajo para que se ajuste a la interfaz de desarrollo del SDK y de lin guider. Dado que ambos
están escritos mayormente en C++, puede requerir una inversión de tiempo y esfuerzo considerable.
radiación (en el caso de un sensor fotográfico, radiación lumı́nica) durante los perı́odos en los cuales no está recibiendo
radiación alguna. Este efecto, en general es más intenso a medida que la temperatura del sensor aumenta.
2 Un widget es un elemento de programación en interfaces de usuario gráficas, como un botón, un cuadro de dialogo
por cfitsio, para que el archivo generado sea compatible con los visores disponibles. No es trivial
aprender a manejar estos tipos de datos y puede requerir una investigación importante relacionada
con el formato, pero no se espera que esta tarea represente un trabajo de complejidad alta.
el firmware y los archivos de configuración de udev para que la carga de dicho firmware se produzca
de manera automática cuando se detecta un dispositivo QHY5T compatible.
Puede ser de mucha ayuda suscribirse al foro de QhyCCD[15] de desarrolladores para GNU/Linux,
en el cual suelen discutirse tópicos relacionados con el desarrollo de drivers y programas para los
dispositivos de este fabricante.
Capı́tulo 8
Apendice A
Para la fotografı́a de objetos de espacio profundo como galaxias y nebulosas, es necesario como se
mencionó anteriormente, realizar tomas con cierto tiempo de exposición. Estos tiempos pueden variar
de varios segundos a varios minutos, dependiendo del brillo del objeto y el o los filtros utilizados.
Sin embargo, cuanto mayor es el tiempo de exposición, mayor es el movimiento aparente del
cielo nocturno. Para contrarrestar este movimiento y ası́ evitar que las estrellas dejen trazos en la
capturas en lugar de aparecer como objetos puntuales, los aficionados utilizan monturas ecuatoriales
motorizadas, las cuales una vez puestas en funcionamiento permiten realizar tomas de entre 1 y 3
minutos, dependiendo de la precisión a la hora de poner la montura en estación. Para tiempos de
exposición mayores a los 3 minutos, sin embargo, es necesario recurrir a otras técnicas ya que no solo
la puesta en estación influye en la calidad del seguimiento celeste, sino también el error periódico
introducido por los engranajes de la montura, la flexión del tubo principal sobre la montura o incluso
el flujo de corriente irregular pasado a los motores[16].
Una de las técnicas más utilizadas consiste en utilizar un segundo telescopio, generalmente más
pequeño, al cual se conecta la cámara guı́a. Tanto la montura como la cámara deben tener soporte
hardware para poder realizar el guiado. Generalmente, la cámara se conecta a la montura directamente
a través del puerto de guiado que implementa el protocolo ST-4. La cámara además se encuentra
conectada a una PC que corre el software de guiado. La cámara envı́a imágenes al software de guiado.
Se selecciona una estrella guı́a en el campo cercano al objeto que se quiere fotografiar y se calibra
el software de guiado para determinar la dirección de la deriva. Una vez calibrado el software, el
guiado se realiza en forma automática. El software analiza las imágenes que genera la cámara guı́a y
determina si la estrella deriva. Si es necesario realizar alguna corrección, el software de guiado invoca a
una rutina del driver de la cámara para que esta le envı́e los pulsos de guiado necesarios a la montura
para mantener la estrella centrada.Un ejemplo de software de guiado que funciona en GNU/Linux es
el lin guider 1 .
En la figura 8.1 puede verse una configuración tı́pica para realizar guiado. Sobre el telescopio
principal (un SkyWatcher 200/1000, en negro) se ve montado un telescopio más pequeño, en este
caso, un tubo guı́a SkyWatcher 80/400 (en color azul) con una cámara guı́a QHY5. Todo el equipo
está montado sobre una montura SkyWatcher HEQ5 con soporte para el protocolo ST-4.
1 http://sourceforge.net/projects/linguider/
71
72 CAPÍTULO 8. APENDICE A
Figura 8.1: Configuración para realizar fotografı́as de larga exposición con guiado.
Para obtener imágenes como la de la figura 8.2 son necesarios varios pasos. La técnica consiste en
tomar varias fotografı́as del mismo objeto. Estas imágenes luego son registradas, de manera que el
objeto a fotografiar siempre se encuentre en la misma posición. Existen varios algoritmos para registrar
imágenes, incluso algunos que logran precisión sub-pixel. Muchos de ellos vienen implementados en los
programas de procesado. Posteriormente las imágenes son apiladas, proceso que consiste en obtener
una única imagen, donde la intensidad del pixel en la posición (x,y) se calcula utilizando los valores de
pixels de la posición (x,y) de todas las imágenes. Suele utilizarse el promedio, la media y la mediana,
aunque existen otros algoritmos como ”Sigma clipping”que pueden utilizarse en escenarios especı́ficos.
Este proceso elimina el ruido y aumenta la señal del objeto a fotografiar. Una vez aumentada la señal,
se puede aplicar diferentes filtros para realzar los detalles, como transformadas de Wavelets2 , Wiener 3
para reducción de ruido, filtrado en frecuencia para eliminar bandas, alinear canales RGB, ecualización
de histograma, etc.
Registax 6 ofrece una entorno para realizar las etapas de registro y apilado, además de algunos
filtros sencillos, como wavelets, ecualización de histograma y alineación de canales, además de algunos
filtros especı́ficos más complejos como ”Derotation”. Este filtro detecta y compensa el movimiento
alrededor del eje de rotación y es sumamente útil en Júpiter. Júpiter tiene un perı́odo de rotación
de 9 hs, con lo cual, capturar imágenes durante más de 45 segundos produce resultados borrosos
a grandes aumentos, ya que es imposible alinear las primeras imágenes con las últimas. Gracias al
filtro “Derotation”, es posible sin embargo obtener imágenes detalladas a partir de varios minutos de
captura. Fotógrafos como Demian Peach[17] y Christopher Go[18] hacen uso de esta misma técnica,
aunque ambos con resultados sumamente diferentes.
2 http://en.wikipedia.org/wiki/Wavelet transform
3 http://en.wikipedia.org/wiki/Wiener filter
8.2. SOBRE LAS TÉCNICAS DE PROCESADO PARA FOTOGRAFÍA LUNAR Y PLANETARIA73
Figura 8.2: Imagen de Saturno obtenida a partir de casi 2000 frames individuales, procesados con
Registax 6 y retocadas con Gimp 2.8
Si bien Registax no funciona de manera nativa en Linux, si es posible hacerlo funcionar mediante
la utilización de Wine4 .
4 http://www.winehq.org/
74 CAPÍTULO 8. APENDICE A
Bibliografı́a
[1] D. L. Fried, “Probability of getting a lucky short-exposure image through turbulence” J. Opt.
Soc. Am. 68, 1651-1657 (1978)
[2] MT9M001 - 1/2-Inch 1.2MP Digital Image Sensor, Rev F (05/2006)
[3] MT9T001 - 1/2-Inch 3.1MP Digital Image Sensor Datasheet, Rev D (07/2005)
[5] Image Sensor Architectures for Digital Cinematography - DALSA Digital Cinema. Pág 8.
[14] Henrique S. Malvar, Li-wei He, and Ross Cutler, “High-quality Linear Interpolation for demosai-
cing of bayer-parrerned color images”, Microsoft Research, IEEE (2004)
[15] QhyCCD Linux World. http://qhyccd.com/ccdbbs/index.php?board=16.0.
[16] Mark J. Coco, “Guiding a Telescope for Imaging”, Sky and Telescope http://www.
skyandtelescope.com/howto/astrophotography/3304266.html. Visitado el 23 de marzo de
2014
[17] D. Peach’s Views of the Solar System. http://www.damianpeach.com/
[18] Astrophotography from Cebu City, Philippines by Christopher Go. http://astro.christone.
net/
75
76 BIBLIOGRAFÍA
Agradecimientos
A Hongyun Qiu quién permitió el acceso a los fuentes del driver para Windows. A Tom Van den Ee-
de, desarrollador del driver para Windows para la cámara QHY5T, su ayuda fue fundamental durante
la última etapa de desarrollo del controlador. A Geoffrey Hausheer quien hizo disponible su contro-
lador para la cámara QHY5 bajo una licencia Libre. A Daniel Holler, Andrew Stepanenko, Henrik
Kressner y demás miembros de la comunidad de usuarios QhyCCD-GNU/Linux quienes contribuye-
ron ideas y código al trabajo aquı́ presentado. A Pavol Ďuriš y Ioannis Ioannou quieres ayudaron a
probar el driver y el visor. A Giampiero Spezzano y Clive Rogers por no permitir que me rindiera en
las horas más oscuras y por el código e ideas que aportaron. A Andoni Zubimendi por su acertada
observación respecto al firmware y la ayuda con el análisis. A Gastón Traberg por su ayuda con el
programa para extraer el firmware. A Emanuel Borda por el interés y la ayuda brindada durante las
primeras etapas del proyecto. A Beatriz Garcı́a, Belén Iazzetta, Aldana Gómez Rı́os y Lautaro De
León, por las observaciones al texto de la tesina. A mi directora, Lı́a Molinari por su entusiasmo.
77