2014-05-08 3 views
0

architecturegraphique basé sur le relotissement ERO souscrit des données

J'ai un terrain. Et une courbe dans cette intrigue. J'ai un noeud dans le fichier et un abonné. Cet abonné s'abonne à certaines données flottantes en cours de publication. Chaque fois que des données sont publiées, je mets à jour la courbe en ajoutant le nouveau point de données à l'ensemble existant.

Problème

Le graphique est pas mis à jour correctement. Au fur et à mesure que les données arrivent à chaque seconde, l'interface graphique est suspendue et après un certain temps, l'interface graphique est interrompue en raison d'une erreur de segmentation.

code

def initUI(self): 

    # x11.XInitThreads() 

    # xlib.XInitThreads() 

    # initialising the window 

    QtGui.QWidget.__init__(self) 

    # self.setGeometry(300, 300, 160, 1000) 
    # self.setWindowTitle('Visualizer') 

    # main layout 

    self.layout = QtGui.QVBoxLayout(self) 

    # Creating the elements in this widget 

    a = QtGui.QLabel("Navigation", self) 

    a.setStyleSheet("QLabel{ background-color: white; color: black; font-size: 25px; }") 

    self.plot = Qwt.QwtPlot(self) 
    self.plot.setCanvasBackground(Qt.black) 
    self.plot.setAxisTitle(Qwt.QwtPlot.xBottom, 'Time') 
    self.plot.setAxisScale(Qwt.QwtPlot.xBottom, 0, 10, 1) 
    self.plot.setAxisTitle(Qwt.QwtPlot.yLeft, 'Temperature') 
    self.plot.setAxisScale(Qwt.QwtPlot.yLeft, 0, 250, 40) 
    self.plot.replot() 

    self.curve = Qwt.QwtPlotCurve('') 
    self.curve.setRenderHint(Qwt.QwtPlotItem.RenderAntialiased) 
    pen = QPen(QColor('limegreen')) 
    pen.setWidth(2) 
    self.curve.setPen(pen) 
    self.curve.attach(self.plot) 

    self.layout.addWidget(a) 
    self.layout.addWidget(self.plot) 

def listener(self):  

    rospy.init_node('listener', anonymous=True) 

    rospy.Subscriber(TOPIC_NAME, String, self.callback) 

def callback(self, data): 

    self.xData.append(self.counter + 1) 
    self.yData.append(int(str(data.data))) 
    self.counter += 1 

    self.curve.setData(self.xData, self.yData) 
    self.plot.replot() 

appel de ces fonctions: -

self.listener() 
self.initUI() 

Une fois que l'auditeur est appelé, l'abonné est automatiquement associé à la fonction de rappel. La fonction de rappel examine les nouvelles données, les ajoute à l'axe des ordonnées, puis recompose le graphique.

Erreur

Je reçois cette erreur chaque fois qu'un nouveau point de données est publié: -

QCoreApplication::sendPostedEvents: Cannot send posted events for objects in another thread 
QPixmap: It is not safe to use pixmaps outside the GUI thread 
QPixmap: It is not safe to use pixmaps outside the GUI thread 
QPainter::begin: Paint device returned engine == 0, type: 2 
QPainter::setPen: Painter not active 
QPainter::setBrush: Painter not active 
QPainter::drawRects: Painter not active 
QPainter::begin: Paint device returned engine == 0, type: 2 
QPainter::translate: Painter not active 
QPainter::save: Painter not active 
QPainter::setRenderHint: Painter must be active to set rendering hints 
QPainter::save: Painter not active 
QPainter::setPen: Painter not active 
QPainter::restore: Unbalanced save/restore 
QPainter::restore: Unbalanced save/restore 
QPainter::end: Painter not active, aborted 

Je ne comprends pas cette erreur.

A propos de l'éditeur

ERO suit le modèle Publisher-Subscribe. J'ai déjà créé un noeud qui publie un entier aléatoire. Cet entier devrait être tracé sur le graphique.

Spécifications

Ubuntu 12.04 
ROS Hydro 
PyQt4 
Qwt5 

Répondre

1

Votre méthode callback est en cours d'exécution dans le fil. Vous ne pouvez pas mettre à jour les objets de l'interface graphique Qt à partir d'un autre thread. C'est pourquoi vous voyez des erreurs et obtenez des erreurs de segmentation.

Les solutions sont:

  • Dans le rappel, ajouter les données à une liste. Utilisez un QTimer a commencé à partir du thread principal de vérifier périodiquement la liste des mises à jour et Replot le graphique (pas une des solutions idéales, mais probablement faire le travail)

  • Dans le rappel, placez les données dans un python Queue.Queue(). Avoir un QThread bloquer à la lecture de cette file d'attente et émettre un signal qt (avec les données qu'il contient) chaque fois que quelque chose est lu à partir du Queue. Connectez une méthode dans votre thread principal à ce signal qt. Votre méthode dans le thread principal obtient ainsi les données et peut mettre à jour le graphique à partir du thread principal.

Voici un tas d'autres questions débordement de pile qui font quelque chose de similaire (envoyer des données à partir d'un fil dans le thread principal qt pour éviter des erreurs de segmentation) ou seront utiles lors de plonger dans les applications PyQt multithread:

Questions connexes