Comandare Arduino tramite il controller dell’Xbox 360

In un precedente post ho descritto la strategia che ho seguito per realizzare tramite Visual Basic un’applicazione in grado di mettere in comunicazione seriale Arduino e il computer, mimando l’invio di stringhe e caratteri già implementato nel Monitor seriale dell’IDE di Arduino. Il passo successivo è stato quello di far inviare i caratteri ad Arduino non più solo manualmente, inserendoli nell’apposita casella di testo, ma anche in base alla specifica pressione di un tasto sul controller dell’Xbox 360 collegato al pc da parte dell’utente. L’interfaccia del programma descritto nel post precedente, XBOX2ARDUINO, si è quindi allargata e modificata fino ad assumere questo aspetto:

screen1

In aggiunta alla parte di sinistra, già descritta in precedenza, è ora presente la parte di destra, deputata alla rilevazione del controller e della pressione di tasti specifici. Dalle caselle combinate in alto è possibile scegliere il periodo di tempo con cui il software aggiorna l’elenco dei comandi ricevuti (“RX refresh period”) e quello con cui rileva la pressione dei tasti sul controller ed invia conseguentemente caratteri ad Arduino (“TX/Controller refresh period”). Sono utilizzati due timer indipendenti per queste funzioni. Si può selezionare il controller di interesse – Windows supporta fino a 4 controller collegati contemporaneamente al pc – e verificare lo stato di tutti gli input sul controller, sia digitali (tasti LB, LS, PU, PL, PR, PD, BA, ST, RS, RB, X, Y, A, B) sia analogici (comandi LT, RT, LSX, LSY, RSX, RSY). Si può anche testare la vibrazione (output analogico), sia per il motore sinistro che per il destro (LV, RV), scegliendo la velocità relativa tramite slider. L’applicazione si può anche utilizzare, a prescindere da Arduino, come tool per testare la connessione al computer dei controller ed il funzionamento corretto di tutti i loro input ed output.

La mappatura degli input e degli output (ovvero l’associazione di specifici caratteri da trasmettere ad Arduino premendo determinati pulsanti sul controller o, al contrario, l’associazione di caratteri da ricevere da Arduino per controllare la vibrazione del controller) è gestita tramite i pulsanti “Map controller inputs” e “Map controller outputs”.

screen2

La mappatura degli input è divisa in input digitali e in input analogici. Nel primo caso, alla pressione di un tasto sul controller è associato l’invio ad Arduino del carattere designato nella casella di testo relativa. Nel secondo caso, quando una levetta di un input analogico viene portata in un determinato range di valori viene inviato uno specifico carattere ad Arduino. In particolare, gli assi dei due stick (LSX, LSY, RSX, RSY) inviano lettere quando portati abbastanza in basso/a sinistra (valori negativi) o abbastanza in alto/a destra (valori positivi), mentre i valori delle levette di throttle che inviano lettere sono medio e alto (sempre positivi). Quando gli input digitali non sono attivati o gli input analogici non sono sufficientemente al di fuori dalle posizioni di riposo, non vengono inviate lettere ad Arduino. L’invio dei comandi dal controller ad Arduino è gestito con la frequenza specificata in “TX/Controller refresh period”.

screen3

La finestra di mappatura output è simile, anche se sono ora presenti solo output analogici. In questo caso, si può scegliere da quale stringa inviata da Arduino far comandare la vibrazione del motore sinistro o di quello destro, entrambi a due differenti velocità liberamente scelte dall’utente con gli slider sottostanti. Per come è implementato il comando del controller in Visual Basic, una volta attivata la vibrazione è necessario inviare un altro comando a parte per farla cessare ed è quindi presente una casella di testo per definire anche la stringa di stop della vibrazione. È da notare che in XBOX2ARDUINO non è possibile attivare contemporaneamente i due motori del controller.

Il software è ovviamente migliorabile in vari modi: un’idea può essere quella di far inviare ad Arduino comandi solo in presenza di fronti positivi e negativi (i momenti in cui un pulsante viene premuto ed in cui viene rilasciato), così da ridurre il traffico di dati verso Arduino ed evitare di saturare in breve tempo la finestra dei messaggi ricevuti. Allo stato attuale, infatti, ad una pressione prolungata dei tasti è associato un continuo invio del messaggio relativo.

