Monthly Archives: January 2013

Arduino Wire Scanner sur le bus I2C

Aujourd’hui je publie un code qui n’est pas de moi mais qui est bien pratique.

En effet, ce code permet de scanner tous les éléments connectés au port  I2C de votre Arduino.

Vous noterez que ce code utilise la librairie Wire qui permet de communiquer avec les équipements I2C.

Un grand merci à son auteur pour ce scanner Arduino I2C.

// Wire Scanner
// 
// 
// Demonstrates the use of the Wire library
// Ping all valid adresses on the I²C bus
// and get the answer to see if there is a slave
// Print an 8 x 16 array with the results
 
// Created by fdufnews 2012 december 14th
 
// This example code is in the public domain.
 
#include <Wire.h>
 
void setup()
{
  Wire.begin();         // join i2c bus (address optional for master)
  Serial.begin(9600);   // start serial for output
  Serial.println();     // Print a banner
  Serial.println();
  Serial.println("I2C slave scanner");
  Serial.println("   reserved adress");
  Serial.println(".  no slave detected");
  Serial.println("X  slave detected");
  Serial.println();
  Serial.println();
  int result;
  Serial.println("   0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F");
  // Scan only valid addresses (8 to 0x7B)
  // 0-7 and 7C-7F are reserved ones
  unsigned char devices=0;                  // holds how many devices found
  for (unsigned char ad=0; ad<0x7C;ad++){
    if(ad%16==0){                           // If at start of a row
      Serial.print(ad>>4,HEX);              // Display high order bit address
      Serial.print(" ");
    }
    if (ad>7){                              // skip address from 0 to 7
      Wire.beginTransmission(ad);           // start transmission
      result = Wire.endTransmission();      // end transmission and store answer
      if (!result) devices++;               // add a device to the count if ACK
      Serial.print(" ");
      Serial.print(result==0?"X ":". ");    // If ACK there is a guy at this address
    }
    else{
      Serial.print("   ");                  // Sorry nobody here
    }
    if(ad%16==15) Serial.println();         // end of the row add a new line
  }
  Serial.println();
  Serial.println();
  Serial.println();
  Serial.print(devices, DEC);
  Serial.print(" device");
  Serial.print(devices>1?"s":"");
  Serial.println(" found on the bus");
}
 
void loop()
{
 
}

 

Comprendre le multiplexeur PWM TLC5940

A quoi sert le composant TLC5940 ?

Le composant TLC5940 est un multiplexeur PWM (Pulse Width Modulation) qui peut gérer jusqu’à 16 canaux PWM. Ainsi avec seulement 3 pins de votre Arduino vous allez pouvoir utiliser jusqu’à 16 canaux PWM.

Tout comme le composant Shift Register 74HC595, le circuit intégré TLC5940 peut être connecté en cascade, ce qui permet d’étendre considérablement le nombre de canaux PWM utilisables.

Cela va donc être parfaitement adapté à mon projet EasyLight pour multiplexer des leds RGB.

Comment utiliser le composant TLC5940 avec Arduino ?

Il existe une bibliothèque nommée TLC5940Arduino qui permet de contrôler simplement un ou plusieurs composants TLC5940 directement avec Arduino.

La librairie TLC5940Arduino peut être téléchargée sur ce site.

 Comment fonctionne le composant TLC5940 ?

Le plus simple pour comprendre le fonctionnement du composant TLC5940 est de lire la fiche technique TLC5940.

Voici le schéma du composant TLC5940:

TLC5940 pins

 

Comme on peut le voir, on a bien nos 16 sorties PWM (de OUT0 à OUT15). Voici le détail des autres pins:

  • XERR: open collector, wire or-ed output that lets you know a TLC5940 is over heated or has a burnt out LED. We can ignore this as it will always be on unless you have current using elements on all of the outputs.
  • SOUT: serial data out from the TLC5940. Unless you wish to try to read the error bits you do not need this to come to the Arduino. If you have more than one TLC5940 this is the line you daisy chain to the SIN of the next package.
  • DCPRG: this selects the source of the current limiter register, you could just tie it high.
  • XLAT: you will need this to latch data after shifting.
  • SCLK: you will need this to shift data.
  • SIN: serial in to TLC5940, this is the output from the Arduino.
  • VPRG: you need this to select either the current limit registers or the duty cycle registers for writing.
  • GSCLK: this is the clock for the PWM. We will reprogram TIMER2 in the Arduino to make this signal. That will cost us the native PWM on that timer, digital 11 on a mega8, 11 and 3 on a mega168.
  • BLANK: this marks the end of a PWM cycle in addition to blanking the output. We will reprogram TIMER1 to generate this signal. That will cost us the native PWMs on digital 9 and digital 10. (Tie a real, physical pull-up resistor on this line to keep things blanked while your Arduino boots. Depending on your hardware, it is possible that the TLC5940 would come up in a configuration that would dissipate too much power.)

 La broche 20 du TLC5940: IREF

