unit fMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, CPort, RComTank, ActnList, JvComponentBase, JvHidControllerClass, RJoystick, CPortCtl, RProfiler, JvJoystick;
type
TfTank = class(TForm)
COM: TComPort;
bConnect: TButton;
al1: TActionList;
aCommand: TAction;
jvHID: TJvHidDeviceController;
cbJoystick: TComboBox;
scrAileron: TScrollBar;
scrPitch: TScrollBar;
scrRudder: TScrollBar;
scrThrottle: TScrollBar;
lRudder: TLabel;
lThrottle: TLabel;
cbFire: TCheckBox;
cbAltFire: TCheckBox;
lhat: TLabel;
cbPort: TComComboBox;
scrLeft: TScrollBar;
scrRight: TScrollBar;
lMotors: TLabel;
scrPan: TScrollBar;
scrTilt: TScrollBar;
lJoy: TLabel;
bBatch: TButton;
joy1: TJvJoystick;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure bConnectClick(Sender: TObject);
procedure scrLeftChange(Sender: TObject);
procedure jvHIDDeviceChange(Sender: TObject);
function jvHIDEnumerate(HidDev: TJvHidDevice; const Idx: Integer): Boolean;
procedure cbJoystickChange(Sender: TObject);
procedure bSendClick(Sender: TObject);
procedure bBatchClick(Sender: TObject);
private
{ Private declarations }
//Joystick:TJvHidDevice;
joyPID,joyVID: Word;
cPort:string;
public
{ Public declarations }
Tank:TRCTank;
Joy:TRjoystick;
lSpeed, rSpeed, lDir, rDir:integer;
DeadX, DeadY: integer;
MaxSpeed:byte;
Speed, Steer: Integer;
pan, tilt:Integer;
panCenter, tiltCenter, maxPan, maxTilt, minPan, minTilt:Byte;
Timer:TRTimer;
procedure OnJoyData;
procedure Command2Tank;
procedure SetupJoy;
procedure ApplyDeadZone(var Param:Integer; Dead:integer);
procedure pause(sec:double);
end;
var
fTank: TfTank;
implementation
uses IniFiles;
const
THatPosString:array [0..8] of string = ('Up', 'UpRight', 'Right', 'RightDown', 'Down', 'LeftDown', 'Left', 'LeftUp', 'Center');
{$R *.dfm}
procedure TfTank.ApplyDeadZone(var Param: Integer; Dead: Integer);
begin
if abs(Param)< Dead then Param:=0;
end;
procedure TfTank.bBatchClick(Sender: TObject);
begin
//F
Tank.SendCommand(1,100,1,100,0,0);
pause(3);
Tank.SendCommand(0,0,0,0,0,0);
pause(0.5);
//B
Tank.SendCommand(2,100,2,100,0,0);
pause(3);
Tank.SendCommand(0,0,0,0,0,0);
//LF
pause(0.5);
Tank.SendCommand(1,140,0,140,0,0);
pause(3);
Tank.SendCommand(0,0,0,0,0,0);
pause(0.5);
//LB
Tank.SendCommand(0,140,1,140,0,0);
pause(3);
Tank.SendCommand(0,0,0,0,0,0);
pause(0.5);
Tank.SendCommand(1,120,1,120,0,0);
pause(3);
Tank.SendCommand(0,0,0,0,0,0);
end;
procedure TfTank.bConnectClick(Sender: TObject);
begin
if Tank.Connected then begin
Tank.Disconnect;
bConnect.Caption:='Connect';
end else begin
Tank.Port:=cbPort.Text;
Tank.Connect;
bConnect.Caption:='Disconnect';
MessageBeep(MB_ICONINFORMATION);
end;
end;
procedure TfTank.bSendClick(Sender: TObject);
begin
Command2Tank;
end;
procedure TfTank.cbJoystickChange(Sender: TObject);
begin
FreeAndNil(Joy);
if cbJoystick.ItemIndex>-1 then begin
joyPID:=TJvHidDevice(cbJoystick.Items.Objects[cbJoystick.ItemIndex]).Attributes.ProductID;
joyVID:=TJvHidDevice(cbJoystick.Items.Objects[cbJoystick.ItemIndex]).Attributes.VendorID;
//Easy touch joystick
if (joyPID=6) and (joyVID=121) then begin
Joy:=TREasyTouchJoystick.Create;
scrPitch.Max:=256;
scrAileron.Max:=256;
end;
//Logitech Extreme 3D Pro
if (joyPID=49685) and (joyVID=1133) then begin
Joy:=TRLogitechExtreme.Create;
scrPitch.Max:=4096;
scrAileron.Max:=1024;
end;
if Assigned(Joy) then begin
Joy.SelectJoystickByID(joyVID, joyPID);
Joy.OnJoyData:=OnJoyData;
end;
// Joy3D.SelectJoystickByID(joyVID,joyPID);
end;
end;
procedure TfTank.Command2Tank;
begin
lDir:=0;
rDir:=0;
//prepare rDir, lDir data based on tracks speed
case lSpeed of
0:lDir:=0; //stop
1..255: lDir:=1; //forward
-255..-1:lDir:=2; //backward
end;
case rSpeed of
0:rDir:=0; //stop
1..255: rDir:=1; //forward
-255..-1:rDir:=2; //backward
end;
// pan:=180-scrPan.Position;
// tilt:=scrTilt.Position;
// lGauge.Caption:='L:'+InttoStr(lSpeed)+' R:'+InttoStr(rSpeed)+' D:'+InttoStr(lDir + rDir shl 2);
Tank.SendCommand(lDir,Abs(lSpeed),rDir,Abs(rSpeed), pan, tilt);
end;
procedure TfTank.FormCreate(Sender: TObject);
var
conf:TIniFile;
begin
conf:=TIniFile.Create(ExtractFilePath(Application.ExeName)+'RTank.ini');
joyVID:=conf.ReadInteger('Joystick','VID',1133);
joyPID:=conf.ReadInteger('Joystick','PID',49685);
DeadX:=conf.ReadInteger('Joystick','DeadX',10);
DeadY:=conf.ReadInteger('Joystick','DeadY',10);
cport:=conf.ReadString('ComPort','Name','COM3');
MaxSpeed:=conf.ReadInteger('Chassis','MaxSpeed',210);
maxPan:=conf.ReadInteger('Camera','MaxPan',170);
maxTilt:=conf.ReadInteger('Camera','MaxTilt',175);
minPan:=conf.ReadInteger('Camera','MinPan',0);
minTilt:=conf.ReadInteger('Camera','MinTilt',10);
panCenter:=conf.ReadInteger('Camera','PanCenter',90);
tiltCenter:=conf.ReadInteger('Camera','TiltCenter',132);
FreeAndNil(conf);
cbPort.ItemIndex:=cbPort.Items.IndexOf(cport);
Tank:=TRCTank.Create;
SetupJoy;
//Camera movements defaults and range
pan:=panCenter;
tilt:=tiltCenter;
end;
procedure TfTank.FormDestroy(Sender: TObject);
var
conf:TIniFile;
begin
conf:=TIniFile.Create(ExtractFilePath(Application.ExeName)+'RTank.ini');
conf.WriteInteger('Joystick','VID',joyVID);
conf.WriteInteger('Joystick','PID',joyPID);
conf.WriteInteger('Joystick','DeadX',DeadX);
conf.WriteInteger('Joystick','DeadY',DeadY);
conf.WriteString('ComPort','Name',cbPort.Text);
conf.WriteInteger('Chassis','MaxSpeed',MaxSpeed);
conf.WriteInteger('Camera','MaxPan',maxPan);
conf.WriteInteger('Camera','MinPan',minPan);
conf.WriteInteger('Camera','MaxTilt',maxTilt);
conf.WriteInteger('Camera','MinTilt',minTilt);
conf.WriteInteger('Camera','PanCenter',panCenter);
conf.WriteInteger('Camera','TiltCenter',tiltCenter);
FreeAndNil(conf);
FreeAndNil(Tank);
FreeAndNil(Joy);
end;
procedure TfTank.jvHIDDeviceChange(Sender: TObject);
begin
cbJoystick.Clear;
jvHID.Enumerate;
end;
function TfTank.jvHIDEnumerate(HidDev: TJvHidDevice; const Idx: Integer): Boolean;
begin
cbJoystick.Items.AddObject(HidDev.ProductName,HidDev);
if (HidDev.Attributes.VendorID=joyVID)and (HidDev.Attributes.ProductID=joyPID) then begin
cbJoystick.ItemIndex:=cbJoystick.Items.IndexOfObject(HidDev);
cbJoystickChange(self);
end;
Result:=true;
end;
procedure TfTank.OnJoyData;
var
Hat:THatPosition;
CenterCamera:Boolean;
begin
Hat:=hCenter;
CenterCamera:=False;
//Easy touch joystick
if (joyPID=6) and (joyVID=121) then begin
scrPitch.Position:=TREasyTouchJoystick(Joy).rZ;
scrAileron.Position:=TREasyTouchJoystick(Joy).Z;
scrRudder.Position:=TREasyTouchJoystick(Joy).X;
scrThrottle.Position:=TREasyTouchJoystick(Joy).Y;
cbFire.Checked:=TREasyTouchJoystick(Joy).Btn1;
cbAltFire.Checked:=TREasyTouchJoystick(Joy).Btn10;
Hat:=TREasyTouchJoystick(Joy).Hat;
CenterCamera:=TREasyTouchJoystick(Joy).Btn2;
Speed:=Round(((TREasyTouchJoystick(Joy).rZ)-127)*2);
Steer:=Round((TREasyTouchJoystick(Joy).Z)-127)*2;
end;
//Logitech Extreme 3D Pro
if (joyPID=49685) and (joyVID=1133) then begin
scrPitch.Position:=TRLogitechExtreme(Joy).Pitch;
scrAileron.Position:=TRLogitechExtreme(Joy).Aileron;
scrRudder.Position:=TRLogitechExtreme(Joy).Rudder;
scrThrottle.Position:=TRLogitechExtreme(Joy).Throttle;
cbFire.Checked:=TRLogitechExtreme(Joy).Btn1;
cbAltFire.Checked:=TRLogitechExtreme(Joy).Btn2;
Hat:=TRLogitechExtreme(Joy).Hat;
CenterCamera:=TRLogitechExtreme(Joy).Btn1;
Speed:=(TRLogitechExtreme(Joy).Pitch div 8)-255; //4096 to -256..256
Steer:=(TRLogitechExtreme(Joy).Aileron div 4)-127; //1024 to -127..128
end;
ApplyDeadZone(Speed,DeadX);
ApplyDeadZone(Steer,DeadY);
if Speed>MaxSpeed then Speed:=MaxSpeed;
if Speed<-MaxSpeed then Speed:=-MaxSpeed;
if Speed>0 then begin
//Forward
//Left/Right turn
lSpeed:=Speed-Steer;
rSpeed:=Speed+Steer;
if lSpeed<0 then lSpeed:=0;
if rSpeed<0 then rSpeed:=0;
if lSpeed>MaxSpeed then lSpeed:=MaxSpeed;
if rSpeed>MaxSpeed then rSpeed:=MaxSpeed;
end else begin
//Backward
//Left/Right turn
lSpeed:=Speed+Steer;
rSpeed:=Speed-Steer;
if lSpeed>0 then lSpeed:=0;
if rSpeed>0 then rSpeed:=0;
if lSpeed<(-MaxSpeed) then lSpeed:=-MaxSpeed;
if rSpeed<(-MaxSpeed) then rSpeed:=-MaxSpeed;
end;
scrLeft.Position:=-lSpeed;
scrRight.Position:=-rSpeed;
if (cbAltFire.Checked) and (bConnect.Caption='Connect') then bConnect.OnClick(Self);
case Hat of
hUp: Inc(Tilt);
hUpRight:begin
Inc(Tilt);Dec(pan);
end;
hRight: Dec(pan);
hRightDown: begin
Dec(Pan); Dec(tilt);
end;
hDown: Dec(Tilt);
hLeftDown: begin
Inc(pan);Dec(tilt);
end;
hLeft: Inc(pan);
hLeftUp: begin
Inc(pan);Inc(tilt);
end;
hCenter: if CenterCamera then begin
pan:=panCenter;
tilt:=tiltCenter;
end;
end;
end.