L’implementazione definitiva di XBOX2ARDUINO è ovviamente molto più lunga e complessa che allo stato del post precedente. Riporto qui il codice dei form e del modulo delle variabili globali per chiunque fosse interessato; sottolineo che il controller è gestito in Visual Basic utilizzando XNA Framework, che dev’essere quindi scaricato ed installato precedentemente in Visual Studio.

frmXBOX2ARDUINO:

' VB program to communicate with Arduino via serial interface
' Thanks to Martyn Currey for providing his tutorials:
' http://www.martyncurrey.com/arduino-and-visual-basic-part-1-receiving-data-from-the-arduino/
' http://www.martyncurrey.com/arduino-and-visual-basic-part-3-controlling-an-arduino/

Imports System
Imports System.IO.Ports
Imports Microsoft.Xna.Framework.Input

Public Class frmXBOX2ARDUINO
    Dim comPORT As String
    Dim receivedData As String = ""
    Dim connected As Boolean = False
    Dim selectedController As Microsoft.Xna.Framework.PlayerIndex

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' Initialize timer, comPORT value, and COM ports list
        timIO.Enabled = False
        timXBOX.Enabled = True
        comPORT = ""
        For Each sp As String In My.Computer.Ports.SerialPortNames
             cmbCOM.Items.Add(sp)
        Next
        cmbController.SelectedItem = "Player 1"
        cmbControllerRefreshTime.SelectedItem = "50 ms"
        cmbRXRefreshTime.SelectedItem = "1 s"
    End Sub

    Private Sub refresh_BTN_Click(sender As Object, e As EventArgs) Handles cmdRefresh.Click
        ' Refresh COM ports list after pressing Refresh button
        cmbCOM.Items.Clear()
        comPORT = ""
        For Each sp As String In My.Computer.Ports.SerialPortNames
            cmbCOM.Items.Add(sp)
        Next
    End Sub

    Private Sub comPort_ComboBox_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cmbCOM.SelectedIndexChanged
        ' Updates comPORT value after changing selection in COM ports list
        If (cmbCOM.SelectedItem <> "") Then
            comPORT = cmbCOM.SelectedItem
        End If
    End Sub

    Private Sub connect_BTN_Click(sender As Object, e As EventArgs) Handles cmdConnect.Click
        If (cmdConnect.Text = "Connect") Then
            ' Opens connection with selected COM port
            If (comPORT <> "") Then
                spt1.Close()
                spt1.PortName = comPORT
                spt1.BaudRate = 9600
                spt1.DataBits = 8
                spt1.Parity = Parity.None
                spt1.StopBits = StopBits.One
                spt1.Handshake = Handshake.None
                spt1.Encoding = System.Text.Encoding.Default
                spt1.ReadTimeout = 10000
                spt1.Open()
                cmdConnect.Text = "Disconnect"
                timIO.Enabled = True
                connected = True
                cmdSend.Enabled = True
            Else
                MsgBox("Select a COM port first.", vbExclamation)
            End If
        Else
            ' Closes connection with selected COM port
            spt1.Close()
            cmdConnect.Text = "Connect"
            timIO.Enabled = False
            connected = False
            cmdSend.Enabled = False
        End If
    End Sub

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles timIO.Tick
        ' Periodically updates received messages list
         Dim dateTimeIndication As String
         Dim receivedDataLength As Integer
         Dim dateTimeLength As Integer
         Dim startPos As Integer

         receivedData = ReceiveSerialData()
         receivedDataLength = receivedData.Length
         If receivedDataLength > 0 Then
             dateTimeIndication = DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") & ": "
             dateTimeLength = dateTimeIndication.Length

             startPos = rtbRX.TextLength
             rtbRX.AppendText(dateTimeIndication)
             rtbRX.Select(startPos, dateTimeLength)
             rtbRX.SelectionColor = Color.Red
             startPos = rtbRX.TextLength
             rtbRX.AppendText(receivedData)
             lblTest.Text = receivedData.Substring(0, 4)
             rtbRX.Select(startPos, receivedDataLength)
             rtbRX.SelectionColor = Color.Black
         End If

         If lblTest.Text = LeftMotorActivationWord1 Then
             GamePad.SetVibration(selectedController, LeftMotorSpeed1, 0)
         End If
         If lblTest.Text = LeftMotorActivationWord2 Then
             GamePad.SetVibration(selectedController, LeftMotorSpeed2, 0)
         End If
         If lblTest.Text = RightMotorActivationWord1 Then
             GamePad.SetVibration(selectedController, 0, RightMotorSpeed1)
         End If
         If lblTest.Text = RightMotorActivationWord2 Then
             GamePad.SetVibration(selectedController, 0, RightMotorSpeed2)
         End If
         If lblTest.Text = MotorDeactivationWord Then
             GamePad.SetVibration(selectedController, 0, 0)
         End If

    End Sub

    Function ReceiveSerialData() As String
        ' Reads strings from the connected Arduino
        Dim Incoming As String
        Try
            Incoming = spt1.ReadExisting()
            If Incoming Is Nothing Then
                Return "nothing" & vbCrLf
            Else
                Return Incoming
            End If
            Catch ex As TimeoutException
            Return "Error: Serial Port read timed out."
        End Try
    End Function

    Private Sub send_BTN_Click(sender As Object, e As EventArgs) Handles cmdSend.Click
        ' Sends user-defined strings to Arduino
        If (connected) Then
            Dim tmp As String
            Dim dateTimeIndication As String
            Dim tmpLength As Integer
            Dim dateTimeLength As Integer
            Dim startPos As Integer

            dateTimeIndication = DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") & ": "
            dateTimeLength = dateTimeIndication.Length
            tmp = txtSend.Text
            tmpLength = tmp.Length
            spt1.WriteLine(tmp)
            tmp = tmp & vbCrLf

            startPos = rtbTX.TextLength
            rtbTX.AppendText(dateTimeIndication)
            rtbTX.Select(startPos, dateTimeLength)
            rtbTX.SelectionColor = Color.Blue
            startPos = rtbTX.TextLength
            rtbTX.AppendText(tmp)
            rtbTX.Select(startPos, tmpLength)
            rtbTX.SelectionColor = Color.Black
        End If
    End Sub

    Private Sub clear_BTN_Click(sender As Object, e As EventArgs) Handles cmdClearRX.Click
        ' Clears RX messages list
        rtbRX.Text = ""
    End Sub

    Private Sub clear_BTN2_Click(sender As Object, e As EventArgs) Handles cmdClearTX.Click
        ' Clears TX messages list
        rtbTX.Text = ""
    End Sub

    Private Sub RichTextBox1_TextChanged(sender As Object, e As EventArgs) Handles rtbRX.TextChanged
        ' Sets the current caret position to the end
        rtbRX.SelectionStart = rtbRX.TextLength
        ' Scrolls RichTextBox automatically
        rtbRX.ScrollToCaret()
    End Sub
    Private Sub RichTextBox2_TextChanged(sender As Object, e As EventArgs) Handles rtbTX.TextChanged
        ' Sets the current caret position to the end
        rtbTX.SelectionStart = rtbTX.TextLength
        ' Scrolls RichTextBox automatically
        rtbTX.ScrollToCaret()
    End Sub

    Private Sub Timer2_Tick(sender As Object, e As EventArgs) Handles timXBOX.Tick
        ' Periodically updates connection state of the selected Xbox 360 controller

        Dim LT As Single
        Dim RT As Single
        Dim LSX As Single
        Dim RSX As Single
        Dim LSY As Single
        Dim RSY As Single

        Select Case cmbController.SelectedItem
            Case "Player 1"
                selectedController = Microsoft.Xna.Framework.PlayerIndex.One
                picController.Image = pic1.Image
            Case "Player 2"
                selectedController = Microsoft.Xna.Framework.PlayerIndex.Two
                picController.Image = pic2.Image
            Case "Player 3"
                selectedController = Microsoft.Xna.Framework.PlayerIndex.Three
                picController.Image = pic3.Image
            Case "Player 4"
                selectedController = Microsoft.Xna.Framework.PlayerIndex.Four
                picController.Image = pic4.Image
        End Select

        LT = GamePad.GetState(selectedController).Triggers.Left
        RT = GamePad.GetState(selectedController).Triggers.Right
        RSX = GamePad.GetState(selectedController).ThumbSticks.Right.X
        RSY = GamePad.GetState(selectedController).ThumbSticks.Right.Y
        LSY = GamePad.GetState(selectedController).ThumbSticks.Left.Y
        LSX = GamePad.GetState(selectedController).ThumbSticks.Left.X

        chkDetected.Checked = GamePad.GetState(selectedController).IsConnected
        chkX.Checked = GamePad.GetState(selectedController).Buttons.X
        chkY.Checked = GamePad.GetState(selectedController).Buttons.Y
        chkA.Checked = GamePad.GetState(selectedController).Buttons.A
        chkB.Checked = GamePad.GetState(selectedController).Buttons.B
        chkLB.Checked = GamePad.GetState(selectedController).Buttons.LeftShoulder
        chkRB.Checked = GamePad.GetState(selectedController).Buttons.RightShoulder
        lblLT.Text = String.Concat("LT: ", LT)
        lblRT.Text = String.Concat("RT: ", RT)
        chkRS.Checked = GamePad.GetState(selectedController).Buttons.RightStick
        chkLS.Checked = GamePad.GetState(selectedController).Buttons.LeftStick
        chkST.Checked = GamePad.GetState(selectedController).Buttons.Start
        chkBA.Checked = GamePad.GetState(selectedController).Buttons.Back
        chkPD.Checked = GamePad.GetState(selectedController).DPad.Down
        chkPU.Checked = GamePad.GetState(selectedController).DPad.Up
        chkPL.Checked = GamePad.GetState(selectedController).DPad.Left
        chkPR.Checked = GamePad.GetState(selectedController).DPad.Right
        lblRSY.Text = String.Concat("RSY: ", RSY)
        lblRSX.Text = String.Concat("RSX: ", RSX)
        lblLSY.Text = String.Concat("LSY: ", LSY)
        lblLSX.Text = String.Concat("LSX: ", LSX)

        ' Sends character to Arduino when activating mapped inputs
        If A_char <> Chr(0) And chkA.Checked = True And timIO.Enabled = True Then
            sendCharacter(A_char)
        End If
        If B_char <> Chr(0) And chkB.Checked = True And timIO.Enabled = True Then
            sendCharacter(B_char)
        End If
        If X_char <> Chr(0) And chkX.Checked = True And timIO.Enabled = True Then
            sendCharacter(X_char)
        End If
        If Y_char <> Chr(0) And chkY.Checked = True And timIO.Enabled = True Then
            sendCharacter(Y_char)
        End If
        If LB_char <> Chr(0) And chkLB.Checked = True And timIO.Enabled = True Then
            sendCharacter(LB_char)
        End If
        If RB_char <> Chr(0) And chkRB.Checked = True And timIO.Enabled = True Then
            sendCharacter(RB_char)
        End If
        If LS_char <> Chr(0) And chkLS.Checked = True And timIO.Enabled = True Then
            sendCharacter(LS_char)
        End If
        If RS_char <> Chr(0) And chkRS.Checked = True And timIO.Enabled = True Then
            sendCharacter(RS_char)
        End If
        If BA_char <> Chr(0) And chkBA.Checked = True And timIO.Enabled = True Then
            sendCharacter(BA_char)
        End If
        If ST_char <> Chr(0) And chkST.Checked = True And timIO.Enabled = True Then
            sendCharacter(ST_char)
        End If
        If PU_char <> Chr(0) And chkPU.Checked = True And timIO.Enabled = True Then
            sendCharacter(PU_char)
        End If
        If PD_char <> Chr(0) And chkPD.Checked = True And timIO.Enabled = True Then
            sendCharacter(PD_char)
        End If
        If PR_char <> Chr(0) And chkPR.Checked = True And timIO.Enabled = True Then
            sendCharacter(PR_char)
        End If
        If PL_char <> Chr(0) And chkPL.Checked = True And timIO.Enabled = True Then
            sendCharacter(PL_char)
        End If
        If LT1_char <> Chr(0) And LT >= 0.33 And LT < 0.66 And timIO.Enabled = True Then
            sendCharacter(LT1_char)
        End If
        If LT2_char <> Chr(0) And LT >= 0.66 And LT <= 1 And timIO.Enabled = True Then
            sendCharacter(LT2_char)
        End If
        If RT1_char <> Chr(0) And RT >= 0.33 And RT < 0.66 And timIO.Enabled = True Then
            sendCharacter(RT1_char)
        End If
        If RT2_char <> Chr(0) And RT >= 0.66 And RT <= 1 And timIO.Enabled = True Then
            sendCharacter(RT2_char)
        End If
        If LSX0_char <> Chr(0) And LSX <= -0.33 And timIO.Enabled = True Then
            sendCharacter(LSX0_char)
        End If
        If LSX2_char <> Chr(0) And LSX >= 0.33 And timIO.Enabled = True Then
            sendCharacter(LSX2_char)
        End If
        If RSX0_char <> Chr(0) And RSX <= -0.33 And timIO.Enabled = True Then
            sendCharacter(RSX0_char)
        End If
        If RSX2_char <> Chr(0) And RSX >= 0.33 And timIO.Enabled = True Then
            sendCharacter(RSX2_char)
        End If
        If LSY0_char <> Chr(0) And LSY <= -0.33 And timIO.Enabled = True Then
            sendCharacter(LSY0_char)
        End If
        If LSY2_char <> Chr(0) And LSY >= 0.33 And timIO.Enabled = True Then
            sendCharacter(LSY2_char)
        End If
        If RSY0_char <> Chr(0) And RSY <= -0.33 And timIO.Enabled = True Then
            sendCharacter(RSY0_char)
        End If
        If RSY2_char <> Chr(0) And RSY >= 0.33 And timIO.Enabled = True Then
            sendCharacter(RSY2_char)
        End If

    End Sub

    Private Sub sendCharacter(keyChar As Char)

        Dim tmp As Char
        Dim dateTimeIndication As String
        Dim dateTimeLength As Integer
        Dim tmpLength As Integer
        Dim startPos As Integer

        dateTimeIndication = DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") & ": "
        dateTimeLength = dateTimeIndication.Length
        tmp = keyChar & vbCrLf
        tmpLength = 1
        spt1.WriteLine(tmp)

        startPos = rtbTX.TextLength
        rtbTX.AppendText(dateTimeIndication)
        rtbTX.Select(startPos, dateTimeLength)
        rtbTX.SelectionColor = Color.Blue
        startPos = rtbTX.TextLength
        rtbTX.AppendText(tmp)
        rtbTX.Select(startPos, tmpLength)
        rtbTX.SelectionColor = Color.Black

    End Sub

    Private Sub cmdInputs_Click(sender As Object, e As EventArgs) Handles cmdInputs.Click
        frmInputs.Show()
    End Sub

    Private Sub cmdOutputs_Click(sender As Object, e As EventArgs) Handles cmdOutputs.Click
        frmOutputs.Show()
    End Sub

    Private Sub chkLV_CheckedChanged(sender As Object, e As EventArgs) Handles chkLV.CheckedChanged
        tkbL.Enabled = chkLV.Checked
        If tkbL.Enabled = False Then
            GamePad.SetVibration(selectedController, 0, 0)
        Else
            GamePad.SetVibration(selectedController, tkbL.Value / 10, 0)
        End If
    End Sub

    Private Sub chkRV_CheckedChanged(sender As Object, e As EventArgs) Handles chkRV.CheckedChanged
        tkbR.Enabled = chkRV.Checked
        If tkbR.Enabled = False Then
            GamePad.SetVibration(selectedController, 0, 0)
        Else
            GamePad.SetVibration(selectedController, 0, tkbR.Value / 10)
        End If
    End Sub

    Private Sub tkbL_Scroll(sender As Object, e As EventArgs) Handles tkbL.Scroll
        GamePad.SetVibration(selectedController, tkbL.Value / 10, 0)
    End Sub

    Private Sub tkbR_Scroll(sender As Object, e As EventArgs) Handles tkbR.Scroll
        GamePad.SetVibration(selectedController, 0, tkbR.Value / 10)
    End Sub

    Private Sub cmbControllerRefreshTime_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cmbControllerRefreshTime.SelectedIndexChanged
        Select Case cmbControllerRefreshTime.Text
            Case "50 ms"
                timXBOX.Interval = 50
            Case "100 ms"
                timXBOX.Interval = 100
            Case "200 ms"
                timXBOX.Interval = 200
            Case "500 ms"
                timXBOX.Interval = 500
            Case "1 s"
                timXBOX.Interval = 1000
        End Select
    End Sub

    Private Sub cmbRXRefreshTime_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cmbRXRefreshTime.SelectedIndexChanged
        Select Case cmbRXRefreshTime.Text
            Case "50 ms"
                timIO.Interval = 50
            Case "100 ms"
                timIO.Interval = 100
            Case "200 ms"
                timIO.Interval = 200
            Case "500 ms"
                timIO.Interval = 500
            Case "1 s"
                timIO.Interval = 1000
        End Select
    End Sub

    Private Sub cmdAbout_Click(sender As Object, e As EventArgs) Handles cmdAbout.Click
        frmAbout.Show()
    End Sub
