VB 游戏控制器控制 Arduino 遥控拖拉机





5.00/5 (5投票s)
本项目介绍了一个初学者/爱好者项目,该项目使用 Visual Basic 通过蓝牙连接发送游戏手柄数据,以控制 Arduino 遥控拖拉机。
引言
本项目介绍了一个初学者/爱好者项目,该项目使用 Visual Basic 通过蓝牙连接发送游戏手柄数据,以控制 Arduino 遥控拖拉机。
背景
机器人项目在许多学校的 STEM 课程以及爱好者中变得越来越受欢迎。 本项目利用 Arduino 和 Visual Basic 代码来控制 Arduino 风格的 Orion 入门机器人拖拉机 (Makeblock ; www.makeblock.com)。 Orion 板是 Arduino 的克隆版。 它非常适合初学者,因为它用 RJ-25 连接代替跳线,并且有自己的库来利用这些连接。 各种模拟和数字端口都用颜色编码,方便使用。 项目的 VB 部分控制游戏手柄,并通过蓝牙将操纵杆输出传输到 Arduino/Orion 控制器。 Arduino 代码提供操纵杆指令的执行,并将指令回显到 VB 程序以进行确认。
目标
- 在 VB.NET 程序中集成游戏手柄
- 从 VB 程序到远程 Arduino 模块的蓝牙通信
- Arduino 控制拖拉机
- 易于理解,带有大量注释的代码
代码
可以通过两种方法来实现操纵杆控制。 一种常用的方法是使用一个操纵杆,获取 X 和 Y 输入的方向,并将它们转换为各种方向向量。
但是,由于我们的远程机器人是拖拉机,因此采用了一种更简单但更实际的方法,游戏手柄上的每个操纵杆都控制拖拉机上的一个履带。 这是一种历史上准确的转向方法。
游戏手柄通过 Winmm.dll 公开。 这是一个较旧的 32 位库,但适合我们在此处的用途。 下一个版本将利用 DirectX 游戏手柄接口。
首先,定义游戏手柄的结构 (https://msdn.microsoft.com/en-us/library/dd757112.aspx)
<StructLayout(LayoutKind.Sequential)>
Public Structure JOYINFOEX
Public dwSize As Integer 'size of this structure, in bytes
Public dwFlags As Integer ' how many items are in the structure; &HFF is all (0-255);
Public dwXpos As Integer
Public dwYpos As Integer
Public dwZpos As Integer
Public dwTpos As Integer
Public dwUpos As Integer
Public dwVpos As Integer
Public dwButtons As Integer
Public dwButtonNumber As Integer
Public dwPOV As Integer
End Structure
创建操纵杆并添加计时器以轮询操纵杆的更改
Public Joypos1 As JOYINFOEX
Joypos1.dwSize = 64 ' Need size of structure for JoyGetPosEx() to work; Joypos1.dwFlags = &HFF ' get all data from joystick
Timer1.Enabled = False ' init Timer1 False until serial port open
计时器事件轮询操纵杆,特别是寻找 Y 轴和 T 轴,它们将确定左侧和右侧履带的方向信息。 然后处理此数据并将其发送到 Arduino/Orion。 由于操纵杆数据以整数 0 到 65536 发送,因此使用偏移量使“0”成为“中点”。 然后处理操纵杆的位置,为前进、停止和倒退生成向上、空挡和向下,这将传递给 Arduino。 此处的 -32 到 32 比例是任意的,但将在项目后续迭代中用于开发单个操纵杆向量。
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
joyGetPosEx(0, Joypos1)
'Up to six axes supported
lblYaxis.Text = "Y = " & (Joypos1.dwYpos.ToString - 32767)
lblTaxis.Text = "T = " & (Joypos1.dwTpos.ToString - 32767)
Dim intJoyConvY As Integer
intJoyConvY = CInt(Math.Round(Joypos1.dwYpos))
If intJoyConvY > -1 Then
If intJoyConvY <= 20000 Then
intJoyConvY = -32
End If
End If
If intJoyConvY > 20000 Then
If intJoyConvY <= 40000 Then
intJoyConvY = 0
End If
End If
If intJoyConvY > 40000 Then
intJoyConvY = 32
End If
Dim intJoyConvT As Integer
intJoyConvT = CInt(Math.Round(Joypos1.dwTpos))
仍在计时器事件中,轮询并将两个游戏手柄轴解析为单独的电机命令,准备好发送到 Arduino
Dim RMotor As Integer
Dim strCmd As String = ""
Dim LMotor As Integer
LMotor = intJoyConvY
RMotor = intJoyConvT
If LMotor = 32 And RMotor = 32 Then
charCmd = "F" '
strCmd = "forward"
End If
If LMotor = -32 And RMotor = -32 Then
charCmd = "B"
strCmd = "backward"
End If
最后,解析后的命令通过蓝牙发送到 Arduino。 每 250 毫秒(可调整以提高性能)轮询游戏手柄,并且仅发送数据中的更改,以避免通信过载。
Try
If charCmd <> charOldCmd Then
rtbMonitor.Text = "" 'clear the text
SerialPort1.Write(charCmd)
rtbMonitor.Text = charCmd & vbCrLf
charOldCmd = charCmd
Else
rtbMonitor.Text = rtbMonitor.Text & "No Changes" & vbCrLf
End If
Catch ex As Exception
MessageBox.Show(ex.Message & " Open Port Before Proceeding")
End Try
End Sub
蓝牙通信通过串行端口进行。 Windows 设备管理器端口部分将标识正确的端口。 使用 Try Catch 结构来捕获错误。 发送到 Arduino 的输出和来自 Arduino 的反馈都捕获在 VB 程序界面的文本框中。
Arduino/Orion 编码
易用性使 Makeblock Orion 非常适合初学者。 Makeblock 库已合并到 Arduino 程序中。 Arduino 以“C”编码,分为两部分。 “Setup”保存变量、包含的库和 Makeblock 特定引用。 Arduino 代码将用 PIN 位置代替这些引用。 对于希望转换为 ArduinoUno 的用户,请识别电机的模拟端口和蓝牙设备的位置,并将输出写入其中。 蓝牙(串口)以 Orion 的默认 115200 波特率打开。
/*Includes */ #include <MeOrion.h> /*inherits MeDCMotor.h and MeBluetooth.h; both open source GPL V 2 */ #include <Wire.h> #include <SoftwareSerial.h> /* These are Makeblock specific*/ MeDCMotor leftMotor(M1); MeDCMotor rightMotor(M2); MeBluetooth bluetooth(PORT_3); /*Variables*/ int leftSpeed = 130; //left motor speed; adjust to specific motor 0 to 255 depending on voltage req'd for motors int rightSpeed = 130; //right motor speed double turnSpeed = 0.6; // reduced speed of inner track for turns but be sure voltage (analog output 0-255) is high enough to run motor
代码的“Loop”部分是“运行”Arduino 的部分。 该代码测试蓝牙连接的功能,调用 readBluetooth() 函数,并将输入字符传递给 Switch/Break 结构,每个 Switch 调用其各自的函数来移动拖拉机。 通过履带速度和方向的不匹配来完成各种转弯。 捕获了两个附加按钮(未显示)以分别增加和减少两个速度变量。
void loop() { if (bluetooth.available()){ char cmd = readBlueTooth(); bluetooth.println(cmd); switch(cmd){ case 'F': forward(); bluetooth.print(cmd); break; case 'B': backward(); bluetooth.print(cmd); break; case 'r': /*lower case r to show minor change*/ toRight(); bluetooth.print(cmd); break; case 'L': spinLeft(); bluetooth.print(cmd); break; /*Bluetooth read function*/ char readBlueTooth(){ char btInput; btInput = (char) bluetooth.read(); return btInput; } /*Motor functions*/ /*For Arduino board: write these functions */ /*to analog pins that control motor functions*/ void forward(){ rightMotor.run(rightSpeed); leftMotor.run(leftSpeed); } void backward(){ leftMotor.run(-leftSpeed); rightMotor.run(-rightSpeed); } void toRight(){ leftMotor.run(leftSpeed); rightMotor.run(rightSpeed*turnSpeed); } /* spin Left*/ void spinLeft(){ rightMotor.run(rightSpeed*turnSpeed); leftMotor.run(-leftSpeed*turnSpeed); }
未来的计划包括使用 DirectX 读取游戏手柄数据的单操纵杆控制模式,以及更详细的操纵杆数学视图。 还可以考虑使用语音识别来控制 Arduino,并将可视化显示集成到 VB 程序中,以实现真正的远程操作。