Windows 10 Core para IoT

Durante la conferencia BUILD en San Francisco publicamos la vista previa de  Windows 10 IoT para Raspberry Pi 2 y MinnowBoard Max. También hemos añadido un Virtual Shield para poder conectar nuestras aplicaciones de Windows 10 con Arduino.

Las aplicaciones de Windows 10 para IoT son en realidad aplicaciones universales que utilizan el Windows 10 Core, pero al ser aplicaciones para un dispositivo que puede no tener una pantalla tenemos dos modos: headed y headless.

En el modo headed será una aplicación universal con interfaz y el modelo de programación es el mismo que para las demás aplicaciones universales que se desarrollarán para teléfono, PC, tableta y XBox. Tendremos XAML para la intefaz y la podremos controlar mediante un teclado y ratón USB conectados al dispositivo.

¿Qué necesito?

Un PC con Windows 10 insider preview, mínimo la versión 10074, para poder ejecutar los comandos para grabar la imagen a la tarjeta SD.

Visual Studio 2015 RC, se puede instalar desde aquí, podemos utilizar la Community Edition, o, como todavía está en RC, también podemos descargar la versión Enterprise: https://www.visualstudio.com/en-us/downloads/visual-studio-2015-downloads-vs.aspx.

Las herramientas para IoT, una vez instalado Visual Studio:  https://dev.windows.com/en-US/downloads/install-dev-tools-visual-studio-2015

Para empezar  a desarrollar para alguna de las plataformas que hemos publicado, el mejor sitio es empezar por https://ms-iot.github.io/content/GetStarted.htm donde nos guiarán paso a paso dependiendo de la placa IoT que estemos usando. A partir de ahora seguiremos el artículo con Raspberry Pi 2, pero para el caso de MinnowBoard será bastante parecido.

Raspberry Pi 2

Empezaremos descargando la imagen de Windows 10 IoT para Raspberry Pi 2, para ello nos tendremos que haber apuntado al programa de IoT preview en Connect, donde podremos descargar la imagen de Windows 10 para nuestro dispositivo. Dentro del archivo zip encontraremos un instalador llamado WindowsDeveloperProgramForIoT que nos instalará una herramienta para descubrir los dispositivos que tengamos conectados en nuestra red, también habrá un archivo Flash.ffu, que nos servirá para instalar la imagen de Windows 10 en la tarjeta SD.

Ejecutamos el siguiente comando:

 wmic diskdrive list brief

Nos proporcionará una lista de discos en nuestro PC, buscamos el DeviceID del disco que se corresponda con nuestra tarjeta SD:

image

Una vez sepamos el número de PHYSICALDRIVE, ya podemos aplicar la imagen con el comando:

 dism.exe /apply-image /imagefile:flash.ffu /applydrive:\\.\physicaldriveN /SkipPlatformCheck

image

Una vez creada la imagen en la tarjeta SD ya podemos introducirla en la Raspberry Pi 2. Es conveniente conectar el cable HDMI y cable de Red antes de darle corriente a través del cable microusb.

La primera vez tardará unos minutos en arrancar, la primera pantalla que veremos nos da la IP asignada a la Raspberry. Si esperamos unos minutos se reiniciará y ya nos aparecerá la aplicación por defecto que nos indicará que tipo de dispositivo tenemos, el nombre y su IP:

image

Primeros pasos: cambio de nombre y credenciales

El nombre por defecto de la placa será minwinpc, pero lo podemos cambiar mediante powershell. Es conveniente cambiarlo para poder identificarla más fácilmente:

Nota: es posible que tengamos que arrancar el servicio WinRM en nuestro PC, mediante el comando “net start WinRM”.

  • Primero tenemos que añadir la IP de nuestra Raspberry a la lista de TrustedHosts, de forma que podamos acceder remotamente:
 Set-Item WSMan:\localhost\Client\TrustedHosts -Value <machine-name or IP Address> 
  • A continuación ejecutamos el siguiente comando como workaround a un pequeño bug de PS:
 remove-module psreadline -force
  • A partir de ahora ya podemos iniciar una sesión remota de PowerShell:
 Enter-PsSession -ComputerName <machine-name or address ip> -Credential <machine-name address ip or localhost>\Administrator

Nos pedirá un password que por defecto es: p@ssw0rd

Puede tardar medio minuto en conectar, una vez conectado ya tenemos acceso, por ejemplo, podemos cambiar el nombre con el comando setcomputername, así podremos añadir ese nombre a TrustedHosts:

