Buenas,
desde hace unos meses vengo posteando sobre el dinero que malgasto en chorradas mis juguetes/hobbies: LEGO Mindstorm, WirelessWebCam, Business Intelligence,etc., sin embargo todavía no había tenido tiempo de "orquestar" todos los componentes en una única solución.
Mi idea original era:
- integrar la webcam y el bot
- aprovechar alguna de las librerías que me permiten interactuar con el LEGO Mindstorm para controlar el mismo; sin cables
- diseñar y crear un cliente que obtenga las imágenes de la webcam, para mostrarlas en tiempo real (lo mas cercano a tiempo real posible); sin cables
- diseñar y crear un repositorio donde registrar todos los movimientos del bot, asi como las imagenes que se obtienen de la webcam
- diseñar y crear un cliente que me permita reproducir en un entorno visual el histórico de movimientos e imágenes de una sesión con el Lego
Pues después de robarme un par de horas de sueño, finalmente me animé con la siguiente propuesta:
Y empece a desglosar las partes y las tareas en ...
LEGO + WebCam
La primera tarea fue bastante simple, debido a que estoy limitado a las piezas actuales que poseo del Lego. Tuve mis dudas sobre si montar la "cpu" del Lego por detrás o por encima de la webcam (estorbaba la antena) pero finalmente decidí montarla arriba del mismo.
Para ver el resultado lo mejor que puedo hacer es dejar un par de imágenes para que vean el bot final (click sobre las mismas para ampliar la imagen):