Sur la broche numérotée 20 du composant TLC5940, il faut brancher une résistance. Pour trouver la valeur de la résistance à utiliser, il suffit d’appliquer la formule suivante:

valeur de la résistance = 39.06 / intensité de la LED

Ainsi dans le cas où l’intensité de vos leds est de 30mA, vous devrez utiliser une résistance de 1302 ohms. On utilisera donc une résistance de 2K ohms.

Si vous utilisez des leds avec des intensités différentes, prenez l’intensité la plus faible comme base.

Comment brancher le composant TLC5940?

Voici le schéma électronique de branchement du composant TLC5940:

tlc5940 schema electronique

Et le schéma de connection e ntre un Arduino et un composant TLC5940:

tlc5940 schema arduino

Comment brancher le composant TLC5940 en cascade ?

Un des intérêts à utiliser le multiplexeur TLC5940 est qu’on peut chainer plusieurs composants ensemble afin d’augmenter de nombre de canaux PWM. On dit alors qu’on met les composants TLC5940 en cascade.

Voici le schéma électronique:

tlc5940 schema electronique cascade

Et voici le schéma de connection entre plusieurs multiplexeur TLC5940 en cascade et un Arduino:

tlc5940 schema arduino cascade

Lorsque l’on utilise les multiplexeurs TLC5940 en cascade, il faut penser à modifier le fichier tlc_config.h de la librairie TLC5940Arduino:

Changez la ligne #define NUM_TLCS 1 pour #define NUM_TLCS n (ou n est le nombre de TLC5940 que vous avez chainé).

Conclusion sur le multiplexeur TLC5940

Les multiplexeurs TLC5940 sont des composants qui ne coûtent pas cher et qui permettent d’augmenter le nombre de canaux PWM de votre Arduino.

Ils sont relativement pratique si vous devez utiliser des leds RGB par exemple. Le schéma suivant illustre parfaitement leur utilisation:

tlc5940 schema led rgb

Attention toutefois lorsque vous utilisez des leds RGB avec le multiplexeur TLC5940 à verifier que vos leds soient à anode commune:

led rgb common anode

Intéraction entre Dotnet et Arduino

Pour mon projet EasyLight, je vais devoir faire interagir un programme développé en DotNet avec un Arduino Uno.

Après avoir parcouru plusieurs forums, j’ai noté qu’il existait plusieurs possibilités:

  • utiliser FirmData pour faire communiquer Arduino et votre programme DotNet
  • faire du code pour connecter votre logiciel DotNet au port COM de votre Arduino

J’ai donc décidé de partir sur cette seconde option en développant 2 parties de code:

  • une classe DotNet
  • un gabarit pour Arduino

Le code s’inspire de pas mal de samples trouvés ici et là sur le net. Je l’ai commenté et il est relativement simple à comprendre.

Voici la classe DotNet Arduino:

Public Class Arduino
 
#Region "Properties"
    Private WithEvents CurrentSerialPort As System.IO.Ports.SerialPort
    Private Property ComPort As String = "COM8"
    Private Property BaudRate As Integer = 9600
    Private WithEvents WatchDogTimer As New System.Timers.Timer(5000) With {.Enabled = True}
 
    Private Receiving As Boolean
    Private BufferPointer As Integer
    Private CBuffer(30) As Byte
#End Region
 
#Region "Event"
    Public Event WatchdogReceived() 'Fires when a watchdog message (heartbeat) is received
    Public Event ConnectionLost() 'Fires when there has not been a watchdog message for 5 seconds
    Public Event LogMessageReceived(ByVal Message As String) 'Gives a system message from the Arduino
#End Region
 
#Region "Constructeur"
    Public Sub New(ByVal _comport As String, ByVal _baudrate As Integer)
        Me.ComPort = Trim(_comport)
        Me.BaudRate = _baudrate
    End Sub
#End Region
 