End Class

frmOutputs:

Public Class frmOutputs

    Private Sub cmdCancel_Click(sender As Object, e As EventArgs) Handles cmdCancel.Click
        ' Closes form
        Me.Close()
    End Sub

    Private Sub cmdOK_Click(sender As Object, e As EventArgs) Handles cmdOK.Click
        ' Closes form and assigns user-defined data to main form
        If checkStrings() = False Then
            If txtActL1.Text <> "" Then
                LeftMotorSpeed1 = tkbL1.Value / 10
                LeftMotorActivationWord1 = txtActL1.Text
            End If
            If txtActL2.Text <> "" Then
                LeftMotorSpeed2 = tkbL2.Value / 10
                LeftMotorActivationWord2 = txtActL2.Text
            End If
            If txtDeact.Text <> "" Then
                MotorDeactivationWord = txtDeact.Text
            End If
            If txtActR2.Text <> "" Then
                RightMotorSpeed2 = tkbR2.Value / 10
                RightMotorActivationWord2 = txtActR2.Text
            End If
            If txtActR1.Text <> "" Then
                RightMotorSpeed1 = tkbR1.Value / 10
                RightMotorActivationWord1 = txtActR1.Text
            End If

            Me.Close()
        Else
            MsgBox("Strings have to be different.", MsgBoxStyle.Exclamation)
        End If

    End Sub

    Private Sub tkbL1_Scroll(sender As Object, e As EventArgs) Handles tkbL1.Scroll
        lblL1.Text = tkbL1.Value / 10
    End Sub

    Private Sub tkbR1_Scroll(sender As Object, e As EventArgs) Handles tkbR1.Scroll
        lblR1.Text = tkbR1.Value / 10
    End Sub

    Private Sub tkbL2_Scroll(sender As Object, e As EventArgs) Handles tkbL2.Scroll
        lblL2.Text = tkbL2.Value / 10
    End Sub

    Private Sub tkbR2_Scroll(sender As Object, e As EventArgs) Handles tkbR2.Scroll
        lblR2.Text = tkbR2.Value / 10
    End Sub

    Function checkStrings() As Boolean
        Dim txt1 As String
        Dim txt2 As String
        Dim txt3 As String
        Dim txt4 As String
        Dim txt5 As String

        txt1 = txtActL1.Text
        txt2 = txtActL2.Text
        txt3 = txtActR1.Text
        txt4 = txtActR2.Text
        txt5 = txtDeact.Text

        If (txt1 = txt2 And txt1 <> "") Or (txt1 = txt3 And txt1 <> "") Or (txt1 = txt4 And txt1 <> "") Or (txt1 = txt5 And txt1 <> "") Or (txt2 = txt3 And txt2 <> "") Or (txt2 = txt4 And txt2 <> "") Or (txt2 = txt5 And txt2 <> "") Or (txt3 = txt4 And txt3 <> "") Or (txt3 = txt5 And txt3 <> "") Or (txt4 = txt5 And txt4 <> "") Then
            Return True
        Else
            Return False
        End If

    End Function

    Private Sub frmOutputs_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        txtActL1.Text = LeftMotorActivationWord1
        txtActL2.Text = LeftMotorActivationWord2
        txtActR1.Text = RightMotorActivationWord1
        txtActR2.Text = RightMotorActivationWord2
        txtDeact.Text = MotorDeactivationWord
        tkbL1.Value = LeftMotorSpeed1 * 10
        tkbL2.Value = LeftMotorSpeed2 * 10
        tkbR1.Value = RightMotorSpeed1 * 10
        tkbR2.Value = RightMotorSpeed2 * 10
        lblL1.Text = tkbL1.Value / 10
        lblR1.Text = tkbR1.Value / 10
        lblL2.Text = tkbL2.Value / 10
        lblR2.Text = tkbR2.Value / 10
    End Sub
