In this application, the GalilTools COM library is used in conjunction with Microsoft Visual Basic 2010 to develop a user interface for the Galil controller. The goal is to create a simple interface that features both directional buttons for mouse interaction and the ability to poll for keyboard input. Using this digital stimulus, the application is to act similar to an analog joystick control interface. The completed user interface is visible below.
To ensure smooth control, the states of all relevant directional inputs are recorded. A similar prototype is used for commanding motion regardless of the input interface method. This creates a consistent feel between the mouse activated buttons and direct keyboard input.
On a 50 millisecond time pitch, the state of the inputs is processed. The result is an increase or decrease in the relevant velocity vector variable. The velocity increase/decrease magnitudes are book kept as the acceleration variables. If the user continuously commands a directional input, the corresponding axis velocity will be adjusted until the saturation condition is met, where the velocity magnitude is greater than the axis' velocity_MAX variable.
In the event that no directional input has been given for an axis of motion, on the 50 millisecond time pitch, the axis velocity vector is adjusted by the deceleration variable to get closer to zero. This effectively linearly slows the motion to a stop, similar to how friction could slow a moving object.
The final task of the repetitive time pitch subroutine is to send a velocity command to the motion controller. This is easily executed using the GalilTools COM library's “command” functionality. An XY Jog is initiated using the command “JG VX,VY” where VX and VY are the X and Y axis velocity vectors, accordingly.
The final features of the application are the “Begin XY Jog” “Stop XY Jog” buttons. The begin button will perform a servo here command and begin motion command for the X and Y axises, effectively enabling motion on the axis. The stop button performs a stop command for the X and Y axises, effectively hauling motion. If the velocity vectors have values in the application but there is not motion, ensure that the “Begin XY Jog” button has been clicked.
The outcome is the creation of a user interface that allows for users to command two axis motion using either keyboard or button based mouse input. Simple physics are incorporated into the application to ensure smooth motion and control. The source listing is approximately 180 lines and is available below. Alternatively the entire project source can be downloaded at this link.
PublicClassmainForm
'Define an array with booleans for each key
Dim Keys(255) AsBoolean
'Define a structure with all relevant axis components
PublicStructureaxis_componets
Public velocity AsInteger
Public velocity_MAX AsInteger
Public acceleration AsInteger
Public deceleration AsInteger
EndStructure
'Initialize axis components for X and Y
Public X AsNewaxis_componets
Public Y AsNewaxis_componets
'Establish controller handle
WithEvents g AsNew Galil.Galil
'Define Keycodes for directional keys
EnumKeyCodes
left = 37
right = 39
up = 38
down = 40
EndEnum
PrivateSub mainForm_Load() HandlesMyBase.Load
'Connect the controller
'g.address = "10.0.5.72"
g.address = ""
Me.Text = g.connection
'Initialize Motion Parameters for X and Y
X.velocity = 0
Y.velocity = 0
X.velocity_MAX = 10000
Y.velocity_MAX = 10000
X.acceleration = 400
Y.acceleration = 400
X.deceleration = 800
Y.deceleration = 800
'Rotate arrow icons to correct orientation
down_arrow.Image.RotateFlip(RotateFlipType.Rotate180FlipNone)
right_arrow.Image.RotateFlip(RotateFlipType.Rotate90FlipNone)
left_arrow.Image.RotateFlip(RotateFlipType.Rotate270FlipNone)
'Start The Timer Up
Timer1.Start()
EndSub
'This allows arrow key presses when focus on stop_jog button
'Intercepts default move to other button
PrivateSub stop_jog_PreviewKeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PreviewKeyDownEventArgs) Handles stop_jog.PreviewKeyDown
SelectCase (e.KeyCode)
CaseKeyCodes.left, KeyCodes.right, KeyCodes.up, KeyCodes.down
e.IsInputKey = True
EndSelect
EndSub
'This allows arrow key presses when focus on begin_jog button
'Intercepts default move to other button
PrivateSub begin_jog_PreviewKeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PreviewKeyDownEventArgs) Handles begin_jog.PreviewKeyDown
SelectCase (e.KeyCode)
CaseKeyCodes.left, KeyCodes.right, KeyCodes.up, KeyCodes.down
e.IsInputKey = True
EndSelect
EndSub
'If key is pressed then set the corresponding boolean of the index in the key array to true
PrivateSub mainForm_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) HandlesMyBase.KeyDown
Keys(e.KeyValue) = True
EndSub
PrivateSub mainForm_KeyUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) HandlesMyBase.KeyUp
Keys(e.KeyValue) = False
EndSub
'Begin Jog Button Action
PrivateSub begin_jog_Click() Handles begin_jog.Click
'Connect server and start motion
g.command("SH XY")
g.command("BG XY")
EndSub
'Stop Jog Button Action
PrivateSub stop_jog_Click() Handles stop_jog.Click
g.command("ST XY")
EndSub
'If form arrow image is clicked on then set the index in the key array to true
PrivateSub up_arrow_MouseDown() Handles up_arrow.MouseDown
Keys(KeyCodes.up) = True
EndSub
PrivateSub down_arrow_MouseDown() Handles down_arrow.MouseDown
Keys(KeyCodes.down) = True
EndSub
PrivateSub left_arrow_MouseDown() Handles left_arrow.MouseDown
Keys(KeyCodes.left) = True
EndSub
PrivateSub right_arrow_MouseDown() Handles right_arrow.MouseDown
Keys(KeyCodes.right) = True
EndSub
'If form arrow image click is released then set the index in the key array to false
PrivateSub up_arrow_MouseUp() Handles up_arrow.MouseUp
Keys(KeyCodes.up) = False
EndSub
PrivateSub down_arrow_MouseUp() Handles down_arrow.MouseUp
Keys(KeyCodes.down) = False
EndSub
PrivateSub left_arrow_MouseUp() Handles left_arrow.MouseUp
Keys(KeyCodes.left) = False
EndSub
PrivateSub right_arrow_MouseUp() Handles right_arrow.MouseUp
Keys(KeyCodes.right) = False
EndSub
'Every timer tick of the clock update the velocity vector and send motion command
PrivateSub Timer1_Tick() Handles Timer1.Tick
'My.Application.Log.WriteEntry(X.velocity.ToString + " " + X.velocity_MAX.ToString)
'Check the Limits and process command X
If (System.Math.Abs(X.velocity) < X.velocity_MAX) Then
'If left or right direction then accelerate the Y axis
If Keys(KeyCodes.right) Then'Right
X.velocity += X.acceleration
EndIf
If Keys(KeyCodes.left) Then'Left
X.velocity -= X.acceleration
EndIf
EndIf
'Check the Limits and process command Y
If (System.Math.Abs(Y.velocity) < Y.velocity_MAX) Then
'If up or down direction then accelerate the Y axis
If Keys(KeyCodes.up) Then'UP
Y.velocity += Y.acceleration
EndIf
If Keys(KeyCodes.down) Then'Down
Y.velocity -= Y.acceleration
EndIf
EndIf
'If there is no directional input then decelerate
If (Keys(KeyCodes.left) + Keys(KeyCodes.right) = 0) Then
'Reduce speeds to zero if under decelleration threshold
'necessary when deceleration is not a multiple of acceleration
If (System.Math.Abs(X.velocity) < X.deceleration) Then
X.velocity = 0
EndIf
'Decelerate the X
If X.velocity > 0 Then
X.velocity -= X.deceleration
ElseIf X.velocity < 0 Then
X.velocity += X.deceleration
EndIf
EndIf
If (Keys(KeyCodes.up) + Keys(KeyCodes.down) = 0) Then
'Reduce speeds to zero if under decelleration threshold
'necessary when deceleration is not a multiple of acceleration
If (System.Math.Abs(Y.velocity) < Y.deceleration) Then
Y.velocity = 0
EndIf
'Decelerate the Y
If Y.velocity > 0 Then
Y.velocity -= Y.deceleration
ElseIf Y.velocity < 0 Then
Y.velocity += Y.deceleration
EndIf
EndIf
'Update velocity output displays
X_velocity_display.Text = X.velocity.ToString()
Y_velocity_display.Text = Y.velocity.ToString()
'Send the velocity commands
g.command("JG " + X.velocity.ToString + "," + Y.velocity.ToString)
'My.Application.Log.WriteEntry("JG " + X.velocity.ToString + "," + Y_velocity.ToString)
EndSub
EndClass