image

A partir de este momento ya podemos añadir el dispositivo a TrustedHosts a través del nombre, por si nos cambia la IP en algún momento.

Gestión remota del dispositivo

Además de tener acceso a través de PowerShell remoto y poder conectar un teclado y ratón a la Raspberry Pi, también tenemos una interfaz web que nos permitirá gestionar y ver qué está pasando dentro del dispositivo.

El instalador que acompañaba a la imagen de Windows 10 para IoT, nos habrá instalado la aplicación Windows IoT Core Watcher que se ejecuta al inicio automáticamente. Esta aplicación nos ayudará a descubrir nuestra Raspberry dentro de la red:

image

Desde esa ventana veremos como podemos abrir una página donde podremos ver los procesos que se están ejecutando, desplegar aplicaciones, depurar, revisar el rendimiento, etc. Windows 10 para IoT implementa un pequeño servidor web, podemos acceder por el nombre del dispositivo o bien a través de su IP.

image

 

Nuestra primera aplicación: el LED que parpadea

Una vez instalados Visual Studio 2015 RC y las herramientas para IoT podemos empezar a desarrollar apps en .Net que podremos desplegar fácilmente a nuestra Raspberry. Tenemos un montón de ejemplos en GitHub y en la página https://microsoft.hackster.io/. Hoy vamos a hacer el ejemplo más sencillo, parpadeo de un LED, a fin de comprobar que lo tenemos todo bien instalado y todo funciona correctamente. Para ello necesitamos, además de la Raspberry Pi 2, un LED, una resistencia de 220 Ω, unos cuantos cables y un “breadboard” para pinchar todos los elementos sin necesidad de soldar. El esquema tanto para Raspberry Pi 2 como para la MinnowBoard están en la página del ejercicio original, yo he utilizado además un “breakout cable” para hacer el montaje un poco más fácil, aunque al ser un ejercicio muy sencillo se puede conectar todo directamente.

Con el breakout nos queda así, el led está conectado al PIN 5 (la pata corta, el –) y a través de la resistencia (no tenía de 220 y he puesto una de 330) al positivo de 3V (pata larga +):

image 

Importante: recordad que un LED es un diodo y la corriente sólo pasa en un sentido. Si no se os enciende, probablemente lo hayáis conectado al revés.El esquema tanto para Raspberry Pi 2 como para la MinnowBoard están en la página del ejercicio original.

Desarrollo con Visual Studio 2015RC y C#

Las aplicaciones para Windows 10 IoT son aplicaciones universales, si, como las que desplegaremos en PC, tabletas, teléfonos y XBox One. Pueden tener interfaz o bien ejecutarse sin, lo que llamamos modo “headless”. Para esta ocasión, vamos a hacer una aplicación con UI, así podremos poner controles para modificar el comportamiento del LED. Conectando un ratón USB podremos controlar la aplicación que se ejecuta en el dispositivo.

Desde Visual Studio, empezaremos creando una Blank Athens Application, vamos a hacer una aplicación de interfaz:

image

Para poder encender el LED vamos a acceder a los pines del puerto GPIO (General Purpose Input/Output), que son los pines que tiene el dispositivo y que nos permite configurarlos como entrada o salida. Para poder abrir los pines necesitamos añadir una referencia al Windows IoT Extension SDK:

image

 

En este momento ya podemos empezar a utilizar GPIO, vamos a alternar los estados Low y High en el pin 5 para encender y apagar el LED. Como es una aplicación universal, en este caso tendrá interfaz, en la MainPage.xml pongo un slider para controlar la velocidad de parpadeo y un bloque de texto para ver algunos mensajes de error:

   <StackPanel>     <Slider Name="timeSlider" Width="100" Minimum="100" Maximum="2000" Value="500" ValueChanged="timeSlider_ValueChanged"></Slider>     <TextBlock Name="gpioStatus" Text="Connecting"></TextBlock>
  </StackPanel>

Ya en el código .cs de la página, creamos un timer para el parpadeo del LED:

 DispatcherTimer timer;

public MainPage() 
{
 this.InitializeComponent();
 timer = new DispatcherTimer();
 timer.Interval = TimeSpan.FromMilliseconds(timeSlider.Value);
 timer.Tick += Timer_Tick;
 initGpio();
 this.Unloaded += MainPage_Unloaded; 
}

