Machine parlante - Talking Machine ( ARDUINO & PICAXE )

Talking Machine Introduction
Nombreux sont les bricoleurs en électronique qui ont déjà pensé à faire une machine parlante.
Certains l'ont d'ailleurs fait et des revues comme Micro-System et Elektor traitaient déjà de ce sujet dans les années 70-80. On parlait alors de synthèse vocale et de générateur de phonèmes.
Aujourd'hui, les GPS en sont un magnifique exemple, mais leurs créateurs sont des professionnels et les techniques utilisées ne sont pas à la portée de l'amateur que je suis. Lorsque je m'y suis intéressé, j'ai découvert plusieurs méthodes qui ne m'ont pas pleinement satisfait.
D'une part, on peut faire parler un ARDUINO. Des travaux remarquables ont déjà été réalisés mais les exemples que j'ai trouvés sont en anglais et le son émis ne m'a pas convaincu de persévérer en ce sens. Je n'ai personnellement rien trouvé en français.
Il existe également des modules électroniques que l'on peut piloter assez facilement. Ils viennent des Etats-Unis , parlent anglais ou espagnol et coûtent  ±60$.
J'ai aussi trouvé une troisième méthode sur un site consacré au modélisme ferroviaire. Ils utilisent un module lecteur MP3 et les messages disponibles sont stockés sur une carte SD.
Je suis resté quelques temps sur ma faim et assez perplexe parce que j'aurais voulu trouver un système qui soit capable de donner une intonation dans la voix émise, un peu comme un GPS. Et puis tous comptes faits, "ma" GPS a une voix sympathique et est très tolérante !
J'ai alors découvert sur Internet l'expression et le concept TTS , text-to-speech en anglais.
Plusieurs sites traitent le sujet. J'ai bien sûr opté pour un qui proposait du code JavaScript permettant l'accès à leur API. Ils proposent généralement plusieurs voix dans 51 langues !  Je me suis d'ailleurs bien amusé en mélangeant la langue écrite avec celle du sujet parlant... 
Assez de bla-bla, au travail !

Schémas et lignes de code
ARDUINO parle  -  ARDUINO talks  -  Talking Machine

Speaking PICAXE


Comme on peut le constater, la communication s'effectue par le biais d'un port série et l'ordinateur est en attente des sollicitations du microcontrôleur.