#Region "Connection / Start / Stop"
 
    'Fonction qui démarre la connection
    Public Sub Start()
        Call StartCommunication()
    End Sub
 
    'Fonction qui stoppe la connection
    Public Sub [Stop]()
        CurrentSerialPort.Close()
        WatchDogTimer.Stop()
    End Sub
 
    'Fonction de connection au arduino
    Private Function StartCommunication() As Boolean
        Dim ret As Boolean = False
        Try
            Dim components As System.ComponentModel.IContainer = New System.ComponentModel.Container()
            CurrentSerialPort = New System.IO.Ports.SerialPort(components)
            CurrentSerialPort.PortName = _ComPort
            CurrentSerialPort.BaudRate = _BaudRate
            CurrentSerialPort.ReceivedBytesThreshold = 1
            CurrentSerialPort.Open()
 
            If Not CurrentSerialPort.IsOpen Then
                WriteLog("[ERROR]" & vbTab & "[" & System.Reflection.MethodBase.GetCurrentMethod.Name & "]" & vbTab & "Unable to open port com...")
                Return ret
            Else
                CurrentSerialPort.DtrEnable = True
                WriteLog("[INFO]" & vbTab & "[" & System.Reflection.MethodBase.GetCurrentMethod.Name & "]" & vbTab & "Serial port is open")
                System.Threading.Thread.Sleep(1000)
 
                'on envoie une commande pour nettoyer le buffer du arduino
                Dim Command As Byte() = {40, 0, 0, 0, 41, 0}
                Me.SendCommand(Command)
                Me.SendCommand(Command)
                WatchDogTimer.Start()
                ret = True
            End If
 
            'On ajoute un handler pour récupérer les infos envoyées par le arduino
            AddHandler CurrentSerialPort.DataReceived, AddressOf OnReceived
        Catch ex As Exception
            WriteLog("[ERROR]" & vbTab & "[" & System.Reflection.MethodBase.GetCurrentMethod.Name & "]" & vbTab & "Error opening port com...")
            ret = False
        End Try
        Return ret
    End Function
 
#End Region
 
#Region "Reception d'une commande"
    'Fonction de traitements des données reçues (données émises par le arduino
    Private Sub OnReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs)
        If Receiving = False Then
            Receiving = True
            Try
                Dim BytesRead As Integer
                While CurrentSerialPort.BytesToRead > 0
                    BytesRead = CurrentSerialPort.Read(CBuffer, BufferPointer, CurrentSerialPort.BytesToRead)
                    BufferPointer += BytesRead
                    While BufferPointer > 0
                        'on recherche le début de commande (
                        Dim CommandStart As Integer = -1
                        For i As Integer = 0 To BufferPointer
                            If CBuffer(i) = CByte(40) Then
                                CommandStart = i
                                Exit For
                            End If
                        Next
 
                        'si aucun debut de commande n'a été trouvé, on nettoie le buffer car la commande est invalide
                        If CommandStart = -1 Then
                            ClearCBuffer()
                        End If
 
                        'si la commande ne commence pas au premier byte alors on supprime les bytes avant la commande
                        If CommandStart > 0 Then
                            LeftShiftCBuffer(CommandStart)
                        End If
 
                        'a partir d'ici le buffer est clean
 
                        'on recherche la fin de commande )
                        Dim Commandend As Integer = 0
                        For i As Integer = 0 To BufferPointer
                            If CBuffer(i) = CByte(41) Then
                                Commandend = i
                                Exit For
                            End If
                        Next
 
                        'si la fin de commande a été trouvée alors on execute la commande
                        If Commandend > 0 Then
                            Dim CommandBytes(Commandend) As Byte
                            For i As Integer = 0 To Commandend
                                CommandBytes(i) = CBuffer(i)
                            Next
                            'on execute la commande
                            ProcessCommand(CommandBytes)
 
                            'on reset le buffer et le pointer
                            LeftShiftCBuffer(Commandend + 1)
                        Else
                            Exit While
                        End If
                    End While
                End While
            Catch ex As Exception
            End Try
            Receiving = False
        End If
    End Sub
 
    'Fonction qui nettoie le buffer de réception
    Private Sub ClearCBuffer()
        For i As Integer = 0 To CBuffer.Length - 1
            CBuffer(i) = 0
        Next
        BufferPointer = 0
    End Sub
 
    'Fonction qui shift le buffer vers la gauche
    Private Sub LeftShiftCBuffer(ByVal NrOfPlaces As Integer)
        For i As Integer = NrOfPlaces To CBuffer.Length - 1
            CBuffer(i - NrOfPlaces) = CBuffer(i)
        Next
        For i As Integer = CBuffer.Length - NrOfPlaces To CBuffer.Length - 1
            CBuffer(i) = 0
        Next
        BufferPointer -= NrOfPlaces
    End Sub
 
    'Fonction de traitement des commandes reçues
    Private Sub ProcessCommand(ByVal CommandBytes As Byte())
        Try
            If ((CommandBytes(0) = CByte(40)) And (CommandBytes(CommandBytes.Length - 1) = CByte(41))) Then 'toutes les commandes sont au format (cmd)
                Dim PType As Char = ChrW(CommandBytes(1))
                Select Case PType
                    Case CChar("S") 'Arduino send it started
                        RaiseEvent WatchdogReceived()
                        If Not IsNothing(WatchDogTimer) Then
                            WatchDogTimer.Stop()
                        End If
                        WatchDogTimer.Start()
 
                    Case CChar("W") 'Arduino send watchdog
                        RaiseEvent WatchdogReceived()
                        If Not IsNothing(WatchDogTimer) Then
                            WatchDogTimer.Stop()
                        End If
                        WatchDogTimer.Start()
 
                    Case Else
                        Dim CommandString As String = String.Empty
                        For i As Integer = 0 To CommandBytes.Length - 1
                            CommandString += CommandBytes(i).ToString + " "
                        Next
                        WriteLog("[MSG]" & vbTab & "[" & System.Reflection.MethodBase.GetCurrentMethod.Name & "]" & vbTab & CommandString)
                End Select
            Else
                Dim CommandString As String = String.Empty
                For i As Integer = 1 To CommandBytes.Length - 1
                    CommandString += CommandBytes(i).ToString
                Next
                WriteLog("[ERROR]" & vbTab & "[" & System.Reflection.MethodBase.GetCurrentMethod.Name & "]" & vbTab & "Bad command format received: " & CommandString)
            End If
        Catch ex As Exception
            WriteLog("[ERROR]" & vbTab & "[" & System.Reflection.MethodBase.GetCurrentMethod.Name & "]" & vbTab & "Bad command format received")
        End Try
    End Sub
