随着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游戏手柄接口。
首先,定义游戏手柄的结构:
Public Structure JOYINFOEX
Public dwSize As Integer
Public dwFlags As Integer
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
Joypos1.dwFlags = &HFF
Timer1.Enabled = False
计时器事件轮询操纵杆,特别关注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)
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
If intJoyConvY > 20000 Then
If intJoyConvY <= 40000 Then
intJoyConvY = 0
End If
If intJoyConvY > 40000 Then
intJoyConvY = 32
End If
End If
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 = ""
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
蓝牙通信是通过串行端口进行的。Windows设备管理器的"端口"部分将识别正确的端口。使用Try Catch结构来捕获错误。发送到Arduino的输出和Arduino的反馈都在VB程序界面的文本框中捕获。
#include
#include
#include
MeDCMotor leftMotor(M1);
MeDCMotor rightMotor(M2);
MeBluetooth bluetooth(PORT_3);
int leftSpeed = 130;
int rightSpeed = 130;
double turnSpeed = 0.6;
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':
toRight();
bluetooth.print(cmd);
break;
case 'L':
spinLeft();
bluetooth.print(cmd);
break;
}
}
}
char readBlueTooth(){
char btInput;
btInput = (char) bluetooth.read();
return btInput;
}
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);
}
void spinLeft(){
rightMotor.run(rightSpeed*turnSpeed);
leftMotor.run(-leftSpeed*turnSpeed);
}