End Class

frmInputs:

Public Class frmInputs

    Private Sub cmdCancel_Click(sender As Object, e As EventArgs) Handles cmdCancel.Click
        ' Closes form
        Me.Close()
    End Sub

    Private Sub cmdOK_Click(sender As Object, e As EventArgs) Handles cmdOK.Click
        ' Closes form and updates key mapping
        A_char = txtSendCA.Text
        B_char = txtSendCB.Text
        X_char = txtSendCX.Text
        Y_char = txtSendCY.Text
        LB_char = txtSendCLB.Text
        RB_char = txtSendCRB.Text
        LS_char = txtSendCLS.Text
        RS_char = txtSendCRS.Text
        PU_char = txtSendCPU.Text
        PD_char = txtSendCPD.Text
        PL_char = txtSendCPL.Text
        PR_char = txtSendCPR.Text
        BA_char = txtSendCBA.Text
        ST_char = txtSendCST.Text
        LT1_char = txtSendCLT1.Text
        LT2_char = txtSendCLT2.Text
        RT1_char = txtSendCRT1.Text
        RT2_char = txtSendCRT2.Text
        LSX0_char = txtSendCLSX0.Text
        LSX2_char = txtSendCLSX2.Text
        RSX0_char = txtSendCRSX0.Text
        RSX2_char = txtSendCRSX2.Text
        LSY0_char = txtSendCLSY0.Text
        LSY2_char = txtSendCLSY2.Text
        RSY0_char = txtSendCRSY0.Text
        RSY2_char = txtSendCRSY2.Text
        Me.Close()
    End Sub

    Private Sub l_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ' Reloads the existing mapping when reopening this form
        txtSendCA.Text = A_char
        txtSendCB.Text = B_char
        txtSendCX.Text = X_char
        txtSendCY.Text = Y_char
        txtSendCLB.Text = LB_char
        txtSendCRB.Text = RB_char
        txtSendCLS.Text = LS_char
        txtSendCRS.Text = RS_char
        txtSendCPU.Text = PU_char
        txtSendCPD.Text = PD_char
        txtSendCPL.Text = PL_char
        txtSendCPR.Text = PR_char
        txtSendCBA.Text = BA_char
        txtSendCST.Text = ST_char
        txtSendCLT1.Text = LT1_char
        txtSendCLT2.Text = LT2_char
        txtSendCRT1.Text = RT1_char
        txtSendCRT2.Text = RT2_char
        txtSendCLSX0.Text = LSX0_char
        txtSendCLSX2.Text = LSX2_char
        txtSendCRSX0.Text = RSX0_char
        txtSendCRSX2.Text = RSX2_char
        txtSendCLSY0.Text = LSY0_char
        txtSendCLSY2.Text = LSY2_char
        txtSendCRSY0.Text = RSY0_char
        txtSendCRSY2.Text = RSY2_char
    End Sub
