Analog Gauge Servo Commander

Here you can ask general questions about sim building, not related to the various hardware sections

Re: Analog Gauge Servo Commander

Postby Tombo » Sat 7. Sep 2013, 08:07

Hi,
ifound this libary http://arduino.cc/de/Reference/Servo is this the right one for my needs?

Code: Select all
#include <Servo.h>

Servo myservo;

void setup()
{
  myservo.attach(9);
  myservo.write(90);  // set servo to mid-point
}

void loop() {}


so this will drive the servo to mid position. So i can change servo.write that it moves according to the values given from xsim?
Sry but like i said i really know nothing about coding :oops:
With this code the servo will be controlled by degrees command. The is another millisecond comannd to. Which one will be the better one?
And what value to put in to output speed or rpm value?
Tombo
 
Posts: 97
Images: 36
Joined: Fri 22. Feb 2013, 20:52
Location: Germany
Has thanked: 6 times
Been thanked: 8 times

Re: Analog Gauge Servo Commander

Postby sirnoname » Sat 7. Sep 2013, 11:34

First you test the code if the servo is good wired. In loop you set it to a degree value. and test your above code is working. If it does and the servo moves you can continue. Calibrate your servo pulse wide that you reach start and stop position. (no need for X-Sim here, this is your calibration setup and your gauge)

You use the first sample code here:
viewtopic.php?t=1083

After this line:
Code: Select all
//Do here stuff to init display and zero to default

you put all setup part (fitting to your servo as described in the library)
Code: Select all
  myservo.attach(9); //Pin number, (and maybe: min pulse wide, max pulse wide - for calibrate start and stop)
  myservo.write(0);  // set servo default position


Then you goto:
Code: Select all
//Do here your LCD or display stuff

And place below there the movement command.
Gear speed and rpm do not have a percent value, so you have to scale it.
Beginning with speed:
Code: Select all
int maxspeed=200; //Maximum of your skala, you must scale it
int maxservodegree=180;
float devider=float(maxspeed)/float(maxservodegree);

float target=float(speed)/devider;
myservo.write(int(target));

float and int are definitions for with or without a "," number.
You can init a variable like target one time, then you cant write "float target" again. Simple remove the float/int for the second gauge or write "float target2".
myservomovecommend represent the command of your library for executing a move for the servo.

After this you must insert after:
Code: Select all
//Do here stuff to set display to zero or default

You must insert your movecommand again for the default position (maybe zero).
Code: Select all
myservo.write(0);


Correct me if there is a math error in scaling to the servo movement.

@vicpopo: do you include such a manual to your post, perhaps with the found servo example?
If a answer is correct or did help you for a solution, please use the solve button.
User avatar
sirnoname
Site Admin
 
Posts: 1829
Images: 45
Joined: Thu 1. Sep 2011, 22:02
Location: Munich, Germany
Has thanked: 35 times
Been thanked: 128 times

Re: Analog Gauge Servo Commander

Postby Tombo » Sat 7. Sep 2013, 12:12

Hi,
i've wired everything up quickly and servo movement will work with the simple libary code.
I've uploaded OBD firmware and Arduino Led is blinking so it's recieving data. I selectet the comport in Obd output and startet RBR for a little test it works
I've included Servo.h and declared Myservo before void setup. I changed servo max movement to 120° because there are no gears on it * Everything else like you said in your post.
but when i drive in revearse the servo is going to max km/h. Any solution?

Code: Select all
#include <Servo.h>

//  X-Sim Sample code for receiving OBD2 values from the extractor without using the converter
//  OBD2 is industry standard, X-Sim will additionally expand the OBD2 PID with gear and other values
//
//  Usage:
//  Arduino has to be connected to a free USB port on the computer where the extractor is running
//  Open the extractor and open the settings menu, there you have to select the OBD2 menu
//  Add now your arduino comport to the OBD2 list.
//  After closing the dialog you will see the arduino LED will be enabled which represents receiving data.
//  After closing the extractor application the LED will switch off.
//  Use this code to insert your own display code at the fitting positions
//  Copyright 2013 Martin Wiedenbauer, X-Sim.de
//
//  References:
//  http://en.wikipedia.org/wiki/OBD-II_PIDs
//  http://elmelectronics.com/DSheets/ELM327DS.pdf
//  http://www.x-sim.de


