Seite 1 von 2
Qt OnChange
Verfasst: 1. März 2010 19:26
von Lord_Luncher
Gibt es eine Möglichkeit eventuell mit Qt oder C++ allgemein. den Joystick via onChange auszulesen? Weil die while schleife kostet mich eine menge resourcen.... Hab mir das so vorgestellt dass wenn sich der wert einer Joystick axe ändert dass dan ein bestimmter code ausgeführt wird... Also eine Art OnChange Methode für die Axe...
Der Joystick soll mir für ein projekt mit einem BeagleBoard helfen. Will nen Quadro Copter mit BeagleBoard basteln und wenn ich nun via joystick controller, Beschleunigungssensoren ansprechen könnte wäre das sehr von vorteil. Will also anstatt den verbauten Potis im Joystick einfach Beschleunigungssensoren verwenden. aber idealer wäre natürlich eine OnChange lösung da ich davon ausgehe dass die weniger prozessor leistung frisst XD Die jetztige frisst 100% ^^
Code: Alles auswählen
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/joystick.h>
#include <stdlib.h>
#include <iostream>
#include <time.h>
#define JOY_DEV "/dev/input/js0"
int main()
{
int joy_fd, *axis=NULL, num_of_axis=0, num_of_buttons=0, x;
char *button=NULL, name_of_joystick[80];
struct js_event js;
if( ( joy_fd = open( JOY_DEV , O_RDONLY)) == -1 )
{
printf( "Couldn't open joystick\n" );
return -1;
}
ioctl( joy_fd, JSIOCGAXES, &num_of_axis );
ioctl( joy_fd, JSIOCGBUTTONS, &num_of_buttons );
ioctl( joy_fd, JSIOCGNAME(80), &name_of_joystick );
axis = (int *) calloc( num_of_axis, sizeof( int ) );
button = (char *) calloc( num_of_buttons, sizeof( char ) );
printf("Joystick detected: %s\n\t%d axis\n\t%d buttons\n\n"
, name_of_joystick
, num_of_axis
, num_of_buttons );
fcntl( joy_fd, F_SETFL, O_NONBLOCK ); /* use non-blocking mode */
int before = 0;
int ts = time(0)+100;
int i = 0;
while( ts > time(0) ) /* infinite loop */
{
i++;
/* read the joystick state */
read(joy_fd, &js, sizeof(struct js_event));
if(js.type == JS_EVENT_AXIS && js.number == 3 && js.value != before)
{
std::cout << js.value << std::endl;
before = js.value;
}
}
std::cout << i/100 << std::endl;
close( joy_fd ); /* too bad we never get here */
return 0;
}
Vielen Dank schon mal im vorraus
Verfasst: 2. März 2010 09:20
von nando
Hi,
du koenntest den code der while schleife in einen thread auslagern
und immer wenn daten gelesen wurdein ein signal emitieren....
dieses signal verbindest du mit einem slot im haupt thread (z.b onChange).
weiss nicht, ob das genau das ist was du suchst...
das mit den resourcen ist mir nicht ganz klar, das read blokiert doch oder?
oder ist es nonblocking?
schau dir in diesem zusammenhang auch mal das posix select an (man select)
alternative 2 waere evtl ohne thread mit einem idle timer, der immer ins read geht sobald keine resourcen gebraucht werden....
gruss,
nando
Verfasst: 2. März 2010 14:21
von Lord_Luncher
Das read blockiert nicht.... das liest sobald es lesen kann und bei nem joystick ist es sehr warscheinlich dass er lesen kann.... und sei es dass er den wert 0 liest XD
Dadurch dass der read ca. 3,5 Millionen mal in der sekunde aufgerufen wird schluckt das Programm extrem resourcen daran würde auch ein Thread leider nix dran ändern
Das mit dem man select werd ich mir mal anschauen.
// edit: Okay man select ist dann wohl auch nicht das was ich brauch ^^
Was ich letztendlich haben will ist eine Methode die jedes mal ausgeführt wird wenn sich der wert vom Joystick ändert. Das ganze aber möglichst resourcen schonend weil wenn ich ne endlosschleife mit nem read hab dann sieht meine Prozessor auslastung praktisch dann wie folgt aus: CoreX: 100%
Da ich das Programm auf einem SingleCore Rechner laufen lassen will ist 100% auslastung eher Suboptimal
Aso: Ein sleep von 1 ms hat zur folge dass der read komischerweise nicht mehr richtig funktioniert.... bzw weit aus zu langsam
Ich weiss ich hab nicht wirklich eine alltägliche Frage ^^
Verfasst: 2. März 2010 14:36
von RHBaum
So unalltäglich ist deine frage nicht ....
unalltäglich ist nur, das du unbedingt eine Dir genehme Antwort hören willst ^^
nen Joystik iss nun mal nicht eventorieentiert wie eine tastatur oder aehnliches ....
wenn dich mal mit joysticks beschaeftigst, siehst das auch an den treiberschnittstellen.
Joystick funktioniert immer nur ala : gibt mir deinen Status.
Achsen stand und buttons sind dann in den status irgendwo codiert.
Falls dir doch irgendwas ein event liefert, isses der Treiber, bzw irgendwelche makro software.
Und die machen genau das, was Du ned machen willst .... sie fragen aller zig millisekunden den stand ab ...
Ein sleep von 1 ms hat zur folge dass der read komischerweise nicht mehr richtig funktioniert.... bzw weit aus zu langsam
Bitte, fuer welche software iss eine abtastung des joy mit 1 khz zu langsam ?
Stell dir mal nen joy mit 4 achsen, und weniger als 32 tasten vor.
bei ner 8 bit aufloesung(0-127) waeren das 4+1 byte = 5kb/s
da bekaemst ueber die klassischen Coms schon langsam probleme.
Ich wuerd sogar versuchen auf 50 - 10Hz runterzukommen, das langt volkommen, moderenere spiele kommen zumindest mit sowas aus ...
Ciao ...
Verfasst: 2. März 2010 15:43
von Lord_Luncher
naja wie bereits beschrieben will ich den joystick nicht als solchen verwenden XD Aber danke für deine Antwort.
Mir ist eben aufgefallen dass da in meinem code fcntl steht, mit dem Kommentar das der read nicht blockt. Wenn ich jedoch die Zeile auskommentiere dann ist zum einen die Auslastung 0% und zum anderen hab ich jeden Wert der vom Joystick erfasst wird. Ziemlich cool würd ich sagen weil so kann ich das ganze in nen Thread packen und sobald der read nicht mehr blockiert wird einfach ne methode ausgeführt.
den Code zum testen von dem blockendem read, als Beispiel wird Axe 3 verwendet.
Code: Alles auswählen
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/joystick.h>
#include <stdlib.h>
#include <iostream>
#include <time.h>
#define JOY_DEV "/dev/input/js0"
int main()
{
int joy_fd, *axis=NULL, num_of_axis=0, num_of_buttons=0, x;
char *button=NULL, name_of_joystick[80];
struct js_event js;
if( ( joy_fd = open( JOY_DEV , O_RDONLY)) == -1 )
{
printf( "Couldn't open joystick\n" );
return -1;
}
ioctl( joy_fd, JSIOCGAXES, &num_of_axis );
ioctl( joy_fd, JSIOCGBUTTONS, &num_of_buttons );
ioctl( joy_fd, JSIOCGNAME(80), &name_of_joystick );
axis = (int *) calloc( num_of_axis, sizeof( int ) );
button = (char *) calloc( num_of_buttons, sizeof( char ) );
printf("Joystick detected: %s\n\t%d axis\n\t%d buttons\n\n"
, name_of_joystick
, num_of_axis
, num_of_buttons );
//fcntl( joy_fd, F_SETFL, O_NONBLOCK ); /* use non-blocking mode */
//int before = 0;
//int ts = time(0)+100;
//int i = 0;
while( 1 ) /* infinite loop */
{
//i++;
/* read the joystick state */
read(joy_fd, &js, sizeof(struct js_event));
if(js.type == JS_EVENT_AXIS && js.number == 3)
{
std::cout << js.value << std::endl;
//before = js.value;
}
}
//std::cout << i/100 << std::endl;
close( joy_fd ); /* too bad we never get here */
return 0;
}
Vielen dank
Ich weiss nicht ob das das war was nando gemeint hat aber er hat mich auf jedenfall auf die Idee gebracht ^^
damit würd ich sagen:
SOLVED
Verfasst: 2. März 2010 16:12
von pfid
Es heißt übrigens Achse

