diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..dc04706 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,237 @@ +cmake_minimum_required(VERSION 3.0.2) +project(Air_Ground_CEC) + +## Compile as C++11, supported in ROS Kinetic and newer +add_compile_options(-std=c++11) + +## 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 + roscpp + std_msgs + cv_bridge + sensor_msgs + image_transport +) + +## 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 installedsudo sh -c 'echo "/usr/local/lib" > /etc/ld.so.conf.d/opencv.conf' +## 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 tag for "message_generation" +## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET +## * If MSG_DEP_SET isn't empty the following dependency has been pulled in +## but can be declared for certainty nonetheless: +## * add a exec_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 +# Message1.msg +# Message2.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 +# std_msgs # Or other packages containing msgs +# ) + +################################################ +## Declare ROS dynamic reconfigure parameters ## +################################################ + +## To declare and build dynamic reconfigure parameters within this +## package, follow these steps: +## * In the file package.xml: +## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" +## * In this file (CMakeLists.txt): +## * add "dynamic_reconfigure" to +## find_package(catkin REQUIRED COMPONENTS ...) +## * uncomment the "generate_dynamic_reconfigure_options" section below +## and list every .cfg file to be processed + +## Generate dynamic reconfigure parameters in the 'cfg' folder +# generate_dynamic_reconfigure_options( +# cfg/DynReconf1.cfg +# cfg/DynReconf2.cfg +# ) + +################################### +## 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 your 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 Air_Ground_CEC +# CATKIN_DEPENDS roscpp +# DEPENDS system_lib +) + +########### +## Build ## +########### + +find_package(OpenCV REQUIRED) +find_package(Qt5 REQUIRED COMPONENTS Widgets ) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTOUIC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + src/include/qnode.hpp + src/include/joystick.h + src/include/dashboard.h + src/main/main.cpp + src/main/mainwindow.cpp + src/main/qnode.cpp + src/main/joystick.cpp + src/main/dashboard.cpp + src/ui/mainwindow.hpp + src/ui/mainwindow.ui + +) + +QT5_add_resources(qrc_Files src/resources/images.qrc) +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( + include/Air_Ground_CEC + ${catkin_INCLUDE_DIRS} + ${OpenCV_INCLUDE_DIRS} +) + +add_executable(Air_Ground_CEC ${SOURCES} ${qrc_Files}) +target_link_libraries(Air_Ground_CEC + Qt5::Widgets + ${catkin_LIBRARIES} + ${OpenCV_LIBRARIES} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/Air_Ground_CEC.cpp +# ) + +## Add cmake target dependencies of the library +## as an example, code may need to be generated before libraries +## either from message generation or dynamic reconfigure +# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Declare a C++ executable +## With catkin_make all packages are built within a single CMake context +## The recommended prefix ensures that target names across packages don't collide +# add_executable(${PROJECT_NAME}_node src/Air_Ground_CEC_node.cpp) + +## Rename C++ executable without prefix +## The above recommended prefix causes long target names, the following renames the +## target back to the shorter version for ease of user use +## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" +# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") + +## Add cmake target dependencies of the executable +## same as for the library above +# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Specify libraries to link a library or executable target against +# target_link_libraries(${PROJECT_NAME}_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 +# catkin_install_python(PROGRAMS +# scripts/my_python_script +# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark executables for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html +# install(TARGETS ${PROJECT_NAME}_node +# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark libraries for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html +# install(TARGETS ${PROJECT_NAME} +# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# RUNTIME DESTINATION ${CATKIN_GLOBAL_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_Air_Ground_CEC.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/README.md b/README.md new file mode 100644 index 0000000..0d88f33 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Air-ground-CEC + +test \ No newline at end of file diff --git a/doc/空地协同无人侦察系统-软件设计规格说明书.doc b/doc/空地协同无人侦察系统-软件设计规格说明书.doc new file mode 100644 index 0000000..21c3aba Binary files /dev/null and b/doc/空地协同无人侦察系统-软件设计规格说明书.doc differ diff --git a/doc/空地协同无人侦察系统-软件需求构思及描述.docx b/doc/空地协同无人侦察系统-软件需求构思及描述.docx new file mode 100644 index 0000000..98af291 Binary files /dev/null and b/doc/空地协同无人侦察系统-软件需求构思及描述.docx differ diff --git a/doc/空地协同无人侦察系统-软件需求规格说明书.docx b/doc/空地协同无人侦察系统-软件需求规格说明书.docx new file mode 100644 index 0000000..8083faa Binary files /dev/null and b/doc/空地协同无人侦察系统-软件需求规格说明书.docx differ diff --git a/model/UML设计图.vsdx b/model/UML设计图.vsdx new file mode 100755 index 0000000..ac1e19d Binary files /dev/null and b/model/UML设计图.vsdx differ diff --git a/package.xml b/package.xml new file mode 100644 index 0000000..9c40002 --- /dev/null +++ b/package.xml @@ -0,0 +1,73 @@ + + + Air_Ground_CEC + 0.1.0 + The Air_Ground_CEC package + + + + + jackyma + + + + + + Apache 2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + roscpp + roscpp + roscpp + + opencv2 + opencv2 + opencv2 + + message_generation + message_generation + message_runtime + + std_msgs sensor_msgs cv_bridge image_transport + std_msgs sensor_msgs cv_bridge image_transport + std_msgs sensor_msgs cv_bridge image_transport + + + + + + + diff --git a/src/Djitellowhite/Djitellowhite.cpp b/src/Djitellowhite/Djitellowhite.cpp new file mode 100644 index 0000000..c8a8f52 --- /dev/null +++ b/src/Djitellowhite/Djitellowhite.cpp @@ -0,0 +1,146 @@ +#include"Djitellowhite.h" +#include +#include + + +#include +#include +#include + +#include +#include + +using namespace cv; +using namespace std; +Tello::Tello(const char* IP) { + this->stream_on=false; + this->host = inet_addr(IP); + cout << "create successfully!" << endl; + +} +Tello::~Tello() {} +void Tello::set_conf(int socket){ + this->sock = socket; +} +void Tello::get_connect(sockaddr_in serveraddr) { + char tmp[10] = {"command"}; + send_message(tmp,serveraddr,0);// 0 -> timeout + cout << "connect successfully!" <host; +} +void Tello::takeoff(sockaddr_in serveraddr) { + char tmp[10] = {"takeoff"}; + send_message(tmp,serveraddr,0);// 0 -> timeout + cout << "takeoff successfully!" < timeout + cout << "land successfully!" <sock,buffer,strlen(buffer),0,(struct sockaddr *)&server_addr, sizeof(server_addr)); + return true; +} +void* Tello::udp_response_receiver(void* arg){ + //int m_SockServer; //创建socket对象 + //sockaddr_in serveraddr; //创建sockaddr_in对象储存自身信息(当有多个端口,可以多个绑定) + //sockaddr_in serveraddrfrom; + + //serveraddr.sin_family = AF_INET; //设置服务器地址家族 + //serveraddr.sin_port = htons(8889); //设置服务器端口号 + //serveraddr.sin_addr.s_addr = inet_addr("0.0.0.0"); + //m_SockServer = socket(AF_INET, SOCK_DGRAM, 0); //创建一个临时变量并赋值给m_SockServer + //int i = bind(m_SockServer, (sockaddr*)&serveraddr, sizeof(serveraddr)); //把名字和套接字绑定 + //std::cout << "bind:" << i << std::endl; + + int socket = *(int *)arg; + + cout << "receive start" << endl; + while(1){ + char buffer[20]; + int iret; + memset(buffer,0,sizeof(buffer)); + + iret = recv(socket, buffer,20,MSG_WAITALL); + if(iret > 0 && iret <10){ + printf("Message from tello: %s\n", buffer); + } + } +} +void Tello::forward(sockaddr_in serveraddr){ + char tmp[15] = {"forward 20"}; + send_message(tmp,serveraddr,0);// 0 -> timeout + cout << "forward successfully!" < timeout + cout << "back successfully!" < timeout + cout << "left successfully!" < timeout + cout << "right successfully!" < timeout + cout << "up successfully!" < timeout + cout << "down successfully!" < timeout + cout << "cw successfully!" < timeout + cout << "ccw successfully!" <stream_on = true; + + cout << "vid"; + VideoCapture cap("udp://@0.0.0.0:11111"); + cout << "cap"; + if(!cap.isOpened()){ + cout << "fuck off"; + return; + } + + Mat frame; + cout << "continue!"; + while(1){ + cap>>frame; + if(frame.empty()) + break; + imshow("video",frame); + waitKey(20); + + } + cap.release(); + + +} diff --git a/src/Djitellowhite/Djitellowhite.h b/src/Djitellowhite/Djitellowhite.h new file mode 100644 index 0000000..bfaa936 --- /dev/null +++ b/src/Djitellowhite/Djitellowhite.h @@ -0,0 +1,80 @@ +#ifndef _DJITELLOWHITE_H +#define _DJITELLOWHITE_H +#include +#include +#include +#include +#include +#include +/*Library for interacting with DJI Ryze Tello drones.*/ + + +//coding = utf - 8 + +/* """C++ wrapper to interact with the Ryze Tello drone using the official Tello api. + Tello API documentation: + [1.3](https://dl-cdn.ryzerobotics.com/downloads/tello/20180910/Tello%20SDK%20Documentation%20EN_1.3.pdf) +*/ + +#define RESPONSE_TIMEOUT 7 //in seconds +#define TAKEOFF_TIMEOUT 20 //in seconds +#define FRAME_GRAB_TIMEOUT 3 +#define TIME_BTW_COMMANDS 0.1 //in seconds +#define TIME_BTW_RC_CONTROL_COMMANDS 0.001 //in seconds +#define RETRY_COUNT 3 //number of retries after a failed command + + +//Video stream, server socket +#define VS_UDP_IP "0.0.0.0" +#define VS_UDP_PORT 11111 + +#define CONTROL_UDP_PORT 8889 +#define STATE_UDP_PORT 8890 + +#define BUFFER_SIZE 1024 +//Constants for video settings +#define BITRATE_AUTO 0 +#define BITRATE_1MBPS 1 +#define BITRATE_2MBPS 2 +#define BITRATE_3MBPS 3 +#define BITRATE_4MBPS 4 +#define BITRATE_5MBPS 5 +#define RESOLUTION_480P "low" +#define RESOLUTION_720P "high" +#define FPS_5 "low" +#define FPS_15 "middle" +#define FPS_30 "high" +#define CAMERA_FORWARD 0 +#define CAMERA_DOWNWARD 1 +//日志模块暂时不写 + +class Tello { +private: + int sock; + bool stream_on; + unsigned long host; +public: + Tello(const char* IP); + ~Tello(); + void set_conf(int socket); + unsigned long gethost(); + void get_connect(sockaddr_in serveraddr); + void takeoff(sockaddr_in serveraddr); + void land(sockaddr_in serveraddr); + void forward(sockaddr_in serveraddr); + void back(sockaddr_in serveraddr); + void left(sockaddr_in serveraddr); + void right(sockaddr_in serveraddr); + void up(sockaddr_in serveraddr); + void down(sockaddr_in serveraddr); + void cw(sockaddr_in serveraddr); + void ccw(sockaddr_in serveraddr); + bool send_message(char* msg,sockaddr_in server_addr,int timeout = RESPONSE_TIMEOUT); + static void *udp_response_receiver(void* arg); + void get_video(sockaddr_in serveraddr); +}; + + + + +#endif diff --git a/src/Djitellowhite/Djitellowhite.o b/src/Djitellowhite/Djitellowhite.o new file mode 100644 index 0000000..12a9638 Binary files /dev/null and b/src/Djitellowhite/Djitellowhite.o differ diff --git a/src/Djitellowhite/Hardwarelistener.h b/src/Djitellowhite/Hardwarelistener.h new file mode 100644 index 0000000..599fa82 --- /dev/null +++ b/src/Djitellowhite/Hardwarelistener.h @@ -0,0 +1,6 @@ +#ifndef _HARDWARELISTENER_H +#define _HARDWARELISTENER_H +#include "Djitellowhite.h" +int listenkeyboard(Tello T,sockaddr_in serveraddr); +int scanKeyboard(); +#endif diff --git a/src/Djitellowhite/Triplet.cpp b/src/Djitellowhite/Triplet.cpp new file mode 100644 index 0000000..9c0ef65 --- /dev/null +++ b/src/Djitellowhite/Triplet.cpp @@ -0,0 +1,45 @@ +#include"Djitellowhite.h" +#include"Hardwarelistener.h" +#include +using namespace std; +int main(void){ + Tello T("192.168.10.1"); + int socket_fd, err; + + if((socket_fd = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP))==-1) + { + cout << "initialized error" << endl; + cout << 0; + return -1; + } + + //cout << 1 << socket_fd; + T.set_conf(socket_fd); + + pthread_t thread_receive; + err = pthread_create(&thread_receive,nullptr,T.udp_response_receiver,&socket_fd); + sleep(3); + struct sockaddr_in serveraddr; + memset(&serveraddr,0,sizeof(serveraddr)); + serveraddr.sin_family=AF_INET; + serveraddr.sin_addr.s_addr=T.gethost(); + serveraddr.sin_port=htons(CONTROL_UDP_PORT); + + + + if(err!=0) + { + cout << err << " " << "can't create thread"; + } + + T.get_connect(serveraddr); + //sleep(1); + //T.takeoff(serveraddr); + T.get_video(serveraddr); + sleep(5); + //T.land(serveraddr); + + pthread_join(thread_receive,NULL); + listenkeyboard(T,serveraddr); + return 0; +} diff --git a/src/Djitellowhite/keyboard.cpp b/src/Djitellowhite/keyboard.cpp new file mode 100644 index 0000000..dcf3ade --- /dev/null +++ b/src/Djitellowhite/keyboard.cpp @@ -0,0 +1,57 @@ +#include +#include +#include "Hardwarelistener.h" +#include + +using namespace std; +int scanKeyboard() +{ + + int in; + + struct termios new_settings; + struct termios stored_settings; + //设置终端参数 + tcgetattr(0,&stored_settings); + new_settings = stored_settings; + new_settings.c_lflag &= (~ICANON); + new_settings.c_cc[VTIME] = 0; + tcgetattr(0,&stored_settings); + new_settings.c_cc[VMIN] = 1; + tcsetattr(0,TCSANOW,&new_settings); + in = getchar(); + tcsetattr(0,TCSANOW,&stored_settings); + + return in; + +} + +//测试函数 +int listenkeyboard(Tello T, sockaddr_in serveraddr){ + while(1){ + switch(scanKeyboard()) + { + case (int)'w': + cout << "forward"<< endl; + T.forward(serveraddr); + break; + case (int)'s': + cout << "back" << endl; + T.back(serveraddr); + break; + case (int)'a': + cout << "left" < +#include +#include +#include +#include +#include +#include +#include +#define PORT 8890 + +void udp_server(int sockfd) +{ + + socklen_t len; + char buf[1024] = {0}; + struct sockaddr_in server_addr; + int n; + int opt = 1; + len = sizeof(server_addr); + memset(&buf, 0, sizeof(buf)); + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = htonl(INADDR_ANY); + server_addr.sin_port = htons(PORT); + + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); //当服务器非正常断开的时候重启服务器,不会进入TIME_WAIT状态 + + if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + printf("can not bind\n"); + exit(1); + } + + while (1) { + printf("========wait for client's request========\n"); + n = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&server_addr, &len); + buf[n] = '\0'; + printf("receive client's data: %s\n", buf); + sendto(sockfd, buf, n, 0, (struct sockaddr *)&server_addr, len); + printf("send data to client: %s\n", buf); + } + + close(sockfd); +} + +int main(int argc, char **argv) +{ + int sockfd; + + if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + printf("create socket false\n"); + exit(1); + } + + udp_server(sockfd); + + exit(0); +} + + diff --git a/src/Djitellowhite/test b/src/Djitellowhite/test new file mode 100755 index 0000000..5becd75 Binary files /dev/null and b/src/Djitellowhite/test differ diff --git a/src/include/dashboard.h b/src/include/dashboard.h new file mode 100644 index 0000000..cf3d39a --- /dev/null +++ b/src/include/dashboard.h @@ -0,0 +1,53 @@ +#ifndef DASHBOARD_H +#define DASHBOARD_H + +#include + +class DashBoard : public QWidget { + Q_OBJECT + public: + enum Gear { + kGear_1 = 1, + kGear_2, + kGear_3, + kGear_4, + kGear_5, + kGear_6, + kGear_7, + kGear_8, + kGear_D, + kGear_N, + kGear_P, + kGear_R + }; + + public: + explicit DashBoard(QWidget* parent = nullptr); + + public slots: + void set_gear(const Gear gear); + void set_rpm(const int rpm); + void set_speed(const int speed); + void set_temperature(const double temperature); + void set_oil(const int oil); + + protected: + void paintEvent(QPaintEvent* event); + + private: + void draw_tachometer(QPainter& painter); // 转速表 + void draw_speedometer(QPainter& painter); // 迈速表 + void draw_gear(QPainter& painter); // 挡位 + void draw_thermometer(QPainter& painter); // 水箱温度计 + void draw_oil_meter(QPainter& painter); // 油表 + + private: + Gear _gear{kGear_N}; + int _rpm; + int _speed; + double _temperature; + int _oil; + QWidget* parent; +}; + +#endif // DASHBOARD_H diff --git a/src/include/joystick.h b/src/include/joystick.h new file mode 100644 index 0000000..26969d3 --- /dev/null +++ b/src/include/joystick.h @@ -0,0 +1,55 @@ +#ifndef JOYSTICK_H +#define JOYSTICK_H + +#include +#include +#include +#include +#include +#include +#include +class JoyStick : public QWidget { + Q_OBJECT + + public: + JoyStick(QWidget *parent = 0); + ~JoyStick(); + enum { + upleft = 0, + up, + upright, + left, + stop, + right, + downleft, + down, + downright + }; + signals: + void keyNumchanged(int num); + + protected: + void paintEvent(QPaintEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + // void resizeEvent(QResizeEvent *event)override; + private: + int mouseX; + int mouseY; + int JoyStickX; //摇杆 + int JoyStickY; + int JoyStickR; + int padX; //底盘 + int padY; + int padR; + double handPadDis; //两圆圆心距离 + bool mousePressed; + QTimer *tim; + + private: + double Pointdis(int a, int b, int x, int y); //两点距离 + int getKeyNum(); +}; + +#endif // JoyStick_H diff --git a/src/include/qnode.hpp b/src/include/qnode.hpp new file mode 100644 index 0000000..9f99191 --- /dev/null +++ b/src/include/qnode.hpp @@ -0,0 +1,64 @@ +#ifndef Air_Ground_CEC_QNODE_HPP_ +#define Air_Ground_CEC_QNODE_HPP_ + +#ifndef Q_MOC_RUN +#include +#endif +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +class QNode : public QThread{ + Q_OBJECT + +public: + QNode(int argc, char **argv); + virtual ~QNode(); + bool init(); + void SubAndPubTopic(); + void KeyboardMove(char key, float speed_linear, float speed_trun); + +Q_SIGNALS: + void speed_x(double x); + void speed_th(double th); + void power(float p); + +private: + int init_argc; + char **init_argv; + ros::Publisher chatter_publisher; + ros::Subscriber chatter_subscriber; + ros::Publisher cmd_pub; + ros::Subscriber cmdVel_sub; + ros::Subscriber power_sub; + + QString odom_topic; + QString batteryState_topic; + + + void speedCallback(const nav_msgs::Odometry::ConstPtr& msg); + void powerCallback(const std_msgs::Float32& message_holder); + void myCallback(const std_msgs::Float64& message_holder); + +}; + +#endif + diff --git a/src/main/dashboard.cpp b/src/main/dashboard.cpp new file mode 100644 index 0000000..d5a6ed3 --- /dev/null +++ b/src/main/dashboard.cpp @@ -0,0 +1,384 @@ +#include "../include/dashboard.h" + +#include +#include +#include + +#include + +#include "QDebug" +DashBoard::DashBoard(QWidget* parent) + : QWidget(parent), + _gear(kGear_1), + _rpm(0), + _speed(0), + _temperature(0), + _oil(0) { + QFontDatabase::addApplicationFont(":/fonts/DejaVuSans.ttf"); + this->resize(parent->size()); + this->parent = parent; +} + +void DashBoard::set_gear(const DashBoard::Gear gear) { + _gear = gear; + update(); +} + +void DashBoard::set_rpm(const int rpm) { + _rpm = rpm; + update(); +} + +void DashBoard::set_speed(const int speed) { + _speed = speed; + _rpm = speed; + update(); +} + +void DashBoard::set_temperature(const double temperature) { + _temperature = temperature; + update(); +} + +void DashBoard::set_oil(const int oil) { + _oil = oil; + update(); +} + +void DashBoard::paintEvent(QPaintEvent* event) { + this->resize(parent->size()); + QWidget::paintEvent(event); + + int side = qMin(int(parent->width() / 1.8), parent->height()); + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + painter.translate(parent->width() / 2, parent->height() / 2); + painter.scale(side / 200.0, side / 200.0); + painter.setPen(Qt::NoPen); + painter.setBrush(Qt::NoBrush); + + draw_tachometer(painter); + draw_speedometer(painter); + draw_gear(painter); + draw_thermometer(painter); + draw_oil_meter(painter); +} + +void DashBoard::draw_tachometer(QPainter& painter) { + static QColor normal_color(26, 245, 245, 245); + static QColor overrun_color(245, 64, 64, 225); + + // 绘制表盘外檐 + painter.save(); + painter.setPen(QPen(normal_color, 1, Qt::SolidLine)); + QRect rect(-95, -95, 190, 190); + painter.drawArc(rect, 0, 270 * 16); + painter.restore(); + + // 绘制红色区域 + painter.save(); + static QRectF rectangle_outer(-95, -95, 190, 190); + static QRectF rectangle_inner(-87, -87, 174, 174); + painter.setBrush(overrun_color); + QPainterPath path; + path.arcTo(rectangle_outer, 0.0, 108.0); + path.arcTo(rectangle_inner, 108, -108); + painter.drawPath(path); + painter.restore(); + + // 绘制大刻度 + painter.save(); + painter.setPen(QPen(normal_color, 1, Qt::SolidLine)); + painter.rotate(90); + for (int i = 0; i < 21; ++i) { + painter.drawLine(88, 0, 94, 0); + painter.rotate(13.5); + } + painter.restore(); + + // 绘制小刻度 + painter.save(); + painter.setPen(QPen(normal_color, 1, Qt::SolidLine)); + painter.rotate(90); + for (int i = 0; i < 100; ++i) { + painter.drawLine(91, 0, 94, 0); + painter.rotate(2.7); + } + painter.restore(); + + // 绘制表盘数字 + painter.save(); + painter.rotate(90); + painter.setPen(normal_color); + painter.setFont(QFont("Times", 14)); + for (int i = 0; i < 11; ++i) { + painter.save(); + if (i > 6) { + painter.setPen(overrun_color); + } + painter.rotate(27.0 * i); + painter.translate(76, 0); + painter.rotate(270 - 27.0 * i); + painter.drawText(QRect(-20, -10, 40, 20), Qt::AlignCenter, + QString::number(i)); + painter.restore(); + } + painter.restore(); + + // 绘制指针 + static const QPoint hand[] = {QPoint(-4, 0), QPoint(0, 94), QPoint(4, 0), + QPoint(0, -6)}; + static QColor hand_color(26, 245, 245, 176); + painter.save(); + painter.setPen(Qt::NoPen); + painter.setBrush(hand_color); + painter.rotate(27.0 * (_rpm / 10.0)); + painter.drawConvexPolygon(hand, 4); + painter.restore(); + + // 绘制文字 + painter.save(); + painter.setPen(normal_color); + painter.setFont(QFont("DejaVu Sans", 8)); + painter.drawText(QRect(-50, -70, 100, 50), Qt::AlignCenter, "×10"); + painter.setFont(QFont("DejaVu Sans", 8, 50, true)); + painter.drawText(QRect(-50, 34, 32, 16), Qt::AlignCenter, "CM/S"); + painter.restore(); +} + +void DashBoard::draw_speedometer(QPainter& painter) { + painter.save(); + + painter.setPen(QColor(64, 64, 245)); + painter.setFont(QFont("DejaVu Sans", 6, 50, true)); + painter.drawText(QRect(80, 50, 70, 20), Qt::AlignCenter, "SPEED"); + + painter.setPen(QColor(26, 245, 245)); + painter.setFont(QFont("DejaVu Sans", 24, 63, true)); + painter.drawText(QRect(80, 50, 70, 50), Qt::AlignBottom | Qt::AlignLeft, + QString("%0").arg(QString::number(_speed), 3, '0')); + + painter.setPen(QColor(26, 245, 245)); + painter.setFont(QFont("DejaVu Sans", 8, 63, true)); + painter.drawText(QRect(145, 75, 40, 20), Qt::AlignBottom | Qt::AlignLeft, + "cm/s"); + + painter.restore(); +} + +void DashBoard::draw_gear(QPainter& painter) { + static QRect gear_rect(0, 0, 80, 80); + static QRect suffix_rect(48, 48, 32, 32); + static QFont suffix_font("DejaVu Sans", 16, 63, true); + + painter.save(); + painter.setPen(QPen(QColor(26, 245, 245), 1, Qt::SolidLine)); + painter.setFont(QFont("DejaVu Sans", 48, 63, true)); + + switch (_gear) { + case kGear_1: + painter.drawText(gear_rect, Qt::AlignCenter, QString::number(_gear)); + painter.setFont(suffix_font); + painter.drawText(suffix_rect, Qt::AlignCenter, "st"); + break; + case kGear_2: + painter.drawText(gear_rect, Qt::AlignCenter, QString::number(_gear)); + painter.setFont(suffix_font); + painter.drawText(suffix_rect, Qt::AlignCenter, "nd"); + break; + case kGear_3: + painter.drawText(gear_rect, Qt::AlignCenter, QString::number(_gear)); + painter.setFont(suffix_font); + painter.drawText(suffix_rect, Qt::AlignCenter, "rd"); + break; + case kGear_4: + case kGear_5: + case kGear_6: + case kGear_7: + case kGear_8: + painter.drawText(gear_rect, Qt::AlignCenter, QString::number(_gear)); + painter.setFont(suffix_font); + painter.drawText(suffix_rect, Qt::AlignCenter, "th"); + break; + case kGear_D: + painter.drawText(gear_rect, Qt::AlignCenter, "D"); + break; + case kGear_N: + painter.drawText(gear_rect, Qt::AlignCenter, "N"); + break; + case kGear_P: + painter.drawText(gear_rect, Qt::AlignCenter, "P"); + break; + case kGear_R: + painter.drawText(gear_rect, Qt::AlignCenter, "R"); + break; + default: + break; + } + + painter.restore(); +} + +void DashBoard::draw_thermometer(QPainter& painter) { + painter.save(); + + painter.drawImage(QRect(115, -60, 8, 16), + QImage("://images/temperature-icon.png")); + + painter.translate(-160, 100); + + static QColor normal_color(26, 245, 245, 245); + static QColor overrun_color(245, 64, 64, 225); + + // 绘制表盘外檐 + painter.save(); + painter.setPen(QPen(normal_color, 1, Qt::SolidLine)); + QRect rect(-300, -300, 600, 600); + painter.drawArc(rect, 12 * 16, 20 * 16); + painter.restore(); + + // 绘制刻度 + painter.save(); + painter.setPen(QPen(normal_color, 1, Qt::SolidLine)); + painter.rotate(-12); + painter.drawLine(300, 0, 306, 0); + painter.rotate(-10); + painter.drawLine(300, 0, 304, 0); + painter.rotate(-10); + painter.drawLine(300, 0, 306, 0); + painter.restore(); + + // 绘制刻度值 + painter.save(); + painter.setPen(normal_color); + painter.setFont(QFont("DejaVu Sans", 6)); + + painter.rotate(-12); + painter.save(); + painter.translate(316, 0); + painter.rotate(12); + painter.drawText(QRect(-20, -10, 40, 20), Qt::AlignCenter, + QString::number(0) + "°C"); + painter.restore(); + + painter.rotate(-10); + painter.save(); + painter.translate(317, 0); + painter.rotate(22); + painter.drawText(QRect(-20, -10, 40, 20), Qt::AlignCenter, + QString::number(50) + "°C"); + painter.restore(); + + painter.rotate(-10); + painter.save(); + painter.translate(320, 0); + painter.rotate(32); + painter.drawText(QRect(-20, -10, 40, 20), Qt::AlignCenter, + QString::number(100) + "°C"); + painter.restore(); + + painter.restore(); + + // 绘制红色区域 + painter.save(); + static QRectF rectangle_outer(-304, -304, 608, 608); + static QRectF rectangle_inner(-300.5, -300.5, 601, 601); + painter.setBrush(overrun_color); + QPainterPath path; + path.arcTo(rectangle_outer, 28, 3.9); + path.arcTo(rectangle_inner, 31.9, -3.9); + painter.drawPath(path); + painter.restore(); + + // 绘制指针 + painter.save(); + painter.setPen(QPen(overrun_color, 1, Qt::SolidLine)); + painter.rotate(-12 - 0.2 * _temperature); + painter.drawLine(298, 0, 306, 0); + painter.restore(); + + painter.restore(); +} + +void DashBoard::draw_oil_meter(QPainter& painter) { + painter.save(); + + painter.drawImage(QRect(-130, -60, 16, 16), + QImage("://images/fuel-icon.png")); + + painter.translate(160, 100); + painter.rotate(180); + + static QColor normal_color(26, 245, 245, 245); + static QColor overrun_color(245, 64, 64, 225); + + // 绘制表盘外檐 + painter.save(); + painter.setPen(QPen(normal_color, 1, Qt::SolidLine)); + QRect rect(-300, -300, 600, 600); + painter.drawArc(rect, -12 * 16, -20 * 16); + painter.restore(); + + // 绘制刻度 + painter.save(); + painter.setPen(QPen(normal_color, 1, Qt::SolidLine)); + painter.rotate(12); + painter.drawLine(300, 0, 306, 0); + painter.rotate(10); + painter.drawLine(300, 0, 304, 0); + painter.rotate(10); + painter.drawLine(300, 0, 306, 0); + painter.restore(); + + // 绘制刻度值 + painter.save(); + painter.setPen(normal_color); + painter.setFont(QFont("DejaVu Sans", 6)); + + painter.rotate(12); + painter.save(); + painter.translate(316, 0); + painter.rotate(168); + painter.drawText(QRect(-20, -10, 40, 20), Qt::AlignCenter, + QString::number(0) + "%"); + painter.restore(); + + painter.rotate(10); + painter.save(); + painter.translate(317, 0); + painter.rotate(158); + painter.drawText(QRect(-20, -10, 40, 20), Qt::AlignCenter, + QString::number(50) + "%"); + painter.restore(); + + painter.rotate(10); + painter.save(); + painter.translate(320, 0); + painter.rotate(148); + painter.drawText(QRect(-20, -10, 40, 20), Qt::AlignCenter, + QString::number(100) + "%"); + painter.restore(); + + painter.restore(); + + // 绘制红色区域 + painter.save(); + static QRectF rectangle_outer(-304, -304, 608, 608); + static QRectF rectangle_inner(-300.5, -300.5, 601, 601); + painter.setBrush(overrun_color); + QPainterPath path; + path.arcTo(rectangle_outer, -12.1, -3.9); + path.arcTo(rectangle_inner, -16, 3.9); + painter.drawPath(path); + painter.restore(); + + // 绘制指针 + painter.save(); + painter.setPen(QPen(overrun_color, 1, Qt::SolidLine)); + painter.rotate(12 + 0.2 * _oil); + painter.drawLine(298, 0, 306, 0); + painter.restore(); + + painter.restore(); +} diff --git a/src/main/joystick.cpp b/src/main/joystick.cpp new file mode 100644 index 0000000..8d6eb41 --- /dev/null +++ b/src/main/joystick.cpp @@ -0,0 +1,105 @@ +#include "../include/joystick.h" + +#include +JoyStick::JoyStick(QWidget* parent) : QWidget(parent) { + setPalette(QPalette(Qt::white)); + resize(parent->width(), parent->height()); + setMinimumSize(100, 100); + mouseX = width() / 2; + mouseY = height() / 2; + tim = new QTimer(this); + connect(tim, &QTimer::timeout, this, + [=] { emit keyNumchanged(getKeyNum()); }); + // connect(this,&JoyStick::keyNumchanged,this,[=](int num){ + // qDebug()<pos().x(); + mouseY = event->pos().y(); + if (r == true) { + update(); + r = false; + } else { + r = true; + } +} +void JoyStick::mouseReleaseEvent(QMouseEvent* event) { + mouseX = width() / 2; + mouseY = height() / 2; + tim->stop(); + mousePressed = false; + emit keyNumchanged(JoyStick::stop); + update(); +} +void JoyStick::mousePressEvent(QMouseEvent* event) { + mouseX = event->pos().x(); + mouseY = event->pos().y(); + tim->start(100); + mousePressed = true; + update(); +} + +double JoyStick::Pointdis(int a, int b, int x, int y) { + return sqrt((double)((x - a) * (x - a) + (y - b) * (y - b))); +} +int JoyStick::getKeyNum() { + int x, y; + int keynum; + x = (int)(JoyStickX * 3.0 / (padR * 2)); + y = (int)(JoyStickY * 3.0 / (padR * 2)); + keynum = 3 * y + x; + return keynum; +} diff --git a/src/main/main.cpp b/src/main/main.cpp new file mode 100644 index 0000000..e31bc33 --- /dev/null +++ b/src/main/main.cpp @@ -0,0 +1,27 @@ + +#include "../ui/mainwindow.hpp" + +#include + +#include + + + +int main(int argc, char** argv) +{ + + + QApplication app(argc, argv); + MainWindow CEC(0,0,0); + + CEC.show(); + return app.exec(); + + return(0); +} + + + +/* + * find . "(" -name "*.cpp" -or -name "*.h" -or -name "*.hpp" -or -name "*.qrc" ")" -print | xargs wc -l + */ diff --git a/src/main/mainwindow.cpp b/src/main/mainwindow.cpp new file mode 100644 index 0000000..a7c0447 --- /dev/null +++ b/src/main/mainwindow.cpp @@ -0,0 +1,325 @@ +#include "../ui/mainwindow.hpp" + + + +MainWindow::MainWindow(int argc, char **argv, QWidget *parent) : + QMainWindow(parent), qnode(argc, argv), + ui(new Ui::MainWindow) + +{ + qnode.init(); + ui->setupUi(this); + initUis(); + connections(); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + + +void MainWindow::initUis(){ + setBtnStyles(); + + + /* + * init + */ + + rock_widget = new JoyStick(ui->JoyStick_widget); + rock_widget->show(); + + + m_DashBoard_x = new DashBoard(ui->widget_speed_x); + m_DashBoard_x->setGeometry(ui->widget_speed_x->rect()); + + m_DashBoard_th = new DashBoard(ui->widget_speed_th); + m_DashBoard_th->setGeometry(ui->widget_speed_th->rect()); + + +} + + +void MainWindow::setBtnStyles(){ + /* + * set PushButton state + */ + + ui->btn_main->setIcon(QIcon("://images/up.png")); + ui->btn_main->setText("mainWidget"); + ui->btn_main->setStyleSheet( + "QPushButton:hover{" + "background-color:rgb(186, 189, 182);" + "border-bottom:2px solid rgb(67, 154, 246);}" + "QPushButton:checked{" + "background-color:cyan;" + "border-bottom:2px solid white}" + "QPushButton:pressed{" + "background-color:rgb(67, 154, 246)}" + "QPushButton{" + "background-color:rgb(238, 238, 236);" + "border:none;" + "padding:0px 0px 0px 0px;" + "margin:0px 0px 0px 0px;}"); + + ui->btn_uav->setStyleSheet( + "QPushButton:hover{" + "background-color:rgb(186, 189, 182);" + "border-bottom:2px solid rgb(67, 154, 246);}" + "QPushButton:checked{" + "background-color:cyan;" + "border-bottom:2px solid white}" + "QPushButton:pressed{" + "background-color:rgb(67, 154, 246)}" + "QPushButton{" + "background-color:rgb(238, 238, 236);" + "border:none;" + "padding:0px 0px 0px 0px;" + "margin:0px 0px 0px 0px;}"); + + ui->btn_ugv->setStyleSheet( + "QPushButton:hover{" + "background-color:rgb(186, 189, 182);" + "border-bottom:2px solid rgb(67, 154, 246);}" + "QPushButton:checked{" + "background-color:cyan;" + "border-bottom:2px solid white}" + "QPushButton:pressed{" + "background-color:rgb(67, 154, 246)}" + "QPushButton{" + "background-color:rgb(238, 238, 236);" + "border:none;" + "padding:0px 0px 0px 0px;" + "margin:0px 0px 0px 0px;}"); + + // 8 -> Forward: ↑ + ui->pushButton_Forward->setShortcut(Qt::Key_8); + ui->pushButton_Forward->setStyleSheet( + "QPushButton{border-image: url(://images/up.png)}" + "QPushButton{border:none}" + "QPushButton:pressed{border-image: url(://images/up_2.png)}"); + ui->pushButton_Forward->setFlat(true); + + // 2 -> Back: ↓ + ui->pushButton_Back->setShortcut(Qt::Key_2); + ui->pushButton_Back->setStyleSheet( + "QPushButton{border-image: url(://images/down.png)}" + "QPushButton{border:none}" + "QPushButton:pressed{border-image: url(://images/down_2.png)}"); + ui->pushButton_Back->setFlat(true); + + // 4 -> Left: ← + ui->pushButton_Left->setShortcut(Qt::Key_4); + ui->pushButton_Left->setStyleSheet( + "QPushButton{border-image: url(://images/left.png)}" + "QPushButton{border:none}" + "QPushButton:pressed{border-image: url(://images/left_2.png)}"); + ui->pushButton_Left->setFlat(true); + + // 6 -> Right: → + ui->pushButton_Right->setShortcut(Qt::Key_6); + ui->pushButton_Right->setStyleSheet( + "QPushButton{border-image: url(://images/right.png)}" + "QPushButton{border:none}" + "QPushButton:pressed{border-image: url(://images/right_2.png)}"); + ui->pushButton_Right->setFlat(true); + + // 7 -> Left_Forward: ↖ + ui->pushButton_Left_Forward->setShortcut(Qt::Key_7); + ui->pushButton_Left_Forward->setStyleSheet( + "QPushButton{border-image: url(://images/up_left.png)}" + "QPushButton{border:none}" + "QPushButton:pressed{border-image: url(://images/up_left_2.png)}"); + ui->pushButton_Left_Forward->setFlat(true); + + // 9 -> Right_Forward: ↗ + ui->pushButton_Right_Forward->setShortcut(Qt::Key_9); + ui->pushButton_Right_Forward->setStyleSheet( + "QPushButton{border-image: url(://images/up_right.png)}" + "QPushButton{border:none}" + "QPushButton:pressed{border-image: url(://images/up_right_2.png)}"); + ui->pushButton_Right_Forward->setFlat(true); + + // 1 -> Left_Back: ↙ + ui->pushButton_Left_Back->setShortcut(Qt::Key_1); + ui->pushButton_Left_Back->setStyleSheet( + "QPushButton{border-image: url(://images/down_left.png)}" + "QPushButton{border:none}" + "QPushButton:pressed{border-image: url(://images/down_left_2.png)}"); + ui->pushButton_Left_Back->setFlat(true); + + // 3 -> Right_Back: ↘ + ui->pushButton_Right_Back->setShortcut(Qt::Key_3); + ui->pushButton_Right_Back->setStyleSheet( + "QPushButton{border-image: url(://images/down_right.png)}" + "QPushButton{border:none}" + "QPushButton:pressed{border-image: url(://images/down_right_2.png)}"); + ui->pushButton_Right_Back->setFlat(true); + +} + + +void MainWindow::slot_keyboard_control(){ + QPushButton *btn = qobject_cast(sender()); + std::string btn_name = btn->text().toStdString(); + char key = ' '; + + if (btn_name == "↙") + key = '1'; + else if (btn_name == "↓") + key = '2'; + else if (btn_name == "↘") + key = '3'; + else if (btn_name == "←") + key = '4'; + //else if (btn_name == "") + // key = '5'; + else if (btn_name == "→") + key = '6'; + else if (btn_name == "↖") + key = '7'; + else if (btn_name == "↑") + key = '8'; + else if (btn_name == "↗") + key = '9'; + + //速度 + float liner = ui->horizontalSlider_linear->value() * 0.01; + float turn = ui->horizontalSlider_raw->value() * 0.01; + //bool is_rage_mode = ui->checkBox_rage_mode->isChecked(); + //std::cout<horizontalSlider_linear->value() * 0.01; + float turn = ui->horizontalSlider_raw->value() * 0.01; + switch (key) { + case upleft: + qnode.KeyboardMove('7', liner, turn); + break; + case up: + qnode.KeyboardMove('8', liner, turn); + break; + case upright: + qnode.KeyboardMove('9', liner, turn); + break; + case left: + qnode.KeyboardMove('4', liner, turn); + break; + case right: + qnode.KeyboardMove('6', liner, turn); + break; + case downleft: + qnode.KeyboardMove('1', liner, turn); + break; + case down: + qnode.KeyboardMove('2', liner, turn); + break; + case downright: + qnode.KeyboardMove('3', liner, turn); + break; + } + +} + +void MainWindow::connections(){ + QObject::connect(ui->btn_main, &QPushButton::clicked, this, [=](){ + ui->stackedWidget_main->setCurrentIndex(0); + }); + QObject::connect(ui->btn_uav, &QPushButton::clicked, this, [=](){ + ui->stackedWidget_main->setCurrentIndex(1); + }); + QObject::connect(ui->btn_ugv, &QPushButton::clicked, this, [=](){ + ui->stackedWidget_main->setCurrentIndex(2); + }); + + QObject::connect(ui->btn_system, &QPushButton::clicked, this, [=](){ + ui->stackedWidget_ros_control->setCurrentIndex(1); + }); + QObject::connect(ui->btn_keyboard, &QPushButton::clicked, this, [=](){ + ui->stackedWidget_ros_control->setCurrentIndex(0); + }); + + /* + * 绑定速度控制按钮 + */ + + // 8 -> Forward: ↑ + connect(ui->pushButton_Forward, SIGNAL(clicked()), this, SLOT(slot_keyboard_control())); + // 2 -> Back: ↓ + connect(ui->pushButton_Back, SIGNAL(clicked()), this, SLOT(slot_keyboard_control())); + // 4 -> Left: ← + connect(ui->pushButton_Left, SIGNAL(clicked()), this, SLOT(slot_keyboard_control())); + // 6 -> Right: → + connect(ui->pushButton_Right, SIGNAL(clicked()), this, SLOT(slot_keyboard_control())); + // 7 -> Left_Forward: ↖ + connect(ui->pushButton_Left_Forward, SIGNAL(clicked()), this, SLOT(slot_keyboard_control())); + // 9 -> Right_Forward: ↗ + connect(ui->pushButton_Right_Forward, SIGNAL(clicked()), this, SLOT(slot_keyboard_control())); + // 1 -> Left_Back: ↙ + connect(ui->pushButton_Left_Back, SIGNAL(clicked()), this, SLOT(slot_keyboard_control())); + // 3 -> Right_Back: ↘ + connect(ui->pushButton_Right_Back, SIGNAL(clicked()), this, SLOT(slot_keyboard_control())); + + connect(rock_widget, SIGNAL(keyNumchanged(int)), this, + SLOT(slot_rockKeyChange(int))); + + //绑定slider的函数 + connect(ui->horizontalSlider_raw, SIGNAL(valueChanged(int)), this, + SLOT(Slider_raw_valueChanged(int))); + connect(ui->horizontalSlider_linear, SIGNAL(valueChanged(int)), this, + SLOT(Slider_linear_valueChanged(int))); + + connect(&qnode, SIGNAL(speed_x(double)), this, SLOT(slot_speed_x(double))); + connect(&qnode, SIGNAL(speed_th(double)), this, SLOT(slot_speed_th(double))); +} + + +void MainWindow::slot_speed_x(double x) { + m_DashBoard_x->set_speed(abs(x * 100)); + if (x > 0.001) { + m_DashBoard_x->set_gear(DashBoard::kGear_D); + } else if (x < -0.001) { + m_DashBoard_x->set_gear(DashBoard::kGear_R); + } else { + m_DashBoard_x->set_gear(DashBoard::kGear_N); + } + QString number = QString::number(abs(x * 100)).mid(0, 2); + if (number[1] == ".") { + number = number.mid(0, 1); + } + //ui.label_speed->setText(number); +} + + +void MainWindow::slot_speed_th(double th){ + m_DashBoard_th->set_speed(abs(th * 100)); + if (th > 0.001) { + m_DashBoard_x->set_gear(DashBoard::kGear_D); + } else if (th < -0.001) { + m_DashBoard_x->set_gear(DashBoard::kGear_R); + } else { + m_DashBoard_x->set_gear(DashBoard::kGear_N); + } + QString number = QString::number(abs(th * 100)).mid(0, 2); + if (number[1] == ".") { + number = number.mid(0, 1); + } +} + + +//滑动条处理槽函数 +void MainWindow::Slider_raw_valueChanged(int v) { + ui->label_raw->setText(QString::number(v)); +} +//滑动条处理槽函数 +void MainWindow::Slider_linear_valueChanged(int v) { + ui->label_linear->setText(QString::number(v)); +} + + diff --git a/src/main/qnode.cpp b/src/main/qnode.cpp new file mode 100644 index 0000000..0ee8df5 --- /dev/null +++ b/src/main/qnode.cpp @@ -0,0 +1,78 @@ +#include "../include/qnode.hpp" + +#include "sensor_msgs/image_encodings.h" + +QNode::QNode(int argc, char **argv) : init_argc(argc), init_argv(argv){ + + + +} + + +QNode::~QNode() { + if (ros::isStarted()) { + ros::shutdown(); // explicitly needed since we use ros::start(); + ros::waitForShutdown(); + } + wait(); +} + +bool QNode::init() { + QSettings topic_setting("ros_controller", "settings"); + odom_topic = topic_setting.value("topic/topic_odom", "odom").toString(); + batteryState_topic = + topic_setting.value("topic/topic_power", "battery_state").toString(); + ros::init(init_argc,init_argv,"Air_Ground_CEC", + ros::init_options::AnonymousName | ros::init_options::NoSigintHandler); + SubAndPubTopic(); + return true; +} + +void QNode::SubAndPubTopic(){ + ros::NodeHandle n; + //创建速度话题的订阅者 + cmdVel_sub = n.subscribe(odom_topic.toStdString(), 200, + &QNode::speedCallback, this); + //power_sub = n.subscribe(batteryState_topic.toStdString(), 1000, + // &QNode::powerCallback, this); + cmd_pub = n.advertise("cmd_vel", 1); +} + +void QNode::KeyboardMove(char key, float speed_linear, float speed_trun){ + std::map> moveBindings { + // {'key', {x, y, z, th}} + {'7', {1, 1, 0, 1}}, {'8', {1, 0, 0, 0}}, {'9', {1, -1, 0, -1}}, + {'4', {0, 0, 0, 1}}, {'5', {0, 0, 0, 0}}, {'6', {0, 0, 0, -1}}, + {'1', {-1, 1, 0, 1}}, {'2', {-1, 0, 0, 0}}, {'3', {-1, -1, 0, -1}} + }; + + float x = moveBindings[key][0]; + float y = moveBindings[key][1]; + float z = moveBindings[key][2]; + float th = moveBindings[key][3]; + + //计算线速度和角速度 + float speed = speed_linear; + float turn = speed_trun; + + + + geometry_msgs::Twist twist; + twist.linear.x = x * speed; + twist.linear.y = y * speed; + twist.linear.z = z * speed; + + twist.angular.x = 0; + twist.angular.y = 0; + twist.angular.z = th * turn; + + cmd_pub.publish(twist); + ros::spinOnce(); +} + +//速度回调函数 +void QNode::speedCallback(const nav_msgs::Odometry::ConstPtr& msg) +{ + emit speed_x(msg->twist.twist.linear.x); + emit speed_th(msg->twist.twist.angular.z); +} diff --git a/src/resources/images.qrc b/src/resources/images.qrc new file mode 100644 index 0000000..5b4cff0 --- /dev/null +++ b/src/resources/images.qrc @@ -0,0 +1,20 @@ + + + images/down.png + images/down_2.png + images/down_left.png + images/down_left_2.png + images/down_right.png + images/down_right_2.png + images/left.png + images/left_2.png + images/right.png + images/right_2.png + images/up.png + images/up_2.png + images/up_left.png + images/up_left_2.png + images/up_right.png + images/up_right_2.png + + diff --git a/src/resources/images/down.png b/src/resources/images/down.png new file mode 100644 index 0000000..1fdba49 Binary files /dev/null and b/src/resources/images/down.png differ diff --git a/src/resources/images/down_2.png b/src/resources/images/down_2.png new file mode 100644 index 0000000..b0f2433 Binary files /dev/null and b/src/resources/images/down_2.png differ diff --git a/src/resources/images/down_left.png b/src/resources/images/down_left.png new file mode 100644 index 0000000..d29e9dc Binary files /dev/null and b/src/resources/images/down_left.png differ diff --git a/src/resources/images/down_left_2.png b/src/resources/images/down_left_2.png new file mode 100644 index 0000000..dd21fc2 Binary files /dev/null and b/src/resources/images/down_left_2.png differ diff --git a/src/resources/images/down_right.png b/src/resources/images/down_right.png new file mode 100644 index 0000000..f65187d Binary files /dev/null and b/src/resources/images/down_right.png differ diff --git a/src/resources/images/down_right_2.png b/src/resources/images/down_right_2.png new file mode 100644 index 0000000..408b905 Binary files /dev/null and b/src/resources/images/down_right_2.png differ diff --git a/src/resources/images/left.png b/src/resources/images/left.png new file mode 100644 index 0000000..2b60f08 Binary files /dev/null and b/src/resources/images/left.png differ diff --git a/src/resources/images/left_2.png b/src/resources/images/left_2.png new file mode 100644 index 0000000..26ea2cc Binary files /dev/null and b/src/resources/images/left_2.png differ diff --git a/src/resources/images/right.png b/src/resources/images/right.png new file mode 100644 index 0000000..0a6ca1d Binary files /dev/null and b/src/resources/images/right.png differ diff --git a/src/resources/images/right_2.png b/src/resources/images/right_2.png new file mode 100644 index 0000000..581bbe8 Binary files /dev/null and b/src/resources/images/right_2.png differ diff --git a/src/resources/images/up.png b/src/resources/images/up.png new file mode 100644 index 0000000..5a5717f Binary files /dev/null and b/src/resources/images/up.png differ diff --git a/src/resources/images/up_2.png b/src/resources/images/up_2.png new file mode 100644 index 0000000..200be6e Binary files /dev/null and b/src/resources/images/up_2.png differ diff --git a/src/resources/images/up_left.png b/src/resources/images/up_left.png new file mode 100644 index 0000000..53d47cb Binary files /dev/null and b/src/resources/images/up_left.png differ diff --git a/src/resources/images/up_left_2.png b/src/resources/images/up_left_2.png new file mode 100644 index 0000000..b8824ba Binary files /dev/null and b/src/resources/images/up_left_2.png differ diff --git a/src/resources/images/up_right.png b/src/resources/images/up_right.png new file mode 100644 index 0000000..21c37f5 Binary files /dev/null and b/src/resources/images/up_right.png differ diff --git a/src/resources/images/up_right_2.png b/src/resources/images/up_right_2.png new file mode 100644 index 0000000..1fa93ac Binary files /dev/null and b/src/resources/images/up_right_2.png differ diff --git a/src/ui/Triplet/.gitignore b/src/ui/Triplet/.gitignore new file mode 100644 index 0000000..fab7372 --- /dev/null +++ b/src/ui/Triplet/.gitignore @@ -0,0 +1,73 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + diff --git a/src/ui/Triplet/Triplet.pro b/src/ui/Triplet/Triplet.pro new file mode 100644 index 0000000..06138d8 --- /dev/null +++ b/src/ui/Triplet/Triplet.pro @@ -0,0 +1,38 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + mainwindow.cpp + +HEADERS += \ + mainwindow.h + +FORMS += \ + mainwindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +INCLUDEPATH += /usr/local/include \ +/usr/local/include/opencv2 \ +/usr/local/include/opencv4 + + +LIBS += /usr/local/lib/libopencv_world.so diff --git a/src/ui/Triplet/main.cpp b/src/ui/Triplet/main.cpp new file mode 100644 index 0000000..fd3e533 --- /dev/null +++ b/src/ui/Triplet/main.cpp @@ -0,0 +1,11 @@ +#include "mainwindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/src/ui/Triplet/mainwindow.cpp b/src/ui/Triplet/mainwindow.cpp new file mode 100644 index 0000000..5a195f4 --- /dev/null +++ b/src/ui/Triplet/mainwindow.cpp @@ -0,0 +1,45 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(importFrame())); + + //InitVideo(); +} + +void MainWindow::importFrame() +{ + capture >> frame; + cvtColor(frame, frame, CV_BGR2RGB); + QImage srcQImage = QImage((uchar*)(frame.data), frame.cols, frame.rows, QImage::Format_RGB888); + ui->label->setPixmap(QPixmap::fromImage(srcQImage)); + ui->label->resize(srcQImage.size()); + ui->label->show(); +} + + + + +MainWindow::~MainWindow() +{ + delete ui; +} + + + +void MainWindow::on_PLAY_clicked() +{ + capture.open("udp://@0.0.0.0:11111"); + timer->start(30); +} + +void MainWindow::on_CLOSE_clicked() +{ + timer->stop(); + capture.release(); +} diff --git a/src/ui/Triplet/mainwindow.h b/src/ui/Triplet/mainwindow.h new file mode 100644 index 0000000..b959c59 --- /dev/null +++ b/src/ui/Triplet/mainwindow.h @@ -0,0 +1,47 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include "opencv2/opencv.hpp" +#include +#include +#include +#include + +using namespace std; +using namespace cv; + +QT_BEGIN_NAMESPACE +namespace Ui { class MainWindow; } +QT_END_NAMESPACE + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + VideoCapture cap; + void InitVideo(); + + +private slots: + + + void importFrame();//read video + + void on_PLAY_clicked();//start video + + void on_CLOSE_clicked();//finish video + +private: + Ui::MainWindow *ui; + VideoCapture capture; + QTimer *timer; + Mat frame; + bool isCamerea = 0; +}; +#endif // MAINWINDOW_H diff --git a/src/ui/Triplet/mainwindow.ui b/src/ui/Triplet/mainwindow.ui new file mode 100644 index 0000000..96a2ec2 --- /dev/null +++ b/src/ui/Triplet/mainwindow.ui @@ -0,0 +1,71 @@ + + + MainWindow + + + + 0 + 0 + 1280 + 768 + + + + MainWindow + + + + + + 1100 + 440 + 80 + 25 + + + + CLOSE + + + + + + 1100 + 250 + 80 + 25 + + + + PLAY + + + + + + 50 + 30 + 731 + 461 + + + + + + + + + + + 0 + 0 + 1280 + 22 + + + + + + + + diff --git a/src/ui/mainwindow.hpp b/src/ui/mainwindow.hpp new file mode 100644 index 0000000..3a50f5e --- /dev/null +++ b/src/ui/mainwindow.hpp @@ -0,0 +1,64 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include + +#include "ui_mainwindow.h" +#include "../include/joystick.h" +#include "../include/qnode.hpp" +#include "../include/dashboard.h" + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(int argc, char **argv, QWidget *parent = 0); + ~MainWindow(); + enum { + upleft = 0, + up, + upright, + left, + stop, + right, + downleft, + down, + downright + }; + + + +public slots: + void slot_keyboard_control(); + //void slot_command_control(int linear, int angular); + void slot_rockKeyChange(int); + void slot_speed_x(double x); + void slot_speed_th(double th); + void Slider_raw_valueChanged(int v); + void Slider_linear_valueChanged(int v); + + + +private: + Ui::MainWindow *ui; + QNode qnode; + JoyStick *rock_widget; + DashBoard *m_DashBoard_x; + DashBoard *m_DashBoard_th; + + void initUis(); + void setBtnStyles(); + void connections(); + + + +}; + +#endif // MAINWINDOW_H diff --git a/src/ui/mainwindow.ui b/src/ui/mainwindow.ui new file mode 100644 index 0000000..4ff96fa --- /dev/null +++ b/src/ui/mainwindow.ui @@ -0,0 +1,886 @@ + + + MainWindow + + + + 0 + 0 + 1440 + 810 + + + + MainWindow + + + + + + + + + + 2 + + + + + + 780 + 200 + 311 + 151 + + + + Main Widget + + + + + + + + 680 + 290 + 271 + 121 + + + + UAV Widget + + + + + + + + 1000 + 30 + 407 + 680 + + + + + + + 1 + + + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 20 + + + + + + + + + + + 64 + 64 + + + + + 64 + 64 + + + + + 15 + + + + + + + + + + + + 64 + 64 + + + + + 64 + 64 + + + + + 15 + + + + QPushButton{border-image: url(://images/up.png);} + + + + + + + + + + + 64 + 64 + + + + + 64 + 64 + + + + + 15 + + + + + + + + + + + + + + + + 64 + 64 + + + + + 64 + 64 + + + + + 15 + + + + + + + + + + + + 90 + 64 + + + + + 90 + 64 + + + + 全向模式(k) + + + K + + + + + + + + 64 + 64 + + + + + 64 + 64 + + + + + 15 + + + + + + + + + + + + + + + + + + + 64 + 64 + + + + + 64 + 64 + + + + + 15 + + + + + + + + + + + + 64 + 64 + + + + + 64 + 64 + + + + + 15 + + + + QPushButton{border-image: url(://images/down.png);} +QPushButton{border:none;} +QPushButton:pressed{border-image: url(://images/down_2.png);} + + + + + + + + + + + 64 + 64 + + + + + 64 + 64 + + + + + 15 + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 20 + + + + + + + + + + 线速度(cm/s): + + + + + + + 100 + + + 1 + + + 50 + + + Qt::Horizontal + + + + + + + 50 + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 20 + + + + + + + + 角速度(cm/s): + + + + + + + 100 + + + 100 + + + Qt::Horizontal + + + + + + + 100 + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + 200 + 200 + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 385 + 21 + + + + + + + + + + + + + + + 0 + 221 + + + + TextLabel + + + + + + + + 300 + 0 + + + + + 12312312 + 12312312 + + + + QListView{ +border-top: 5px solid qlineargradient(y0:0, y1:1,stop: 0 #ececef, stop: 1 white); +border-left: 5px solid qlineargradient(x0:0, x1:1,stop: 0 #ececef, stop: 1 white); + border-bottom: 5px solid qlineargradient(y0:0, y1:1,stop: 0 white, stop: 1 #ececef); +border-right: 5px solid qlineargradient(x0:0, x1:1,stop: 0 white, stop: 1 #ececef); +background-color: rgb(255,255,255); +} + + + + + + + + + + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 20 + + + + + + + + + 0 + 45 + + + + system + + + + + + + + 0 + 45 + + + + keyboard + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + + + 240 + 380 + 302 + 300 + + + + + 300 + 300 + + + + + + + + + + 580 + 380 + 302 + 300 + + + + + 300 + 300 + + + + + + + + + + + + + 0 + + + + + + 0 + 60 + + + + + + + + + + + 32 + 32 + + + + + + + + + 0 + 60 + + + + + + + + + + + 32 + 32 + + + + + + + + + 0 + 60 + + + + ArrowCursor + + + + + + + + + + ../../../../../catkin_ws/src/Ros_Qt5_Gui_App/ui../../../../../catkin_ws/src/Ros_Qt5_Gui_App/ui + + + + 32 + 32 + + + + + + + + + 0 + 60 + + + + PointingHandCursor + + + QPushButton:hover{ +background-color:rgb(186, 189, 182); +border-bottom:2px solid rgb(67, 154, 246); +} +QPushButton:checked{ +background-color:cyan; +border-bottom:2px solid white +} +QPushButton:pressed{ +background-color:rgb(67, 154, 246) +} +QPushButton{ +background-color:rgb(238, 238, 236); +border:none; +padding:0px 0px 0px 0px; +margin:0px 0px 0px 0px; +} + + + + + + + ../../../../../catkin_ws/src/Ros_Qt5_Gui_App/ui../../../../../catkin_ws/src/Ros_Qt5_Gui_App/ui + + + + 32 + 32 + + + + + + + + + 0 + 60 + + + + PointingHandCursor + + + QPushButton:hover{ +background-color:rgb(186, 189, 182); +border-bottom:2px solid rgb(67, 154, 246); +} +QPushButton:checked{ +background-color:cyan; +border-bottom:2px solid white +} +QPushButton:pressed{ +background-color:rgb(67, 154, 246) +} +QPushButton{ +background-color:rgb(238, 238, 236); +border:none; +padding:0px 0px 0px 0px; +margin:0px 0px 0px 0px; +} + + + + + + + ../../../../../catkin_ws/src/Ros_Qt5_Gui_App/ui../../../../../catkin_ws/src/Ros_Qt5_Gui_App/ui + + + + 32 + 32 + + + + + + + + + + + +