bool extractordetected=false;   //Will get updated from last positive or negative receive
int receivebuffer[20]={0};      //Receive buffer
Servo myservo;

void setup()
{
   pinMode(13, OUTPUT); //Arduino UNO LED off
   digitalWrite(13, LOW);
   Serial.begin(9600);

   //Do here stuff to init display and zero to default
 
  myservo.attach(9); //Pin number, (and maybe: min pulse wide, max pulse wide - for calibrate start and stop)
  myservo.write(0);  // set servo default position

}

int HexToInt(int c)
{
   if (c >= '0' && c <= '9')
   {
      return c - '0';
   }
   else if (c >= 'a' && c <= 'f')
   {
      return c - 'a' + 10;
   }
   else if (c >= 'A' && c <= 'F')
   {
      return c - 'A' + 10;
   }
   else
   {
      return -1; // getting here is bad: it means the character was invalid
   }
}

int ParseReceiveBuffer(int commandhighbyte, int commandlowbyte, int receivelength)
{
   //First character is removed of the receivebuffer string and must not be verified again
   if( receivebuffer[0]=='1' && receivebuffer[2]==commandhighbyte && receivebuffer[3]==commandlowbyte )
   {
      //Parse 2 byte values on position 5 and 6 in the buffer string
      if(receivelength==7)
      {
         int highresult=HexToInt(receivebuffer[5]);
         int lowresult =HexToInt(receivebuffer[6]);
         if(highresult==-1 || lowresult==-1){return -1;}
         return ((16*highresult) + lowresult);
      }
      //Parse 4 byte values on position 5,6,8 and 9 in the buffer string
      if(receivelength==10)
      {
         int tophighresult=HexToInt(receivebuffer[5]);
         int toplowresult =HexToInt(receivebuffer[6]);
         int highresult=HexToInt(receivebuffer[8]);
         int lowresult =HexToInt(receivebuffer[9]);
         if(tophighresult==-1 || toplowresult==-1 || highresult==-1 || lowresult==-1){return -1;}
         return ((4096*tophighresult) + (256*toplowresult) + (16*highresult) + lowresult);
      }
   }
   return -1; //Something is wrong with the returned OBD2 echo command byte
}

//This function will wait for the first character in receivetrigger and will parse the result
int ReceiveValueWithTimeout(int receivetrigger, int commandhighbyte, int commandlowbyte, int receivelength)
{
   int arduinoserialbuffer=0;
   int buffercount=-1;
   for(int z=0; z < 500; z++) //500ms timeout should be enough
   {
      while(Serial.available())
      {
         if(buffercount==-1)
         {
            arduinoserialbuffer = Serial.read();
            if(arduinoserialbuffer != receivetrigger) //Wait until the trigger is reached, ignore echo, first character is not in the buffer
            {
               buffercount=-1;
            }
            else
            {
               buffercount=0;
            }
         }
         else
         {
            arduinoserialbuffer = Serial.read();
            receivebuffer[buffercount]=arduinoserialbuffer;
            buffercount++;
            if(buffercount > receivelength) //buffer has now waitlen character length
            {
               return ParseReceiveBuffer(commandhighbyte, commandlowbyte, receivelength);
               buffercount=-1;
            }
         }
      }
      delay(1);
   }
   return -1;
}

void SendEchoDisabled() //not used here and a part of the OBD2 ELM327 specifications, as INFO
{
   //ATE0 Echo disabled
   Serial.write('A');
   Serial.write('T');
   Serial.write('E');
   Serial.write('0');
   Serial.write('\r');
}

//010c Request RPM, remember:  OBD2 RPM is ((A*256)+B)/4
int GetOBD2RpmValue()
{
   //010c
   Serial.write('0');
   Serial.write('1');
   Serial.write('0');
   Serial.write('c');
   Serial.write('\r');
   return ReceiveValueWithTimeout('4','0','C',10);
}

