diff --git a/.gitignore b/.gitignore index dec3952..02a1a5f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ build/ devel/ +qt-gui.workspace.user +qt-gui.workspace.user.* +.autosave - +.vscode/ diff --git a/qt-gui.workspace.user b/qt-gui.workspace.user index 0597703..f79686e 100644 --- a/qt-gui.workspace.user +++ b/qt-gui.workspace.user @@ -1,10 +1,10 @@ - + EnvironmentId - {de92f17b-cfa5-4e5f-be58-539386c90a02} + {87d6e2af-d768-4e25-a852-033ba8fb5a4a} ProjectExplorer.Project.ActiveTarget @@ -54,21 +54,33 @@ ProjectExplorer.Project.PluginSettings - + + + ProjectExplorer.Project.Target.0 Desktop Desktop - {8789de66-e1cb-46cc-926e-16dff52b0033} + {f4cc9e8d-34cc-4663-9466-ea6b16c693b9} 0 0 0 - 0 + + true + CatkinMake Step + + ROSProjectManager.ROSCatkinMakeStep + + + + 0 + + 1 Build ProjectExplorer.BuildSteps.Build @@ -81,11 +93,28 @@ 2 false - + + CMAKE_PREFIX_PATH=/home/ros/owr-qtgui/devel:/home/ros/owr_software/rover/devel:/home/ros/ros_deps/devel:/opt/ros/kinetic + LD_LIBRARY_PATH=/home/ros/owr-qtgui/devel/lib:/home/ros/owr_software/rover/devel/lib:/home/ros/ros_deps/devel/lib:/opt/ros/kinetic/lib:/opt/ros/kinetic/lib/x86_64-linux-gnu:/opt/qt57/lib/x86_64-linux-gnu:/opt/qt57/lib + PATH=/opt/ros/kinetic/bin:/opt/qt57/bin:/home/ros/bin:/home/ros/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin + PKG_CONFIG_PATH=/home/ros/owr-qtgui/devel/lib/pkgconfig:/home/ros/owr_software/rover/devel/lib/pkgconfig:/home/ros/ros_deps/devel/lib/pkgconfig:/opt/ros/kinetic/lib/pkgconfig:/opt/ros/kinetic/lib/x86_64-linux-gnu/pkgconfig:/opt/qt57/lib/pkgconfig + PWD=/home/ros/owr-qtgui + PYTHONPATH=/home/ros/owr-qtgui/devel/lib/python2.7/dist-packages:/home/ros/owr_software/rover/devel/lib/python2.7/dist-packages:/home/ros/ros_deps/devel/lib/python2.7/dist-packages:/opt/ros/kinetic/lib/python2.7/dist-packages + ROSLISP_PACKAGE_DIRECTORIES=/home/ros/owr-qtgui/devel/share/common-lisp:/home/ros/owr_software/rover/devel/share/common-lisp:/home/ros/ros_deps/devel/share/common-lisp + ROS_DISTRO=kinetic + ROS_ETC_DIR=/opt/ros/kinetic/etc/ros + ROS_MASTER_URI=http://localhost:11311 + ROS_PACKAGE_PATH=/home/ros/owr-qtgui/src:/home/ros/owr_software/rover/src:/home/ros/ros_deps/src:/opt/ros/kinetic/share + ROS_ROOT=/opt/ros/kinetic/share/ros + ROS_VERSION=1 + SHLVL=3 + TERM=xterm + _=/usr/bin/env + Debug Debug ROSProjectManager.ROSBuildConfiguration - 66064112 + 0 0 @@ -108,7 +137,7 @@ Release Release ROSProjectManager.ROSBuildConfiguration - 66064112 + 48753808 1 @@ -131,7 +160,7 @@ Release with Debug Information Release with Debug Information ROSProjectManager.ROSBuildConfiguration - 66064112 + 48753808 2 @@ -154,7 +183,7 @@ Minimum Size Release Minimum Size Release ROSProjectManager.ROSBuildConfiguration - 66064112 + 48753808 3 4 diff --git a/qt-gui.workspace.user.c4b94e6 b/qt-gui.workspace.user.c4b94e6 deleted file mode 100644 index 9c84531..0000000 --- a/qt-gui.workspace.user.c4b94e6 +++ /dev/null @@ -1,474 +0,0 @@ - - - - - - EnvironmentId - {c4b94e68-9795-4497-900f-d14295903913} - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - false - true - - Cpp - - ROSProject.CppCodeStyle - - - - QmlJS - - QmlJSGlobal - - - 2 - UTF-8 - false - 4 - false - 80 - true - true - 1 - true - false - 0 - true - true - 0 - 8 - true - 1 - true - true - true - false - - - - ProjectExplorer.Project.PluginSettings - - - - ProjectExplorer.Project.Target.0 - - Desktop - Desktop - {757774ac-697e-4d58-91eb-6b232c21b800} - 0 - 0 - 0 - - /home/ros/qt-gui/build - - - true - catkin_make - - ROSProjectManager.ROSMakeStep - - all - - false - - - - 1 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - catkin_make - - ROSProjectManager.ROSMakeStep - - clean - - true - - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - CMAKE_PREFIX_PATH=/home/ros/qt-gui/devel:/opt/ros/kinetic - LD_LIBRARY_PATH=/home/ros/qt-gui/devel/lib:/opt/ros/kinetic/lib:/opt/qt57/lib/x86_64-linux-gnu:/opt/qt57/lib - PATH=/opt/ros/kinetic/bin:/opt/qt57/bin:/home/ros/bin:/home/ros/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin - PKG_CONFIG_PATH=/opt/ros/kinetic/lib/pkgconfig:/opt/qt57/lib/pkgconfig - PWD=/home/ros/qt-gui - PYTHONPATH=/opt/ros/kinetic/lib/python2.7/dist-packages - ROSLISP_PACKAGE_DIRECTORIES=/home/ros/qt-gui/devel/share/common-lisp - ROS_DISTRO=kinetic - ROS_ETC_DIR=/opt/ros/kinetic/etc/ros - ROS_MASTER_URI=http://localhost:11311 - ROS_PACKAGE_PATH=/home/ros/qt-gui/src:/opt/ros/kinetic/share - ROS_ROOT=/opt/ros/kinetic/share/ros - SHLVL=4 - _=/usr/bin/env - - Default - Default - ROSProjectManager.ROSBuildConfiguration - kinetic - - - - /home/ros/qt-gui/build - - - true - catkin_make - - ROSProjectManager.ROSMakeStep - - all - - false - - - - 1 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - catkin_make - - ROSProjectManager.ROSMakeStep - - clean - - true - - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - CMAKE_PREFIX_PATH=/home/ros/qt-gui/devel:/opt/ros/kinetic - LD_LIBRARY_PATH=/home/ros/qt-gui/devel/lib:/opt/ros/kinetic/lib:/opt/qt57/lib/x86_64-linux-gnu:/opt/qt57/lib - PATH=/opt/ros/kinetic/bin:/opt/qt57/bin:/home/ros/bin:/home/ros/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin - PKG_CONFIG_PATH=/opt/ros/kinetic/lib/pkgconfig:/opt/qt57/lib/pkgconfig - PWD=/home/ros/qt-gui - PYTHONPATH=/opt/ros/kinetic/lib/python2.7/dist-packages - ROSLISP_PACKAGE_DIRECTORIES=/home/ros/qt-gui/devel/share/common-lisp - ROS_DISTRO=kinetic - ROS_ETC_DIR=/opt/ros/kinetic/etc/ros - ROS_MASTER_URI=http://localhost:11311 - ROS_PACKAGE_PATH=/home/ros/qt-gui/src:/opt/ros/kinetic/share - ROS_ROOT=/opt/ros/kinetic/share/ros - SHLVL=5 - _=/usr/bin/env - - Debug - Debug - ROSProjectManager.ROSBuildConfiguration - - -DCMAKE_BUILD_TYPE=Debug - - - /home/ros/qt-gui/build - - - true - catkin_make - - ROSProjectManager.ROSMakeStep - - all - - false - - - - 1 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - catkin_make - - ROSProjectManager.ROSMakeStep - - clean - - true - - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - CMAKE_PREFIX_PATH=/home/ros/qt-gui/devel:/opt/ros/kinetic - LD_LIBRARY_PATH=/home/ros/qt-gui/devel/lib:/opt/ros/kinetic/lib:/opt/qt57/lib/x86_64-linux-gnu:/opt/qt57/lib - PATH=/opt/ros/kinetic/bin:/opt/qt57/bin:/home/ros/bin:/home/ros/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin - PKG_CONFIG_PATH=/opt/ros/kinetic/lib/pkgconfig:/opt/qt57/lib/pkgconfig - PWD=/home/ros/qt-gui - PYTHONPATH=/opt/ros/kinetic/lib/python2.7/dist-packages - ROSLISP_PACKAGE_DIRECTORIES=/home/ros/qt-gui/devel/share/common-lisp - ROS_DISTRO=kinetic - ROS_ETC_DIR=/opt/ros/kinetic/etc/ros - ROS_MASTER_URI=http://localhost:11311 - ROS_PACKAGE_PATH=/home/ros/qt-gui/src:/opt/ros/kinetic/share - ROS_ROOT=/opt/ros/kinetic/share/ros - SHLVL=6 - _=/usr/bin/env - - Release - Release - ROSProjectManager.ROSBuildConfiguration - - -DCMAKE_BUILD_TYPE=Release - - - /home/ros/qt-gui/build - - - true - catkin_make - - ROSProjectManager.ROSMakeStep - - all - - false - - - - 1 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - catkin_make - - ROSProjectManager.ROSMakeStep - - clean - - true - - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - CMAKE_PREFIX_PATH=/home/ros/qt-gui/devel:/opt/ros/kinetic - LD_LIBRARY_PATH=/home/ros/qt-gui/devel/lib:/opt/ros/kinetic/lib:/opt/qt57/lib/x86_64-linux-gnu:/opt/qt57/lib - PATH=/opt/ros/kinetic/bin:/opt/qt57/bin:/home/ros/bin:/home/ros/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin - PKG_CONFIG_PATH=/opt/ros/kinetic/lib/pkgconfig:/opt/qt57/lib/pkgconfig - PWD=/home/ros/qt-gui - PYTHONPATH=/opt/ros/kinetic/lib/python2.7/dist-packages - ROSLISP_PACKAGE_DIRECTORIES=/home/ros/qt-gui/devel/share/common-lisp - ROS_DISTRO=kinetic - ROS_ETC_DIR=/opt/ros/kinetic/etc/ros - ROS_MASTER_URI=http://localhost:11311 - ROS_PACKAGE_PATH=/home/ros/qt-gui/src:/opt/ros/kinetic/share - ROS_ROOT=/opt/ros/kinetic/share/ros - SHLVL=7 - _=/usr/bin/env - - Release with Debug Information - Release with Debug Information - ROSProjectManager.ROSBuildConfiguration - - -DCMAKE_BUILD_TYPE=RelWithDebInfo - - - /home/ros/qt-gui/build - - - true - catkin_make - - ROSProjectManager.ROSMakeStep - - all - - false - - - - 1 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - catkin_make - - ROSProjectManager.ROSMakeStep - - clean - - true - - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - CMAKE_PREFIX_PATH=/home/ros/qt-gui/devel:/opt/ros/kinetic - LD_LIBRARY_PATH=/home/ros/qt-gui/devel/lib:/opt/ros/kinetic/lib:/opt/qt57/lib/x86_64-linux-gnu:/opt/qt57/lib - PATH=/opt/ros/kinetic/bin:/opt/qt57/bin:/home/ros/bin:/home/ros/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin - PKG_CONFIG_PATH=/opt/ros/kinetic/lib/pkgconfig:/opt/qt57/lib/pkgconfig - PWD=/home/ros/qt-gui - PYTHONPATH=/opt/ros/kinetic/lib/python2.7/dist-packages - ROSLISP_PACKAGE_DIRECTORIES=/home/ros/qt-gui/devel/share/common-lisp - ROS_DISTRO=kinetic - ROS_ETC_DIR=/opt/ros/kinetic/etc/ros - ROS_MASTER_URI=http://localhost:11311 - ROS_PACKAGE_PATH=/home/ros/qt-gui/src:/opt/ros/kinetic/share - ROS_ROOT=/opt/ros/kinetic/share/ros - SHLVL=8 - _=/usr/bin/env - - Minimum Size Release - Minimum Size Release - ROSProjectManager.ROSBuildConfiguration - - -DCMAKE_BUILD_TYPE=MinSizeRel - - 5 - - - 0 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - Deploy locally - - ProjectExplorer.DefaultDeployConfiguration - - 1 - - - false - false - 1000 - - true - - false - false - false - false - true - 0.01 - 10 - true - 1 - 25 - - 1 - true - false - true - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - - ROS Run Configuration - ROSProjectManager.ROSRunConfiguration - - Run - - ROSProjectManager.ROSRunConfiguration.RunStepList - - - - ROSProjectManager.ROSRunStep - true - - rosrun - gui - gui - - 1 - - 3768 - false - true - false - false - true - - 1 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.FileVersion - 18 - - - Version - 18 - - diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 4b94de3..526dc55 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -10,7 +10,7 @@ project(gui) ############################################################################## # qt_build provides the qt cmake glue, roscpp the comms for a default talker -find_package(catkin REQUIRED COMPONENTS qt_build roscpp sensor_msgs image_transport ros_video_components) +find_package(catkin REQUIRED COMPONENTS qt_build roscpp sensor_msgs image_transport ros_video_components owr_messages) set(QML_IMPORT_PATH "${QML_IMPORT_PATH};${CATKIN_GLOBAL_LIB_DESTINATION}" ) set(QML_IMPORT_PATH2 "${QML_IMPORT_PATH};${CATKIN_GLOBAL_LIB_DESTINATION}" ) include_directories(${catkin_INCLUDE_DIRS}) @@ -33,6 +33,7 @@ find_package(Qt5 COMPONENTS Core Gui Qml Quick REQUIRED) ############################################################################## file(GLOB QT_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} resources/*.qrc) +file(GLOB QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} resources/*.qml) file(GLOB_RECURSE QT_MOC RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} FOLLOW_SYMLINKS include/gui/*.hpp) QT5_ADD_RESOURCES(QT_RESOURCES_CPP ${QT_RESOURCES}) @@ -49,6 +50,7 @@ file(GLOB_RECURSE QT_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} FOLLOW_SYMLINK ############################################################################## add_executable(gui ${QT_SOURCES} ${QT_RESOURCES_CPP} ${QT_FORMS_HPP} ${QT_MOC_HPP}) +add_dependencies(gui ${QML_FILES}) qt5_use_modules(gui Quick Core) target_link_libraries(gui ${QT_LIBRARIES} ${catkin_LIBRARIES}) target_include_directories(gui PUBLIC include ${catkin_INCLUDE_DIRS}) diff --git a/src/gui/include/gui/main_application.hpp b/src/gui/include/gui/main_application.hpp index 78e62c4..8a79608 100644 --- a/src/gui/include/gui/main_application.hpp +++ b/src/gui/include/gui/main_application.hpp @@ -15,6 +15,7 @@ class Main_Application : public QQmlApplicationEngine { // this defines a slot that will be called when the application is idle public slots: void main_loop(); + void handle(QString str); private: ros::NodeHandle nh; diff --git a/src/gui/package.xml b/src/gui/package.xml index 9f59592..1510a7e 100644 --- a/src/gui/package.xml +++ b/src/gui/package.xml @@ -54,7 +54,6 @@ roscpp libqt4-dev - diff --git a/src/gui/resources/main_window.qml b/src/gui/resources/main_window.qml index 94db240..c75bad9 100644 --- a/src/gui/resources/main_window.qml +++ b/src/gui/resources/main_window.qml @@ -1,4 +1,4 @@ -import QtQuick 2.0 +import QtQuick 2.5 import QtQuick.Window 2.2 import bluesat.owr 1.0 @@ -12,36 +12,44 @@ Window { visible: true minimumHeight: 600 minimumWidth: 600 - Image { id: logo source: "/images/bluesatLogo.png" - width: 244 - height: 116 - anchors.horizontalCenter: parent.horizontalCenter + anchors.right: parent.left + anchors.rightMargin: -200 + anchors.left: parent.left + anchors.leftMargin: 0 + z: 100 + anchors.bottom: camera_switching_container.top + anchors.bottomMargin: -54 + anchors.topMargin: 0 + opacity: 0.5 + anchors.top: parent.top fillMode: Image.PreserveAspectFit } - Item { id: video_pane - x: 198 - width: 245 - anchors.horizontalCenterOffset: 1 - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: logo.bottom - anchors.topMargin: 75 + z: -1 + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.top: parent.top + anchors.topMargin: 0 anchors.bottom: parent.bottom - anchors.bottomMargin: 8 + anchors.bottomMargin: 0 ROSVideoComponent { // @disable-check M16 objectName: "videoStream" id: videoStream - // @disable-check M16` - anchors.bottom: parent.bottom // @disable-check M16 - anchors.bottomMargin: 0 + fillColor: qsTr("#000000") + // @disable-check M16 + anchors.fill: parent + // @disable-check M16 + anchors.bottom: parent.bottom // @disable-check M16 anchors.top: parent.top // @disable-check M16 @@ -49,31 +57,29 @@ Window { // @disable-check M16 anchors.right: parent.right // @disable-check M16 - topic: topic.text + topic: camera_switching.camera_topic + Text { + id: text1 + text: videoStream.topic + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: 10 + font.pixelSize: 12 + } } } - TextInput { - id: topic - x: 40 - y: 335 - width: 80 - height: 20 - text: qsTr("/cam0") - font.pixelSize: 12 - } - - Item { id: signal_strength_container + z: 4 anchors.right: parent.right anchors.rightMargin: 0 anchors.top: parent.top - anchors.topMargin: 85 - anchors.left: logo.right - anchors.leftMargin: 103 - anchors.bottom: video_pane.top - anchors.bottomMargin: 16 + anchors.topMargin: 0 + anchors.left: parent.right + anchors.leftMargin: -172 + anchors.bottom: parent.top + anchors.bottomMargin: -100 ROSSignalStrength { // @disable-check M16 objectName: "signal_strength" @@ -91,17 +97,80 @@ Window { // @disable-check M16 topic: qsTr("/rover/signal") } - } + Item{ + id: camera_switching_container + width: 50 + height: 660 + anchors.topMargin: 0 + anchors.leftMargin: 0 + anchors.rightMargin: -800 + anchors.bottom: parent.top + anchors.right: parent.left + anchors.left: parent.left + anchors.top: parent.top + anchors.bottomMargin: -800 + ROSCameraSwitching { + // @disable-check M16 + objectName: "camera_switching" + id: camera_switching + // @disable-check M16 + anchors.bottom: parent.bottom + // @disable-check M16 + anchors.bottomMargin: 0 + // @disable-check M16 + anchors.top: parent.top + // @disable-check M16 + anchors.topMargin: 0 + // @disable-check M16 + anchors.left: parent.left + // @disable-check M16 + anchors.right: parent.right + // @disable-check M16 + topic: qsTr("/owr/control/availableFeeds") + //focus:true; + Shortcut { + sequence: "0" + onActivated: camera_switching.camera_number = 0 + } + Shortcut { + sequence: "1" + onActivated: camera_switching.camera_number = 1 + } + Shortcut { + sequence: "2" + onActivated: camera_switching.camera_number = 2 + } + Shortcut { + sequence: "3" + onActivated: camera_switching.camera_number = 3 + } + Shortcut { + sequence: "4" + onActivated: camera_switching.camera_number = 4 + } + Shortcut { + sequence: "5" + onActivated: camera_switching.camera_number = 5 + } + Shortcut { + sequence: "6" + onActivated: camera_switching.camera_number = 6 + } + Shortcut { + sequence: "7" + onActivated: camera_switching.camera_number = 7 + } -//below is the task for SV-13 + } + } Item { - id: signal_strength_container_1 + id: driving_mode_switching_container anchors.bottomMargin: -94 anchors.leftMargin: -494 anchors.topMargin: 164 @@ -126,10 +195,9 @@ Window { anchors.right: parent.right // @disable-check M16 topic: qsTr("/rover/driving_mode_switching") + } - - - + } Rectangle{ x:80 @@ -138,10 +206,7 @@ Window { height:20 focus: true; Keys.enabled: true; - Keys.forwardTo: [box_front,box_crab,box_four]; - - - + Keys.forwardTo: [box_front,box_crab,box_four,ROSTimer]; //rectangle for front wheel steering Rectangle{ @@ -159,11 +224,8 @@ Window { font.pointSize:12 font.bold:true } - - } - //rectangle for crab wheel steering Rectangle{ x:320 @@ -180,79 +242,133 @@ Window { font.pointSize:12 font.bold:true } - - } + //rectangle for four wheel steering Rectangle{ - x:440 - y:180 - width:120 - height:20 - id: box_four - border.color: "black" - color:"white" - Text { - - text: "four" - anchors.horizontalCenter:parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - font.pointSize:12 - font.bold:true - } - + x:440 + y:180 + width:120 + height:20 + id: box_four + border.color: "black" + color:"white" + Text { + text: "four" + anchors.horizontalCenter:parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + font.pointSize:12 + font.bold:true + } + // @disable-check M16 + //focus: true + + //key press response + Keys.onPressed: { + + + switch(event.key){ + //if A is pressed + //change color to red + + case Qt.Key_A: + box_front.color = "red" + box_crab.color = "white"; + box_four.color="white" + driving_mode_switching.sendmessage(); + break; + + //if r is pressed + //change color to red + case Qt.Key_S: + box_front.color = "white" + box_crab.color = "red"; + box_four.color="white" + driving_mode_switching.sendmessage(); + break; + + case Qt.Key_D: + box_front.color="white" + box_crab.color = "white" + box_four.color = "red" + driving_mode_switching.sendmessage(); + break; + default: + return; + } + event.accepted = true; + //Keys.enable = false; + } } + } + DriveModeWidget { + id: drive_mode + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: signal_strength_container.left + anchors.leftMargin: 0 + anchors.top: signal_strength_container.bottom + anchors.topMargin: 10 + } + VoltageMeterWidget { + id: voltage_meter + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: drive_mode.left + anchors.leftMargin: 0 + anchors.top: drive_mode.bottom + anchors.topMargin: 30 + } - //key press response - Keys.onPressed: { - - - switch(event.key){ - //if A is pressed - //change color to red - - case Qt.Key_A: - box_front.color = "red" - box_crab.color = "white"; - box_four.color="white" - driving_mode_switching.sendmessage(); - break; - - //if r is pressed - //change color to red - case Qt.Key_S: - box_front.color = "white" - box_crab.color = "red"; - box_four.color="white" - driving_mode_switching.sendmessage(); - break; - - case Qt.Key_D: - box_front.color="white" - box_crab.color = "white" - box_four.color = "red" - driving_mode_switching.sendmessage(); - break; - default: - return; - } - event.accepted = true; - - } + ROSTimer { + // @disable-check M16 + objectName: "timerDisplay" + id: timerDisplay + // @disable-check M16 + anchors.bottom: video_pane.bottom + // @disable-check M16 + anchors.bottomMargin: 5 + // @disable-check M16 + anchors.right: video_pane.right + // @disable-check M16 + anchors.rightMargin: 5 + // @disable-check M16 + focus:true; + // @disable-check M16 + width: 160 + // @disable-check M16 + height: 80 } + ROSJoystickListener { + // @disable-check M16 + objectName: "bot_joystick" + // @disable-check M16 + topic: "/joy" + // @disable-check M16 + onButton_down: { + var start_number = camera_switching.camera_number; + + // handle the case where no camera is selected + if(start_number < 0) { + start_number = 0; + } + if(button === 4) { // Left Buffer + camera_switching.camera_number = (start_number - 1) % 8; + } else if(button === 5) { // Right Buffer + camera_switching.camera_number = (start_number + 1) % 8; + } } - } diff --git a/src/gui/src/main_application.cpp b/src/gui/src/main_application.cpp index 7af9853..6619968 100644 --- a/src/gui/src/main_application.cpp +++ b/src/gui/src/main_application.cpp @@ -1,41 +1,72 @@ #include +#include #include "ros_video_components/ros_video_component.hpp" #include "ros_video_components/ros_signal_strength.hpp" #include "ros_video_components/ros_driving_mode_switching.hpp" +#include "ros_video_components/ros_voltage_meter.hpp" +#include "ros_video_components/ros_camera_switching.hpp" +#include "ros_video_components/ros_timer.hpp" +#include "ros_video_components/ros_joystick_listener.hpp" +#include "ros_video_components/ros_drive_mode.hpp" #include "gui/main_application.hpp" - - -Main_Application::Main_Application() { - -} +Main_Application::Main_Application() {} void Main_Application::run() { - qmlRegisterType("bluesat.owr", 1, 0, "ROSVideoComponent"); qmlRegisterType("bluesat.owr", 1, 0, "ROSSignalStrength"); qmlRegisterType("bluesat.owr", 1, 0, "ROSDrivingModeSwitching"); - + qmlRegisterType("bluesat.owr", 1, 0, "ROSVoltageMeter"); + qmlRegisterType("bluesat.owr", 1, 0, "ROSCameraSwitching"); + qmlRegisterType("bluesat.owr", 1, 0, "ROSTimer"); + qmlRegisterType("bluesat.owr", 1, 0, "ROSJoystickListener"); + qmlRegisterType("bluesat.owr", 1, 0, "ROSDriveMode"); // this loads the qml file we are about to create this->load(QUrl(QStringLiteral("qrc:/main_window.qml"))); // Setup a timer to get the application's idle loop - QTimer * timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(main_loop())); - timer->start(0); + QTimer * timer_idle = new QTimer(this); + connect(timer_idle, SIGNAL(timeout()), this, SLOT(main_loop())); + timer_idle->start(0); // setup the video component + ROS_Video_Component * video = this->rootObjects()[0]->findChild(QString("videoStream")); video->setup(&nh); + ROS_Signal_Strength * signal_strength = this->rootObjects()[0]->findChild(QString("signal_strength")); signal_strength->setup(&nh); + ROS_Driving_Mode_Switching* driving_mode_switching = this->rootObjects()[0]->findChild(QString("driving_mode_switching")); driving_mode_switching ->setup(&nh); + + ROS_Voltage_Meter * voltage_meter = this->rootObjects()[0]->findChild(QString("voltage_meter")); + voltage_meter->setup(&nh); + + ROS_Camera_Switching * camera_switching = this->rootObjects()[0]->findChild(QString("camera_switching")); + camera_switching->setup(&nh); + + Ros_Joystick_Listener * bot_joystick = this->rootObjects()[0]->findChild(QString("bot_joystick")); + bot_joystick->setup(&nh); + + Ros_Drive_Mode * drive_mode = this->rootObjects()[0]->findChild(QString("drive_mode")); + drive_mode->setup(&nh); + + // setup the timer + ROSTimer * stopwatch = this->rootObjects()[0]->findChild(QString("timerDisplay")); + // the following code section is for debugging + + if (stopwatch != NULL) { + connect(stopwatch, SIGNAL(valueChanged(QString)), this, SLOT(handle(QString))); + } + } void Main_Application::main_loop() { - ros::spinOnce(); +} +void Main_Application::handle(QString str) { + qDebug() << str; } diff --git a/src/owr_messages/CMakeLists.txt b/src/owr_messages/CMakeLists.txt new file mode 100644 index 0000000..890c1cf --- /dev/null +++ b/src/owr_messages/CMakeLists.txt @@ -0,0 +1,169 @@ +cmake_minimum_required(VERSION 2.8.3) +project(owr_messages) + +## Find catkin macros and libraries +## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) +## is used, also find other catkin packages +find_package(catkin REQUIRED COMPONENTS + message_runtime + message_generation + roscpp + rospy + sensor_msgs + std_msgs + geometry_msgs +) + +## System dependencies are found with CMake's conventions +# find_package(Boost REQUIRED COMPONENTS system) + + +## Uncomment this if the package has a setup.py. This macro ensures +## modules and global scripts declared therein get installed +## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html +# catkin_python_setup() + +################################################ +## Declare ROS messages, services and actions ## +################################################ + +## To declare and build messages, services or actions from within this +## package, follow these steps: +## * Let MSG_DEP_SET be the set of packages whose message types you use in +## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). +## * In the file package.xml: +## * add a build_depend and a run_depend tag for each package in MSG_DEP_SET +## * If MSG_DEP_SET isn't empty the following dependencies might have been +## pulled in transitively but can be declared for certainty nonetheless: +## * add a build_depend tag for "message_generation" +## * add a run_depend tag for "message_runtime" +## * In this file (CMakeLists.txt): +## * add "message_generation" and every package in MSG_DEP_SET to +## find_package(catkin REQUIRED COMPONENTS ...) +## * add "message_runtime" and every package in MSG_DEP_SET to +## catkin_package(CATKIN_DEPENDS ...) +## * uncomment the add_*_files sections below as needed +## and list every .msg/.srv/.action file to be processed +## * uncomment the generate_messages entry below +## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) + +## Generate messages in the 'msg' folder + add_message_files( + FILES + activeCameras.msg + stream.msg + ) + +## Generate services in the 'srv' folder +# add_service_files( +# FILES +# Service1.srv +# Service2.srv +# ) + +## Generate actions in the 'action' folder +# add_action_files( +# FILES +# Action1.action +# Action2.action +# ) + +## Generate added messages and services with any dependencies listed here + generate_messages( + DEPENDENCIES + sensor_msgs + std_msgs + geometry_msgs + ) + +################################### +## catkin specific configuration ## +################################### +## The catkin_package macro generates cmake config files for your package +## Declare things to be passed to dependent projects +## INCLUDE_DIRS: uncomment this if you package contains header files +## LIBRARIES: libraries you create in this project that dependent projects also need +## CATKIN_DEPENDS: catkin_packages dependent projects also need +## DEPENDS: system dependencies of this project that dependent projects also need +catkin_package( +# INCLUDE_DIRS include +# LIBRARIES owr_messages +# CATKIN_DEPENDS message_runtime roscpp rospy sensor_msgs std_msgs +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +# include_directories(include) +include_directories( + ${catkin_INCLUDE_DIRS} +) + +## Declare a cpp library +# add_library(owr_messages +# src/${PROJECT_NAME}/owr_messages.cpp +# ) + +## Declare a cpp executable +# add_executable(owr_messages_node src/owr_messages_node.cpp) + +## Add cmake target dependencies of the executable/library +## as an example, message headers may need to be generated before nodes +# add_dependencies(owr_messages_node owr_messages_generate_messages_cpp) + +## Specify libraries to link a library or executable target against +# target_link_libraries(owr_messages_node +# ${catkin_LIBRARIES} +# ) + +############# +## Install ## +############# + +# all install targets should use catkin DESTINATION variables +# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html + +## Mark executable scripts (Python etc.) for installation +## in contrast to setup.py, you can choose the destination +# install(PROGRAMS +# scripts/my_python_script +# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark executables and/or libraries for installation +# install(TARGETS owr_messages owr_messages_node +# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark cpp header files for installation +# install(DIRECTORY include/${PROJECT_NAME}/ +# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +# FILES_MATCHING PATTERN "*.h" +# PATTERN ".svn" EXCLUDE +# ) + +## Mark other files for installation (e.g. launch and bag files, etc.) +# install(FILES +# # myfile1 +# # myfile2 +# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +# ) + +############# +## Testing ## +############# + +## Add gtest based cpp test target and link libraries +# catkin_add_gtest(${PROJECT_NAME}-test test/test_owr_messages.cpp) +# if(TARGET ${PROJECT_NAME}-test) +# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) +# endif() + +## Add folders to be run by python nosetests +# catkin_add_nosetests(test) diff --git a/src/owr_messages/msg/activeCameras.msg b/src/owr_messages/msg/activeCameras.msg new file mode 100644 index 0000000..3fb907b --- /dev/null +++ b/src/owr_messages/msg/activeCameras.msg @@ -0,0 +1,2 @@ +stream[] cameras +int32 num diff --git a/src/owr_messages/msg/camera_angle~ b/src/owr_messages/msg/camera_angle~ new file mode 100644 index 0000000..1600bca --- /dev/null +++ b/src/owr_messages/msg/camera_angle~ @@ -0,0 +1,3 @@ +Vector3 angle +Int32 feed_number + diff --git a/src/owr_messages/msg/stream.msg b/src/owr_messages/msg/stream.msg new file mode 100644 index 0000000..212ef45 --- /dev/null +++ b/src/owr_messages/msg/stream.msg @@ -0,0 +1,4 @@ +int32 stream +bool on +int32 height +int32 width diff --git a/src/owr_messages/package.xml b/src/owr_messages/package.xml new file mode 100644 index 0000000..44069ee --- /dev/null +++ b/src/owr_messages/package.xml @@ -0,0 +1,64 @@ + + + owr_messages + 0.0.0 + The owr_messages package + + + + + ros + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + roscpp + rospy + sensor_msgs + geometry_msgs + std_msgs + message_runtime + roscpp + rospy + sensor_msgs + std_msgs + geometry_msgs + + + + + + + + + + + diff --git a/src/ros_video_components/CMakeLists.txt b/src/ros_video_components/CMakeLists.txt index 4fae33c..54fd036 100644 --- a/src/ros_video_components/CMakeLists.txt +++ b/src/ros_video_components/CMakeLists.txt @@ -10,13 +10,14 @@ project(ros_video_components) ############################################################################## # qt_build provides the qt cmake glue, roscpp the comms for a default talker -find_package(catkin REQUIRED COMPONENTS qt_build roscpp sensor_msgs image_transport) +find_package(catkin REQUIRED COMPONENTS qt_build roscpp sensor_msgs image_transport owr_messages) + include_directories(include ${catkin_INCLUDE_DIRS}) # Use this to define what the package will export (e.g. libs, headers). # Since the default here is to produce only a binary, we don't worry about # exporting anything. catkin_package( - CATKIN_DEPENDS qt_build roscpp sensor_msgs image_transport + CATKIN_DEPENDS qt_build roscpp sensor_msgs image_transport owr_messages INCLUDE_DIRS include LIBRARIES RosVideoComponents ) @@ -27,7 +28,7 @@ catkin_package( # this comes from qt_build's qt-ros.cmake which is automatically # included via the dependency ca ll in package.xml -find_package(Qt5 COMPONENTS Core Qml Quick REQUIRED) +find_package(Qt5 COMPONENTS Core Qml Widgets Quick REQUIRED) ############################################################################## # Sections @@ -49,6 +50,6 @@ file(GLOB_RECURSE QT_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} FOLLOW_SYMLINK # Binaries ############################################################################## add_library(RosVideoComponents ${QT_SOURCES} ${QT_RESOURCES_CPP} ${QT_FORMS_HPP} ${QT_MOC_HPP}) -qt5_use_modules(RosVideoComponents Quick Core) +qt5_use_modules(RosVideoComponents Quick Core Widgets) target_link_libraries(RosVideoComponents ${QT_LIBRARIES} ${catkin_LIBRARIES}) target_include_directories(RosVideoComponents PUBLIC include) diff --git a/src/ros_video_components/include/ros_video_components/owr_ros_components.hpp b/src/ros_video_components/include/ros_video_components/owr_ros_components.hpp index 53e4ff1..fd01ba5 100644 --- a/src/ros_video_components/include/ros_video_components/owr_ros_components.hpp +++ b/src/ros_video_components/include/ros_video_components/owr_ros_components.hpp @@ -1,3 +1,10 @@ +/* + * Date Started: 25/07/16 + * Original Author: Harry J.E Day + * Editors: + * Purpose: C++ code representation of the QML package + * This code is released under the MIT License. Copyright BLUEsat UNSW, 2017 + */ #ifndef OWR_ROS_COMPONENTS_H #define OWR_ROS_COMPONENTS_H diff --git a/src/ros_video_components/include/ros_video_components/ros_camera_switching.hpp b/src/ros_video_components/include/ros_video_components/ros_camera_switching.hpp new file mode 100644 index 0000000..cfe41a4 --- /dev/null +++ b/src/ros_video_components/include/ros_video_components/ros_camera_switching.hpp @@ -0,0 +1,86 @@ +/* + * Date Started: 8/07/18 + * Original Author: Raghav Hariharan + * Editors: Harry J.E Day + * Purpose: Widget for selecting a camera topic + * This code is released under the MIT License. Copyright BLUEsat UNSW, 2017 + */ +#ifndef ROS_CAMERA_SWITCHING_H +#define ROS_CAMERA_SWITCHING_H + +//QT +#include +#include +#include +#include + +#include + +//ROS +#include +#include "owr_messages/activeCameras.h" + +#define NUM_CAMERAS 8 + +const int NO_CAMERA_SELECTED = -1; + +class ROS_Camera_Switching : public QQuickPaintedItem { + //make this a Qt Widget + Q_OBJECT + /** + * defines a qml value for the topic + */ + Q_PROPERTY(QString topic READ get_topic WRITE set_topic NOTIFY topic_changed) + + /** + * the selected camera topic + */ + Q_PROPERTY(QString camera_topic READ get_camera_topic NOTIFY camera_topic_changed) + + /** + * the number of the camera + */ + Q_PROPERTY(int camera_number READ get_camera_number WRITE set_camera_number NOTIFY camera_number_changed) + + + public: + // Constructor, takes parent widget, which defaults to null + ROS_Camera_Switching(QQuickItem * parent = 0); + + void paint(QPainter *painter); + void setup(ros::NodeHandle * nh); + + //getters and setters + void set_topic(const QString &new_value); + QString get_topic() const; + + QString get_camera_topic() const; + + int get_camera_number() const; + void set_camera_number(int cam_num); + + signals: + void topic_changed(); + void camera_topic_changed(); + void camera_number_changed(); + + private: + void receive_feeds(const owr_messages::activeCameras::ConstPtr & msg); + + // ROS + ros::NodeHandle * nh; + ros::Subscriber available_feeds; + ros::Publisher control_feeds; + QString topic_value; + QString camera_topic_value; + + bool ros_ready; + + // Used changing camera colours + QColor cam_colours[NUM_CAMERAS]; + int camera_number; + protected: + //void keyPressEvent(QKeyEvent *k) override; + +}; +#endif // ROS_CAMERA_SWITCHING_H diff --git a/src/ros_video_components/include/ros_video_components/ros_drive_mode.hpp b/src/ros_video_components/include/ros_video_components/ros_drive_mode.hpp new file mode 100644 index 0000000..f0ecf6f --- /dev/null +++ b/src/ros_video_components/include/ros_video_components/ros_drive_mode.hpp @@ -0,0 +1,93 @@ +/** + * Date Started: 01/09/18 + * Original Author: Harry J.E Day + * Editors: + * Purpose: Shows the driving mode + * This code is released under the MIT License. Copyright BLUEsat UNSW, 2018 + */ +#ifndef ROS_DRIVE_MODE_H +#define ROS_DRIVE_MODE_H + + +#include +#include + +#include +#include + +const short CRAB = 0; +const short FOUR = 1; +const short SWERVE = 2; + +class Ros_Drive_Mode : public QQuickItem { + //make this a Qt Widget + Q_OBJECT + + /** + * defines a qml value for the topic to subscribe to + */ + Q_PROPERTY(QString topic READ get_topic WRITE set_topic NOTIFY topic_changed) + Q_PROPERTY(QString mode READ get_mode NOTIFY mode_changed) + + + public: + /** + * Constructor for the ROS_Drive_Mode class, initialises default variables + * @param parent the parent widget + */ + Ros_Drive_Mode(QQuickItem * parent = 0) : + topic_value(), + mode_value("---- "), + ros_ready(false), + QQuickItem(parent) {} + + //getters and setters + + /** + * Used to handle the topic being set in qml. + * Updates the subscriber + * @param new_value the new value for the topic. + */ + void set_topic(const QString &new_value); + /** + * Used to retrieve the topic from QML + * @return the value of the topic string + */ + QString get_topic() const; + /** + * Used to retrieve the string representing the driving mode + * @return the string of the mode + */ + QString get_mode() const; + /** + * Called to set the node handle. + * Initalises all of the ros functionality. + * @param nh the node handle + */ + void setup(ros::NodeHandle * nh); + + signals: + /** + * Emitted when the topic is channged + */ + void topic_changed(); + /** + * Emitted when we receive a new mode callback + */ + void mode_changed(); + + private: + /** + * Ros callback for the mode being changed + * @param msg the mode message + */ + void mode_callback(const std_msgs::Int16::ConstPtr & msg); + + QString topic_value; + bool ros_ready; + ros::Subscriber mode_sub; + ros::NodeHandle * nh; + QString mode_value; + +}; +#endif // ROS_DRIVE_MODE_H diff --git a/src/ros_video_components/include/ros_video_components/ros_joystick_listener.hpp b/src/ros_video_components/include/ros_video_components/ros_joystick_listener.hpp new file mode 100644 index 0000000..8dd8afd --- /dev/null +++ b/src/ros_video_components/include/ros_video_components/ros_joystick_listener.hpp @@ -0,0 +1,55 @@ +/* + * Date Started: 13/08/18 + * Original Author: Harry J.E Day + * Editors: + * Purpose: Joystick listener used to receive joystick messages + * This code is released under the MIT License. Copyright BLUEsat UNSW, 2018 + */ +#ifndef ROS_JOYSTICK_LISTENER_H +#define ROS_JOYSTICK_LISTENER_H + + +#include +#include + +#include +#include + + +class Ros_Joystick_Listener : public QQuickItem { + //make this a Qt Widget + Q_OBJECT + + /** + * defines a qml value for the topic to subscribe to + */ + Q_PROPERTY(QString topic READ get_topic WRITE set_topic NOTIFY topic_changed) + + + public: + Ros_Joystick_Listener(QQuickItem * parent = 0) : + topic_value(), + ros_ready(false), + QQuickItem(parent) {} + + //getters and setters + void set_topic(const QString &new_value); + QString get_topic() const; + void setup(ros::NodeHandle * nh); + + signals: + void topic_changed(); + void button_down(const qint32 & button); + void button_up(const qint32 & button); + + private: + void joystick_callback(const sensor_msgs::Joy::ConstPtr & msg); + QString topic_value; + bool ros_ready; + ros::Subscriber joy_sub; + ros::NodeHandle * nh; + sensor_msgs::Joy current_state; + + +}; +#endif // ROS_JOYSTICK_LISTENER_H diff --git a/src/ros_video_components/include/ros_video_components/ros_signal_strength.hpp b/src/ros_video_components/include/ros_video_components/ros_signal_strength.hpp index 5f0b9c7..5afc74b 100644 --- a/src/ros_video_components/include/ros_video_components/ros_signal_strength.hpp +++ b/src/ros_video_components/include/ros_video_components/ros_signal_strength.hpp @@ -1,17 +1,24 @@ +/* + * Date Started: 11/02/17 + * Original Author: Sajid Anower + * Editors: + * Purpose: Widget to display signal strength of the antenna + * This code is released under the MIT License. Copyright BLUEsat UNSW, 2017 + */ #ifndef ROS_SIGNAL_STRENGTH_H #define ROS_SIGNAL_STRENGTH_H -//QT +// QT #include #include -//ROS +// ROS #include #include class ROS_Signal_Strength : public QQuickPaintedItem { - //make this a Qt Widget + // make this a Qt Widget Q_OBJECT // defines a qml value for the topic Q_PROPERTY(QString topic READ get_topic WRITE set_topic NOTIFY topic_changed) @@ -23,7 +30,7 @@ class ROS_Signal_Strength : public QQuickPaintedItem { void paint(QPainter *painter); void setup(ros::NodeHandle * nh); - //getters and setters + // getters and setters void set_topic(const QString &new_value); QString get_topic() const; @@ -38,8 +45,8 @@ class ROS_Signal_Strength : public QQuickPaintedItem { ros::Subscriber signal_sub; QString topic_value; bool ros_ready; - - int data; //the signal strength in decibels + + int data; // the signal strength in decibels }; #endif // ROS_SIGNAL_STRENGTH_H diff --git a/src/ros_video_components/include/ros_video_components/ros_timer.hpp b/src/ros_video_components/include/ros_video_components/ros_timer.hpp new file mode 100644 index 0000000..4c8fe9a --- /dev/null +++ b/src/ros_video_components/include/ros_video_components/ros_timer.hpp @@ -0,0 +1,40 @@ +#ifndef ROS_TIMER_HPP +#define ROS_TIMER_HPP + +#include +#include +#include +#include +#include +#include + +#define ON 1 +#define OFF 0 + +class ROSTimer : public QQuickPaintedItem { + Q_OBJECT + public: + ROSTimer(QQuickItem *parent = 0); + void paint(QPainter *painter); + void keyPressEvent(QKeyEvent *k); + //void run(); + //void setup(ros::NodeHandle * nh); + + signals: + void valueChanged(QString text); + + private slots: + void show(); + + private: + int ms_elapsed; + QTime time; + QTime time_elapsed; + QString text; + QTimer *stopwatch; + int status; + //ros::NodeHandle nh; + //QString format(int milisecs); +}; + +#endif // ROS_TIMER_HPP diff --git a/src/ros_video_components/include/ros_video_components/ros_video_component.hpp b/src/ros_video_components/include/ros_video_components/ros_video_component.hpp index 296933f..f92fbef 100644 --- a/src/ros_video_components/include/ros_video_components/ros_video_component.hpp +++ b/src/ros_video_components/include/ros_video_components/ros_video_component.hpp @@ -1,3 +1,10 @@ +/* + * Date Started: 25/12/16 + * Original Author: Harry J.E Day + * Editors: + * Purpose: Widget that renders a video from a ROS sensor_msgs/Image stream. + * This code is released under the MIT License. Copyright BLUEsat UNSW, 2018 + */ #ifndef ROS_VIDEO_COMPONENT_H #define ROS_VIDEO_COMPONENT_H @@ -6,11 +13,13 @@ #include #include +#include + //ROS #include #include #include - +//#include "owr_messages/activeCameras.h" class ROS_Video_Component : public QQuickPaintedItem { //make this a Qt Widget @@ -25,6 +34,8 @@ class ROS_Video_Component : public QQuickPaintedItem { void paint(QPainter *painter); void setup(ros::NodeHandle * nh); + protected: + //getters and setters void set_topic(const QString &new_value); QString get_topic() const; @@ -32,6 +43,7 @@ class ROS_Video_Component : public QQuickPaintedItem { signals: void topic_changed(); + private: void receive_image(const sensor_msgs::Image::ConstPtr & msg); @@ -45,7 +57,6 @@ class ROS_Video_Component : public QQuickPaintedItem { // Used for buffering the image QImage * current_image; uchar * current_buffer; - }; #endif // ROS_VIDEO_COMPONENT_H diff --git a/src/ros_video_components/include/ros_video_components/ros_voltage_meter.hpp b/src/ros_video_components/include/ros_video_components/ros_voltage_meter.hpp new file mode 100644 index 0000000..b2d56ec --- /dev/null +++ b/src/ros_video_components/include/ros_video_components/ros_voltage_meter.hpp @@ -0,0 +1,56 @@ +/* + * Date Started: 8/09/18 + * Original Author: Sajid Ibne Anower + * Editors: + * Purpose: Widget to display voltage of the batteries + * This code is released under the MIT License. Copyright BLUEsat UNSW, 2018 + */ +#ifndef ROS_VOLTAGE_METER_H +#define ROS_VOLTAGE_METER_H + +// QT +#include +#include + +// ROS +#include +#include + +class ROS_Voltage_Meter : public QQuickItem { + // make this a Qt Widget + Q_OBJECT + // defines a qml value for the topic + Q_PROPERTY(QString topic READ get_topic WRITE set_topic NOTIFY topic_changed) + Q_PROPERTY(double volt_value READ get_volt NOTIFY volt_update) + + public: + // Constructor, takes parent widget, which defaults to null + ROS_Voltage_Meter(QQuickItem * parent = 0): + topic_value("/sensors/voltmeter"), + volt_value(0.0), + ros_ready(false), + QQuickItem(parent) {} + + void setup(ros::NodeHandle * nh); + + // getters and setters + void set_topic(const QString &new_value); + QString get_topic() const; + double get_volt() const; + + signals: + void topic_changed(); + void volt_update(); + + private: + void receive_volt_callback(const std_msgs::Float32::ConstPtr & msg); + + // ROS + QString topic_value; + bool ros_ready; + ros::Subscriber volt_sub; + ros::NodeHandle * nh; + double volt_value; +}; + +#endif // ROS_VOLTAGE_METER_H diff --git a/src/ros_video_components/package.xml b/src/ros_video_components/package.xml index 53dbf31..0525090 100644 --- a/src/ros_video_components/package.xml +++ b/src/ros_video_components/package.xml @@ -41,18 +41,20 @@ catkin - catkin - catkin qt_build roscpp image_transport sensor_msgs libqt4-dev + owr_messages + qt_build image_transport sensor_msgs roscpp libqt4-dev + owr_messages + diff --git a/src/ros_video_components/resources/DriveModeWidget.qml b/src/ros_video_components/resources/DriveModeWidget.qml new file mode 100644 index 0000000..cb87196 --- /dev/null +++ b/src/ros_video_components/resources/DriveModeWidget.qml @@ -0,0 +1,47 @@ +import QtQuick 2.0 +import bluesat.owr 1.0 + +Item { + id: drive_mode_widget + + ROSDriveMode { + objectName: "drive_mode" + id: driveMode + topic: "/cmd_vel/mode" + + } + + Text { + id: driveModeText + color: "#d23a00" + text: driveMode.mode + fontSizeMode: Text.HorizontalFit + clip: false + anchors.left: parent.horizontalCenter + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.top: parent.top + anchors.leftMargin: 15 + horizontalAlignment: Text.AlignLeft + font.pointSize: 10 + font.bold: true + } + + Text { + id: driveText + text: qsTr("Drive:") + fontSizeMode: Text.HorizontalFit + anchors.top: parent.top + anchors.topMargin: 0 + anchors.bottom: parent.bottom + anchors.bottomMargin: 0 + color: "#d23a00" + horizontalAlignment: Text.AlignLeft + font.pointSize: 10 + font.bold: true + anchors.right: parent.horizontalCenter + anchors.rightMargin: 15 + anchors.left: parent.left + anchors.leftMargin: 0 + } +} diff --git a/src/ros_video_components/resources/VoltageMeterWidget.qml b/src/ros_video_components/resources/VoltageMeterWidget.qml new file mode 100644 index 0000000..5c97a79 --- /dev/null +++ b/src/ros_video_components/resources/VoltageMeterWidget.qml @@ -0,0 +1,53 @@ +import QtQuick 2.0 +import bluesat.owr 1.0 + +Item { + id: voltage_meter_widget + ROSVoltageMeter { + objectName: "voltage_meter" + id: voltageMeter + topic: "/sensors/voltmeter" + // @disable-check M16` + anchors.bottom: parent.bottom + // @disable-check M16 + anchors.bottomMargin: 0 + // @disable-check M16 + anchors.top: parent.top + // @disable-check M16 + anchors.left: parent.left + // @disable-check M16 + anchors.right: parent.right + } + Text { + id: voltageValue + color: "#d23a00" + text: voltageMeter.volt_value + fontSizeMode: Text.HorizontalFit + clip: false + anchors.left: parent.horizontalCenter + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.top: parent.top + anchors.leftMargin: 40 + horizontalAlignment: Text.AlignLeft + font.pointSize: 10 + font.bold: true + } + Text { + id: voltageValueText + text: qsTr("Volt:") + fontSizeMode: Text.HorizontalFit + anchors.top: parent.top + anchors.topMargin: 0 + anchors.bottom: parent.bottom + anchors.bottomMargin: 0 + color: "#d23a00" + horizontalAlignment: Text.AlignLeft + font.pointSize: 10 + font.bold: true + anchors.right: parent.horizontalCenter + anchors.rightMargin: 15 + anchors.left: parent.left + anchors.leftMargin: 0 + } +} diff --git a/src/ros_video_components/resources/components.qrc b/src/ros_video_components/resources/components.qrc new file mode 100644 index 0000000..e4976ba --- /dev/null +++ b/src/ros_video_components/resources/components.qrc @@ -0,0 +1,8 @@ + + + DriveModeWidget.qml + + + VoltageMeterWidget.qml + + diff --git a/src/ros_video_components/src/owr_ros_components.cpp b/src/ros_video_components/src/owr_ros_components.cpp index bbf8b04..9c91a0f 100644 --- a/src/ros_video_components/src/owr_ros_components.cpp +++ b/src/ros_video_components/src/owr_ros_components.cpp @@ -1,6 +1,18 @@ +/* + * Date Started: 25/07/16 + * Original Author: Harry J.E Day + * Editors: + * Purpose: C++ code representation of the QML package + * This code is released under the MIT License. Copyright BLUEsat UNSW, 2017 + */ #include "ros_video_components/owr_ros_components.hpp" #include "ros_video_components/ros_video_component.hpp" #include "ros_video_components/ros_signal_strength.hpp" +#include "ros_video_components/ros_voltage_meter.hpp" +#include "ros_video_components/ros_camera_switching.hpp" +#include "ros_video_components/ros_timer.hpp" +#include "ros_video_components/ros_joystick_listener.hpp" +#include "ros_video_components/ros_drive_mode.hpp" //add the new include directory #include "ros_video_components/ros_driving_mode_switching.hpp" @@ -8,7 +20,10 @@ void OWR_ROS_Components::registerTypes(const char *uri) { qmlRegisterType("bluesat.owr", 1, 0, "ROSVideoComponent"); qmlRegisterType("bluesat.owr", 1, 0, "ROSSignalStrength"); - - //new Register Type qmlRegisterType("bluesat.owr", 1, 0, "ROSDrivingModeSwitching"); + qmlRegisterType("bluesat.owr", 1, 0, "ROSVoltageMeter"); + qmlRegisterType("bluesat.owr", 1, 0, "ROSCameraSwitching"); + qmlRegisterType("bluesat.owr", 1, 0, "ROSTimer"); + qmlRegisterType("bluesat.owr", 1, 0, "ROSJoystickListener"); + qmlRegisterType("bluesat.owr", 1, 0, "ROSDriveMode"); } diff --git a/src/ros_video_components/src/ros_camera_switching.cpp b/src/ros_video_components/src/ros_camera_switching.cpp new file mode 100644 index 0000000..ee43233 --- /dev/null +++ b/src/ros_video_components/src/ros_camera_switching.cpp @@ -0,0 +1,180 @@ +/* + * Date Started: 8/07/18 + * Original Author: Raghav Hariharan + * Editors: Harry J.E Day + * Purpose: Widget for selecting a camera topic + * This code is released under the MIT License. Copyright BLUEsat UNSW, 2017 + */ +#include "ros_video_components/ros_camera_switching.hpp" +#include + +ROS_Camera_Switching::ROS_Camera_Switching(QQuickItem * parent) : + QQuickPaintedItem(parent), + topic_value("/owr/control/availableFeeds"), + camera_topic_value(), + ros_ready(false), + camera_number(NO_CAMERA_SELECTED) + { + +} + +void ROS_Camera_Switching::setup(ros::NodeHandle * nh) { + available_feeds = nh->subscribe( + topic_value.toStdString(), + 1, + &ROS_Camera_Switching::receive_feeds, + this + ); + + for( int i = 0; i < NUM_CAMERAS; i++){ + cam_colours[i] = QColor::fromRgb(255, 0, 0); + } + + ros_ready = true; + + control_feeds = nh->advertise("/owr/control/activateFeeds", 1); + ROS_INFO("Setup of camera switching component is complete"); + +} + +static const QColor RED = QColor::fromRgb(255, 0, 0); //RED indicate camera is not connected +static const QColor GREEN = QColor::fromRgb(128, 255, 0); //GREEN indicates camera is in use by us +static const QColor DARK_GREEN = QColor::fromRgb(0, 51, 0); //GREEN indicates camera is in use +static const QColor ORANGE = QColor::fromRgb(255, 165, 0); //ORANGE indicates that a camera is connected + +void ROS_Camera_Switching::receive_feeds(const owr_messages::activeCameras::ConstPtr &msg){ + + for( int i = 0; i < NUM_CAMERAS; i++){ + cam_colours[i] = RED; + } + + bool on; + for( int j = 0; j < NUM_CAMERAS ; j++){ + for(int k = 0; k < msg->num; k++){ + if(msg->cameras[k].stream == j){ + on = msg->cameras[k].on; + if(!on) { + cam_colours[j] = ORANGE; + } else if(on) { + if(j == camera_number) { + cam_colours[j] = GREEN; + } else { + cam_colours[j] = DARK_GREEN; + } + } + } + } + } + + update(); +} + +void ROS_Camera_Switching::set_camera_number(int cam) { + ROS_INFO("Camera change to %d", cam); + if(camera_number < 0) { + camera_number = NO_CAMERA_SELECTED; + } + // disable existing feed + owr_messages::stream msg; + if(camera_number != NO_CAMERA_SELECTED && ros_ready) { + msg.stream = camera_number; + msg.on = false; + control_feeds.publish(msg); + } + camera_number = cam; + + if(camera_number != NO_CAMERA_SELECTED && ros_ready) { + msg.stream = camera_number; + msg.on = true; + control_feeds.publish(msg); + } + + if(camera_number != NO_CAMERA_SELECTED) { + std::ostringstream topic_in; + topic_in << "/cam" << cam; + camera_topic_value = QString(topic_in.str().c_str()); + } else { + camera_topic_value = QString(); + } + emit camera_topic_changed(); + emit camera_number_changed(); +} + +void ROS_Camera_Switching::paint(QPainter * painter) { + + //Rectangle for cam 0 + QRectF cam_0(20, 80, 50, 50); + //Qpainter->drawRoundedRect(cam0, 8, 8); + painter->fillRect(cam_0,cam_colours[0]); + painter->drawText(cam_0,Qt::AlignCenter,tr("0")); + + //Rectangle for cam 1 + QRectF cam_1(20, 160, 50, 50); + //painter->drawRoundedRect(cam1, 8, 8); + painter->fillRect(cam_1,cam_colours[1]); + painter->drawText(cam_1,Qt::AlignCenter,tr("1")); + + //Rectangle for cam 2 + QRectF cam_2(20, 240, 50, 50); + //painter->drawRoundedRect(cam2, 8, 8); + painter->fillRect(cam_2,cam_colours[2]); + painter->drawText(cam_2,Qt::AlignCenter,tr("2")); + + //Rectangle for cam 3 + QRectF cam_3(20, 320, 50, 50); + //painter->drawRoundedRect(cam3, 8, 8); + painter->fillRect(cam_3,cam_colours[3]); + painter->drawText(cam_3,Qt::AlignCenter,tr("3")); + + //Rectangle for cam 4 + QRectF cam_4(20, 400, 50, 50); + //painter->drawRoundedRect(cam4, 8, 8); + painter->fillRect(cam_4,cam_colours[4]); + painter->drawText(cam_4,Qt::AlignCenter,tr("4")); + + //Rectangle for cam 5 + QRectF cam_5(20, 480, 50, 50); + //painter->drawRoundedRect(cam5, 8, 8); + painter->fillRect(cam_5,cam_colours[5]); + painter->drawText(cam_5,Qt::AlignCenter,tr("5")); + + //Rectangle for cam 6 + QRectF cam_6(20, 560, 50, 50); + //painter->drawRoundedRect(cam6, 8, 8); + painter->fillRect(cam_6,cam_colours[6]); + painter->drawText(cam_6,Qt::AlignCenter,tr("6")); + + //Rectangle for cam 7 + QRectF cam_7(20, 640, 50, 50); + //painter->drawRoundedRect(cam7, 8, 8); + painter->fillRect(cam_7,cam_colours[7]); + painter->drawText(cam_7,Qt::AlignCenter,tr("7")); +} + +void ROS_Camera_Switching::set_topic(const QString & new_value) { + if(topic_value != new_value) { + topic_value = new_value; + if(ros_ready) { + available_feeds.shutdown(); + available_feeds = nh->subscribe( + topic_value.toStdString(), + 1, + &ROS_Camera_Switching::receive_feeds, + this + ); + } + emit topic_changed(); + } +} + +QString ROS_Camera_Switching::get_topic() const { + return topic_value; +} + +QString ROS_Camera_Switching::get_camera_topic() const { + return camera_topic_value; +} + +int ROS_Camera_Switching::get_camera_number() const { + return camera_number; +} diff --git a/src/ros_video_components/src/ros_drive_mode.cpp b/src/ros_video_components/src/ros_drive_mode.cpp new file mode 100644 index 0000000..52d8326 --- /dev/null +++ b/src/ros_video_components/src/ros_drive_mode.cpp @@ -0,0 +1,72 @@ +/* + * Date Started: 13/08/18 + * Original Author: Harry J.E Day + * Editors: + * Purpose: Joystick listener used to receive joystick messages + * This code is released under the MIT License. Copyright BLUEsat UNSW, 2018 + */ + +#include "ros_video_components/ros_drive_mode.hpp" + +void Ros_Drive_Mode::set_topic(const QString & new_value) { + ROS_INFO("new value %s", new_value.toStdString().c_str()); + if(topic_value != new_value) { + topic_value = new_value; + if(!topic_value.isEmpty()) { + if(ros_ready) { + ROS_INFO("new value %s", new_value.toStdString().c_str()); + mode_sub.shutdown(); + mode_sub = nh->subscribe( + topic_value.toStdString(), + 1, + &Ros_Drive_Mode::mode_callback, + this + ); + } + } else { + mode_sub.shutdown(); + } + emit topic_changed(); + } +} + +QString Ros_Drive_Mode::get_topic() const { + return topic_value; +} + +QString Ros_Drive_Mode::get_mode() const { + return mode_value; +} + +void Ros_Drive_Mode::setup(ros::NodeHandle * nh) { + this->nh = nh; + if(!topic_value.isEmpty()) { + ROS_INFO("Looking for joysticks at %s", topic_value.toStdString().c_str()); + mode_sub = nh->subscribe( + topic_value.toStdString(), + 1, + &Ros_Drive_Mode::mode_callback, + this + ); + } + + + ros_ready = true; + +} + +void Ros_Drive_Mode::mode_callback(const std_msgs::Int16::ConstPtr & msg) { + + switch(msg->data) { + case CRAB: + mode_value = QString("CRAB "); + break; + case FOUR: + mode_value = QString("FOUR "); + break; + case SWERVE: + mode_value = QString("SWERVE"); + break; + } + emit mode_changed(); +} diff --git a/src/ros_video_components/src/ros_driving_mode_switching.cpp b/src/ros_video_components/src/ros_driving_mode_switching.cpp index 8e6e990..0c50e7e 100644 --- a/src/ros_video_components/src/ros_driving_mode_switching.cpp +++ b/src/ros_video_components/src/ros_driving_mode_switching.cpp @@ -30,7 +30,7 @@ void ROS_Driving_Mode_Switching::setup(ros::NodeHandle * nh) { ); ros_ready = true; - //ROS_INFO("Setup of video component complete"); + //ROS_INFO("Setup of driving mode switching component complete"); } diff --git a/src/ros_video_components/src/ros_joystick_listener.cpp b/src/ros_video_components/src/ros_joystick_listener.cpp new file mode 100644 index 0000000..a926b5c --- /dev/null +++ b/src/ros_video_components/src/ros_joystick_listener.cpp @@ -0,0 +1,70 @@ +/* + * Date Started: 13/08/18 + * Original Author: Harry J.E Day + * Editors: + * Purpose: Joystick listener used to receive joystick messages + * This code is released under the MIT License. Copyright BLUEsat UNSW, 2018 + */ + +#include "ros_video_components/ros_joystick_listener.hpp" + +void Ros_Joystick_Listener::set_topic(const QString & new_value) { + ROS_INFO("new value %s", new_value.toStdString().c_str()); + if(topic_value != new_value) { + topic_value = new_value; + if(!topic_value.isEmpty()) { + if(ros_ready) { + ROS_INFO("new value %s", new_value.toStdString().c_str()); + joy_sub.shutdown(); + joy_sub = nh->subscribe( + topic_value.toStdString(), + 1, + &Ros_Joystick_Listener::joystick_callback, + this + ); + } + } else { + joy_sub.shutdown(); + } + emit topic_changed(); + } +} + +QString Ros_Joystick_Listener::get_topic() const { + return topic_value; +} + + +void Ros_Joystick_Listener::setup(ros::NodeHandle * nh) { + this->nh = nh; + if(!topic_value.isEmpty()) { + ROS_INFO("Looking for joysticks at %s", topic_value.toStdString().c_str()); + joy_sub = nh->subscribe( + topic_value.toStdString(), + 1, + &Ros_Joystick_Listener::joystick_callback, + this + ); + } + + + ros_ready = true; + +} +void Ros_Joystick_Listener::joystick_callback(const sensor_msgs::Joy::ConstPtr & msg) { + + if(current_state.buttons.size() != msg->buttons.size()) { + current_state.buttons.resize(msg->buttons.size()); + } + // go through each button and signal any changes + for(int i = 0; i < msg->buttons.size(); ++i) { + if(msg->buttons[i] != current_state.buttons[i]) { + current_state.buttons[i] = msg->buttons[i]; + if(msg->buttons[i]) { + emit button_down(i); + } else { + emit button_up(i); + } + } + } +} diff --git a/src/ros_video_components/src/ros_signal_strength.cpp b/src/ros_video_components/src/ros_signal_strength.cpp index fabd2cd..fe0d68d 100644 --- a/src/ros_video_components/src/ros_signal_strength.cpp +++ b/src/ros_video_components/src/ros_signal_strength.cpp @@ -1,3 +1,10 @@ +/* + * Date Started: 11/02/17 + * Original Author: Sajid Anower + * Editors: + * Purpose: Widget to display signal strength of the antenna + * This code is released under the MIT License. Copyright BLUEsat UNSW, 2017 + */ #include "ros_video_components/ros_signal_strength.hpp" #define RECT_X 0 @@ -17,93 +24,78 @@ ROS_Signal_Strength::ROS_Signal_Strength(QQuickItem * parent) : QQuickPaintedItem(parent), topic_value("/rover/signal"), ros_ready(false), - data(50) { -} + data(50) {} void ROS_Signal_Strength::setup(ros::NodeHandle * nh) { - + signal_sub = nh->subscribe( - "/rover/signal", //TODO - 1, - &ROS_Signal_Strength::receive_signal, - this + "/rover/signal", // TODO + 1, + &ROS_Signal_Strength::receive_signal, + this ); - ros_ready = true; - //ROS_INFO("Setup of video component complete"); } +void ROS_Signal_Strength::paint(QPainter * painter) { + int x = RECT_X; + int y = RECT_Y; + int widthV = width(); // RECT_WIDTH; + int heightV = height(); // RECT_HEIGHT; + QLinearGradient linearGradient(0, 0, 100, 100); + int num = 0; + float hash = HASH; + if (data >= MAXDATA) { + num = MAXNUM; + } else if (data <= TOO_WEAK) { + num = 0; + linearGradient.setColorAt(0.0, Qt::white); + painter->setBrush(linearGradient); + } else { + num = (data/hash) + 1; + } + // draw the outer main rectangle + painter->drawRect(x, y, widthV - 1, heightV - 1); -void ROS_Signal_Strength::paint(QPainter * painter) { - - //int data = 82; //int data = getSignalStrength(); - // http://doc.qt.io/qt-4.8/qpainter.html#setViewport - int x = RECT_X; - int y = RECT_Y; - int widthV = width();// / RECT_WIDTH; - int heightV = height();// / RECT_HEIGHT; - - QLinearGradient linearGradient(0, 0, 100, 100); - int num = 0; - float hash = HASH; - if(data >= MAXDATA){ - num = MAXNUM; - }else if(data <= TOO_WEAK){ - num = 0; - linearGradient.setColorAt(0.0, Qt::white); - painter->setBrush(linearGradient); - }else{ - num = (data/hash) +1; - } - painter->drawRect(x, y, widthV - 1, heightV - 1); //draw the main rectangle - - int i = 0; - - int barWidth = widthV/MAXNUM; - int barHeight = heightV/MAXNUM; - y += ((MAXNUM-1) * heightV) /MAXNUM; - const int increment = heightV/MAXNUM; - //ROS_INFO("y is %d, barHeight is %d\n",y, barHeight); - if(num == 0){ - //print flashing "NO SIGNAL" on the screen - /*QLabel * label = new QLabel(&mainWindow); - label->setText("NO SIGNAL\n"); - mainWindow.show();*/ - ROS_INFO("NO SIGNAL\n"); - }else{ - for(i = 1; i <= num; i++){ - - if(num >= GREEN/*(MAXNUM - (MAXNUM/NUMCOLOR))*/){ - linearGradient.setColorAt(0.2, Qt::green); - }else if(num >= YELLOW/*(MAXNUM/NUMCOLOR)*/){ - linearGradient.setColorAt(0.2, Qt::yellow); - }else{ - linearGradient.setColorAt(0.2, Qt::red); - } - painter->setBrush(linearGradient); - //ROS_INFO("x is %d, y is %d, barWidth %d, barHeight %d", x ,y,barWidth, barHeight); - painter->drawRect(x, y, barWidth, barHeight); - x += barWidth; //move x along - barHeight += increment; //increase height - y -= increment; //decrease height - } - } - + int i = 0; + + int barWidth = widthV/MAXNUM; + int barHeight = heightV/MAXNUM; + y += ((MAXNUM-1) * heightV) /MAXNUM; + const int increment = heightV/MAXNUM; + if (num == 0) { + ROS_INFO("NO SIGNAL\n"); + } else { + for (i = 1; i <= num; i++) { + if (num >= GREEN) { + linearGradient.setColorAt(0.2, Qt::green); + } else if (num >= YELLOW) { + linearGradient.setColorAt(0.2, Qt::yellow); + } else { + linearGradient.setColorAt(0.2, Qt::red); + } + painter->setBrush(linearGradient); + painter->drawRect(x, y, barWidth, barHeight); + x += barWidth; // move x along + barHeight += increment; // increase height + y -= increment; // decrease height + } + } } void ROS_Signal_Strength::set_topic(const QString & new_value) { - ROS_INFO("set_topic"); - if(topic_value != new_value) { + ROS_INFO("set_topic"); + if (topic_value != new_value) { topic_value = new_value; - if(ros_ready) { + if (ros_ready) { signal_sub.shutdown(); signal_sub = nh->subscribe( - topic_value.toStdString(), //TODO - 1, - &ROS_Signal_Strength::receive_signal, - this - ); + topic_value.toStdString(), // TODO + 1, + &ROS_Signal_Strength::receive_signal, + this + ); } emit topic_changed(); } @@ -113,8 +105,9 @@ QString ROS_Signal_Strength::get_topic() const { return topic_value; } -void ROS_Signal_Strength::receive_signal(const std_msgs::Float32::ConstPtr & msg){ - data = msg->data; - ROS_INFO("Received signal message"); - update(); +void ROS_Signal_Strength:: + receive_signal(const std_msgs::Float32::ConstPtr & msg) { + data = msg->data; + ROS_INFO("Received signal message"); + update(); } diff --git a/src/ros_video_components/src/ros_timer.cpp b/src/ros_video_components/src/ros_timer.cpp new file mode 100644 index 0000000..19ca691 --- /dev/null +++ b/src/ros_video_components/src/ros_timer.cpp @@ -0,0 +1,81 @@ +#include "ros_video_components/ros_timer.hpp" + +ROSTimer::ROSTimer(QQuickItem *parent) : QQuickPaintedItem(parent) { + time.setHMS(0, 0, 0, 0); + ms_elapsed = 0; + status = OFF; + stopwatch = new QTimer(this); + //stopwatch->start(INTERVAL); + show(); + connect(stopwatch, SIGNAL(timeout()), this, SLOT(show())); + +} + +void ROSTimer::show() { + + //text = QString::number(elapsed); + + if (status == ON) { + int elapsed = time_elapsed.elapsed(); + time = time.addMSecs(elapsed - ms_elapsed); + ms_elapsed = elapsed; + } + text = time.toString("hh:mm:ss.zzz"); + + // blinking separator + if ((time.second() % 2) == 1) { + text[2] = ' '; + text[5] = ' '; + } + + emit valueChanged(text); + update(); +} + +void ROSTimer::keyPressEvent(QKeyEvent *k) { + if (k->key() == Qt::Key_Space) { + // press SPACE to pause/resume + if (status == ON) { + stopwatch->stop(); + qDebug() << "Timer: STOP"; + } else { + stopwatch->start(1); + time_elapsed.start(); + ms_elapsed = 0; + qDebug() << "Timer: START"; + } + status = 1 - status; // flip status + } else if (k->key() == Qt::Key_R) { + // press R to reset + stopwatch->stop(); + status = OFF; + time.setHMS(0, 0, 0, 0); + ms_elapsed = 0; + show(); + qDebug() << "Timer: RESET"; + } +} + +void ROSTimer::paint(QPainter *painter) { + + // set font + QFont text_font("Sans Serif", 10, QFont::Bold); + QFont title_font("Sans Serif", 6, QFont::Bold); + + if (!text.isNull() && !text.isEmpty()) { + QRect border = QRect(0, 0, 140, 50); + QRect text_bound = QRect(5, 5, 130, 40); + + // draw background + QBrush brush(Qt::gray, Qt::SolidPattern); + painter->fillRect(border, brush); + painter->setPen(Qt::blue); + painter->drawRect(border); + + // draw text + painter->setFont(text_font); + painter->drawText(text_bound, Qt::AlignHCenter | Qt::AlignBottom, text); + painter->setFont(title_font); + painter->drawText(text_bound, Qt::AlignTop, "TIMER\nSPACE=start/stop R=reset"); + } +} diff --git a/src/ros_video_components/src/ros_video_component.cpp b/src/ros_video_components/src/ros_video_component.cpp index 6ecc114..42370a5 100644 --- a/src/ros_video_components/src/ros_video_component.cpp +++ b/src/ros_video_components/src/ros_video_component.cpp @@ -1,10 +1,11 @@ #include "ros_video_components/ros_video_component.hpp" +#include ROS_Video_Component::ROS_Video_Component(QQuickItem * parent) : QQuickPaintedItem(parent), current_image(NULL), current_buffer(NULL), - topic_value("/cam0"), + topic_value(), ros_ready(false), img_trans(NULL) { @@ -13,14 +14,16 @@ ROS_Video_Component::ROS_Video_Component(QQuickItem * parent) : void ROS_Video_Component::setup(ros::NodeHandle * nh) { img_trans = new image_transport::ImageTransport(*nh); - //TODO: make these parameters of the component - image_sub = img_trans->subscribe( - topic_value.toStdString(), - 1, - &ROS_Video_Component::receive_image, - this, - image_transport::TransportHints("compressed") - ); + //TODO: make these parameters of the componen + if(!topic_value.isEmpty()) { + image_sub = img_trans->subscribe( + topic_value.toStdString(), + 1, + &ROS_Video_Component::receive_image, + this, + image_transport::TransportHints("compressed") + ); + } ros_ready = true; ROS_INFO("Setup of video component complete"); @@ -30,11 +33,13 @@ void ROS_Video_Component::receive_image(const sensor_msgs::Image::ConstPtr &msg) // check to see if we already have an image frame, if we do then we need to // delete it to avoid memory leaks if( current_image ) { + delete current_image; } // allocate a buffer of sufficient size to contain our video frame uchar * temp_buffer = (uchar *) malloc(sizeof(uchar) * msg->data.size()); + memcpy(temp_buffer, msg->data.data(), msg->data.size()); // and copy the message into the buffer // we need to do this because QImage api requires the buffer we pass in to @@ -47,8 +52,6 @@ void ROS_Video_Component::receive_image(const sensor_msgs::Image::ConstPtr &msg) QImage::Format_RGB888 // TODO: detect the type from the message ); - ROS_INFO("Recieved Message"); - // We then swap out of bufer to avoid memory leaks if(current_buffer) { delete current_buffer; @@ -61,22 +64,41 @@ void ROS_Video_Component::receive_image(const sensor_msgs::Image::ConstPtr &msg) void ROS_Video_Component::paint(QPainter * painter) { if(current_image) { - painter->drawImage(QPoint(0,0), *(this->current_image)); + // scale on the largest edge + // using the algorith here: https://stackoverflow.com/questions/6565703/math-algorithm-fit-image-to-screen-retain-aspect-ratio + float new_height, new_width; + // which one has the largest ration + if( (width()/height()) > (current_image->width()/current_image->height())) { + new_width = (current_image->width() * height())/ (float) current_image->height(); + new_height = height(); + } else { + new_width = width(); + new_height = (current_image->height() * width())/ (float)current_image->width(); + } + painter->drawImage(QRect((width()- new_width)/2 , (height()- new_height)/2, new_width, new_height), *(this->current_image)); + } else if (topic_value.isEmpty()) { + painter->drawText(QPoint(10,10), "No Topic Selected"); } } void ROS_Video_Component::set_topic(const QString & new_value) { + ROS_INFO("new value %s", new_value.toStdString().c_str()); if(topic_value != new_value) { topic_value = new_value; - if(ros_ready) { + if(!topic_value.isEmpty()) { + if(ros_ready) { + ROS_INFO("new value %s", new_value.toStdString().c_str()); + image_sub.shutdown(); + image_sub = img_trans->subscribe( + topic_value.toStdString(), + 1, + &ROS_Video_Component::receive_image, + this, + image_transport::TransportHints("compressed") + ); + } + } else { image_sub.shutdown(); - image_sub = img_trans->subscribe( - topic_value.toStdString(), - 1, - &ROS_Video_Component::receive_image, - this, - image_transport::TransportHints("compressed") - ); } emit topic_changed(); } diff --git a/src/ros_video_components/src/ros_voltage_meter.cpp b/src/ros_video_components/src/ros_voltage_meter.cpp new file mode 100644 index 0000000..718af2e --- /dev/null +++ b/src/ros_video_components/src/ros_voltage_meter.cpp @@ -0,0 +1,47 @@ +/* + * Date Started: 8/09/18 + * Original Author: Sajid Ibne Anower + * Editors: + * Purpose: Widget to display voltage of the batteries + * This code is released under the MIT License. Copyright BLUEsat UNSW 2018 + * Trivia: This code was written on the plane from Sydney to Warsaw, + * on the way to participating in ERC2018 + */ +#include "ros_video_components/ros_voltage_meter.hpp" + +void ROS_Voltage_Meter::setup(ros::NodeHandle * nh) { + volt_sub = nh->subscribe( + "/sensors/voltmeter", + 1, + &ROS_Voltage_Meter::receive_volt_callback, + this); + ros_ready = true; +} + +void ROS_Voltage_Meter::set_topic(const QString & new_value) { + if (topic_value != new_value) { + topic_value = new_value; + if (ros_ready) { + volt_sub.shutdown(); + volt_sub = nh->subscribe( + topic_value.toStdString(), + 1, + &ROS_Voltage_Meter::receive_volt_callback, + this); + } + emit topic_changed(); + } +} + +QString ROS_Voltage_Meter::get_topic() const { + return topic_value; +} + +double ROS_Voltage_Meter::get_volt() const { + return volt_value; +} + +void ROS_Voltage_Meter :: receive_volt_callback(const std_msgs::Float32::ConstPtr & msg) { + volt_value = msg->data; + emit volt_update(); +}