#End Region
 
#Region "Emission d'une commande"
    'Fonction qui envoie une commande
    Public Sub SendCommand(ByVal Command As Byte())
        Try
            If Command.Length > 0 Then
                If CurrentSerialPort.IsOpen Then
                    CurrentSerialPort.Write(Command, 0, Command.Length - 1)
                End If
            End If
        Catch ex As Exception
        End Try
    End Sub
#End Region
 
#Region "Fonctions Diverses"
    'Fonction qui permet de savoir lorsqu'on n'a pas reçu de signal du arduino depuis 5 secondes
    Private Sub WatchdogTimerElaped(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles WatchDogTimer.Elapsed
        WriteLog("[ERROR]" & vbTab & "[" & System.Reflection.MethodBase.GetCurrentMethod.Name & "]" & vbTab & "Connection lost...")
        RaiseEvent ConnectionLost()
        If Not IsNothing(WatchDogTimer) Then
            WatchDogTimer.Stop()
        End If
    End Sub
 
    'Fonction de notification de message
    Private Sub WriteLog(ByVal Message As String)
        RaiseEvent LogMessageReceived(Message)
    End Sub
#End Region
 
End Class

Et voici le gabarit de sketch Arduino qu’il vous faudra compléter avec votre code :

// Interaction entre Arduino et DotNet
// (Ce code fonctionne avec la classe DotNet "Arduino" )
// (Ce code s'inspire de plusieurs projets libres)
// www.zem.fr
 
int pt = 0;  			        			//Pointeur courant
boolean cfound = false;		        		//Fin de commande trouvée
byte currentCmd[200];                     	//Buffer de commande
long previousMillis = 0;                	//Interval de verification du watchdog
long interval = 1000;                   	//Interval d'émission entre 2 watchdogs
 
#define SOC 40								//Byte de debut de commande
#define EOC 41								//Byte de fin de commande
 
void setup() {
	Serial.flush();
	Serial.begin(9600);
	delay(500);
	Serial.print("(S)");					//On envoie une commande pour notifier que l'arduino est démarré
}
 
void loop() {
 
	//STEP1: Lecture du Buffer
	int sa;
	byte bt;
	sa = Serial.available();	        	//On recupere les données du port serie
	if (sa > 0) {			        		//On ecrit le buffer dans une variable jusqu'à ce que l'on rencontre le caractère de fin de commande
		for (int i=0; i < sa; i++){
			bt = Serial.read();
			currentCmd[pt] = bt;
			pt++;
			if (bt == EOC) {
				cfound = true;
				break;						//Le caractere de fin a été trouvé, on pourra proceder à l'execution de la commande
			}
		} 
	}
 
	//STEP2: Execution d'une commande
	if (cfound) {
		if (int(stringIn[0]) == SOC) {		//On verifie que le premier caractère est le caractere de debut de commande
			RunCommand();
		}
		ResetCurrentCmd();
		cfound = false;
	}
 
	//STEP3: Divers traitements
	//Vous pouvez ajouter des traitements ici
 
	//STEP4: Déclenchement du WatchDog
	if (millis() - previousMillis > interval) {
		previousMillis = millis();   
		Serial.print("(W)");       
	}
}
 
//Fonction qui reset la commande courante
void ResetCurrentCmd(void) {
  for (int i=0; i<=200; i++) {
    currentCmd[i] = 0;
    pt = 0;
  }
}
 
//Fonction qui distribue les differentes commandes
void RunCommand(void) {
	char c = stringIn[1];                	//Type de commande
 
	switch (c) {
		case 'D':							//Mode Dynamic
			break;
 
		case 'F':							//Mode Static
			break;
 
		break;
	}
}

[.Net] Convertir une couleur hexadécimale en Couleur

Toujours pour mon projet EasyLight, j’ai développé une petite fonction qui convertit un code couleur hexadécimal en Media.Color.

Le code hexadécimal peut être au format #FFFFFF ou bien au format FFFFFF. Le code retourne un System.Windows.Media.Color, ce qui vous permettra de récupérer ses propriétés R, G ou B 🙂

'Fonction qui convertit une couleur hexadecimale en couleur
Private Shared Function HexToColor(ByVal hex As String) As System.Windows.Media.Color
	hex = hex.Replace("#", "")
	Dim r As Byte = 0
	Dim g As Byte = 0
	Dim b As Byte = 0
 
	If hex.Length = 6 Then '#RRGGBB
		r = Byte.Parse(hex.Substring(0, 2), Globalization.NumberStyles.AllowHexSpecifier)
		g = Byte.Parse(hex.Substring(2, 2), Globalization.NumberStyles.AllowHexSpecifier)
		b = Byte.Parse(hex.Substring(4, 2), Globalization.NumberStyles.AllowHexSpecifier)
	ElseIf hex.Length = 3 Then '#RGB
		r = Byte.Parse(hex(0).ToString() + hex(0).ToString(), Globalization.NumberStyles.AllowHexSpecifier)
		g = Byte.Parse(hex(1).ToString() + hex(1).ToString(), Globalization.NumberStyles.AllowHexSpecifier)
		b = Byte.Parse(hex(2).ToString() + hex(2).ToString(), Globalization.NumberStyles.AllowHexSpecifier)
	End If
	Return System.Windows.Media.Color.FromRgb(r, g, b)
End Function

[.Net] Convertir un nombre dans un format lisible

Pour mon projet EasyLight, j’ai dû faire une fonction qui convertit un nombre dans un format lisible et compréhensible pour le commun des mortels.

L’exemple classique est de convertir un nombre de bytes en GigaBytes, MégaBytes, etc…

Pour faire cette conversion de nombre, je vous propose la fonction suivante:

'Fonction qui convertit un nombre en format Human Readable
Private Shared Function ConvertToHumanReadable(ByVal value As Double, Optional ByVal diviser As Integer = 1024, Optional ByVal nbDecimal As Integer = 0) As String
	Dim _units() As String = {"", "K", "M", "G", "T", "P", "E", "Z", "Y"}
	Dim size As Double = value
	Dim i As Integer = 0
	While size >= diviser
		size /= diviser
		i += 1
	End While
	Return Math.Round(size, nbDecimal) & _units(i)
End Function

Cette fonction vous permettra de convertir un nombre dans ses différents multiple rapidement et facilement.

[.Net] Exécuter une application DotNet au démarrage de Windows

Pour un de mes projets (EasyLight, plus de détails prochainement) qui mêle Arduino et DotNet, j’ai eu à développer pas mal de fonctions qui peuvent être réutilisées dans pas mal de projets.

Une des choses que je suis souvent amené à faire est de lancer une application DotNet au démarrage de Windows.

Pour démarrer automatiquement votre application, vous avez plusieurs solutions:

  • Créer un service Windows qui exécutera votre application au démarrage de Windows. Le problème de cette solution est qu’elle n’est utilisable que pour des applications en tâche de fond sans interface graphique.
  • Ajouter une clé dans la base de registre qui exécutera votre logiciel DotNet une fois que Windows est lancé.

C’est cette seconde méthode que j’utilise sur plusieurs de mes logiciels. Voici la fonction qui permet de démarrer automatiquement votre logiciel au démarrage de Windows:

'Fonction qui permet le demarre de l'executable en meme temps que Windows
Public Sub CheckAutoStart()
	Dim Assembly As Assembly = Application.ResourceAssembly
	Dim ExePath As String = (New Uri(Assembly.GetExecutingAssembly().GetName().CodeBase)).LocalPath
	Dim AssemblyName As String = Split(Assembly.FullName, ",").First
	Dim RegistryKeyName As RegistryKey
	Try
		RegistryKeyName = Registry.CurrentUser.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Run\", True)
		If My.Settings.AutoStart Then
			RegistryKeyName.SetValue(AssemblyName, ExePath)
		Else
			If RegistryKeyName.GetValue(AssemblyName) IsNot Nothing Then
				RegistryKeyName.DeleteValue(AssemblyName)
			End If
		End If
	Catch ex As Exception
		'on ne fait rien
	End Try
End Sub

[.Net] Récupérer, Modifier et Travailler avec les pixels et les bitmap

dotnet microsoft

Pour un de mes projets (dont je parlerai plus longuement dans quelques mois), j’ai eu besoin de faire des captures d’écran via une application Dotnet.

Une fois la capture réalisée, j’ai voulu lire et modifier les valeurs RGB de certains pixels.

Certains traitements tels que la mise à jour de nombreux pixels sont coûteux en ressource, c’est pourquoi j’ai fait une petite classe nommée SpeedBitmap. Cette classe permet ainsi d’optimiser certains traitements.

Voici les fonctionnalités de ma classe SpeedBitmap:

  • réaliser une capture d’écran
  • lire le code RGB d’un pixel
  • modifier le code RGB d’un pixel
  • bloquer et débloquer un bitmap afin d’optimiser les temps de traitement

Les fonctions de bloquage et débloquage du bitmap sont relativement pratiques si vous avez à effectuer de nombreux traitements sur le bitmap.

Voici ma classe pratique pour travailler avec des screenshots:

Private Class SpeedBitmap
#Region "Properties"
        Private pixelBytes() As Byte
        Private bmpData As BitmapData
        Private Depth As PixelFormat = PixelFormat.Format24bppRgb
        Private Width As Integer
#End Region
 
#Region "Mappage des fonctions Win32"
        <DllImport("gdi32.dll", EntryPoint:="DeleteDC")>
        Public Shared Function DeleteDC(ByVal hdc As IntPtr) As IntPtr
        End Function
 
        <DllImport("gdi32.dll", EntryPoint:="DeleteObject")>
        Public Shared Function DeleteObject(ByVal hObject As IntPtr) As IntPtr
        End Function
 
        <DllImport("gdi32.dll", EntryPoint:="BitBlt")>
        Public Shared Function BitBlt(ByVal hdcDest As IntPtr, ByVal nXDest As Integer, ByVal nYDest As Integer, ByVal nWidth As Integer, _
                                   ByVal nHeight As Integer, ByVal hdcSrc As IntPtr, ByVal nXSrc As Integer, ByVal nYSrc As Integer, ByVal dwRop As Integer) As Boolean
        End Function
 
        <DllImport("gdi32.dll", EntryPoint:="CreateCompatibleBitmap")>
        Public Shared Function CreateCompatibleBitmap(ByVal hdc As IntPtr, ByVal nWidth As Integer, ByVal nHeight As Integer) As IntPtr
        End Function
 
        <DllImport("gdi32.dll", EntryPoint:="CreateCompatibleDC")>
        Public Shared Function CreateCompatibleDC(ByVal hdc As IntPtr) As IntPtr
        End Function
 
        <DllImport("gdi32.dll", EntryPoint:="SelectObject")>
        Public Shared Function SelectObject(ByVal hdc As IntPtr, ByVal hgdiobjBmp As IntPtr) As IntPtr
        End Function
 
        <DllImport("user32.dll", EntryPoint:="GetDesktopWindow")>
        Public Shared Function GetDesktopWindow() As IntPtr
        End Function
 
        <DllImport("user32.dll", EntryPoint:="GetDC")>
        Public Shared Function GetDC(ByVal hWnd As IntPtr) As IntPtr
        End Function
 
        <DllImport("user32.dll", EntryPoint:="GetSystemMetrics")>
        Public Shared Function GetSystemMetrics(ByVal nIndex As Integer) As Integer
        End Function
 
        <DllImport("user32.dll", EntryPoint:="ReleaseDC")>
        Public Shared Function ReleaseDC(ByVal hWnd As IntPtr, ByVal hDC As IntPtr) As IntPtr
        End Function
#End Region
 
        'Fonction qui lock le bitmap
        Public Sub LockBitmap(ByVal bm As Bitmap)
            ' Lock the bitmap data.
            Width = bm.Width
            Dim bounds As Rectangle = New Rectangle(0, 0, bm.Width, bm.Height)
            bmpData = bm.LockBits(bounds, ImageLockMode.ReadWrite, Depth)
 
            ' Allocate room for the data.
            Dim total_size As Integer = bmpData.Stride * bmpData.Height
            ReDim pixelBytes(total_size)
 
            ' Copy the data into the g_PixBytes array.
            Marshal.Copy(bmpData.Scan0, pixelBytes, 0, total_size)
        End Sub
 
        'Fonction qui unlock le bitmap
        Public Sub UnlockBitmap(ByVal bm As Bitmap)
            ' Copy the data back into the bitmap.
            Dim total_size As Integer = bmpData.Stride * bmpData.Height
            Marshal.Copy(pixelBytes, 0, bmpData.Scan0, total_size)
 
            ' Unlock the bitmap.
            bm.UnlockBits(bmpData)
 
            ' Release resources.
            pixelBytes = Nothing
            bmpData = Nothing
        End Sub
 
        'Fonction qui recupere la couleur d'un pixel
        Public Function GetPixel(ByVal x As Integer, ByVal y As Integer) As Color
            Dim clr As Color = Color.Empty
 
            'Get color components count
            Dim cCount As Integer = 24 \ 8
 
            'Get start index of the specified pixel
            Dim i As Integer = ((y * Width) + x) * cCount
 
            If (i > pixelBytes.Length - cCount) Then
                Throw New IndexOutOfRangeException()
            End If
 
            Dim b As Byte = pixelBytes(i)
            Dim g As Byte = pixelBytes(i + 1)
            Dim r As Byte = pixelBytes(i + 2)
            clr = Color.FromArgb(r, g, b)
 
            Return clr
        End Function
 
        'Fonction qui met à jour la couleur pour un pixel
        Public Sub SetPixel(ByVal x As Integer, ByVal y As Integer, ByVal clr As Color)
            'Get color components count
            Dim cCount As Integer = Depth \ 8
 
            'Get start index of the specified pixel
            Dim i As Integer = ((y * Width) + x) * cCount
            pixelBytes(i) = clr.B
            pixelBytes(i + 1) = clr.G
            pixelBytes(i + 2) = clr.R
        End Sub
 
        'Fonction qui prend un screenshot de votre écran
        Public Function Capture() As Bitmap
            Dim screenX, screenY As Integer
            Dim hBmp As IntPtr
            Dim hdcScreen As IntPtr = GetDC(GetDesktopWindow())
            Dim hdcCompatible As IntPtr = CreateCompatibleDC(hdcScreen)
            screenX = GetSystemMetrics(0)
            screenY = GetSystemMetrics(1)
            hBmp = CreateCompatibleBitmap(hdcScreen, screenX, screenY)
 
            If (hBmp <> IntPtr.Zero) Then
                Dim hOldBmp As IntPtr = SelectObject(hdcCompatible, hBmp)
                BitBlt(hdcCompatible, 0, 0, screenX, screenY, hdcScreen, 0, 0, 13369376)
                SelectObject(hdcCompatible, hOldBmp)
                DeleteDC(hdcCompatible)
                ReleaseDC(GetDesktopWindow(), hdcScreen)
                Dim bmp As Bitmap = System.Drawing.Image.FromHbitmap(hBmp)
                DeleteObject(hBmp)
                GC.Collect()
                Return bmp
            End If
            Return Nothing
        End Function
    End Class

Contrôler un mini servo avec Arduino

Avec mon pote Idleman, on a pour projet de réaliser un robot (mais chut j’en dis pas plus pour le moment), et qui dit robot dit moteur, articulation, etc…

N’ayant jamais piloter de servo moteurs, j’ai décidé d’acheter sur la baie des mini servo de 9g.

mini servo

 

Fonctionnement d’un servo moteur

Tout d’abord, il faut s’avoir qu’un servo permet d’effecter des déplacements en translation ou en rotation. De nombreux objets du quotidien utilisent des servo moteurs: voitures télécommandées, drône, électroménager, …

Les différents types de servos se distingue par 3 caractéristiques:

  • leur vitesse de rotation par seconde
  • leur course en degré
  • leur couple exprimé en kg.cm

Le fonctionnement d’un servo est relativement simple. Il suffit d’envoyer une impulsion dont la durée est comprise entre 0,5ms et 2,5ms au servo. Cette impulsion déterminera la position du guide du servo. Ainsi la valeur de 1,5ms donne au servomoteur la position centrale.

Ces impulsion doivent être envoyée de manière périodique, généralement toutes les 50ms.

Il n’y a rien de compliquer pour brancher un servo. Les servos ont généralement 3 fils:

  • un rouge: qui doit être branché au 5V (ou 12V suivant votre servo)
  • un noir : qui doit être branché à la masse
  • un orange (ou autre couleur) : qui  est le fil de tension de commande 0-5V

C’est donc via le fil orange que les commandes seront passées à votre servo. Ce fil devra obligatoire être relié à votre Arduino sur un pin PWN.

Voyons maintenant comment connecter un mini servo à notre Arduino.

Connecter un servo sur un Arduino

Voici le montage que j’ai réalisé pour tester mon mini servo:

arduino mini servo

 

Il suffit ensuite de charger le sketch suivant dans votre Arduino. Ce script utilise la librairie Servo nativement disponible dans l’outil de développement de votre Arduino.

// Sweep
// by BARRAGAN <http://barraganstudio.com> 
// This example code is in the public domain.
 
#include <Servo.h> 
 
Servo myservo;  // create servo object to control a servo 
                // a maximum of eight servo objects can be created 
 
int pos = 0;    // variable to store the servo position 
 
void setup() 
{ 
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object 
} 
 
void loop() 
{ 
  for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees 
  {                                  // in steps of 1 degree 
    myservo.write(pos);              // tell servo to go to position in variable 'pos' 
    delay(15);                       // waits 15ms for the servo to reach the position 
  } 
  for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees 
  {                                
    myservo.write(pos);              // tell servo to go to position in variable 'pos' 
    delay(15);                       // waits 15ms for the servo to reach the position 
  } 
}

Ce sketch est issu des exemples fournis avec Arduino. Il permet de faire tourner votre servo de 0 à 180 degré.

J’espère que cela vous aidera.

[.Net] Erreur “This assembly may have been downloaded from the Web”

Aujourd’hui j’ai rencontré une erreur un peu bizarre lorsque j’ai déployé un serveur de compilation pour générer mes différents projets DotNet.

Ce serveur est une machine sur mon réseau de production qui ne fait que compiler chaque jour mes différentes solutions .Net afin que je puisse disposer à chaque instant d’une version à jour de mes logiciels.

Manque de bol, en déplaçant plusieurs solutions, j’ai eu une erreur de dépendance de librairies.

L’erreur est la suivante:

Could not load the assembly file:///C:\Users\shenhengbin\Downloads\WP7\Demo\Phone.Controls.Samples.dll. This assembly may have been downloaded from the Web.  If an assembly has been downloaded from the Web, it is flagged by Windows as being a Web file, even if it resides on the local computer. This may prevent it from being used in your project. You can change this designation by changing the file properties. Only unblock assemblies that you trust. See http://go.microsoft.com/fwlink/?LinkId=179545 for more information.

Après une bonne demi heure de recherche, j’ai trouvé comment corriger ce problème sans avoir à modifier les références dans mes projets.

Il faut éditer le fichier machine.config qui se trouve dans le répertoire C:\Windows\Microsoft.NET\Framework\(your version)\Config.

Ensuite il faut remplacer:

<runtime />

par:

<runtime>
	<loadFromRemoteSources enabled="true"/>
</runtime>

Il ne reste plus qu’à enregistrer le fichier et cela devrait fonctionner. En espérant que celà vous aidera.

Monitorer votre serveur Linux grace à MRTG

Aujourd’hui j’ai dû installer un logiciel de monitoring sur mes serveurs Linux afin de pouvoir superviser l’utilisation de la bande passante.

Pour faire celà, il m’a suffit d’installer MRTG (Multi Router Traffic Grapher) qui est un logiciel permettant de créer des graphiques sur le trafic réseau.

Il envoie des requêtes SNMP pour interroger des équipements réseaux tels que des routeurs,  des commutateurs, ou bien encore des serveurs disposant d’une MIB SNMP.

Installation d’Apache, MRTG et SNMP

Pour pouvoir utiliser MRTG, il nous apache et snmp. S’ils sont déjà installés, ne les réinstallez pas:

apt-get install apache2 mrtg snmpd

Configuration du SNMP

Faire une sauvegarde de la configuration snmp de base:

mv /etc/snmp/snmpd.conf /etc/snmp/snmpd.conf.bak

puis éditez le fichier de configuration de snmp:

nano /etc/snmp/snmpd.conf

et écrivez le contenu suivant:

rocommunity  public
syslocation  "France"
syscontact  votre@email.fr
com2sec public localhost public
group public v1 public
group public v2c public
group public usm public
view all included .1
access public "" any noauth exact all none none

Ensuite il faut éditer le fichier /etc/default/snmpd:

nano /etc/default/snmpd

Et vérifier que le fichier contient les lignes suivantes:

SNMPDRUN=yes
SNMPDOPTS='-Lsd -Lf /dev/null -u snmp -g snmp -I -smux -p /var/run/snmpd.pid -c /etc/snmp/snmpd.conf'
TRAPDRUN=yes
SNMPDCOMPAT=yes

La configuration du service snmp est désormais terminée, vous devez redémarrer le service snmp:

/etc/init.d/snmpd restart

Configuration de MRTG

Créez un dossier pour MRTG:

mkdir /var/www/mrtg
chmod o+w /var/www/mrtg

Créez un fichier de configuration:

cfgmaker --global 'WorkDir:/var/www/mrtg' --ifref=name --ifdesc=eth --global 'Options[_]: bits' --output /etc/mrtg.cfg   public@localhost

Ensuite, créez un fichier d’index:

indexmaker /etc/mrtg.cfg > /var/www/mrtg/index.html

Puis démarrez MRTG:

env LANG=C /usr/bin/mrtg /etc/mrtg.cfg

Il se peut que des erreurs apparaissent au lancement de Mrtg. Rassurez-vous c’est tout à fait normal. Il suffit d’exécuter plusieurs fois la commande ci-dessus et vous n’aurez plus l’erreur.

Il ne nous reste plus qu’à ajouter une tache planifiée:

crontab -e

Et ajoutez cette ligne dans le gestionnaire des crons:

*/5 * * * * env LANG=C /usr/bin/mrtg /etc/mrtg.cfg

L’installation de MRTG est terminée. Vous n’avez plus qu’à attendre 5 minutes puis vous pourrez consulter vos graphiques de statistiques en utilisant l’adresse suivante http://votre_ip/mrtg/.

Vous obtiendrez alors des graphiques de statistiques de consommation de bande passante de ce genre:

mrtg bandwidth