//010d Request speed in kmh
int GetOBD2SpeedValue()
{
   //010d
   Serial.write('0');
   Serial.write('1');
   Serial.write('0');
   Serial.write('d');
   Serial.write('\r');
   return ReceiveValueWithTimeout('4','0','D',7);
}

//01e0 Request gear number
int GetOBD2GearValue()
{
   //01e0
   Serial.write('0');
   Serial.write('1');
   Serial.write('e');
   Serial.write('0');
   Serial.write('\r');
   return ReceiveValueWithTimeout('4','E','0',7);
}

void loop()
{
   int speed=0;
   int rpm=0;
   int gear=GetOBD2GearValue();
   while(gear >= 0)
   {
      if(extractordetected==false)
      {
         SendEchoDisabled();   //Will cause a OK\r as answer from the extractor, ignored in this code
         extractordetected=true;
      }
      //Read all values
      gear = GetOBD2GearValue(); //Notice: offset +1 because of reverse gear
      speed= GetOBD2SpeedValue();
      rpm  = GetOBD2RpmValue();
                rpm=rpm/4 ; //remember OBD2 RPM is ((A*256)+B)/4
      if(gear!=-1 && speed!=-1 && rpm!=-1)
      {
         digitalWrite(13, HIGH); //We have connection and all values are ok, turn on the LED
         //Do here your LCD or display stuff

int maxspeed=200; //Maximum of your skala, you must scale it
int maxservodegree=120;
float devider=float(maxspeed)/float(maxservodegree);

float target=float(speed)/devider;
myservo.write(int(target));


      }
   }
   extractordetected=false;
   digitalWrite(13, LOW); //No connection, turn off the LED

   //Do here stuff to set display to zero or default


myservo.write(0);

   delay(2000); //No serial connection, poll serial port all two seconds + readtimeout until a running extractor is detected
}
Tombo
 
Posts: 97
Images: 36
Joined: Fri 22. Feb 2013, 20:52
Location: Germany
Has thanked: 6 times
Been thanked: 8 times

Re: Analog Gauge Servo Commander

Postby vicpopo » Sat 7. Sep 2013, 12:28

Hi Sir,

That was expected but need time.First tested with servo but for rpm I didn't find the solution to program it correctly cause not fast enough.
I ordered small 5 v stepper motor , easy to program but gear ratio to high 1/64.
User avatar
vicpopo
 
Posts: 645
Joined: Fri 20. Apr 2012, 18:04
Location: Strasbourg France
Has thanked: 39 times
Been thanked: 80 times

Re: Analog Gauge Servo Commander

Postby sirnoname » Sat 7. Sep 2013, 12:29

speed=abs(speed);

Will remove the negative value.
If course this works similar:
Code: Select all
if(speed < 0){speed=speed * -1;}

Insert this before the second code.

Where you got so fast a arduino?
Arduino nano cost 10€ and mini servos 2,50 at ePray. But needs time from china, two weeks.
If a answer is correct or did help you for a solution, please use the solve button.
User avatar
sirnoname
Site Admin
 
Posts: 1829
Images: 45
Joined: Thu 1. Sep 2011, 22:02
Location: Munich, Germany
Has thanked: 35 times
Been thanked: 128 times

Re: Analog Gauge Servo Commander

Postby Tombo » Sat 7. Sep 2013, 12:42

:lol: like i read here it's always good the have a arduino at home i got one :P
no i'm trying around with your xpid to build a motion sim and while i stuck there i wan't to try other things.
Ok everything seems to be working but servo moves really bad. Any possibility to get smooth servo movement? Or is this becaause of my servo
or mybe use the millisecond comand if possible? http://www.paulodowd.com/2011/11/arduino-smooth-rc-servo-motor-control.html

And you say servo will be to slow for rpm?
Tombo
 
Posts: 97
Images: 36
Joined: Fri 22. Feb 2013, 20:52
Location: Germany
Has thanked: 6 times
Been thanked: 8 times

Re: Analog Gauge Servo Commander

Postby sirnoname » Sat 7. Sep 2013, 13:31

smoothness is your part :)
Of course it will not be realistic aircore if you insert realtime ingame values, the analogue OSD gauge in a game is also smoothed.
instead of giving a new position you must increment to reach new position like this:
On top of all as global variable (First line of code after all includes).
Code: Select all
int smoothspeedtarget=0;

