#!/usr/bin/env python # # Copyright (C) 2017 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # A simple GUI to remotely actuate the Vehicle HAL via the eumalator import argparse import sys from threading import Thread from PyQt5 import QtCore from PyQt5 import QtWidgets import VehicleHalProto_pb2 from vhal_emulator import Vhal import vhal_consts_2_0 as c # Define a simple thread that receives messages from a vhal object (v) and prints them def rxThread(v): while(1): msg = v.rxMsg() if (msg.msg_type == VehicleHalProto_pb2.SET_PROPERTY_RESP): if msg.status == 0: print('Success (%s)' % msg.status) else: print('Error (%s)' % msg.status) else: print(msg) # Main window setup def window(): app = QtWidgets.QApplication(sys.argv) dialog = QtWidgets.QDialog() dialog.setWindowTitle('VHal Driver') dialog.setGeometry(100, 100, 200, 50) topLevelLayout = QtWidgets.QHBoxLayout() dialog.setLayout(topLevelLayout) shiftLayout = QtWidgets.QVBoxLayout() topLevelLayout.addLayout(shiftLayout) gearTitle = QtWidgets.QLabel(dialog) gearTitle.setText('Gear Shift') shiftLayout.addWidget(gearTitle) gearDisplay = QtWidgets.QLabel(dialog) shiftLayout.addWidget(gearDisplay) slider = QtWidgets.QSlider(QtCore.Qt.Vertical) slider.setMinimum(0) slider.setMaximum(2) slider.setInvertedAppearance(True) slider.valueChanged.connect(lambda:sliderMove(slider, gearDisplay)) shiftLayout.addWidget(slider) sliderMove(slider, gearDisplay) buttonLayout = QtWidgets.QVBoxLayout() topLevelLayout.addLayout(buttonLayout) signalButtonGroup = QtWidgets.QButtonGroup() bNoSignal = QtWidgets.QPushButton('None') bNoSignal.setCheckable(True) bNoSignal.setChecked(True) buttonLayout.addWidget(bNoSignal) signalButtonGroup.addButton(bNoSignal) bHazards = QtWidgets.QPushButton('Hazards') bHazards.setCheckable(True) buttonLayout.addWidget(bHazards) signalButtonGroup.addButton(bHazards) bLeft = QtWidgets.QPushButton('Left') bLeft.setCheckable(True) buttonLayout.addWidget(bLeft) signalButtonGroup.addButton(bLeft) bRight = QtWidgets.QPushButton('Right') bRight.setCheckable(True) buttonLayout.addWidget(bRight) signalButtonGroup.addButton(bRight) signalButtonGroup.buttonClicked.connect(lambda: onSignalClicked(signalButtonGroup)) dialog.show() sys.exit(app.exec_()) def onSignalClicked(group): print('signal ' + group.checkedButton().text() + ' is active') try: vhal.setProperty(c.VEHICLEPROPERTY_TURN_SIGNAL_STATE, 0, group.checkedId()) except: print('Ignoring error setting property 0x{:08X}'.format(c.VEHICLEPROPERTY_TURN_SIGNAL_STATE)) def sliderMove(slider, gearDisplay): if slider.value() == 0: gearName = 'park' vhal.setProperty(c.VEHICLEPROPERTY_GEAR_SELECTION, 0, c.VEHICLEGEAR_GEAR_PARK) elif slider.value() == 1: gearName = 'reverse' vhal.setProperty(c.VEHICLEPROPERTY_GEAR_SELECTION, 0, c.VEHICLEGEAR_GEAR_REVERSE) elif slider.value() == 2: gearName = 'drive' vhal.setProperty(c.VEHICLEPROPERTY_GEAR_SELECTION, 0, c.VEHICLEGEAR_GEAR_DRIVE) else: gearName = 'UNK' print('slider %s requested %s = %s' % (slider.objectName(), slider.value(), gearName)) gearDisplay.setText(gearName) if __name__ == '__main__': parser = argparse.ArgumentParser(description='Vehicle HAL Driver UI') parser.add_argument('--serial', '-s', action='store', dest='serial', default=None, required=False, help='Select which device to connect to') args = parser.parse_args() print('Starting VHal driver GUI') vhal = Vhal(c.vhal_types_2_0, device=args.serial) # Start a receive thread to consume any replies from the vhal print('Starting receiver thread') rx = Thread(target=rxThread, args=(vhal,)) rx.setDaemon(True) rx.start() # Put the car in park so we start in a known state (consistent with the GUI default state) vhal.setProperty(c.VEHICLEPROPERTY_GEAR_SELECTION, 0, c.VEHICLEGEAR_GEAR_PARK) # Start the main UI -- never returns window()