End Class

Module1:

Module Module1
    Public LeftMotorSpeed1 As Single
    Public RightMotorSpeed1 As Single
    Public LeftMotorSpeed2 As Single
    Public RightMotorSpeed2 As Single
    Public LeftMotorActivationWord1 As String
    Public LeftMotorActivationWord2 As String
    Public MotorDeactivationWord As String
    Public RightMotorActivationWord1 As String
    Public RightMotorActivationWord2 As String
    Public A_char As Char
    Public B_char As Char
    Public LB_char As Char
    Public RB_char As Char
    Public X_char As Char
    Public Y_char As Char
    Public LS_char As Char
    Public RS_char As Char
    Public BA_char As Char
    Public ST_char As Char
    Public PU_char As Char
    Public PD_char As Char
    Public PL_char As Char
    Public PR_char As Char
    Public LT1_char As Char
    Public LT2_char As Char
    Public RT1_char As Char
    Public RT2_char As Char
    Public LSX0_char As Char
    Public LSX2_char As Char
    Public LSY0_char As Char
    Public LSY2_char As Char
    Public RSX0_char As Char
    Public RSX2_char As Char
    Public RSY0_char As Char
    Public RSY2_char As Char
End Module

Il codice sorgente e l’ultima release possono essere scaricati da GitHub agli indirizzi https://github.com/VikingStormtrooper/XBOX2ARDUINO (codice sorgente) e https://github.com/VikingStormtrooper/XBOX2ARDUINO/releases (release).

Lascia un commento