in your movement code before the movement command for servos:
Code: Select all
if(target >= smoothspeedtarget){smoothspeedtarget+=1;}
if(target < smoothspeedtarget){smoothspeedtarget-=1;}
myservo.write(smoothspeedtarget));

1 representing a smooth delay and could be changed if too slow. But if bigger than 1you must add end level detection after the above code:
Code: Select all
if(target >= smoothspeedtarget){smoothspeedtarget+=3;}
if(target < smoothspeedtarget){smoothspeedtarget-=3;}
if(smoothspeedtarget < 0){smoothspeedtarget=0;}
if(smoothspeedtarget > maxservodegree){smoothspeedtarget=servodegree;}
myservo.write(smoothspeedtarget));


Remember, there are arduino projects to drive the aircores direcly of an real dashboard. Servos do have some lower resolution and can reach about 100 positions per 180° (or less, I do not remember exactly). Not very easy to get a change of 1kmh with +/- 2kmh with 100 positions at a 200kmh skala.
If a answer is correct or did help you for a solution, please use the solve button.
User avatar
sirnoname
Site Admin
 
Posts: 1829
Images: 45
Joined: Thu 1. Sep 2011, 22:02
Location: Munich, Germany
Has thanked: 35 times
Been thanked: 128 times

Re: Analog Gauge Servo Commander

Postby Tombo » Sat 7. Sep 2013, 14:12

Where did i find such projects? because the smooth code makes it worse. it is moving quite slow.
Tombo
 
Posts: 97
Images: 36
Joined: Fri 22. Feb 2013, 20:52
Location: Germany
Has thanked: 6 times
Been thanked: 8 times

Re: Analog Gauge Servo Commander

Postby sirnoname » Sat 7. Sep 2013, 15:05

You are right, the second code is wrong, you need a mean value filter over some last values:

global variables on top:
Code: Select all
int meanbuffer[30]={0};
int meanoffset=0;
int maxmeanoffset=20; //decrease here for faster reactions 1-29


Movement code:
Code: Select all
int maxspeed=200; //Maximum of your skala, you must scale it
int maxservodegree=120;
float devider=float(maxspeed)/float(maxservodegree);

float target=float(speed)/devider;
meanbuffer[meanoffset]=int(target);
meanoffset++;
if(meanoffset > maxmeanoffset){meanoffset=0;}
int smoothspeedtarget=0;
for(int m=0; m < maxmeanoffset; m++)
{
 smoothspeedtarget+=meanbuffer[m];
}
smoothspeedtarget=smoothspeedtarget/maxmeanoffset;
myservo.write(smoothspeedtarget);


and as default empty the buffer:
Code: Select all
myservo.write(0);
for(int e=0; e < maxmeanoffset; e++)
{
 meanbuffer[e]=0;
}


Check the blinking serial port LEDs, they should blink very fast.

For the aircores part you must dig the internet by yourself.
http://www.google.de/#q=aircore+arduino
The best one and most used one wins. Add your dashboard manufacturer name to the search results, every dashboard has other types of aircores.
If a answer is correct or did help you for a solution, please use the solve button.
User avatar
sirnoname
Site Admin
 
Posts: 1829
Images: 45
Joined: Thu 1. Sep 2011, 22:02
Location: Munich, Germany
Has thanked: 35 times
Been thanked: 128 times

Re: Analog Gauge Servo Commander

Postby vicpopo » Sat 7. Sep 2013, 15:46

Hi Sir,

Below the little stepper motors with controller.Normally with these they should work.When you talk about air core gauge you think about this kind of material?
http://cgi.ebay.fr/ws/eBayISAPI.dll?ViewItem&item=370853745130&ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1497.l2649#ht_6100wt_1388
User avatar
vicpopo
 
Posts: 645
Joined: Fri 20. Apr 2012, 18:04
Location: Strasbourg France
Has thanked: 39 times
Been thanked: 80 times

PreviousNext

Return to Motion simulator building Q&A

Who is online

Users browsing this forum: No registered users and 1 guest