En el método initGpio vamos a inicializar la conexión con el PIN 5, utilizamos la clase Windows.Devices.Gpio.GpioController para obtener acceso al pin:

 GpioPin pin;
bool light;

private void initGpio()
{
    var gpio = GpioController.GetDefault();

    if (gpio == null)
    {
        pin = null;
        gpioStatus.Text = "No GPIO controller found.";
    }
    else
    {
        pin = gpio.OpenPin(5);

        if (pin == null)
        {
            gpioStatus.Text = "Pin not initialized";
        }
        else
        {
            pin.Write(GpioPinValue.High);
            pin.SetDriveMode(GpioPinDriveMode.Output);
            gpioStatus.Text = "Pin initialized";
            light = true;
            timer.Start();
        }
    }
}

Y en el timer vamos alternando entre los valores GpioPinValue.High y Low:

 private void Timer_Tick(object sender, object e)
{
    if (pin != null)
    {
        if (light)
        {
            pin.Write(GpioPinValue.Low);
        }
        else
        {
            pin.Write(GpioPinValue.High);
        }
    }
    light = !light;
}

Hay que tener en cuenta que estamos utilizando recursos no manejados, como los pines del GPIO, así que debemos tener cuidado de liberarlos cuando no los estemso utilizando. La clase Pin tiene un método dispose al que deberemos llamar al salir de la pantalla:

 private void MainPage_Unloaded(object sender, RoutedEventArgs e)
{
    if (pin != null)
        pin.Dispose();
}

Para acabar cambiamos el intervalo cuando cambia el slider para hacer algo interesante:

 private void timeSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
    if(timer!=null)
        timer.Interval = TimeSpan.FromMilliseconds(timeSlider.Value);
}

Despliegue y depuración

Una vez realizado el desarrollo, tenemos que desplegar la aplicación en la Raspberry Pi 2. Para ello, primero configuraremos el proyecto para ARM en el caso de RPI2. Si usamos MinnowBoard Max será x86. El despliegue se realiza mediante depuración remota en el dispositivo. En la pantalla de configuración de depuración del proyecto tendremos que decirle dónde queremos desplegar y usar la máquina remota sin autentificación:

image

Al ejecutar la aplicación y si hemos conectado todo correctamente deberíamos ver un LED parpadeando como éste:

ezgif.com-gif-maker (1)

Notas y algunos comandos útiles:

Tras este primer proyecto hemos comprobado que todo nos funciona y tenemos acceso al bus GPIO, ahora puedes continuar con todos los proyectos que encontrarás en https://microsoft.hackster.io/, desde una estación meteorológica hasta un kit completo de robótica.

Durante el desarrollo con este tipo de dispositivos y utilizando el software en preview nos podemos encontrar con algunos problemas. Os dejo aquí algunas notas y comandos que me han venido bien.

  • Las tarjetas SD tienden a corromperse y aunque podemos volver a grabar la imagen, a veces eso no es suficiente. La herramienta SD Formatter nos dejará la tarjeta completamente límpia de nuevo y lista para volver a planchar la imagen de Windows 10 for IoT.

  • Si el MSVCMON.EXE no se está ejecutando, podemos ponerlo en marcha  con el siguiente comando desde el PowerShell remoto:

     schtasks /run /th StartMsVsmon 
    
  • Puede que tengamos que sincronizar la hora de nuestra máquina para que funcione bien el depurador, si estamos en España podemos usar el comando tzutil para establecer UTC+1, pero como lo hacemos desde PowerShell tendremos que usar Invoke-Expression:

     Invoke-Expression "cmd.exe /c tzutil /s ""Romance Standard Time"""
    
    w32tm /resync 
    
  • Ya lo hemos visto al principio, pero no está de más recordar los comandos básicos para acceder por powershell remoto:

    • Asignar permisos para poder acceder por PowerShell remoto:

       Set-Item WSMan:\localhost\Client\TrustedHosts -Value <IP o nombre del dispositivo>
      
    • Acceder por PowerShell remoto:

       Enter-PSSession -ComputerName <IP o nombre del dispositivo> -Credential localhost\Administrator
      
    • Listado de comandos de PowerShell: https://ms-iot.github.io/content/win10/tools/CommandLineUtils.htm

 

¡Que os divirtáis mucho con vuestros dispositivos IoT!

Juan Manuel Servera

@jmservera

IoT & Web Technical Evangelist