J'ai opté pour une gestion de la communication en Visual Basic mais nodejs (avec npm) fonctionne très bien aussi.
J'en profite d'ailleurs à ce stade pour saluer et remercier toutes les personnes qui ont mis du contenu en ligne et m'ont permis de m'informer et me former              (cf Remerciements en fin d'article).

 Si vous désirez utiliser un ARDUINO (on peut en faire un voltmètre parlant...) :

/* Exemple :  ARDUINO_to_VB.ino
 * 
 *  En appuyant sur le Bouton-poussoir (Input 8),
 *  Arduino envoie la valeur du potentiomètre (A0)
 *  sur le Port série.
 * 
 *  Attention :  veillez à utiliser le même numéro de Port
 *  lorsque vous y ferez référence dans le code Visual Basic
 *  Ici j'ai utilisé "COM3"
*/

int sensorValue ;
boolean Envoi;   // BP pour envoyer la valeur

void setup()
{
    pinMode(8, INPUT_PULLUP);
    Serial.begin(9600);
}

void loop()
{
     Envoi=!digitalRead(8);
     if (Envoi){
        sensorValue = analogRead(A0);
        Serial.println(sensorValue);
        delay(250);    // N'est utile que si on garde son doigt sur le BP
     }
}


Si vous désirez utiliser un PICAXE (ou un autre microcontrôleur) :

; PICAXE_vers_TTS.bas
; Application créée pour PICAXE 20M2
; B.0 est utilisé comme Port Série pour l'envoi des données
; EXEMPLE :  envoi répétitif des caractères 0 à 9 , 1 caract./ 3 Sec.

setfreq m8                             ; T9600_8  requis !

let dirsB=%11111111               ; Port B configuré en sortie

main:

for bptr=48 to 57                     ; Caractères ASCII 0 à 9
    serout B.0,T9600_8,(bptr)    ; envoi du caractère
    serout B.0,T9600_8,(10)      ; CR nécessaire
    pause 3000                        ; envoi d'un caractère / 3 Sec.
next bptr

goto main


Le texte du message prononcé fera le chemin suivant :
Talking ARDUINO
Code écrit en Visual Basic (à compiler pour obtenir en finalité un fichier exécutable) :

' Objets requis :
'  Form1 , Button1 nommé connect_BTN , Label nommé Potentiometer , SerialPort1 , WebBrowser1 et Timer1 avec Interval=250
'  Aucune image du Browser n'est requise car le seul but recherché est le générateur vocal TTS
'  Pour permettre le design de la form1, le Browser1 a été caché derrière le Button1 mais
'  une autre méthode aurait été de réduire ses dimensions à 0
'
Imports System
Imports System.IO.Ports
Imports System.Windows.Forms
Imports System.Security.Permissions

<PermissionSet(SecurityAction.Demand, Name:="FullTrust")>
<System.Runtime.InteropServices.ComVisibleAttribute(True)>
Public Class Form1
    Dim Incoming As String
    Dim receivedData As String = ""

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        WebBrowser1.Navigate("C:\...\Text_to_Speech.htm")
        WebBrowser1.Visible = False
        Timer1.Enabled = False
        Potentiometer.Text = "---"
    End Sub

    Private Sub connect_BTN_Click(ByVal sender As Object, ByVal e As EventArgs) Handles connect_BTN.Click
        If (connect_BTN.Text = "Connect") Then
            SerialPort1.Close()
            SerialPort1.PortName = "com3"       ' Attention :  com doit correspondre à celui du microcontrôleur !
            SerialPort1.BaudRate = 9600
            SerialPort1.DataBits = 8
            SerialPort1.Parity = Parity.None
            SerialPort1.StopBits = StopBits.One
            SerialPort1.Handshake = Handshake.None
            SerialPort1.Encoding = System.Text.Encoding.Default
            SerialPort1.ReadTimeout = 10000
            SerialPort1.Open()
            connect_BTN.Text = "Dis-connect"
            Timer1.Enabled = True
        Else
            SerialPort1.Close()
            connect_BTN.Text = "Connect"
            Timer1.Enabled = False
        End If

    End Sub

    Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles Timer1.Tick
        ' Important : la valeur du timer doit correspondre à l'Arduino (ou un peu moins)
        Incoming = SerialPort1.ReadExisting()
        Potentiometer.Text = Incoming
        If (Incoming > "") Then
            Dim sujet() As String = {Incoming}
            Dim elements As HtmlElementCollection = WebBrowser1.Document.All
            Me.WebBrowser1.Document.InvokeScript("Talk", sujet)
            ' Ce qui suit simule un click sur le bouton 'parle' de la page HTML
            For Each Webpageelement As HtmlElement In elements
                If Webpageelement.GetAttribute("id") = "parle" Then
                    Webpageelement.InvokeMember("click")
                End If
            Next
            Incoming = ""
        End If
    End Sub

End Class


Création de la fenêtre de lancement de l'application :

Automation PC













Un peu de HTML et de JavaScript pour terminer :

<!--   Text_to_Speech.htm   -->
<html>
<head>
<meta http-equiv="x-ua-compatible" content="IE=10">
<!-- Cette balise n'est utile qu'aux anciennes versions de Internet Explorer -->
<script type="text/JavaScript" src="https://code.responsivevoice.org/responsivevoice.js"></script>
</head>


<body BGCOLOR="#999966">

<script type="text/javascript">
    responsiveVoice.setDefaultVoice("French Female");
</script>

<script type="text/javascript">
function Private_Speech(){
    var parole="Aucun message reçu";
    responsiveVoice.speak(parole);}   
</script>

<script type="text/JavaScript">
function Talk(sujet){
    responsiveVoice.speak(sujet);}   
</script>

<!--  Le bouton ci-dessous permet un fonctionnement en local, sans perturber la commande venant de VB  -->
<button id="local" style="min-width:70; min-height:35; background-color:orange; position: absolute;
         top: 50; left: 70;" onclick="Private_Speech()">Fais-moi parler...</button>
<!-- Ce bouton ne sert qu'aux tests -->

<!--  Le bouton ci-dessous n'est pas visible mais est commandé par Visual Basic  -->
<button id="parle" onclick="Talk()" style="visibility:hidden"></button>
<!-- Ne pas modifier l'id du bouton, elle est utilisée par Visual Basic -->

</body>
</html>



Note de PC Automation :
D'autres méthodes et techniques existent certainement pour arriver aux mêmes fins.
Le projet développé ci-dessus a été réalisé grâce à Visual Studio 2017 et testé avec Internet Explorer 11 ainsi que Firefox Quantum.
Je n'ai aucune idée quant à la possibilité de fonctionnement avec d'autres navigateurs Internet.
Je suis juste un bricoleur qui avait envie de partager quelque chose.


Références et remerciements :

-Kanasz Robert (Site Code Project) pour son article "Calling JavaScript function from WinForms and vice-versa"
-Gustavo Machado (Site medium.com) pour son article "Arduino and Node.js via Serial port"
-Martyn Currey (Site personnel) pour son article "Receiving Data From the Arduino"
-w3schools.com - "The world's largest web developer site" - pour leurs "Tutorials, references, and examples"
-OpenClassrooms pour les cours en ligne sur JavaScript et node
-theorycircuit (Site instructables.com) pour l'article "Visual-Basic-Arduino-Interface"
-Doombreaker sur dotnetperls.com pour la vidéo "VB.net - Click a button in html"
-Stack Overflow pour leurs forums
-ResponsiveVoice.org pour la mise à disposition de code JavaScript permettant l'accès à leur API "Text-To-Speech"
   ( Attention :  les conditions d'utilisation sont sous licence et réglementées ! ) 





Aucun commentaire:

Enregistrer un commentaire

Les commentaires constructifs sont les bienvenus.
Contact par mail via mon profil dans la colonne de droite.