Verfasst: 2. März 2010 16:53
von Lord_Luncher
naja im englischen isses Axe und deshalb hab ichs hingetippt auch wenns nich ganz grammatikalisch korrekt ist XD
Für die jenigen die bisher ein Ähnliches Probelm wie ich hatten mit einer Joystick abfrage, poste ich hier mal die resultierende Klasse mit Beispielcode XD
joystick.cpp
Code: Alles auswählen
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/joystick.h>
#include "joystick.h"
Joystick::Joystick(char dir[])
{
if( ( this->fd = open( dir , O_RDONLY)) == -1 )
{
printf("ERROR (Joystick Constructor): Joystick was not found!");
}
ioctl( this->fd, JSIOCGAXES, &this->axes );
ioctl( this->fd, JSIOCGBUTTONS, &this->buttons );
ioctl( this->fd, JSIOCGNAME(80), &this->name );
this->start();
}
void Joystick::run()
{
while( 1 )
{
read(this->fd, &(this->js), sizeof(struct js_event));
if(js.type == JS_EVENT_AXIS)
this->onChangeAxe(js.number, js.value);
else
this->onChangeButton(js.number, js.value);
}
}
void Joystick::getName(char* buffer[], int bufferSize)
{
if(bufferSize > 80 || bufferSize < 0)
bufferSize = 80;
for(int i = 0; i < bufferSize; i++)
*buffer[i] = this->name[i];
}
int Joystick::getNumAxes()
{
return this->axes;
}
int Joystick::getNumButtons()
{
return this->buttons;
}
joystick.h
Code: Alles auswählen
#ifndef JOYSTICK_H
#define JOYSTICK_H
#include <linux/joystick.h>
#include <QThread>
class Joystick : public QThread
{
private:
virtual void onChangeAxe(int axe, int value);
virtual void onChangeButton(int btt, int value);
int axes;
int buttons;
char name[80];
struct js_event js;
int fd;
public:
Joystick(char dir[]);
void run();
int getNumAxes();
int getNumButtons();
void getName(char* buffer[], int bufferSize);
};
#endif // JOYSTICK_H
Und hier noch Ein Beispiel wie die Klasse zu verwenden ist:
Code: Alles auswählen
#include <iostream>
#include "joystick.h"
using namespace std;
void Joystick::onChangeAxe(int axe, int value)
{
cout << "Axe: " << axe << " - " << value << endl;
}
void Joystick::onChangeButton(int button, int value)
{
cout << "Button: " << button << " - " << value << endl;
}
int main()
{
Joystick js("/dev/input/js0");
while(js.isRunning())
sleep(1000);
}
Verfasst: 2. März 2010 17:01
von pfid
was macht onChangeAxe()? Verschickst du da Signale? Dann könntest du das ganze eventuell noch mit dem ein oder anderen Mutex verschlanken.
Verfasst: 2. März 2010 17:17
von Lord_Luncher
Naja alles was ich mach steht eigentlich im code XD eigentlich auch realtiv simpel XD onChangeAxe wird in der Methode Joystick::run() aufgerufen
Was bitte sind Mutex?
Verfasst: 3. März 2010 08:15
von pfid
Du hast einen Thread der einen Joystick pollt. Irgendwie willst du, wenn du das irgendwann mal verwendest, doch bestimmt die Information in den Mainthread oder in eine andere Klasse bekommen. Willst du in onChangeAxe() ein Signal verschicken, oder wie sieht die konkrete Anwendung aus?
Das wäre dann evtl. etwas ungünstig, wenn du die Eventloop mit einer beliebig großen Menge an Events flutest.
Verfasst: 3. März 2010 12:42
von RHBaum
Mit seiner loesung "pollt" er ja nicht, sondern macht sich zunutze, das der joy treiber bei linux in die geraetedatei schreibt, und triggert auf die schreibvorgaenge (fnctl) .
Wenn er die werte casht kann er nur auf aenderungen reagieren ....
Weiss ned wir granular der joy treiber die geraetedatei schreibt, aber denk wenn er alle aenderungen an die mainapp schickt, und mal bissi an dem ding rumspielt, er alleinb scho durch das mappen der events auf den mainthread, den mainthread selber auf 100% systemlast zumüllen könnt.
Aber das wird er selber rausfinden muessen ...
Ciao ...
Verfasst: 3. März 2010 13:17
von chrislo1976
Lord_Luncher hat geschrieben:naja im englischen isses Axe ...
Will ja jetzt nicht klugscheißern (und ist auch off-topic), aber in dem Englisch dass ich verwende bedeutet "Axe" im deutschen "Axt"
Gruß,
Christian
Verfasst: 3. März 2010 13:46
von nando
Hi,
wie waere es mit einem (Q)timer, der dann nur alle X ms read aufruft ??
Gruss,
Nando
Verfasst: 3. März 2010 14:19
von RHBaum
wie waere es mit einem (Q)timer, der dann nur alle X ms read aufruft ??
Er iss ja schon in nem eigenen thread (zumindest plant er das) ... Da waer der timer nur nen umweg ...
Ich wuerd eigentlich nichtblockend abrufen und den thread selber fuer das intervall schlafen legen (aehnlich sleep).
Aber dann wuerd er nicht mehr die volle aufloesung mitbekommen ( bzw nur wenn sein intervall kürzer iss als das vom joy treiber), was er aber expliziet ablehnt.
Da ich ned weiss warum er es so genau braucht ....
kann er nur selber testen, was seine systemlast an der stelle macht wenn er das ueber den signal/slot mechanismus schickt (toll generisch, aber recht inperformant).
Wenn der joy treiber selber nur alle 100ms pollt, wird er mit seiner loesung Null Probleme haben ...
Wenn der doch schneller daten holt ... muss er sich was anderes einfallen lassen.
Z.b. das was die joy daten so hochgranular braucht, zumindest anteilmaessig in den lesethread da verlagern und gleich dort abarbeiten. Entlastet vielleicht das mappen ueber threads auf ein ertraegliches Mass. weinn seine aufbereiteten daten deutlich weniger und seltener sind ...
Ciao ..
Verfasst: 3. März 2010 15:21
von Lord_Luncher
Also so wie ich das jetzt gelöst hab wird onChnageAxe nur dann aufgerufen wenn sich auch ein Achsen wert ändert.
Mein Sinn und Zweck wird sein einen Beschleunigungssensor ansatt des potentiometers im joystick zu bauen. daher brauch ich eine Lösung die eine möglichst schnelle reaktion auf eine Änderung zulässt.
Also wenn ich ein sleep einbaue und dann unblocking das ganze durchlaufe dann ist es selbst bei 1ms komischerweise zu langsam... ich weiss nicht ob der bei jedem Schleifendurchlauf nur einen Button bzw Achse abfragt oder so....
Wie ich das ganze mit dem QuadroCopter letztendlich umsetzen werde weiss ich noch nicht 100%ig aber ich denke sobald ich per USB ein paar günstige digitale outputs bekomme lässt sich drüber reden sich gedanken um die motorensteuerung zu machen
Aber ich bin denke ich schon mal auf der sicherren seite wenn ich versuche eine möglichst perfomace starke und gleichzeitig etwas bastel was kaum rechenleistung verbraucht.