I want to show you my first prototype of my Head G-Force Simulation Seat.
It is far from perfect, but i learned a lot.
Idea:
The Idea came to me, when i heard, that a lot of Formula 1 drivers have to have really good neck muscles, and that it is near impossible to withstand those forces as a normal human beeing.
I also recognised, that the normal 2 DOF Motionseats, whiche tilt around a point beneath the seat, have the problem, that they lie to you in the first instance. The problem is, that if you are making a right turn, then the seat has to tilt to the left, so the gravitatinal field can line up with the acceleration field of the game. But to get there, you have to accelerate the Seat to the left, so you will feel a push from the right, which isn't, what you would feel in the car.
A solution to this problem is to move the tilting point of the Seat above the head of the driver. But because you can't put the tilting point as high as you want, the head feels less of an acceleration, if the seat is accelerated, than your feet. A solution to this, could be a seperate G-Force simulation for the head.
The Seat:
It is a really simple construction, as you can see in the pictures. There is a electric motor, which pulls on a cable to simulate the g-forces. The cable is guided by the 4 rollers and is attached to a quick chanche mechanism. This is to chanche helmets, to accomodate for different head sizes.
The whole consturction with the electric motors and the two arms can be moved up and down, so different people with different heights can enjoy the experiace.
Controll
The electric motor is controlled by an Arduino Uno with an H-Bridge. The code is written by myselve. It is a DC motor with 75 W (30 V, 2.5 A). The h-Bridge is an LN298N.
I use the USO setup in the sim converter to talk to the Arduino. The Arduino read the COM Port and controlls the Motor. Sadly at this point, i wasn't able controll it with the PID-controller. So right now, the values are just set to the output of the Arduino, as a pwm signal.
It works better than i thought, but it doesnt acctually controll the foce, it controlls the speed of the motor. But with the resistance of the motor and the controll voltage the current is proportional to the voltage, which results in a proportional force but only if the motor isnt turning. As soon as the motor starts to spin, the current as well as the force will drop.
My goal is to controll the current and therefore controll the force.
As for the electrical circuit, i just jused the circuit proposed in figure 6 in the datasheet of the LN298N. https://www.sparkfun.com/datasheets/Robotics/L298_H_Bridge.pdf
X-Sim USO Setup
Here is my USO Setup in the X-Sim converter.
To check the COM Port i used a free trial version of Device Monitoring Studio. But you can also use an other serial port sniffing, analyzer programm.
Material:
I got the racing seat from my uncle, who drives actual racing cars. As you can see, it is a pretty old one.
The motor is from ricardo.ch (swiss ebay)
Right now, i use an Arduino Uno
Most of the electric components are from a local electronics shop.
To drive the car, i use my G27 steeringwheel.
To power the motor, i use my Lab Powersuply, but at some point i want to swith to an other one.
The Helmets i got from a local motorcylce store for free. Those are old helmets, which aren't save any more to use on the street.
Code:
And here is my current code for the Arduino.
- Code: Select all
//#include <PWM.h>
//int32_t frequency = 25000; //frequency (in Hz)
#include <PID_v1.h>
#define serialBuffersize 8
#define debug 0
int ledPin = 8;
// 75459507 = Max x-sim g-force Value for RBR
// 1000000 = Max x-sim g-force Value for GTR2
// Pin Setup Motorcontroll
int MotorInput1_Pin = 2;
int MotorInput2_Pin = 3;
int Motor_pwm_Pin = 11;
int currentsense_Pin = A0;
// PID Motorcontroll
int Voltage_currentsense = 0;
double Setpoint, Input, Output; //I/O for PID
double aggKp=20, aggKi=0, aggKd=2; //original: aggKp=40, aggKi=2, aggKd=10, Aggressive Turning,50,20,20
double consKp=10, consKi=20, consKd=1; //original consKp=20, consKi=1, consKd=5, Conservative Turning,20,10,10
PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT); //Initialize PID
int MotorForce = 0;
// Serial data handling
char serialBuffer[serialBuffersize];
String command;
boolean Datastart = false;
int serialIndex = 0;
int setForce = 0;
int oldsetForce = 0;
int whilelooper = 1;
void setup() {
Serial.begin(115200);
//Pin Setup Motorcontroll
pinMode(MotorInput1_Pin, OUTPUT);
pinMode(MotorInput2_Pin, OUTPUT);
pinMode(Motor_pwm_Pin, OUTPUT);
pinMode(currentsense_Pin, INPUT);
digitalWrite(MotorInput1_Pin, LOW);
digitalWrite(MotorInput2_Pin, LOW);
digitalWrite(Motor_pwm_Pin, LOW);
// PID Motorcontroll
myPID.SetMode(AUTOMATIC);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
}
void loop() {
while (whilelooper == 1){
while(Serial.available() > 0){
char charBuffer = Serial.read(); //string from USO --> L~a01~E 8bit resolution\decimal output
#if debug
Serial.print("charBuffer read: ");
Serial.println(charBuffer);
#endif
if (charBuffer == 'E'){ // E marks end of dataset from x-sim
command = String(serialBuffer);
#if debug
Serial.println("serialBuffer");
Serial.println(serialBuffer);
Serial.println(command);
#endif
for( int i = 0; i < sizeof(serialBuffer); ++i ){
serialBuffer[i] = (char)0;
}
serialBuffer[serialIndex] = 0;
Datastart = false;
serialIndex = 0;
#if debug
Serial.println("new serialBuffer");
Serial.println(serialBuffer);
#endif
}
else if (Datastart == true && isDigit(charBuffer) > 0){
#if debug
Serial.print("charBuffer aufbau: ");
Serial.println(charBuffer);
#endif
serialBuffer[serialIndex++] = charBuffer;
#if debug
Serial.print("serialBuffer aufbau: ");
Serial.println(serialBuffer);
#endif
}
else if (charBuffer == 'S'){ // S marks start of dataset from x-sim
Datastart = true;
#if debug
Serial.print("Serialbuffer S: ");
Serial.println(serialBuffer);
#endif
}
} //end while(Serial.available() > 0)
setForce = command.toInt();
command = "";
if (setForce > 0 && setForce != oldsetForce){
oldsetForce = setForce;
setForce = 0;
/*
Serial.print("command: ");
Serial.println(command);
Serial.print("Data: ");
Serial.println(oldsetForce);
Serial.println("---------------------------------------");
*/
}
if (oldsetForce >= 127){
MotorForce = abs(oldsetForce-127)*2;
digitalWrite(ledPin, HIGH);
digitalWrite(MotorInput1_Pin, HIGH);
digitalWrite(MotorInput2_Pin, LOW);
} else {
MotorForce = abs(127-oldsetForce)*2;
digitalWrite(ledPin, LOW);
digitalWrite(MotorInput1_Pin, LOW);
digitalWrite(MotorInput2_Pin, HIGH);
}
Voltage_currentsense = analogRead(currentsense_Pin);
Input = Voltage_currentsense/4;
Setpoint = MotorForce;
//myPID.Compute();
/*Serial.print("Setpt: ");
Serial.println(Setpoint);
Serial.print("Input: ");
Serial.println(Input);
Serial.print("Output: ");
Serial.println(Output);
//delay(1000);
*/
//Serial.print("MotorForce: ");
//Serial.println(MotorForce);
analogWrite(Motor_pwm_Pin, MotorForce);
//Serial.print("currentsense: ");
//Serial.println(Voltage_currentsense);
} // end while (whilelooper)
} //end void loop()
Improvements:
Because the force on the helmet is insertet on the top, it can get quite uncomfotable, because the resulting torque wants to rotate the helmet around your head. My decision, to put it on top was, because it is easier to build a quickchanche mechanism and because i wanted to try to drive with an Oculus Rift DK2. This works with 2 out of 3 helmets. Those helmets are socalled jet helmets. The one, which doesn't work, is an integral helmet. Because of the Oculus Rift, i thought, i can't attache the cable to the side of the helmet, because you want to be able to look around. But because most of the time i use the seat with a monotor, i would attache the cable on the side.
The current roller guides for the cable have a really big friction, which also chanches drastically if, the cable isn't perfectly alligned.
As for now, i can only simulate lateral forces.
The project is very much still in progress and i will post future chanches/improvements here.
I hope it was interessting and you got some information out of it. I am open for ideas, critics and nice replyes.
Greetings from Switzerland