#!python #Compass display app for NMEA 0183 HDG message testing #Exit the app by closing the graphic compass window #The Compass Widget code is borrowed from here: #https://wiki.python.org/moin/PyQt/Compass%20widget #If you use Anaconda Python 2.7 you will only need to install pyserial #from here: http://pyserial.sourceforge.net/ import sys, serial, threading, time from PyQt4.Qt import * def read_from_port(ser): global e global compass, label while not e.is_set(): reading = ser.readline() reading = reading.strip("\n") print reading ml = reading.split(",") if ( ml[0] == "$HCHDG" ): compass.setAngle(float(ml[1])) label.setText(ml[1]) print "Thread exiting" class CompassWidget(QWidget): angleChanged = pyqtSignal(float) def __init__(self, parent = None): QWidget.__init__(self, parent) self._angle = 0.0 self._margins = 10 self._pointText = {0: "N", 45: "NE", 90: "E", 135: "SE", 180: "S", 225: "SW", 270: "W", 315: "NW"} def paintEvent(self, event): painter = QPainter() painter.begin(self) painter.setRenderHint(QPainter.Antialiasing) painter.fillRect(event.rect(), self.palette().brush(QPalette.Window)) self.drawMarkings(painter) self.drawNeedle(painter) painter.end() def drawMarkings(self, painter): painter.save() painter.translate(self.width()/2, self.height()/2) scale = min((self.width() - self._margins)/120.0, (self.height() - self._margins)/120.0) painter.scale(scale, scale) font = QFont(self.font()) font.setPixelSize(10) metrics = QFontMetricsF(font) painter.setFont(font) painter.setPen(self.palette().color(QPalette.Shadow)) i = 0 while i < 360: if i % 45 == 0: painter.drawLine(0, -40, 0, -50) painter.drawText(-metrics.width(self._pointText[i])/2.0, -52, self._pointText[i]) else: painter.drawLine(0, -45, 0, -50) painter.rotate(15) i += 15 painter.restore() def drawNeedle(self, painter): painter.save() painter.translate(self.width()/2, self.height()/2) painter.rotate(self._angle) scale = min((self.width() - self._margins)/120.0, (self.height() - self._margins)/120.0) painter.scale(scale, scale) painter.setPen(QPen(Qt.NoPen)) painter.setBrush(self.palette().brush(QPalette.Shadow)) painter.drawPolygon( QPolygon([QPoint(-10, 0), QPoint(0, -45), QPoint(10, 0), QPoint(0, 45), QPoint(-10, 0)]) ) painter.setBrush(self.palette().brush(QPalette.Highlight)) painter.drawPolygon( QPolygon([QPoint(-5, -25), QPoint(0, -45), QPoint(5, -25), QPoint(0, -30), QPoint(-5, -25)]) ) painter.restore() def sizeHint(self): return QSize(150, 150) def angle(self): return self._angle @pyqtSlot(float) def setAngle(self, angle): if angle != self._angle: self._angle = angle self.angleChanged.emit(angle) self.update() angle = pyqtProperty(float, angle, setAngle) if __name__ == "__main__": port ='COM17' #you need to set this to match your own environment baud = 38400 serial_port =serial.Serial(port, baud) print serial_port i = 0 app = QApplication(sys.argv) window = QWidget() compass = CompassWidget() label = QLabel('0.0') label.setAlignment(Qt.AlignCenter) layout = QVBoxLayout() layout.addWidget(compass) layout.addWidget(label) window.setLayout(layout) window.show() e = threading.Event() thread = threading.Thread(target=read_from_port, args=(serial_port,)) thread.start() app.exec_() e.set() time.sleep(2) serial_port.close()