VB.Net / Lego / Wireless WebCam
Simplemente me hice referencia a mi mismo, a anteriores posts, Lego y .Net, WebCam y .Net, ya escribí un par de veces sobre como acceder y manejar los servicios del bot (utilizando Microsoft Robotics Studio o Nxt# - Mindstorms for .Net) y además cómo implementar un cliente para obtener las imágenes de la webcam utilizando algunas features de System.Net.WebClient.
Era necesario desarrollar un par de interfaces visuales para poder integrar toda la solución. Una de ellas que permita controlar el bot y la siguiente que permita visualizar el histórico:

El primer tab permite controlar los movimientos del bot y ver en tiempo casi real las imágenes que muestra la cámara montada sobre el mismo. La 2da pestaña (o 2do tab) repite el historico de movimientos realizados por el lego, mostrando la dirección en la que se estaba moviendo y las imágenes que se capturaron con la webcam. (al final un video de demo :D)
Lego History Repository
En este escenario, apliqué un principio por el que me guío siempre: "cuando más simple, mejor". En mi base de datos sólo poseo una tabla RobotHistory donde registro las acciones que realiza el bot y ademas he creado 3 procedimientos almacenados para trabajar con los datos de la misma, AddHistory, ClearHistory y GetHistory. (los nombres de los SPs lo dicen todo ¿no?)
Estos son los campos de la tabla RobotHistory:
- HistoryId representa el id autonumérico
- HistoryDate almacena la fecha y hora de la acción
- HistoryAction representa el tipo de acción
- MoveDescription un string para mejorar la experiencia del usuario en la vista del histórico
- WebCamImage un campo del tipo image para almacenar las imágenes que se obtienen de la WebCam.

Para interactuar con los procedimientos almacenados y para ahorrarme un par de líneas de desarrollo, utilice el módulo de acceso a datos de Enterprise Library. Por ejemplo para invocar el siguiente procedimiendo almacenado que inserta un registro en el histórico de movimientos:
ALTER PROCEDURE [dbo].[AddHistory]
(
@HistoryAction int = 0,
@MoveDescription varchar(250) = '',
@WebCamImage image = null
) AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from interfering with SELECT statements.
SET NOCOUNT ON;
--Insert Values
INSERT INTO RobotHistory
(HistoryAction, MoveDescription, WebCamImage)
VALUES
(@HistoryAction, @MoveDescription, @WebCamImage)
-- Return Id
SELECT @@Identity as HistoryId
END
implementé un código vb.net que crea 2 sobrecargas sobre una misma función AddHistory, para poder recibir los datos necesarios para el SP y opcionalmente una imagen o el array de bytes que corresponde a esa imagen:
''' <summary>
''' Adds the history.
''' </summary>
''' <param name="HistoryAction">The history action.</param>
''' <param name="MoveDescription">The move description.</param>
''' <param name="WebCamPic">The web cam pic.</param>
''' <returns></returns>
Public Shared Function AddHistory(ByVal HistoryAction As DataActions, ByVal MoveDescription As String, Optional ByVal WebCamPic As System.Drawing.Bitmap = Nothing) As Integer
Dim ms As New IO.MemoryStream
If Not WebCamPic Is Nothing Then
WebCamPic.Save(ms, Drawing.Imaging.ImageFormat.Bmp)
End If
Return AddHistory(HistoryAction, MoveDescription, ms.GetBuffer())
End Function
''' <summary>
''' Adds the history.
''' </summary>
''' <param name="HistoryAction">The history action.</param>
''' <param name="MoveDescription">The move description.</param>
''' <param name="WebCamPic">The web cam pic.</param>
''' <returns></returns>
Public Shared Function AddHistory(ByVal HistoryAction As DataActions, ByVal MoveDescription As String, ByVal WebCamPic() As Byte) As Integer
Dim db As Microsoft.Practices.EnterpriseLibrary.Data.Database = DatabaseFactory.CreateDatabase()
Dim ds As DataSet = db.ExecuteDataSet("AddHistory", HistoryAction, MoveDescription, WebCamPic)
Return ds.Tables(0).Rows(0)(0)
End Function
Para identificar todas las acciones posibles que se podian realizar, trabajé con una enumeración bastante simple que representa los valores que se registrarán en la base de datos y me permitirán consultar el historial de movimientos e imágenes del bot.
Public Enum DataActions As Integer
GoFoward_ButtonClick
GoFoward_ButtonDown
GoFoward_ButtonUp
GoBackward_ButtonClick
GoBackward_ButtonDown
GoBackward_ButtonUp
TurnLeft_ButtonClick
TurnLeft_ButtonDown
TurnLeft_ButtonUp
TurnRight_ButtonClick
TurnRight_ButtonDown
TurnRight_ButtonUp
Stop_ButtonClick
Stop_ButtonDown
Stop_ButtonUp
Save_Movie
End Enum
Bot in action !!!
Pues una vez que he ensamblado todas las partes, solo me queda poner todo en acción y tratar de no olvidarme el bot fuera porque los gatitos lo destruyen. A continuación comparto 2 videos con la captura de la aplicación en ejecución, donde se puede ver como se controla y se ven las imágenes del bot y además otro video con la filmación del bot en vivo respondiendo a las acciones que le envío. (si estás trabajando con una buena conexion a internet, aconsejo poner play en ambos videos al mismo tiempo y pueden ver la escena casi en simultáneo)
App in action
Video: LegoWithWebCam
Live Bot (versión Youtube disponible aquí)
Video: LegoWithWebCamLive
Para finalizar, simplemente comentar que desde hace mucho no me divertía tanto como con el Lego Mindstorm y con algún que otro gadget que tengo por ahi. Es cada vez más fácil lograr integrar todos estos productitos (aunque sea para una chorrada divertida como este post) y gracias a estos pequeños retos personales, nos podemos dar el lujo de aprender un poco de tecnologías que aunque parece imposible, tal vez apliquemos en los proyectos donde nos encontremos.
El código fuente completo de la solución se puede descargar desde aquí (gracias geeks again) y en futuros posts explicaré como hice el módulo que repite el histórico del bot y como llevar esta solución completa a Microsoft Robotics Studio.
Saludos
El Bruno
PD: despues de mostrarselo a un amigo, ya me ha empezado a sugerir cambios y modificaciones que refuerzan la frase "nada es imposible para la persona que no tiene que hacerlo"; ¿estará relacionado con el cargo de brown dispatcher que ejerce este amigote? jejeje :D
Crossposting from
ElBruno.com