commit 6d8c61d5b9d5525fac133eeb77f43210bfb8450c Author: raiots Date: Fri Aug 2 10:24:38 2024 +0800 init diff --git a/.catkin_workspace b/.catkin_workspace new file mode 100644 index 0000000..52fd97e --- /dev/null +++ b/.catkin_workspace @@ -0,0 +1 @@ +# This file currently only serves to mark the location of a catkin workspace for tool integration diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..35d74bb --- /dev/null +++ b/.gitignore @@ -0,0 +1,51 @@ +devel/ +logs/ +build/ +bin/ +lib/ +msg_gen/ +srv_gen/ +msg/*Action.msg +msg/*ActionFeedback.msg +msg/*ActionGoal.msg +msg/*ActionResult.msg +msg/*Feedback.msg +msg/*Goal.msg +msg/*Result.msg +msg/_*.py +build_isolated/ +devel_isolated/ + +# Generated by dynamic reconfigure +*.cfgc +/cfg/cpp/ +/cfg/*.py + +# Ignore generated docs +*.dox +*.wikidoc + +# eclipse stuff +.project +.cproject + +# qcreator stuff +CMakeLists.txt.user + +srv/_*.py +*.pcd +*.pyc +qtcreator-* +*.user + +/planning/cfg +/planning/docs +/planning/src + +*~ + +# Emacs +.#* + +# Catkin custom files +CATKIN_IGNORE diff --git a/1722404103.1162927.jpg b/1722404103.1162927.jpg new file mode 100644 index 0000000..2e8a4b0 Binary files /dev/null and b/1722404103.1162927.jpg differ diff --git a/1722421527.3884041.jpg b/1722421527.3884041.jpg new file mode 100644 index 0000000..0a2ec3e Binary files /dev/null and b/1722421527.3884041.jpg differ diff --git a/1722503579.3659685.jpg b/1722503579.3659685.jpg new file mode 100644 index 0000000..54c8057 Binary files /dev/null and b/1722503579.3659685.jpg differ diff --git a/1722503676.4216077.jpg b/1722503676.4216077.jpg new file mode 100644 index 0000000..a215efd Binary files /dev/null and b/1722503676.4216077.jpg differ diff --git a/1722503845.860872.jpg b/1722503845.860872.jpg new file mode 100644 index 0000000..c1accf3 Binary files /dev/null and b/1722503845.860872.jpg differ diff --git a/1722504321.978011.jpg b/1722504321.978011.jpg new file mode 100644 index 0000000..e0738ed Binary files /dev/null and b/1722504321.978011.jpg differ diff --git a/1722511537.5434725.jpg b/1722511537.5434725.jpg new file mode 100644 index 0000000..1e28716 Binary files /dev/null and b/1722511537.5434725.jpg differ diff --git a/1722511563.774326.jpg b/1722511563.774326.jpg new file mode 100644 index 0000000..843c019 Binary files /dev/null and b/1722511563.774326.jpg differ diff --git a/1722519264.8660655.jpg b/1722519264.8660655.jpg new file mode 100644 index 0000000..1cd097e Binary files /dev/null and b/1722519264.8660655.jpg differ diff --git a/1722520961.9444659.jpg b/1722520961.9444659.jpg new file mode 100644 index 0000000..790d095 Binary files /dev/null and b/1722520961.9444659.jpg differ diff --git a/1722520985.796584.jpg b/1722520985.796584.jpg new file mode 100644 index 0000000..484df6b Binary files /dev/null and b/1722520985.796584.jpg differ diff --git a/1722521016.014052.jpg b/1722521016.014052.jpg new file mode 100644 index 0000000..e0cd315 Binary files /dev/null and b/1722521016.014052.jpg differ diff --git a/autostart/.color_sorting.bash.swp b/autostart/.color_sorting.bash.swp new file mode 100644 index 0000000..f7b1287 Binary files /dev/null and b/autostart/.color_sorting.bash.swp differ diff --git a/autostart/.jetmax_control.bash.swp b/autostart/.jetmax_control.bash.swp new file mode 100644 index 0000000..6a26dbe Binary files /dev/null and b/autostart/.jetmax_control.bash.swp differ diff --git a/autostart/alphabetically.bash b/autostart/alphabetically.bash new file mode 100755 index 0000000..6a85e90 --- /dev/null +++ b/autostart/alphabetically.bash @@ -0,0 +1,10 @@ +#!/bin/bash +source /opt/ros/melodic/setup.bash +source ~/ros/devel/setup.bash + +export ROS_HOME=/home/hiwonder/.ros +rosrun alphabetically alphabetically_main.py & + +PID=$! +wait "$PID" + diff --git a/autostart/alphabetically.service b/autostart/alphabetically.service new file mode 100644 index 0000000..821f53d --- /dev/null +++ b/autostart/alphabetically.service @@ -0,0 +1,16 @@ +[Unit] +Requires=roscore.service usb_cam.service jetmax_control.service +After=NetworkManager.service time-sync.target usb_cam.service jetmax_control.service + +[Service] +Type=simple +User=hiwonder +Restart=always +RestartSec=5 +KillMode=mixed +ExecStart=/home/hiwonder/ros/autostart/alphabetically.bash + +[Install] +WantedBy=multi-user.target + + diff --git a/autostart/camera_cal.bash b/autostart/camera_cal.bash new file mode 100755 index 0000000..70769d8 --- /dev/null +++ b/autostart/camera_cal.bash @@ -0,0 +1,10 @@ +#!/bin/bash +source /opt/ros/melodic/setup.bash +source ~/ros/devel/setup.bash + +export ROS_HOME=/home/hiwonder/.ros +roslaunch camera_cal camera_cal.launch & + +PID=$! +wait "$PID" + diff --git a/autostart/camera_cal.service b/autostart/camera_cal.service new file mode 100644 index 0000000..b1ca3bc --- /dev/null +++ b/autostart/camera_cal.service @@ -0,0 +1,15 @@ +[Unit] +Requires=roscore.service usb_cam.service jetmax_control.service +After=NetworkManager.service time-sync.target usb_cam.service jetmax_control.service + +[Service] +Type=simple +User=hiwonder +Restart=always +RestartSec=5 +ExecStart=/home/hiwonder/ros/autostart/camera_cal.bash + +[Install] +WantedBy=multi-user.target + + diff --git a/autostart/color_sorting.bash b/autostart/color_sorting.bash new file mode 100755 index 0000000..93b4f5c --- /dev/null +++ b/autostart/color_sorting.bash @@ -0,0 +1,10 @@ +#!/bin/bash +source /opt/ros/melodic/setup.bash +source ~/ros/devel/setup.bash + +export ROS_HOME=/home/hiwonder/.ros +rosrun color_sorting color_sorting_main.py & + +PID=$! +wait "$PID" + diff --git a/autostart/color_sorting.service b/autostart/color_sorting.service new file mode 100644 index 0000000..1f81c63 --- /dev/null +++ b/autostart/color_sorting.service @@ -0,0 +1,14 @@ +[Unit] +Requires=roscore.service usb_cam.service jetmax_control.service lab_config.service camera_cal.service +After=NetworkManager.service usb_cam.service jetmax_control.service + +[Service] +Type=simple +User=hiwonder +Restart=always +RestartSec=5 +ExecStart=/home/hiwonder/ros/autostart/color_sorting.bash + +[Install] +WantedBy=multi-user.target + diff --git a/autostart/jetmax_control.bash b/autostart/jetmax_control.bash new file mode 100755 index 0000000..a828a96 --- /dev/null +++ b/autostart/jetmax_control.bash @@ -0,0 +1,11 @@ +#!/bin/bash +source /opt/ros/melodic/setup.bash +source ~/ros/devel/setup.bash + +export ROS_HOME=/home/hiwonder/.ros +rosrun remote_control remote_control_joystick.py & +rosrun jetmax_control jetmax_control_main.py & + +PID=$! +wait "$PID" + diff --git a/autostart/jetmax_control.service b/autostart/jetmax_control.service new file mode 100644 index 0000000..188c878 --- /dev/null +++ b/autostart/jetmax_control.service @@ -0,0 +1,15 @@ +[Unit] +Requires=roscore.service rosbridge.service +After=NetworkManager.service time-sync.target roscore.service rosbridge.service + +[Service] +Type=simple +User=hiwonder +Restart=always +RestartSec=5 +KillMode=mixed +ExecStart=/home/hiwonder/ros/autostart/jetmax_control.bash + +[Install] +WantedBy=multi-user.target + diff --git a/autostart/lab_config.bash b/autostart/lab_config.bash new file mode 100755 index 0000000..68b57d8 --- /dev/null +++ b/autostart/lab_config.bash @@ -0,0 +1,10 @@ +#!/bin/bash +source /opt/ros/melodic/setup.bash +source ~/ros/devel/setup.bash + +export ROS_HOME=/home/hiwonder/.ros +roslaunch lab_config lab_config_manager.launch & + +PID=$! +wait "$PID" + diff --git a/autostart/lab_config.service b/autostart/lab_config.service new file mode 100644 index 0000000..2fad120 --- /dev/null +++ b/autostart/lab_config.service @@ -0,0 +1,15 @@ +[Unit] +Requires=roscore.service usb_cam.service +After=NetworkManager.service usb_cam.service + +[Service] +Type=simple +User=hiwonder +Restart=always +RestartSec=5 +ExecStart=/home/hiwonder/ros/autostart/lab_config.bash + +[Install] +WantedBy=multi-user.target + + diff --git a/autostart/object_tracking.bash b/autostart/object_tracking.bash new file mode 100755 index 0000000..ca87c26 --- /dev/null +++ b/autostart/object_tracking.bash @@ -0,0 +1,10 @@ +#!/bin/bash +source /opt/ros/melodic/setup.bash +source ~/ros/devel/setup.bash + +export ROS_HOME=/home/hiwonder/.ros +rosrun object_tracking object_tracking_main.py & + +PID=$! +wait "$PID" + diff --git a/autostart/object_tracking.service b/autostart/object_tracking.service new file mode 100644 index 0000000..4de18b6 --- /dev/null +++ b/autostart/object_tracking.service @@ -0,0 +1,16 @@ +[Unit] +Requires=roscore.service usb_cam.service +After=NetworkManager.service usb_cam.service + +[Service] +Type=simple +User=hiwonder +Restart=always +RestartSec=5 +KillMode=mixed +ExecStart=/home/hiwonder/ros/autostart/object_tracking.bash + +[Install] +WantedBy=multi-user.target + + diff --git a/autostart/palletizing.bash b/autostart/palletizing.bash new file mode 100755 index 0000000..aaa7534 --- /dev/null +++ b/autostart/palletizing.bash @@ -0,0 +1,10 @@ +#!/bin/bash +source /opt/ros/melodic/setup.bash +source /home/hiwonder/ros/devel/setup.bash + +export ROS_HOME=/home/hiwonder/.ros +rosrun palletizing palletizing_main.py & + +PID=$! +wait "$PID" + diff --git a/autostart/palletizing.service b/autostart/palletizing.service new file mode 100644 index 0000000..f109d68 --- /dev/null +++ b/autostart/palletizing.service @@ -0,0 +1,15 @@ +[Unit] +Requires=roscore.service usb_cam.service jetmax_control.service camera_cal.service +After=NetworkManager.service usb_cam.service jetmax_control.service + +[Service] +Type=simple +User=hiwonder +Restart=always +RestartSec=5 +ExecStart=/home/hiwonder/ros/autostart/palletizing.bash + +[Install] +WantedBy=multi-user.target + + diff --git a/autostart/rosbridge.bash b/autostart/rosbridge.bash new file mode 100755 index 0000000..0c1ccdf --- /dev/null +++ b/autostart/rosbridge.bash @@ -0,0 +1,10 @@ +#!/bin/bash +source /opt/ros/melodic/setup.bash +source ~/ros/devel/setup.bash + +export ROS_HOME=/home/hiwonder/.ros +roslaunch /home/hiwonder/ros/autostart/rosbridge_websocket.launch & + +PID=$! +wait "$PID" + diff --git a/autostart/rosbridge.service b/autostart/rosbridge.service new file mode 100644 index 0000000..fc1066e --- /dev/null +++ b/autostart/rosbridge.service @@ -0,0 +1,15 @@ +[Unit] +Requires=roscore.service +After=NetworkManager.service time-sync.target roscore.service + +[Service] +Type=simple +User=hiwonder +Restart=always +RestartSec=5 +ExecStart=/home/hiwonder/ros/autostart/rosbridge.bash + +[Install] +WantedBy=multi-user.target + + diff --git a/autostart/rosbridge_websocket.launch b/autostart/rosbridge_websocket.launch new file mode 100644 index 0000000..576c952 --- /dev/null +++ b/autostart/rosbridge_websocket.launch @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/autostart/roscore.service b/autostart/roscore.service new file mode 100644 index 0000000..d62a723 --- /dev/null +++ b/autostart/roscore.service @@ -0,0 +1,17 @@ +[Unit] +Description=roscore starter +After=NetworkManager.service time-sync.target + +[Service] +# Start roscore as a fork and then wait for the tcp port to be opened +# —————————————————————- +# Source all the environment variables, start roscore in a fork +# Since the service type is forking, systemd doesn’t mark it as +# ‘started’ until the original process exits, so we have the +# non-forked shell wait until it can connect to the tcp opened by +# roscore, and then exit, preventing conflicts with dependant services +Type=forking +ExecStart=/bin/bash -c "source /opt/ros/melodic/setup.bash;roscore & while ! echo exit |nc localhost 11311 > /dev/null;do sleep 1;done" + +[Install] +WantedBy=multi-user.target diff --git a/autostart/usb_cam.bash b/autostart/usb_cam.bash new file mode 100755 index 0000000..c032b70 --- /dev/null +++ b/autostart/usb_cam.bash @@ -0,0 +1,10 @@ +#!/bin/bash +source /opt/ros/melodic/setup.bash +source ~/ros/devel/setup.bash + +export ROS_HOME=/home/hiwonder/.ros +roslaunch /home/hiwonder/ros/autostart/usb_cam.launch & + +PID=$! +wait "$PID" + diff --git a/autostart/usb_cam.launch b/autostart/usb_cam.launch new file mode 100644 index 0000000..d645891 --- /dev/null +++ b/autostart/usb_cam.launch @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/autostart/usb_cam.service b/autostart/usb_cam.service new file mode 100644 index 0000000..b62f06c --- /dev/null +++ b/autostart/usb_cam.service @@ -0,0 +1,16 @@ +[Unit] +Requires=roscore.service +After=NetworkManager.service time-sync.target roscore.service + +[Service] +Type=simple +User=hiwonder +Restart=always +RestartSec=5 +KillMode=mixed +ExecStart=/home/hiwonder/ros/autostart/usb_cam.bash + +[Install] +WantedBy=multi-user.target + + diff --git a/autostart/waste_classification.bash b/autostart/waste_classification.bash new file mode 100755 index 0000000..fd0e308 --- /dev/null +++ b/autostart/waste_classification.bash @@ -0,0 +1,10 @@ +#!/bin/bash +source /opt/ros/melodic/setup.bash +source ~/ros/devel/setup.bash + +export ROS_HOME=/home/hiwonder/.ros +rosrun waste_classification waste_classification_main.py & + +PID=$! +wait "$PID" + diff --git a/autostart/waste_classification.service b/autostart/waste_classification.service new file mode 100644 index 0000000..7a677bf --- /dev/null +++ b/autostart/waste_classification.service @@ -0,0 +1,16 @@ +[Unit] +Requires=roscore.service usb_cam.service jetmax_control.service +After=NetworkManager.service usb_cam.service jetmax_control.service + +[Service] +Type=simple +User=hiwonder +Restart=always +RestartSec=5 +KillMode=mixed +ExecStart=/home/hiwonder/ros/autostart/waste_classification.bash + +[Install] +WantedBy=multi-user.target + + diff --git a/camera_params.npz b/camera_params.npz new file mode 100644 index 0000000..82cbcd5 Binary files /dev/null and b/camera_params.npz differ diff --git a/src/Ai_JetMax/CMakeLists.txt b/src/Ai_JetMax/CMakeLists.txt new file mode 100644 index 0000000..eaad9af --- /dev/null +++ b/src/Ai_JetMax/CMakeLists.txt @@ -0,0 +1,203 @@ +cmake_minimum_required(VERSION 3.0.2) +project(Ai_JetMax) + +## 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 +) + +## 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 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 Ai_JetMax +# CATKIN_DEPENDS python +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( +# include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/Ai_JetMax.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/Ai_JetMax_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_Ai_JetMax.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/Ai_JetMax/package.xml b/src/Ai_JetMax/package.xml new file mode 100644 index 0000000..75055c2 --- /dev/null +++ b/src/Ai_JetMax/package.xml @@ -0,0 +1,59 @@ + + + Ai_JetMax + 0.0.0 + The Ai_JetMax package + + + + + hiwonder + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + + + + + + + + diff --git a/src/Ai_JetMax/scripts/.apriltag_position.py.swp b/src/Ai_JetMax/scripts/.apriltag_position.py.swp new file mode 100644 index 0000000..fe2723d Binary files /dev/null and b/src/Ai_JetMax/scripts/.apriltag_position.py.swp differ diff --git a/src/Ai_JetMax/scripts/apriltag_distance.py b/src/Ai_JetMax/scripts/apriltag_distance.py new file mode 100755 index 0000000..13e4801 --- /dev/null +++ b/src/Ai_JetMax/scripts/apriltag_distance.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import time +import rospy +import numpy as np +import threading +from sensor_msgs.msg import Image +from std_msgs.msg import Bool +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from std_srvs.srv import Empty +from jetmax_control.msg import SetServo +import hiwonder +import queue +import pupil_apriltags as apriltag +import yaml + + +""" +Apriltag 这是apriltag的简单距离探测, +请将Jetmax调整到摄像头朝前的形态 +请将标签正对摄像头 +""" + +ROS_NODE_NAME = "apriltag_detector" +TAG_SIZE = 33.30 + + +class AprilTagDetect: + def __init__(self): + self.camera_params = None + self.K = None + self.R = None + self.T = None + + + def load_camera_params(self): + self.camera_params = rospy.get_param('/camera_cal/block_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + + +def image_proc_a(img): + frame_gray = cv2.cvtColor(np.copy(img), cv2.COLOR_RGB2GRAY) # 将画面转为灰度图 + params = [state.K[0][0], state.K[1][1], state.K[0][2], state.K[1][2]] # 相机内参 + tags = at_detector.detect(frame_gray, estimate_tag_pose=True, camera_params=params, tag_size=TAG_SIZE) # 进行AprilTag的检测 + if not tags: + hiwonder.buzzer.off() + for tag in tags: + corners = tag.corners.reshape(1, -1, 2).astype(int) # 检测到的AprilTag的四个角的点 + center = tag.center.astype(int) # AprilTag中心点 + + cv2.drawContours(img, corners, -1, (255, 0, 0), 3) # 画出外框 + cv2.circle(img, tuple(center), 5, (255, 255, 0), 10) # 画出中心点 + + point_3d = np.array([[16.65, -16.65, 0], + [-16.65,-16.65, 0], + [-16.65, 16.65, 0], + [16.65, 16.65, 0]], dtype=np.double) + point_2d = np.array([tag.corners[0].astype(int), + tag.corners[1].astype(int), + tag.corners[2].astype(int), + tag.corners[3].astype(int)], + dtype=np.double) + + dist_coefs = np.array([0,0,0,0], dtype=np.double) + found, rvec, tvec = cv2.solvePnP(point_3d, point_2d, state.K, None) + rotM = cv2.Rodrigues(rvec)[0] + camera_position = -np.matrix(rotM).T * np.matrix(tvec) + distance = -camera_position.T.tolist()[0][2] + print("Distance: {:0.2f}mm".format(distance)) + if distance < 150: + hiwonder.buzzer.on() + else: + hiwonder.buzzer.off() + + + + img_h, img_w = img.shape[:2] + cv2.line(img, (int(img_w / 2 - 10), int(img_h / 2)), (int(img_w / 2 + 10), int(img_h / 2)), (0, 255, 255), 2) + cv2.line(img, (int(img_w / 2), int(img_h / 2 - 10)), (int(img_w / 2), int(img_h / 2 + 10)), (0, 255, 255), 2) + return img + + +def image_proc_b(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = image.copy() + frame_result = image_proc_a(frame_result) + bgr_image = cv2.cvtColor(frame_result, cv2.COLOR_RGB2BGR) + cv2.imshow('result', bgr_image) + cv2.waitKey(1) + + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +if __name__ == '__main__': + state = AprilTagDetect() + jetmax = hiwonder.JetMax() + sucker = hiwonder.Sucker() + at_detector = apriltag.Detector() + image_queue = queue.Queue(maxsize=1) + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + jetmax.go_home() + state.load_camera_params() + if state.camera_params is None: + rospy.logerr('Can not load camera parameters') + sys.exit(-1) + rospy.ServiceProxy('/jetmax/go_home', Empty)() + rospy.Publisher('/jetmax/end_effector/sucker/command', Bool, queue_size=1).publish(data=False) + rospy.Publisher('/jetmax/end_effector/servo1/command', SetServo, queue_size=1).publish(data=90, duration=0.5) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) + while not rospy.is_shutdown(): + image_proc_b() diff --git a/src/Ai_JetMax/scripts/apriltag_position.py b/src/Ai_JetMax/scripts/apriltag_position.py new file mode 100755 index 0000000..bffc98d --- /dev/null +++ b/src/Ai_JetMax/scripts/apriltag_position.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import time +import rospy +import numpy as np +import threading +from sensor_msgs.msg import Image +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from std_srvs.srv import Empty +from jetmax_control.msg import SetServo +import hiwonder +import queue +import pupil_apriltags as apriltag +import yaml + + +""" +Apriltag 识别定位实验 +将jetmax调整到摄像头朝下的形态 +将id1及其他id的apriltag放于摄像头下方, 程序将识别apriltag并计算其他tag相对与id1的tag的位置 +""" + +ROS_NODE_NAME = "apriltag_detector" +TAG_SIZE = 33.30 + + +class AprilTagDetect: + def __init__(self): + self.camera_params = None + self.K = None + self.R = None + self.T = None + + def load_camera_params(self): + self.camera_params = rospy.get_param('/camera_cal/block_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + r_mat = np.zeros((3, 3), dtype=np.float64) + cv2.Rodrigues(self.R, r_mat) + self.r_mat = r_mat + +def camera_to_world(cam_mtx, r_mat, t, img_points): + """ + 通过图片坐标及相机内外参计算现实位置 + """ + inv_k = np.asmatrix(cam_mtx).I + # invR * T + inv_r = np.asmatrix(r_mat).I # 3*3 + transPlaneToCam = np.dot(inv_r, np.asmatrix(t)) # 3*3 dot 3*1 = 3*1 + world_pt = [] + coords = np.zeros((3, 1), dtype=np.float64) + for img_pt in img_points: + coords[0][0] = img_pt[0][0] + coords[1][0] = img_pt[0][1] + coords[2][0] = 1.0 + worldPtCam = np.dot(inv_k, coords) # 3*3 dot 3*1 = 3*1 + # [x,y,1] * invR + worldPtPlane = np.dot(inv_r, worldPtCam) # 3*3 dot 3*1 = 3*1 + # zc + scale = transPlaneToCam[2][0] / worldPtPlane[2][0] + # zc * [x,y,1] * invR + scale_worldPtPlane = np.multiply(scale, worldPtPlane) + # [X,Y,Z]=zc*[x,y,1]*invR - invR*T + worldPtPlaneReproject = np.asmatrix(scale_worldPtPlane) - np.asmatrix(transPlaneToCam) # 3*1 dot 1*3 = 3*3 + pt = np.zeros((3, 1), dtype=np.float64) + pt[0][0] = worldPtPlaneReproject[0][0] + pt[1][0] = worldPtPlaneReproject[1][0] + pt[2][0] = 0 + world_pt.append(pt.T.tolist()) + return world_pt + +def image_proc_a(img): + frame_gray = cv2.cvtColor(np.copy(img), cv2.COLOR_RGB2GRAY) # 将画面转为灰度图 + params = [state.K[0][0], state.K[1][1], state.K[0][2], state.K[1][2]] # 相机内参 + tags = at_detector.detect(frame_gray, estimate_tag_pose=True, camera_params=params, tag_size=TAG_SIZE) # 进行AprilTag的检测 + for tag in tags: + corners = tag.corners.reshape(1, -1, 2).astype(int) # 检测到的AprilTag的四个角的点 + center = tag.center.astype(int) # AprilTag中心点 + + cv2.drawContours(img, corners, -1, (255, 0, 0), 3) # 画出外框 + cv2.circle(img, tuple(center), 5, (255, 255, 0), 10) # 画出中心点 + + rotM = tag.pose_R + tvec = tag.pose_t + + if tag.tag_id == 1: #如果是id1就将外参保存起来 + state.r_mat = rotM + state.T = tvec + else: + #如果如果不是id1 就计算相关对位置 + x, y, _ = camera_to_world(state.K, state.r_mat, state.T, tag.center.reshape((1,1,2)))[0][0] + #计算欧拉角 + theta_z = math.atan2(rotM[1, 0], rotM[0, 0])*180.0/math.pi + theta_y = math.atan2(-1.0*rotM[2, 0], math.sqrt(rotM[2, 1]**2 + rotM[2, 2]**2))*180.0/math.pi + theta_x = math.atan2(rotM[2, 1], rotM[2, 2])*180.0/math.pi + print("id:{}, x:{:0.2f}mm, y:{:0.2f}mm, angle:{:0.2f}deg".format(tag.tag_id, x, y, theta_z)) + s1 = "id:{}".format(tag.tag_id) + s2 = "x:{:0.2f}mm, y:{:0.2f}mm".format(x, y) + s3 = "angle:{:0.2f}deg".format(theta_z) + cv2.putText(img, s1, (center[0] - 50, center[1]), 0, 0.7, (0, 255, 0), 2) + cv2.putText(img, s2, (center[0] - 50, center[1]+20), 0, 0.7, (0, 255, 0), 2) + cv2.putText(img, s3, (center[0] - 50, center[1] + 40), 0, 0.7, (0, 255, 0), 2) + + + img_h, img_w = img.shape[:2] + cv2.line(img, (int(img_w / 2 - 10), int(img_h / 2)), (int(img_w / 2 + 10), int(img_h / 2)), (0, 255, 255), 2) + cv2.line(img, (int(img_w / 2), int(img_h / 2 - 10)), (int(img_w / 2), int(img_h / 2 + 10)), (0, 255, 255), 2) + return img + + +def image_proc_b(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = image.copy() + frame_result = image_proc_a(frame_result) + bgr_image = cv2.cvtColor(frame_result, cv2.COLOR_RGB2BGR) + cv2.imshow('result', bgr_image) + cv2.waitKey(1) + + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +if __name__ == '__main__': + state = AprilTagDetect() + jetmax = hiwonder.JetMax() + sucker = hiwonder.Sucker() + at_detector = apriltag.Detector() + image_queue = queue.Queue(maxsize=1) + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + jetmax.go_home() + state.load_camera_params() + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback, queue_size=1) + if state.camera_params is None: + rospy.logerr('Can not load camera parameters') + sys.exit(-1) + while not rospy.is_shutdown(): + image_proc_b() diff --git a/src/Ai_JetMax/scripts/apriltag_tracking.py b/src/Ai_JetMax/scripts/apriltag_tracking.py new file mode 100755 index 0000000..dc2b30a --- /dev/null +++ b/src/Ai_JetMax/scripts/apriltag_tracking.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import time +import rospy +import numpy as np +import threading +from sensor_msgs.msg import Image +from std_msgs.msg import Bool +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from std_srvs.srv import Empty +from jetmax_control.msg import SetServo +import hiwonder +import queue +import pupil_apriltags as apriltag +import yaml + + +""" +Apriltag追踪实验 +请将jetmax调整到摄像头朝前状态 +jetmax将追踪apriltag左右上向前后移动 +程序将维持apriltag在画面中心,摄像头前方15cm处 +程序没有对出现多个apriltag的情况做处理, 多个apriltag同时出现可能错乱 +若标签距离摄像头过远,程序会因机械臂无法到达目标位置而退出 +""" + +ROS_NODE_NAME = "apriltag_detector" +TAG_SIZE = 33.30 + + +class AprilTagDetect: + def __init__(self): + self.is_running = False + self.moving_block = None + self.image_sub = None + self.runner = None + self.count = 0 + self.level = 0 + self.lock = threading.RLock() + self.camera_params = None + self.K = None + self.R = None + self.T = None + self.pid_x = hiwonder.PID(0.07, 0, 0) + self.pid_y = hiwonder.PID(0.05, 0, 0) + self.pid_z = hiwonder.PID(0.05, 0, 0) + self.servo_x = 500 + + def reset(self): + self.is_running = False + self.moving_block = None + self.image_sub = None + self.runner = None + self.count = 0 + self.level = 0 + + def load_camera_params(self): + self.camera_params = rospy.get_param('/camera_cal/block_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + + +def rotation_mtx_to_euler(R): + sy = math.sqrt(R[0, 0] * R[0, 0] + R[1, 0] * R[1, 0]) + singular = sy < 1e-6 + if not singular: + x = math.atan2(R[2, 1], R[2, 2]) + y = math.atan2(-R[2, 0], sy) + z = math.atan2(R[1, 0], R[0, 0]) + else: + x = math.atan2(-R[1, 2], R[1, 1]) + y = math.atan2(-R[2, 0], sy) + z = 0 + return np.array([x, y, z]) + + +def RotateByZ(Cx, Cy, thetaZ): + rz = thetaZ*math.pi/180.0 + outX = math.cos(rz)*Cx - math.sin(rz)*Cy + outY = math.sin(rz)*Cx + math.cos(rz)*Cy + return outX, outY +def RotateByY(Cx, Cz, thetaY): + ry = thetaY*math.pi/180.0 + outZ = math.cos(ry)*Cz - math.sin(ry)*Cx + outX = math.sin(ry)*Cz + math.cos(ry)*Cx + return outX, outZ +def RotateByX(Cy, Cz, thetaX): + rx = thetaX*math.pi/180.0 + outY = math.cos(rx)*Cy - math.sin(rx)*Cz + outZ = math.sin(rx)*Cy + math.cos(rx)*Cz + return outY, outZ + +def image_proc_a(img): + frame_gray = cv2.cvtColor(np.copy(img), cv2.COLOR_RGB2GRAY) # 将画面转为灰度图 + params = [state.K[0][0], state.K[1][1], state.K[0][2], state.K[1][2]] # 相机内参 + tags = at_detector.detect(frame_gray, estimate_tag_pose=True, camera_params=params, tag_size=TAG_SIZE) # 进行AprilTag的检测 + for tag in tags: + corners = tag.corners.reshape(1, -1, 2).astype(int) # 检测到的AprilTag的四个角的点 + center = tag.center.astype(int) # AprilTag中心点 + + cv2.drawContours(img, corners, -1, (255, 0, 0), 3) # 画出外框 + cv2.circle(img, tuple(center), 5, (255, 255, 0), 10) # 画出中心点 + + point_3d = np.array([[16.65, -16.65, 0], + [-16.65,-16.65, 0], + [-16.65, 16.65, 0], + [16.65, 16.65, 0]], dtype=np.double) + point_2d = np.array([tag.corners[0].astype(int), + tag.corners[1].astype(int), + tag.corners[2].astype(int), + tag.corners[3].astype(int)], + dtype=np.double) + + dist_coefs = np.array([0,0,0,0], dtype=np.double) + found, rvec, tvec = cv2.solvePnP(point_3d, point_2d, state.K, None) + rotM = cv2.Rodrigues(rvec)[0] + camera_postion = -np.matrix(rotM).T * np.matrix(tvec) + print(camera_postion.T) + #计算三轴的旋转角 + thetaZ = math.atan2(rotM[1, 0], rotM[0, 0])*180.0/math.pi + thetaY = math.atan2(-1.0*rotM[2, 0], math.sqrt(rotM[2, 1]**2 + rotM[2, 2]**2))*180.0/math.pi + thetaX = math.atan2(rotM[2, 1], rotM[2, 2])*180.0/math.pi + # camera coordinates + x = tvec[0] + y = tvec[1] + z = tvec[2] + (x, y) = RotateByZ(x, y, -1.0*thetaZ) + (x, z) = RotateByY(x, z, -1.0*thetaY) + (y, z) = RotateByX(y, z, -1.0*thetaX) + Cx = x*-1 + Cy = y*-1 + Cz = z*-1 + print("camera position:",Cx, Cy, Cz) + print("camera rotation:", thetaX, thetaY, thetaZ) + center_x, center_y = tag.center + e_x = 320 - center_x + e_y = 240 - center_y + e_z = -150 - Cz + + state.pid_x.update(e_x) + state.servo_x -= state.pid_x.output + jetmax.set_servo(1, state.servo_x, 0.04) + cur = list(jetmax.position) + state.pid_y.update(e_y) + state.pid_z.update(e_z) + cur[2] -= state.pid_y.output + cur[1] += state.pid_z.output + jetmax.set_position(cur, 0.04) + + + + img_h, img_w = img.shape[:2] + cv2.line(img, (int(img_w / 2 - 10), int(img_h / 2)), (int(img_w / 2 + 10), int(img_h / 2)), (0, 255, 255), 2) + cv2.line(img, (int(img_w / 2), int(img_h / 2 - 10)), (int(img_w / 2), int(img_h / 2 + 10)), (0, 255, 255), 2) + return img + + +def image_proc_b(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = image.copy() + frame_result = image_proc_a(frame_result) + bgr_image = cv2.cvtColor(frame_result, cv2.COLOR_RGB2BGR) + cv2.imshow('result', bgr_image) + cv2.waitKey(1) + + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +if __name__ == '__main__': + state = AprilTagDetect() + jetmax = hiwonder.JetMax() + sucker = hiwonder.Sucker() + at_detector = apriltag.Detector() + image_queue = queue.Queue(maxsize=1) + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + jetmax.go_home() + state.load_camera_params() + if state.camera_params is None: + rospy.logerr('Can not load camera parameters') + sys.exit(-1) + rospy.ServiceProxy('/jetmax/go_home', Empty)() + rospy.Publisher('/jetmax/end_effector/sucker/command', Bool, queue_size=1).publish(data=False) + rospy.Publisher('/jetmax/end_effector/servo1/command', SetServo, queue_size=1).publish(data=90, duration=0.5) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) + while not rospy.is_shutdown(): + image_proc_b() diff --git a/src/Ai_JetMax/scripts/auto_reg.py b/src/Ai_JetMax/scripts/auto_reg.py new file mode 100755 index 0000000..df04525 --- /dev/null +++ b/src/Ai_JetMax/scripts/auto_reg.py @@ -0,0 +1,259 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import threading +import numpy as np +import rospy +from sensor_msgs.msg import Image +from std_msgs.msg import Bool +from std_srvs.srv import Empty +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from color_sorting.srv import SetTarget, SetTargetResponse, SetTargetRequest +from std_msgs.msg import Bool +from jetmax_control.msg import SetServo +import hiwonder + +ROS_NODE_NAME = "color_sorting" +IMAGE_PROC_SIZE = 640, 480 +unit_block_corners = np.asarray([[0, 0, 0], + [20, -20, 0], # TAG_SIZE = 33.30mm + [-20, -20, 0], + [-20, 20, 0], + [20, 20, 0]], + dtype=np.float64) +unit_block_img_pts = None + + +def camera_to_world(cam_mtx, r, t, img_points): + inv_k = np.asmatrix(cam_mtx).I + r_mat = np.zeros((3, 3), dtype=np.float64) + cv2.Rodrigues(r, r_mat) + # invR * T + inv_r = np.asmatrix(r_mat).I # 3*3 + transPlaneToCam = np.dot(inv_r, np.asmatrix(t)) # 3*3 dot 3*1 = 3*1 + world_pt = [] + coords = np.zeros((3, 1), dtype=np.float64) + for img_pt in img_points: + coords[0][0] = img_pt[0][0] + coords[1][0] = img_pt[0][1] + coords[2][0] = 1.0 + worldPtCam = np.dot(inv_k, coords) # 3*3 dot 3*1 = 3*1 + # [x,y,1] * invR + worldPtPlane = np.dot(inv_r, worldPtCam) # 3*3 dot 3*1 = 3*1 + # zc + scale = transPlaneToCam[2][0] / worldPtPlane[2][0] + # zc * [x,y,1] * invR + scale_worldPtPlane = np.multiply(scale, worldPtPlane) + # [X,Y,Z]=zc*[x,y,1]*invR - invR*T + worldPtPlaneReproject = np.asmatrix(scale_worldPtPlane) - np.asmatrix(transPlaneToCam) # 3*1 dot 1*3 = 3*3 + pt = np.zeros((3, 1), dtype=np.float64) + pt[0][0] = worldPtPlaneReproject[0][0] + pt[1][0] = worldPtPlaneReproject[1][0] + pt[2][0] = 0 + world_pt.append(pt.T.tolist()) + return world_pt + + +class ColorSortingState: + def __init__(self): + self.target_colors = {} + self.target_positions = { + 'red': ((238, -15, 95), -5), + 'green': ((238, 35, 95), 8), + 'blue': ((238, 85, 95), 18) + } + self.heartbeat_timer = None + self.is_running = False + self.image_sub = None + self.lock = threading.RLock() + self.runner = None + self.count = 0 + self.camera_params = None + self.K = None + self.R = None + self.T = None + self.WIDTH = None + + def load_camera_params(self): + global unit_block_img_pts + self.camera_params = rospy.get_param('/camera_cal/block_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + img_pts, jac = cv2.projectPoints(unit_block_corners, self.R, self.T, self.K, None) + unit_block_img_pts = img_pts.reshape(5, 2) + l_p1 = unit_block_img_pts[-1] + l_p2 = unit_block_img_pts[-2] + self.WIDTH = math.sqrt((l_p1[0] - l_p2[0]) ** 2 + (l_p1[1] - l_p2[1]) ** 2) + print(unit_block_img_pts) + + +def moving(rect): + cur_x, cur_y, cur_z = jetmax.position + try: + x, y, _ = camera_to_world(state.K, state.R, state.T, np.array(rect[0]).reshape((1, 1, 2)))[0][0] + # Calculate the distance between the current position and the target position to control the movement speed + t = math.sqrt(x * x + y * y + 120 * 120) / 140 + angle = rect[2] + + new_x, new_y = cur_x + x, cur_y + y + + # Pick up the block + hiwonder.pwm_servo1.set_position(90 + angle, 0.1) # 90度时吸嘴的默认角度, 先偏转再回到九十度就摆正了 + + jetmax.set_position((new_x, new_y, 120), t) #到达木块上方 + rospy.sleep(t) + sucker.set_state(True) #吸取模块 + jetmax.set_position((new_x, new_y, 85), 1) + rospy.sleep(1.05) + + cur_x, cur_y, cur_z = jetmax.position + jetmax.set_position((cur_x, cur_y, 120), 0.8) #抬起机械臂 + rospy.sleep(1) + hiwonder.pwm_servo1.set_position(90, 0.1) #吸嘴角度回正 + rospy.sleep(0.2) + + # Go to the target position + jetmax.set_position((cur_x, cur_y, 85), 1) #重新放下 + rospy.sleep(1.1) + sucker.release(3) #放开吸嘴 + jetmax.set_position((cur_x, cur_y, 120), 0.8) #抬起机械臂 + rospy.sleep(0.8) + + except Exception as e: + rospy.logerr("ERROR") + finally: + # 回中位 + sucker.release(3) + hiwonder.pwm_servo1.set_position(90, 0.5) + jetmax.go_home(2) + rospy.sleep(2.5) + state.runner = None + + +def point_xy(pt_a, pt_b, r): + x_a, y_a = pt_a + x_b, y_b = pt_b + if x_a == x_b: + return x_a, y_a + (r / abs((y_b - y_a))) * (y_b - y_a) + k = (y_a - y_b) / (x_a - x_b) + b = y_a - k * x_a + A = k ** 2 + 1 + B = 2 * ((b - y_a) * k - x_a) + C = (b - y_a) ** 2 + x_a ** 2 - r ** 2 + x1 = (-B + math.sqrt(B ** 2 - 4 * A * C)) / (2 * A) + x2 = (-B - math.sqrt(B ** 2 - 4 * A * C)) / (2 * A) + y1 = k * x1 + b + y2 = k * x2 + b + dist_1 = math.sqrt((x1 - x_b) ** 2 + (y1 - y_b) ** 2) + dist_2 = math.sqrt((x2 - x_b) ** 2 + (y2 - y_b) ** 2) + if dist_1 <= dist_2: + return x1, y1 + else: + return x2, y2 + + +def image_proc(img): + if state.runner is not None: + return img + img_h, img_w = img.shape[:2] + frame_gb = cv2.GaussianBlur(np.copy(img), (5, 5), 5) + frame_lab = cv2.cvtColor(frame_gb, cv2.COLOR_RGB2LAB) # Convert rgb to lab + + blocks = [] + for color_name, color in state.target_colors.items(): # Loop through all selected colors + frame_mask = cv2.inRange(frame_lab, tuple(color['min']), tuple(color['max'])) + eroded = cv2.erode(frame_mask, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) + dilated = cv2.dilate(eroded, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) + contours = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] + contour_area = map(lambda c: (c, math.fabs(cv2.contourArea(c))), contours) + contour_area = list(filter(lambda c: c[1] > 1000, contour_area)) # Eliminate contours that are too small + + if len(contour_area) > 0: + for contour, area in contour_area: # Loop through all the contours found + rect = cv2.minAreaRect(contour) + center_x, center_y = rect[0] + box = cv2.boxPoints(rect) # The four vertices of the minimum-area-rectangle + box_list = box.tolist() + box = np.int0(box) + ap = max(box_list, key=lambda p: math.sqrt((p[0] - state.K[0][2]) ** 2 + (p[1] - state.K[1][2]) ** 2)) + index_ap = box_list.index(ap) + p1 = box_list[index_ap - 1 if index_ap - 1 >= 0 else 3] + p2 = box_list[index_ap + 1 if index_ap + 1 <= 3 else 0] + n_p1 = point_xy(ap, p1, state.WIDTH) + n_p2 = point_xy(ap, p2, state.WIDTH) + + c_x, c_y = None, None + if n_p1 and n_p2: + x_1, y_1 = n_p1 + x_2, y_2 = n_p2 + c_x = (x_1 + x_2) / 2 + c_y = (y_1 + y_2) / 2 + cv2.circle(img, (int(n_p1[0]), int(n_p1[1])), 2, (255, 255, 0), 10) + cv2.circle(img, (int(n_p2[0]), int(n_p2[1])), 2, (255, 255, 0), 10) + cv2.circle(img, (int(c_x), int(c_y)), 2, (0, 0, 0), 10) + + cv2.circle(img, (int(ap[0]), int(ap[1])), 2, (0, 255, 255), 10) + cv2.drawContours(img, [box], -1, hiwonder.COLORS[color_name.upper()], 2) + cv2.circle(img, (int(center_x), int(center_y)), 1, hiwonder.COLORS[color_name.upper()], 5) + rect = list(rect) + if c_x: + rect[0] = c_x, c_y + else: + rect[0] = (center_x, center_y) + x, y = rect[0] + cv2.circle(img, (int(x), int(y)), 2, (255, 255, 255), 5) + angle = rect[2] + rect[2] = angle - 90 if angle > 45 else angle + blocks.append((rect, color_name)) + + if len(blocks) > 0: +#print(blocks) + for block in blocks: + rect, color_name = block + (x, y), _, angle = rect + print(angle, end=', ') + if abs(angle) > 5: + print("start x:{:0.2f}, y:{:0.2f}, angle:{:0.2f}".format(x, y, angle)) + state.runner = threading.Thread(target=moving, args=(rect, ), daemon=True) + state.runner.start() + print("\n") + + cv2.line(img, (int(img_w / 2 - 10), int(img_h / 2)), (int(img_w / 2 + 10), int(img_h / 2)), (0, 255, 255), 2) + cv2.line(img, (int(img_w / 2), int(img_h / 2 - 10)), (int(img_w / 2), int(img_h / 2 + 10)), (0, 255, 255), 2) + return img + + +def image_callback(ros_image): + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = np.copy(image) + frame_result = image_proc(frame_result) + image_bgr = cv2.cvtColor(frame_result, cv2.COLOR_RGB2BGR) + cv2.imshow('result', image_bgr) + cv2.waitKey(1) + + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + state = ColorSortingState() + state.load_camera_params() + if state.camera_params is None: + rospy.logerr("Can not load camera params") + sys.exit(-1) + jetmax = hiwonder.JetMax() + sucker = hiwonder.Sucker() + jetmax.go_home() + rospy.sleep(1) + color_ranges = rospy.get_param('/lab_config_manager/color_range_list', {}) + state.target_colors['red'] = color_ranges['red'] + state.target_colors['green'] = color_ranges['green'] + state.target_colors['blue'] = color_ranges['blue'] + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) + try: + rospy.spin() + except KeyboardInterrupt: + sys.exit(0) diff --git a/src/Ai_JetMax/scripts/color_angle.py b/src/Ai_JetMax/scripts/color_angle.py new file mode 100755 index 0000000..0241477 --- /dev/null +++ b/src/Ai_JetMax/scripts/color_angle.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import threading +import numpy as np +import rospy +from sensor_msgs.msg import Image +import hiwonder + +ROS_NODE_NAME = "color_angle" +unit_block_corners = np.asarray([[0, 0, 0], + [20, -20, 0], # TAG_SIZE = 33.30mm + [-20, -20, 0], + [-20, 20, 0], + [20, 20, 0]], + dtype=np.float64) +unit_block_img_pts = None + + +def camera_to_world(cam_mtx, r, t, img_points): + inv_k = np.asmatrix(cam_mtx).I + r_mat = np.zeros((3, 3), dtype=np.float64) + cv2.Rodrigues(r, r_mat) + # invR * T + inv_r = np.asmatrix(r_mat).I # 3*3 + transPlaneToCam = np.dot(inv_r, np.asmatrix(t)) # 3*3 dot 3*1 = 3*1 + world_pt = [] + coords = np.zeros((3, 1), dtype=np.float64) + for img_pt in img_points: + coords[0][0] = img_pt[0][0] + coords[1][0] = img_pt[0][1] + coords[2][0] = 1.0 + worldPtCam = np.dot(inv_k, coords) # 3*3 dot 3*1 = 3*1 + # [x,y,1] * invR + worldPtPlane = np.dot(inv_r, worldPtCam) # 3*3 dot 3*1 = 3*1 + # zc + scale = transPlaneToCam[2][0] / worldPtPlane[2][0] + # zc * [x,y,1] * invR + scale_worldPtPlane = np.multiply(scale, worldPtPlane) + # [X,Y,Z]=zc*[x,y,1]*invR - invR*T + worldPtPlaneReproject = np.asmatrix(scale_worldPtPlane) - np.asmatrix(transPlaneToCam) # 3*1 dot 1*3 = 3*3 + pt = np.zeros((3, 1), dtype=np.float64) + pt[0][0] = worldPtPlaneReproject[0][0] + pt[1][0] = worldPtPlaneReproject[1][0] + pt[2][0] = 0 + world_pt.append(pt.T.tolist()) + return world_pt + + +class State: + def __init__(self): + self.target_colors = {} + self.runner = None + self.camera_params = None + self.K = None + self.R = None + self.T = None + self.WIDTH = None + + + def load_camera_params(self): + global unit_block_img_pts + self.camera_params = rospy.get_param('/camera_cal/block_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + img_pts, jac = cv2.projectPoints(unit_block_corners, self.R, self.T, self.K, None) + unit_block_img_pts = img_pts.reshape(5, 2) + l_p1 = unit_block_img_pts[-1] + l_p2 = unit_block_img_pts[-2] + self.WIDTH = math.sqrt((l_p1[0] - l_p2[0]) ** 2 + (l_p1[1] - l_p2[1]) ** 2) + print(unit_block_img_pts) + + + +def point_xy(pt_a, pt_b, r): + x_a, y_a = pt_a + x_b, y_b = pt_b + if x_a == x_b: + return x_a, y_a + (r / abs((y_b - y_a))) * (y_b - y_a) + k = (y_a - y_b) / (x_a - x_b) + b = y_a - k * x_a + A = k ** 2 + 1 + B = 2 * ((b - y_a) * k - x_a) + C = (b - y_a) ** 2 + x_a ** 2 - r ** 2 + x1 = (-B + math.sqrt(B ** 2 - 4 * A * C)) / (2 * A) + x2 = (-B - math.sqrt(B ** 2 - 4 * A * C)) / (2 * A) + y1 = k * x1 + b + y2 = k * x2 + b + dist_1 = math.sqrt((x1 - x_b) ** 2 + (y1 - y_b) ** 2) + dist_2 = math.sqrt((x2 - x_b) ** 2 + (y2 - y_b) ** 2) + if dist_1 <= dist_2: + return x1, y1 + else: + return x2, y2 + + +def image_proc(img): + img_h, img_w = img.shape[:2] + frame_gb = cv2.GaussianBlur(np.copy(img), (5, 5), 5) + frame_lab = cv2.cvtColor(frame_gb, cv2.COLOR_RGB2LAB) # Convert rgb to lab + blocks = [] + for color_name, color in state.target_colors.items(): # Loop through all selected colors + frame_mask = cv2.inRange(frame_lab, tuple(color['min']), tuple(color['max'])) + eroded = cv2.erode(frame_mask, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) + dilated = cv2.dilate(eroded, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) + contours = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] + contour_area = map(lambda c: (c, math.fabs(cv2.contourArea(c))), contours) + contour_area = list(filter(lambda c: c[1] > 1000, contour_area)) # Eliminate contours that are too small + + if len(contour_area) > 0: + for contour, area in contour_area: # Loop through all the contours found + rect = cv2.minAreaRect(contour) + center_x, center_y = rect[0] + box = cv2.boxPoints(rect) # The four vertices of the minimum-area-rectangle + box_list = box.tolist() + box = np.int0(box) + + cv2.drawContours(img, [box], -1, hiwonder.COLORS[color_name.upper()], 2) + cv2.circle(img, (int(center_x), int(center_y)), 1, hiwonder.COLORS[color_name.upper()], 5) + angle = rect[2] + angle = angle - 90 if angle > 45 else angle + s = "Angle:{:0.2f}deg".format(angle) + cv2.putText(img, s, (int(center_x), int(center_y)), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 255, 255), 2) + print(s) + + cv2.line(img, (int(img_w / 2 - 10), int(img_h / 2)), (int(img_w / 2 + 10), int(img_h / 2)), (0, 255, 255), 2) + cv2.line(img, (int(img_w / 2), int(img_h / 2 - 10)), (int(img_w / 2), int(img_h / 2 + 10)), (0, 255, 255), 2) + print("\n") + + return img + + +def image_callback(ros_image): + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = np.copy(image) + frame_result = image_proc(frame_result) + image_bgr = cv2.cvtColor(frame_result, cv2.COLOR_RGB2BGR) + cv2.imshow("result", image_bgr) + cv2.waitKey(1) + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + state = State() + state.load_camera_params() + if state.camera_params is None: + rospy.logerr("Can not load camera params") + sys.exit(-1) + jetmax = hiwonder.JetMax() + jetmax.go_home() + rospy.sleep(1) + state.target_colors = rospy.get_param('/lab_config_manager/color_range_list', {}) + del[state.target_colors['white']] + del[state.target_colors['black']] + del[state.target_colors['ball']] + del[state.target_colors['tennis']] + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) + try: + rospy.spin() + except KeyboardInterrupt: + sys.exit(0) diff --git a/src/Ai_JetMax/scripts/color_detect.py b/src/Ai_JetMax/scripts/color_detect.py new file mode 100755 index 0000000..7379fea --- /dev/null +++ b/src/Ai_JetMax/scripts/color_detect.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import numpy as np +from sensor_msgs.msg import Image +import hiwonder +import rospy + +ROS_NODE_NAME = "color_detect" + +def image_proc(img): + img_h, img_w = img.shape[:2] + frame_gb = cv2.GaussianBlur(np.copy(img), (5, 5), 5) + frame_lab = cv2.cvtColor(frame_gb, cv2.COLOR_RGB2LAB) # 转换rgb到lab + + blocks = [] + for color_name, color in target_colors.items(): # 遍历所有颜色阈值 + frame_mask = cv2.inRange(frame_lab, tuple(color['min']), tuple(color['max'])) + eroded = cv2.erode(frame_mask, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) + dilated = cv2.dilate(eroded, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) + contours = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] + contour_area = map(lambda c: (c, math.fabs(cv2.contourArea(c))), contours) + contour_area = list(filter(lambda c: c[1] > 1200, contour_area)) # 去除过小的色块 + + if len(contour_area) > 0: + for contour, area in contour_area: # Loop through all the contours found + (center_x, center_y), r = cv2.minEnclosingCircle(contour) + cv2.circle(img, (int(center_x), int(center_y)), 1, hiwonder.COLORS[color_name.upper()], 5) + cv2.circle(img, (int(center_x), int(center_y)), int(r), hiwonder.COLORS[color_name.upper()], 2) + cv2.putText(img, color_name.upper(), (int(center_x), int(center_y)), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (255, 255, 255), 2) + + cv2.line(img, (int(img_w / 2 - 10), int(img_h / 2)), (int(img_w / 2 + 10), int(img_h / 2)), (0, 255, 255), 2) + cv2.line(img, (int(img_w / 2), int(img_h / 2 - 10)), (int(img_w / 2), int(img_h / 2 + 10)), (0, 255, 255), 2) + return img + + +def image_callback(ros_image): + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = np.copy(image) + frame_result = image_proc(frame_result) + image_bgr = cv2.cvtColor(frame_result, cv2.COLOR_RGB2BGR) + cv2.imshow("result", image_bgr) + cv2.waitKey(1) + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + jetmax = hiwonder.JetMax() + jetmax.go_home() + rospy.sleep(1) + target_colors = rospy.get_param('/lab_config_manager/color_range_list', {}) + del[target_colors['white']] + del[target_colors['black']] + image_sub = rospy.Subscriber("/usb_cam/image_rect_color", Image, image_callback, queue_size=1) + + try: + rospy.spin() + except KeyboardInterrupt: + sys.exit(0) diff --git a/src/Ai_JetMax/scripts/color_position.py b/src/Ai_JetMax/scripts/color_position.py new file mode 100755 index 0000000..08bae76 --- /dev/null +++ b/src/Ai_JetMax/scripts/color_position.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import threading +import numpy as np +import rospy +from sensor_msgs.msg import Image +from std_msgs.msg import Bool +from std_srvs.srv import Empty +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from color_sorting.srv import SetTarget, SetTargetResponse, SetTargetRequest +from std_msgs.msg import Bool +from jetmax_control.msg import SetServo +import hiwonder + +ROS_NODE_NAME = "color_pos" +IMAGE_PROC_SIZE = 640, 480 +unit_block_corners = np.asarray([[0, 0, 0], + [20, -20, 0], # TAG_SIZE = 33.30mm + [-20, -20, 0], + [-20, 20, 0], + [20, 20, 0]], + dtype=np.float64) +unit_block_img_pts = None + + +def camera_to_world(cam_mtx, r, t, img_points): + inv_k = np.asmatrix(cam_mtx).I + r_mat = np.zeros((3, 3), dtype=np.float64) + cv2.Rodrigues(r, r_mat) + # invR * T + inv_r = np.asmatrix(r_mat).I # 3*3 + transPlaneToCam = np.dot(inv_r, np.asmatrix(t)) # 3*3 dot 3*1 = 3*1 + world_pt = [] + coords = np.zeros((3, 1), dtype=np.float64) + for img_pt in img_points: + coords[0][0] = img_pt[0][0] + coords[1][0] = img_pt[0][1] + coords[2][0] = 1.0 + worldPtCam = np.dot(inv_k, coords) # 3*3 dot 3*1 = 3*1 + # [x,y,1] * invR + worldPtPlane = np.dot(inv_r, worldPtCam) # 3*3 dot 3*1 = 3*1 + # zc + scale = transPlaneToCam[2][0] / worldPtPlane[2][0] + # zc * [x,y,1] * invR + scale_worldPtPlane = np.multiply(scale, worldPtPlane) + # [X,Y,Z]=zc*[x,y,1]*invR - invR*T + worldPtPlaneReproject = np.asmatrix(scale_worldPtPlane) - np.asmatrix(transPlaneToCam) # 3*1 dot 1*3 = 3*3 + pt = np.zeros((3, 1), dtype=np.float64) + pt[0][0] = worldPtPlaneReproject[0][0] + pt[1][0] = worldPtPlaneReproject[1][0] + pt[2][0] = 0 + world_pt.append(pt.T.tolist()) + return world_pt + + +class State: + def __init__(self): + self.target_colors = {} + self.runner = None + self.camera_params = None + self.K = None + self.R = None + self.T = None + self.WIDTH = None + + + def load_camera_params(self): + global unit_block_img_pts + self.camera_params = rospy.get_param('/camera_cal/block_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + img_pts, jac = cv2.projectPoints(unit_block_corners, self.R, self.T, self.K, None) + unit_block_img_pts = img_pts.reshape(5, 2) + l_p1 = unit_block_img_pts[-1] + l_p2 = unit_block_img_pts[-2] + self.WIDTH = math.sqrt((l_p1[0] - l_p2[0]) ** 2 + (l_p1[1] - l_p2[1]) ** 2) + print(unit_block_img_pts) + + + +def point_xy(pt_a, pt_b, r): + x_a, y_a = pt_a + x_b, y_b = pt_b + if x_a == x_b: + return x_a, y_a + (r / abs((y_b - y_a))) * (y_b - y_a) + k = (y_a - y_b) / (x_a - x_b) + b = y_a - k * x_a + A = k ** 2 + 1 + B = 2 * ((b - y_a) * k - x_a) + C = (b - y_a) ** 2 + x_a ** 2 - r ** 2 + x1 = (-B + math.sqrt(B ** 2 - 4 * A * C)) / (2 * A) + x2 = (-B - math.sqrt(B ** 2 - 4 * A * C)) / (2 * A) + y1 = k * x1 + b + y2 = k * x2 + b + dist_1 = math.sqrt((x1 - x_b) ** 2 + (y1 - y_b) ** 2) + dist_2 = math.sqrt((x2 - x_b) ** 2 + (y2 - y_b) ** 2) + if dist_1 <= dist_2: + return x1, y1 + else: + return x2, y2 + + +def image_proc(img): + img_h, img_w = img.shape[:2] + frame_gb = cv2.GaussianBlur(np.copy(img), (5, 5), 5) + frame_lab = cv2.cvtColor(frame_gb, cv2.COLOR_RGB2LAB) # Convert rgb to lab + blocks = [] + for color_name, color in state.target_colors.items(): # Loop through all selected colors + frame_mask = cv2.inRange(frame_lab, tuple(color['min']), tuple(color['max'])) + eroded = cv2.erode(frame_mask, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) + dilated = cv2.dilate(eroded, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) + contours = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] + contour_area = map(lambda c: (c, math.fabs(cv2.contourArea(c))), contours) + contour_area = list(filter(lambda c: c[1] > 1000, contour_area)) # Eliminate contours that are too small + + if len(contour_area) > 0: + for contour, area in contour_area: # Loop through all the contours found + rect = cv2.minAreaRect(contour) + center_x, center_y = rect[0] + box = cv2.boxPoints(rect) # The four vertices of the minimum-area-rectangle + box_list = box.tolist() + box = np.int0(box) + ap = max(box_list, key=lambda p: math.sqrt((p[0] - state.K[0][2]) ** 2 + (p[1] - state.K[1][2]) ** 2)) + index_ap = box_list.index(ap) + p1 = box_list[index_ap - 1 if index_ap - 1 >= 0 else 3] + p2 = box_list[index_ap + 1 if index_ap + 1 <= 3 else 0] + n_p1 = point_xy(ap, p1, state.WIDTH) + n_p2 = point_xy(ap, p2, state.WIDTH) + + c_x, c_y = None, None + if n_p1 and n_p2: + x_1, y_1 = n_p1 + x_2, y_2 = n_p2 + c_x = (x_1 + x_2) / 2 + c_y = (y_1 + y_2) / 2 + cv2.circle(img, (int(n_p1[0]), int(n_p1[1])), 2, (255, 255, 0), 10) + cv2.circle(img, (int(n_p2[0]), int(n_p2[1])), 2, (255, 255, 0), 10) + cv2.circle(img, (int(c_x), int(c_y)), 2, (0, 0, 0), 10) + + cv2.circle(img, (int(ap[0]), int(ap[1])), 2, (0, 255, 255), 10) + cv2.drawContours(img, [box], -1, hiwonder.COLORS[color_name.upper()], 2) + cv2.circle(img, (int(center_x), int(center_y)), 1, hiwonder.COLORS[color_name.upper()], 5) + rect = list(rect) + if c_x: + rect[0] = c_x, c_y + else: + rect[0] = (center_x, center_y) + x, y = rect[0] + cv2.circle(img, (int(x), int(y)), 1, (255, 255, 255), 5) + real_x, real_y, _ = camera_to_world(state.K, state.R, state.T, np.array((x, y)).reshape((1, 1, 2)))[0][0] + s = "{} x:{:0.2f} y:{:0.2f}".format(color_name.upper(), real_x, real_y) + print(s) + cv2.putText(img, s, (int(center_x), int(center_y)), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 255, 255), 2) + + cv2.line(img, (int(img_w / 2 - 10), int(img_h / 2)), (int(img_w / 2 + 10), int(img_h / 2)), (0, 255, 255), 2) + cv2.line(img, (int(img_w / 2), int(img_h / 2 - 10)), (int(img_w / 2), int(img_h / 2 + 10)), (0, 255, 255), 2) + print("\n") + + return img + + +def image_callback(ros_image): + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = np.copy(image) + frame_result = image_proc(frame_result) + image_bgr = cv2.cvtColor(frame_result, cv2.COLOR_RGB2BGR) + cv2.imshow("result", image_bgr) + cv2.waitKey(1) + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + state = State() + state.load_camera_params() + if state.camera_params is None: + rospy.logerr("Can not load camera params") + sys.exit(-1) + jetmax = hiwonder.JetMax() + jetmax.go_home() + rospy.sleep(1) + state.target_colors = rospy.get_param('/lab_config_manager/color_range_list', {}) + del[state.target_colors['white']] + del[state.target_colors['black']] + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) + try: + rospy.spin() + except KeyboardInterrupt: + sys.exit(0) diff --git a/src/Ai_JetMax/scripts/face_detect.py b/src/Ai_JetMax/scripts/face_detect.py new file mode 100755 index 0000000..8271f2c --- /dev/null +++ b/src/Ai_JetMax/scripts/face_detect.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +import sys +import math +import rospy +import time +import queue +import threading +import cv2 +import numpy as np +import hiwonder +from sensor_msgs.msg import Image as RosImage + +from PIL import Image +import torch +from facenet_pytorch import MTCNN + +device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') +print(device) + +mtcnn = MTCNN(keep_all=True, min_face_size=50, factor=0.709, post_process=False, device=device) + +ROS_NODE_NAME = 'face_expression' +jetmax = hiwonder.JetMax() +image_queue = queue.Queue(maxsize=1) + + +def show_faces(img, boxes, landmarks, color): + new_boxes = [] + new_landmarks = [] + for bb, ll in zip(boxes, landmarks): + x1 = int(hiwonder.misc.val_map(bb[0], 0, 160, 0, 640)) + y1 = int(hiwonder.misc.val_map(bb[1], 0, 160, 0, 480)) + x2 = int(hiwonder.misc.val_map(bb[2], 0, 160, 0, 640)) + y2 = int(hiwonder.misc.val_map(bb[3], 0, 160, 0, 480)) + cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) + new_boxes.append([x1, y1, x2, y2]) + landmarks_curr_face = [] + if len(landmarks): + for j in range(5): + lx = int(hiwonder.misc.val_map(ll[j][0], 0, 160, 0, 640)) + ly = int(hiwonder.misc.val_map(ll[j][1], 0, 160, 0, 480)) + cv2.circle(img, (lx, ly), 2, color, 2) + landmarks_curr_face.append([lx, ly]) + new_landmarks.append(landmarks_curr_face) + return img, new_boxes, new_landmarks + + + +def image_proc_a(image): + img_ret = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) + org_img1 = np.copy(image) + image = cv2.resize(image, (160, 160)) + boxes, _, landmarks = mtcnn.detect(Image.fromarray(image), landmarks=True) + if boxes is None: + return img_ret + boxes = list(boxes) + landmarks = list(landmarks) + + img_ret, boxes, landmarks = show_faces(img_ret, boxes, landmarks, (0, 255, 0)) + return img_ret + +def image_proc_b(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + image = image_proc_a(image) + toc = time.time() + cv2.imshow(ROS_NODE_NAME, image) + cv2.waitKey(1) + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + jetmax.go_home(1) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', RosImage, image_callback) + try: + while not rospy.is_shutdown(): + image_proc_b() + except Exception as e: + rospy.logerr(e) + print(e.__traceback__.tb_lineno) + sys.exit() diff --git a/src/Ai_JetMax/scripts/kill_app_funcs.sh b/src/Ai_JetMax/scripts/kill_app_funcs.sh new file mode 100755 index 0000000..5f463f9 --- /dev/null +++ b/src/Ai_JetMax/scripts/kill_app_funcs.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +sudo kill -9 $(ps -elf|grep -v grep|grep python3|grep alphabetically|awk '{print $4}') >/dev/null 2>&1 +sudo systemctl stop alphabetically.service + +sudo kill -9 $(ps -elf|grep -v grep|grep python3|grep waste_classification|awk '{print $4}') >/dev/null 2>&1 +sudo systemctl stop waste_classification.service + +sudo kill -9 $(ps -elf|grep -v grep|grep python3|grep object_tracking|awk '{print $4}') >/dev/null 2>&1 +sudo systemctl stop object_tracking.service + +sudo kill -9 $(ps -elf|grep -v grep|grep python3|grep color_sorting|awk '{print $4}') >/dev/null 2>&1 +sudo systemctl stop color_sorting.service + + diff --git a/src/Ai_JetMax/scripts/letter_recognition.py b/src/Ai_JetMax/scripts/letter_recognition.py new file mode 100755 index 0000000..e566ef7 --- /dev/null +++ b/src/Ai_JetMax/scripts/letter_recognition.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +import os +import sys +import cv2 +import math +import time +import queue +import random +import threading +import numpy as np +import rospy +from sensor_msgs.msg import Image +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +import hiwonder +from hiwonder import serial_servo as ss +from yolov5_tensorrt import Yolov5TensorRT + + +ROS_NODE_NAME = "hiwjfkalsdjfkla" +IMAGE_SIZE = 640, 480 +CHARACTERS_ENGINE_PATH = os.path.join(sys.path[0], 'models/characters_v5_160.trt') +CHARACTER_LABELS = tuple([i for i in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ']) +CHARACTER_NUM = 26 +TRT_INPUT_SIZE = 160 +COLORS = tuple([tuple([random.randint(10, 255) for j in range(3)]) for i in range(CHARACTER_NUM)]) +TARGET_POSITION = (-200, -180, 65) +yolov5_chars = Yolov5TensorRT(CHARACTERS_ENGINE_PATH, TRT_INPUT_SIZE, CHARACTER_NUM) + + +def image_proc(img_in): + result_image = cv2.cvtColor(img_in, cv2.COLOR_RGB2BGR) + + outputs = yolov5_chars.detect(np.copy(img_in)) + boxes, confs, classes = yolov5_chars.post_process(img_in, outputs, 0.60) + + for box, cls_id, cls_conf in zip(boxes, classes, confs): + x1 = box[0] / TRT_INPUT_SIZE * 640 + y1 = box[1] / TRT_INPUT_SIZE * 480 + x2 = box[2] / TRT_INPUT_SIZE * 640 + y2 = box[3] / TRT_INPUT_SIZE * 480 + char = CHARACTER_LABELS[cls_id] + cv2.putText(result_image, char + " " + str(float(cls_conf))[:4], (int(x1), int(y1) - 5), + cv2.FONT_HERSHEY_SIMPLEX, 0.7, COLORS[cls_id], 2) + cv2.rectangle(result_image, (int(x1), int(y1)), (int(x2), int(y2)), COLORS[cls_id], 3) + print(x1, y1, x2, y2, char) + + return result_image + + +def show_fps(img=None): + global fps, fps_t0 + """Draw fps number at top-left corner of the image.""" + # fps cal + fps_t1 = time.time() + fps_cur = (1.0 / (fps_t1 - fps_t0)) + fps = fps_cur if fps == 0.0 else (fps * 0.8 + fps_cur * 0.2) + fps_t0 = fps_t1 + + font = cv2.FONT_HERSHEY_PLAIN + line = cv2.LINE_AA + fps_text = 'FPS: {:.2f}'.format(fps) + if img is not None: + cv2.putText(img, fps_text, (11, 20), font, 1.0, (32, 32, 32), 4, line) + cv2.putText(img, fps_text, (10, 20), font, 1.0, (240, 240, 240), 1, line) + return img + + +def image_proc_b(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + result_img = image_proc(image) + show_fps(result_img) + cv2.cvtColor(result_img, cv2.COLOR_RGB2BGR) + cv2.imshow(ROS_NODE_NAME, result_img) + cv2.waitKey(1) + + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +if __name__ == '__main__': + fps_t0 = time.time() + fps = 0 + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + image_queue = queue.Queue(maxsize=1) + jetmax = hiwonder.JetMax() + jetmax.go_home() + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) # 订阅摄像头画面 + while not rospy.is_shutdown(): + image_proc_b() diff --git a/src/Ai_JetMax/scripts/models b/src/Ai_JetMax/scripts/models new file mode 120000 index 0000000..ec57a6d --- /dev/null +++ b/src/Ai_JetMax/scripts/models @@ -0,0 +1 @@ +/home/hiwonder/models \ No newline at end of file diff --git a/src/Ai_JetMax/scripts/number_recognition.py b/src/Ai_JetMax/scripts/number_recognition.py new file mode 100755 index 0000000..43c8ac9 --- /dev/null +++ b/src/Ai_JetMax/scripts/number_recognition.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +import os +import sys +import cv2 +import math +import rospy +import numpy as np +from sensor_msgs.msg import Image +import queue +import hiwonder +from yolov5_tensorrt import Yolov5TensorRT +import random +import threading + +ROS_NODE_NAME = "virtual_calculator" +TRT_ENGINE_PATH = os.path.join(sys.path[0], "models/numbers_v5_160.trt") +TRT_INPUT_SIZE = 160 +TRT_CLASS_NAMES = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', '*', '/', '=') +TRT_NUM_CLASSES = 15 +COLORS = [(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) for i in range(TRT_NUM_CLASSES)] + + +def image_proc_a(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + outputs = yolov5.detect(image) + boxes, confs, classes = yolov5.post_process(image, outputs, 0.6) + width = image.shape[1] + height = image.shape[0] + for box, cls_conf, cls_id in zip(boxes, confs, classes): + x1 = int(box[0] / TRT_INPUT_SIZE * width) + y1 = int(box[1] / TRT_INPUT_SIZE * height) + x2 = int(box[2] / TRT_INPUT_SIZE * width) + y2 = int(box[3] / TRT_INPUT_SIZE * height) + card_name = str(TRT_CLASS_NAMES[cls_id]) + cv2.putText(image, card_name + " " + str(float(cls_conf))[:4], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, + 0.7, COLORS[cls_id], 2) + cv2.rectangle(image, (x1, y1), (x2, y2), COLORS[cls_id], 2) + print(x1, y1, x2, y2, card_name) + + image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) + cv2.imshow(ROS_NODE_NAME, image) + cv2.waitKey(1) + + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + yolov5 = Yolov5TensorRT(TRT_ENGINE_PATH, TRT_INPUT_SIZE, TRT_NUM_CLASSES) + jetmax = hiwonder.JetMax() + jetmax.go_home(2) + rospy.sleep(2) + image_queue = queue.Queue(maxsize=1) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback, queue_size=1) # Subscribe to the camera + while not rospy.is_shutdown(): + image_proc_a() diff --git a/src/Ai_JetMax/scripts/waste_classification.py b/src/Ai_JetMax/scripts/waste_classification.py new file mode 100755 index 0000000..26e79e0 --- /dev/null +++ b/src/Ai_JetMax/scripts/waste_classification.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +import os +import sys +import cv2 +import math +import rospy +import numpy as np +import threading +import queue +import hiwonder +from sensor_msgs.msg import Image +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from std_srvs.srv import Empty +from std_msgs.msg import Bool +from jetmax_control.msg import SetServo +from yolov5_tensorrt import Yolov5TensorRT + +ROS_NODE_NAME = "waste_classification_1" + +TRT_ENGINE_PATH = os.path.join(sys.path[0], "models/waste_v5_160.trt") +TRT_INPUT_SIZE = 160 +TRT_CLASS_NAMES = ('Banana Peel', 'Broken Bones', 'Cigarette End', 'Disposable Chopsticks', + 'Ketchup', 'Marker', 'Oral Liquid Bottle', 'Plate', + 'Plastic Bottle', 'Storage Battery', 'Toothbrush', 'Umbrella') +TRT_NUM_CLASSES = 12 +WASTE_CLASSES = { + 'food_waste': ('Banana Peel', 'Broken Bones', 'Ketchup'), + 'hazardous_waste': ('Marker', 'Oral Liquid Bottle', 'Storage Battery'), + 'recyclable_waste': ('Plastic Bottle', 'Toothbrush', 'Umbrella'), + 'residual_waste': ('Plate', 'Cigarette End', 'Disposable Chopsticks'), +} +COLORS = { + 'recyclable_waste': (0, 0, 255), + 'hazardous_waste': (255, 0, 0), + 'food_waste': (0, 255, 0), + 'residual_waste': (80, 80, 80) +} + +TARGET_POSITION = { + 'recyclable_waste': (170, -65, 65, 65), + 'hazardous_waste': (170, -15, 65, 85), + 'food_waste': (170, 35, 65, 100), + 'residual_waste': (170, 85, 65, 118) +} + + +def image_proc(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + outputs = yolov5.detect(image) + boxes, confs, classes = yolov5.post_process(image, outputs, 0.65) + width = image.shape[1] + height = image.shape[0] + cards = [] + for box, cls_conf, cls_id in zip(boxes, confs, classes): + x1 = int(box[0] / TRT_INPUT_SIZE * width) + y1 = int(box[1] / TRT_INPUT_SIZE * height) + x2 = int(box[2] / TRT_INPUT_SIZE * width) + y2 = int(box[3] / TRT_INPUT_SIZE * height) + waste_name = TRT_CLASS_NAMES[cls_id] + waste_class_name = '' + for k, v in WASTE_CLASSES.items(): + if waste_name in v: + waste_class_name = k + break + cards.append((cls_conf, x1, y1, x2, y2, waste_class_name)) + cv2.putText(image, waste_class_name, (x1, y1 - 25), + cv2.FONT_HERSHEY_SIMPLEX, 0.7, COLORS[waste_class_name], 2) + cv2.putText(image, waste_name + "{:0.2f}".format(float(cls_conf)), (x1, y1 - 5), + cv2.FONT_HERSHEY_SIMPLEX, 0.7, COLORS[waste_class_name], 2) + cv2.rectangle(image, (x1, y1), (x2, y2), COLORS[waste_class_name], 3) + + image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) + cv2.imshow('result', image) + cv2.waitKey(1) + + + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + image_queue = queue.Queue(maxsize=2) + jetmax = hiwonder.JetMax() + jetmax.go_home(2) + rospy.sleep(2) + yolov5 = Yolov5TensorRT(TRT_ENGINE_PATH, TRT_INPUT_SIZE, TRT_NUM_CLASSES) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) + while not rospy.is_shutdown(): + image_proc() diff --git a/src/Ai_JetMax/scripts/yolov5_tensorrt.py b/src/Ai_JetMax/scripts/yolov5_tensorrt.py new file mode 100644 index 0000000..194835e --- /dev/null +++ b/src/Ai_JetMax/scripts/yolov5_tensorrt.py @@ -0,0 +1,207 @@ +import cv2 +import sys +import os +import tensorrt as trt +import pycuda.autoinit +import pycuda.driver as cuda +import numpy as np +import math + + +# Simple helper data class that's a little nicer to use than a 2-tuple. +class HostDeviceMem: + def __init__(self, host_mem, device_mem): + self.host = host_mem + self.device = device_mem + + def __str__(self): + return "Host:\n" + str(self.host) + "\nDevice:\n" + str(self.device) + + def __repr__(self): + return self.__str__() + + +def sigmoid_v(array): + return np.reciprocal(np.exp(-array) + 1.0) + + +def sigmoid(x): + return 1 / (1 + math.exp(-x)) + + +def non_max_suppression(boxes, confs, classes, iou_thres=0.6): + x1 = boxes[:, 0] + y1 = boxes[:, 1] + x2 = boxes[:, 2] + y2 = boxes[:, 3] + areas = (x2 - x1 + 1) * (y2 - y1 + 1) + order = confs.flatten().argsort()[::-1] + keep = [] + while order.size > 0: + i = order[0] + keep.append(i) + xx1 = np.maximum(x1[i], x1[order[1:]]) + yy1 = np.maximum(y1[i], y1[order[1:]]) + xx2 = np.minimum(x2[i], x2[order[1:]]) + yy2 = np.minimum(y2[i], y2[order[1:]]) + w = np.maximum(0.0, xx2 - xx1 + 1) + h = np.maximum(0.0, yy2 - yy1 + 1) + inter = w * h + ovr = inter / (areas[i] + areas[order[1:]] - inter) + inds = np.where(ovr <= iou_thres)[0] + order = order[inds + 1] + boxes = boxes[keep] + confs = confs[keep] + classes = classes[keep] + return boxes, confs, classes + + +def xywh2xyxy(x): + # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right + y = np.zeros_like(x) + y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x + y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y + y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x + y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y + return y + + +def nms(pred, iou_thres=0.4): + boxes = xywh2xyxy(pred[..., 0:4]) + # best class only + confs = np.amax(pred[:, 5:], 1, keepdims=True) + classes = np.argmax(pred[:, 5:], axis=-1) + return non_max_suppression(boxes, confs, classes) + + +def make_grid(nx, ny): + """ + Create scaling tensor based on box location + Source: https://github.com/ultralytics/yolov5/blob/master/models/yolo.py + Arguments + nx: x-axis num boxes + ny: y-axis num boxes + Returns + grid: tensor of shape (1, 1, nx, ny, 80) + """ + nx_vec = np.arange(nx) + ny_vec = np.arange(ny) + yv, xv = np.meshgrid(ny_vec, nx_vec) + grid = np.stack((yv, xv), axis=2) + grid = grid.reshape(1, 1, ny, nx, 2) + return grid + + +def pre_process(img_in, w, h): + img_in = cv2.resize(img_in, (w, h), interpolation=cv2.INTER_LINEAR) + # img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + # img = img.transpose((2, 0, 1)).astype(np.float16) + img_in = np.transpose(img_in, (2, 0, 1)).astype(np.float32) + img_in = np.expand_dims(img_in, axis=0) + img_in /= 255.0 + img_in = np.ascontiguousarray(img_in) + return img_in + + +class Yolov5TensorRT: + def __init__(self, model, input_size, classes_num): + # load tensorrt engine + self.input_size = input_size + TRT_LOGGER = trt.Logger(trt.Logger.INFO) + with open(model, 'rb') as f, trt.Runtime(TRT_LOGGER) as runtime: + engine = runtime.deserialize_cuda_engine(f.read()) + self.context = engine.create_execution_context() + # allocate memory + inputs, outputs, bindings = [], [], [] + stream = cuda.Stream() + for binding in engine: + size = trt.volume(engine.get_binding_shape(binding)) + dtype = trt.nptype(engine.get_binding_dtype(binding)) + host_mem = cuda.pagelocked_empty(size, dtype) + device_mem = cuda.mem_alloc(host_mem.nbytes) + bindings.append(int(device_mem)) + if engine.binding_is_input(binding): + inputs.append(HostDeviceMem(host_mem, device_mem)) + else: + outputs.append(HostDeviceMem(host_mem, device_mem)) + # save to class + self.inputs = inputs + self.outputs = outputs + self.bindings = bindings + self.stream = stream + # post processing config + self.strides = np.array([8., 16., 32.]) + anchors = np.array([ + [[10, 13], [16, 30], [33, 23]], + [[30, 61], [62, 45], [59, 119]], + [[116, 90], [156, 198], [373, 326]], + ]) + self.nl = len(anchors) + self.nc = classes_num # classes + self.no = self.nc + 5 # outputs per anchor + self.na = len(anchors[0]) + a = anchors.copy().astype(np.float32) + a = a.reshape(self.nl, -1, 2) + self.anchors = a.copy() + self.anchor_grid = a.copy().reshape(self.nl, 1, -1, 1, 1, 2) + self.output_shapes = [ + (1, 3, int(input_size / 8), int(input_size / 8), self.nc + 5), + (1, 3, int(input_size / 16), int(input_size / 16), self.nc + 5), + (1, 3, int(input_size / 32), int(input_size / 32), self.nc + 5) + ] + + def detect(self, img): + shape_orig_WH = (img.shape[1], img.shape[0]) + resized = pre_process(img, self.input_size, self.input_size) + outputs = self.inference(resized) + # reshape from flat to (1, 3, x, y, 85) + reshaped = [] + for output, shape in zip(outputs, self.output_shapes): + reshaped.append(output.reshape(shape)) + return reshaped + + def inference(self, img): + # copy img to input memory + # self.inputs[0]['host'] = np.ascontiguousarray(img) + self.inputs[0].host = np.ravel(img) + # transfer data to the gpu + [cuda.memcpy_htod_async(inp.device, inp.host, self.stream) for inp in self.inputs] + # run inference + self.context.execute_async_v2(bindings=self.bindings, stream_handle=self.stream.handle) + # fetch outputs from gpu + [cuda.memcpy_dtoh_async(out.host, out.device, self.stream) for out in self.outputs] + # synchronize stream + self.stream.synchronize() + return [out.host for out in self.outputs] + + def post_process(self, image, outputs, conf_thres=0.2): + """ + Transforms raw output into boxes, confs, classes + Applies NMS thresholding on bounding boxes and confs + Parameters: + output: raw output tensor + Returns: + boxes: x1,y1,x2,y2 tensor (dets, 4) + confs: class * obj prob tensor (dets, 1) + classes: class type tensor (dets, 1) + """ + scaled = [] + grids = [] + for out in outputs: + out = sigmoid_v(out) + _, _, width, height, _ = out.shape + grid = make_grid(width, height) + grids.append(grid) + scaled.append(out) + z = [] + for out, grid, stride, anchor in zip(scaled, grids, self.strides, self.anchor_grid): + _, _, width, height, _ = out.shape + out[..., 0:2] = (out[..., 0:2] * 2. - 0.5 + grid) * stride + out[..., 2:4] = (out[..., 2:4] * 2) ** 2 * anchor + + out = out.reshape((1, 3 * width * height, self.no)) + z.append(out) + pred = np.concatenate(z, 1) + xc = pred[..., 4] > conf_thres + pred = pred[xc] + return nms(pred) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..cd58121 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,69 @@ +# toplevel CMakeLists.txt for a catkin workspace +# catkin/cmake/toplevel.cmake + +cmake_minimum_required(VERSION 3.0.2) + +project(Project) + +set(CATKIN_TOPLEVEL TRUE) + +# search for catkin within the workspace +set(_cmd "catkin_find_pkg" "catkin" "${CMAKE_SOURCE_DIR}") +execute_process(COMMAND ${_cmd} + RESULT_VARIABLE _res + OUTPUT_VARIABLE _out + ERROR_VARIABLE _err + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_STRIP_TRAILING_WHITESPACE +) +if(NOT _res EQUAL 0 AND NOT _res EQUAL 2) + # searching fot catkin resulted in an error + string(REPLACE ";" " " _cmd_str "${_cmd}") + message(FATAL_ERROR "Search for 'catkin' in workspace failed (${_cmd_str}): ${_err}") +endif() + +# include catkin from workspace or via find_package() +if(_res EQUAL 0) + set(catkin_EXTRAS_DIR "${CMAKE_SOURCE_DIR}/${_out}/cmake") + # include all.cmake without add_subdirectory to let it operate in same scope + include(${catkin_EXTRAS_DIR}/all.cmake NO_POLICY_SCOPE) + add_subdirectory("${_out}") + +else() + # use either CMAKE_PREFIX_PATH explicitly passed to CMake as a command line argument + # or CMAKE_PREFIX_PATH from the environment + if(NOT DEFINED CMAKE_PREFIX_PATH) + if(NOT "$ENV{CMAKE_PREFIX_PATH}" STREQUAL "") + if(NOT WIN32) + string(REPLACE ":" ";" CMAKE_PREFIX_PATH $ENV{CMAKE_PREFIX_PATH}) + else() + set(CMAKE_PREFIX_PATH $ENV{CMAKE_PREFIX_PATH}) + endif() + endif() + endif() + + # list of catkin workspaces + set(catkin_search_path "") + foreach(path ${CMAKE_PREFIX_PATH}) + if(EXISTS "${path}/.catkin") + list(FIND catkin_search_path ${path} _index) + if(_index EQUAL -1) + list(APPEND catkin_search_path ${path}) + endif() + endif() + endforeach() + + # search for catkin in all workspaces + set(CATKIN_TOPLEVEL_FIND_PACKAGE TRUE) + find_package(catkin QUIET + NO_POLICY_SCOPE + PATHS ${catkin_search_path} + NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) + unset(CATKIN_TOPLEVEL_FIND_PACKAGE) + + if(NOT catkin_FOUND) + message(FATAL_ERROR "find_package(catkin) failed. catkin was neither found in the workspace nor in the CMAKE_PREFIX_PATH. One reason may be that no ROS setup.sh was sourced before.") + endif() +endif() + +catkin_workspace() diff --git a/src/Sensor/CMakeLists.txt b/src/Sensor/CMakeLists.txt new file mode 100644 index 0000000..3fa25d8 --- /dev/null +++ b/src/Sensor/CMakeLists.txt @@ -0,0 +1,203 @@ +cmake_minimum_required(VERSION 3.0.2) +project(Sensor) + +## 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 +) + +## 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 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 Sensor +# CATKIN_DEPENDS python +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( +# include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/Sensor.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/Sensor_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_Sensor.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/Sensor/package.xml b/src/Sensor/package.xml new file mode 100644 index 0000000..64defd8 --- /dev/null +++ b/src/Sensor/package.xml @@ -0,0 +1,59 @@ + + + Sensor + 0.0.0 + The Sensor package + + + + + hiwonder + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + + + + + + + + diff --git a/src/Sensor/scripts/FER b/src/Sensor/scripts/FER new file mode 120000 index 0000000..b3ae897 --- /dev/null +++ b/src/Sensor/scripts/FER @@ -0,0 +1 @@ +/home/hiwonder/ros/src/jetmax_demos/scripts/FER \ No newline at end of file diff --git a/src/Sensor/scripts/PixelToRealworld b/src/Sensor/scripts/PixelToRealworld new file mode 160000 index 0000000..cc2fe1b --- /dev/null +++ b/src/Sensor/scripts/PixelToRealworld @@ -0,0 +1 @@ +Subproject commit cc2fe1bfae20fe2bcb9abfb6c3062af0b995b876 diff --git a/src/Sensor/scripts/Servo_Double_main.py b/src/Sensor/scripts/Servo_Double_main.py new file mode 100755 index 0000000..bc493fa --- /dev/null +++ b/src/Sensor/scripts/Servo_Double_main.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 + +import hiwonder +import time + +""" +jetmax上的舵机的位置数值范围为0~1000, 对应0~240度 +需要注意, 舵机的位置数值和时间数值都需要用整数 +""" +def main(): + hiwonder.serial_servo.set_position(1, 600, 2000) #让id为1的舵机用2000毫秒时间从当前位置运动到600位置 + time.sleep(1) + hiwonder.serial_servo.set_position(1, 300, 2000) #让id为1的舵机用2000毫秒时间从当前位置运动到300位置 + time.sleep(1) + hiwonder.serial_servo.set_position(1, 500, 2000) #让id为1的舵机用2000毫秒时间从当前位置运动到500位置 + time.sleep(1) + hiwonder.serial_servo.set_position(2, 600, 2000) #让id为1的舵机用2000毫秒时间从当前位置运动到600位置 + time.sleep(1) + hiwonder.serial_servo.set_position(2, 300, 2000) #让id为1的舵机用2000毫秒时间从当前位置运动到300位置 + time.sleep(1) + hiwonder.serial_servo.set_position(2, 500, 2000) #让id为1的舵机用2000毫秒时间从当前位置运动到500位置 + time.sleep(1) + hiwonder.serial_servo.set_position(3, 300, 2000) #让id为1的舵机用2000毫秒时间从当前位置运动到300位置 + time.sleep(1) + hiwonder.serial_servo.set_position(3, 600, 2000) #让id为1的舵机用2000毫秒时间从当前位置运动到600位置 + time.sleep(1) + hiwonder.serial_servo.set_position(3, 500, 2000) #让id为1的舵机用2000毫秒时间从当前位置运动到500位置 + time.sleep(1) + + hiwonder.pwm_servo1.set_position(135, 1) #控制1号舵机用1秒转动到90度位置 + time.sleep(1) + hiwonder.pwm_servo1.set_position(45, 1) #控制1号舵机用1秒转动到90度位置 + time.sleep(1) + hiwonder.pwm_servo1.set_position(90, 1) #控制1号舵机用1秒转动到90度位置 + time.sleep(1) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/Sensor/scripts/Stackbot/manual_control.py b/src/Sensor/scripts/Stackbot/manual_control.py new file mode 100755 index 0000000..2c834e9 --- /dev/null +++ b/src/Sensor/scripts/Stackbot/manual_control.py @@ -0,0 +1,70 @@ + +import time + +# 假设jetmax是机械臂的控制模块 +import hiwonder + + +jetmax = hiwonder.JetMax() +sucker = hiwonder.Sucker() + + +import sys +import tty +import termios +import time + +# 假设jetmax是机械臂的控制模块 +# from your_jetmax_library import jetmax + +# 设置初始位置 +position = [-100, -265.94, 80] +step = 5 # 每次移动的步长 +time_to_move = 0.1 # 运动时间 + +# 控制机械臂的位置函数 +def set_position(position, time_to_move): + print(f"Setting position to {position} in {time_to_move} seconds") + # 在这里调用机械臂的接口 + jetmax.set_position(tuple(position), time_to_move) + +# 获取单个字符输入的函数 +def getch(): + fd = sys.stdin.fileno() + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(sys.stdin.fileno()) + ch = sys.stdin.read(1) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + return ch + +print("Use WASD to move in the XY plane, R and F to move along Z. Press 'q' to quit.") + +try: + while True: + char = getch() + if char == 'w': + position[1] += step # Y 轴增加 + elif char == 's': + position[1] -= step # Y 轴减少 + elif char == 'a': + position[0] -= step # X 轴减少 + elif char == 'd': + position[0] += step # X 轴增加 + elif char == 'r': + position[2] += step # Z 轴增加 + elif char == 'f': + position[2] -= step # Z 轴减少 + elif char == 'q': + break + + set_position(position, time_to_move) + time.sleep(0.1) + +except KeyboardInterrupt: + print("Program interrupted.") +finally: + print("Program exited.") + + diff --git a/src/Sensor/scripts/arm_debug.py b/src/Sensor/scripts/arm_debug.py new file mode 100644 index 0000000..d4e3abe --- /dev/null +++ b/src/Sensor/scripts/arm_debug.py @@ -0,0 +1,28 @@ +import hiwonder +import time +from PixelToRealworld.predefinedconstants import * + +jetmax = hiwonder.JetMax() +sucker = hiwonder.Sucker() + +jetmax.go_home(1) +time.sleep(1) + +ort_point = (0, -162.94, 212.8 - 28) + +new_point = ort_point +new_point = (new_point[0] , new_point[1] - 80, new_point[2] - 130) + +ele_point = (-86, -115.94, 212.8) + +# px, py = input("请输入像素坐标:").split() +# px, py = int(px), int(py) +target = pixel2robot(300, 165)[0] +# print(target) + +# jetmax.set_position((target[0], target[1], 70), 1) +# jetmax.set_position((-75.41654829, -156.86319459, 70), 1) +jetmax.set_position(ort_point, 1) +time.sleep(1) + +print(jetmax.position) diff --git a/src/Sensor/scripts/arm_move_main.py b/src/Sensor/scripts/arm_move_main.py new file mode 100755 index 0000000..477f4a2 --- /dev/null +++ b/src/Sensor/scripts/arm_move_main.py @@ -0,0 +1,141 @@ +import time +import hiwonder + +from PixelToRealworld.predefinedconstants import * + +jetmax = hiwonder.JetMax() +sucker = hiwonder.Sucker() + +pre_x, pre_y, pre_z = 123, -195, 65 +ori_x, ori_y, ori_z = 0, -212, 60 +stack_id = 0 + +STACK_P_X, STACK_P_Y = 125, -175.94 +FIRST_Z = 70 + + +class Stackbot: + def __init__(self): + self.stack_xyz = [STACK_P_X, STACK_P_Y] + self.ori_x, self.ori_y, self.ori_z = 0, -212, 60 + self.first_z = 70 + self.stack_pick_angle = 0 + self.current_level = 0 + + + def pick_stack(self, stack_id): + stack_xyz = [STACK_P_X, STACK_P_Y] + + jetmax.go_home(1) + time.sleep(1) + + hiwonder.pwm_servo1.set_position(180, 0.1) + time.sleep(0.5) + + jetmax.set_position((stack_xyz[0], stack_xyz[1], FIRST_Z + 100), 1) + time.sleep(2) + + sucker.suck() + jetmax.set_position((stack_xyz[0], stack_xyz[1], FIRST_Z - 5), 2) + + time.sleep(3) + self.stack_pick_angle = hiwonder.serial_servo.read_position(1) + + jetmax.set_position((stack_xyz[0], stack_xyz[1], pre_z + 100), 1) + time.sleep(1) + + jetmax.go_home(1) + time.sleep(1) + # current_angle = hiwonder.serial_servo.read_position(1) + # hiwonder.pwm_servo1.set_position(180 + (current_angle-self.stack_pick_angle) * 0.25 , 0.1) + # time.sleep(1) + + def place_stack(self, stack_id, px, py, theta, level): + stack_xyz = pixel2robot(px, py)[0] + stack_xyz = (stack_xyz[0], stack_xyz[1], FIRST_Z + level * 12) + + jetmax.set_position((stack_xyz[0], stack_xyz[1], stack_xyz[2] + 100), 1) + time.sleep(1) + + current_angle = hiwonder.serial_servo.read_position(1) + # hiwonder.pwm_servo1.set_position(180 + (current_angle-self.stack_pick_angle) * 0.25 - theta, 0.1) + print(current_angle, self.stack_pick_angle) + time.sleep(1) + + + + if stack_id == 6: + hiwonder.pwm_servo1.set_position(180 + (current_angle-self.stack_pick_angle) * 0.25 + 30, 0.5) + else: + hiwonder.pwm_servo1.set_position(180 + (current_angle-self.stack_pick_angle) * 0.25 - theta, 0.5) + + time.sleep(1) + + jetmax.set_position((stack_xyz[0], stack_xyz[1], stack_xyz[2] + 10), 2) + time.sleep(2) + + + + sucker.release() + + +if __name__ == '__main__': + # jetmax.go_home(1) + # time.sleep(1) + + # jetmax.set_position((ori_x, ori_y, 200), 1) + # hiwonder.pwm_servo1.set_position(180, 0.1) + # pick_stack(1) + sucker.release() + stackbot = Stackbot() + stackbot.pick_stack(1) + stackbot.place_stack(1, 379, 209, 30, 0) + + stackbot.pick_stack(2) + stackbot.place_stack(2, 172, 217, 150, 0) + + stackbot.pick_stack(3) + stackbot.place_stack(3, 300, 430, 90, 0) + + stackbot.pick_stack(4) + stackbot.place_stack(4, 274, 120, 90, 1) + + stackbot.pick_stack(5) + stackbot.place_stack(5, 180, 373, 30, 1) + + stackbot.pick_stack(6) + stackbot.place_stack(6, 412, 333, 150, 1) + + # while True: + # ori_z += 16 + # pick_stack(stack_id) + + + # jetmax.set_position((ori_x, ori_y, ori_z), 1) + # time.sleep(1) + + # sucker.release() + # time.sleep(2) + + # stack_id += 1 + + # while True: + # jetmax.set_position((cur_x-100, cur_y, cur_z), 1) + # time.sleep(2) + # jetmax.set_position((cur_x+100, cur_y, cur_z), 1) + # time.sleep(2) + # jetmax.set_position((cur_x, cur_y, cur_z), 1) + # time.sleep(2) + + # jetmax.set_position((cur_x, cur_y-50, cur_z), 1) + # time.sleep(2) + # jetmax.set_position((cur_x, cur_y+50, cur_z), 1) + # time.sleep(2) + # jetmax.set_position((cur_x, cur_y, cur_z), 1) + # time.sleep(2) + + # jetmax.set_position((cur_x, cur_y, cur_z-100), 1) + # time.sleep(2) + # jetmax.set_position((cur_x, cur_y, cur_z), 0.5) + # time.sleep(2) + diff --git a/src/Sensor/scripts/asr.py b/src/Sensor/scripts/asr.py new file mode 100755 index 0000000..b8617ad --- /dev/null +++ b/src/Sensor/scripts/asr.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +# coding=utf8 +''' + * 只能识别汉字,将要识别的汉字转换成拼音字母,每个汉字之间空格隔开,比如:幻尔科技 --> huan er ke ji + * 最多添加50个词条,每个词条最长为79个字符,每个词条最多10个汉字 + * 每个词条都对应一个识别号(1~255随意设置)不同的语音词条可以对应同一个识别号, + * 比如“幻尔科技”和“幻尔”都可以将识别号设置为同一个值 + * 模块上的STA状态灯:亮起表示正在识别语音,灭掉表示不会识别语音,当识别到语音时状态灯会变暗,或闪烁,等待读取后会恢复当前的状态指示 +''' +import smbus2 +import time +import numpy +#幻尔科技语音识别模块例程# + +class ASR: + # Global Variables + address = 0x79 + bus = None + + ASR_RESULT_ADDR = 100 + #识别结果存放处,通过不断读取此地址的值判断是否识别到语音,不同的值对应不同的语音 + + ASR_WORDS_ERASE_ADDR = 101 + #擦除所有词条 + + ASR_MODE_ADDR = 102 + #识别模式设置,值范围1~3 + #1:循环识别模式。状态灯常亮(默认模式) + #2:口令模式,以第一个词条为口令。状态灯常灭,当识别到口令词时常亮,等待识别到新的语音,并且读取识别结果后即灭掉 + #3:按键模式,按下开始识别,不按不识别。支持掉电保存。状态灯随按键按下而亮起,不按不亮 + + ASR_ADD_WORDS_ADDR = 160 + #词条添加的地址,支持掉电保存 + + def __init__(self, bus=1): + self.bus = smbus2.SMBus(bus) + + def readByte(self): + try: + result = self.bus.read_byte(self.address) + except: + return None + return result + + def writeByte(self, val): + try: + value = self.bus.write_byte(self.address, val) + except: + return False + if value != 0: + return False + return True + + def writeData(self, reg, val): + try: + self.bus.write_byte(self.address, reg) + self.bus.write_byte(self.address, val) + except: + pass + + def getResult(self): + if ASR.writeByte(self, self.ASR_RESULT_ADDR): + return -1 + try: + value = self.bus.read_byte(self.address) + except: + return None + return value + + ''' + * 添加词条函数, + * idNum:词条对应的识别号,1~255随意设置。识别到该号码对应的词条语音时, + * 会将识别号存放到ASR_RESULT_ADDR处,等待主机读取,读取后清0 + * words:要识别汉字词条的拼音,汉字之间用空格隔开 + * + * 执行该函数,词条是自动往后排队添加的。 + ''' + def addWords(self, idNum, words): + buf = [idNum] + for i in range(0, len(words)): + buf.append(eval(hex(ord(words[i])))) + try: + self.bus.write_i2c_block_data(self.address, self.ASR_ADD_WORDS_ADDR, buf) + except: + pass + time.sleep(0.1) + + def eraseWords(self): + try: + result = self.bus.write_byte_data(self.address, self.ASR_WORDS_ERASE_ADDR, 0) + except: + return False + time.sleep(0.1) + if result != 0: + return False + return True + + def setMode(self, mode): + try: + result = self.bus.write_byte_data(self.address, self.ASR_MODE_ADDR, mode) + except: + return False + time.sleep(0.1) + if result != 0: + return False + return True + +if __name__ == "__main__": + asr = ASR() + + #添加的词条和识别模式是可以掉电保存的,第一次设置完成后,可以将1改为0 + if 1: + asr.eraseWords() + asr.setMode(2) + asr.addWords(1, 'kai shi') + asr.addWords(2, 'fen jian hong se') + asr.addWords(3, 'fen jian lv se') + asr.addWords(4, 'fen jian lan se') + asr.addWords(5, 'fen jian biao qian yi') + asr.addWords(6, 'fen jian biao qian er') + asr.addWords(7, 'fen jian biao qian san') + asr.addWords(8, 'ting zhi fen jian') + while 1: + data = asr.getResult() + if data: + print("result:", data) + time.sleep(0.01) diff --git a/src/Sensor/scripts/buzzer_control.py b/src/Sensor/scripts/buzzer_control.py new file mode 100755 index 0000000..cfe09a3 --- /dev/null +++ b/src/Sensor/scripts/buzzer_control.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 + +import hiwonder +import time + +""" +控制蜂鸣器 +""" + +def main(): + while True: + #jetmax上的蜂鸣器为有源蜂鸣器只能控制开关,不可控制音调 + for i in range(5): + hiwonder.buzzer.on() #打开蜂鸣器 + time.sleep(0.1) # + hiwonder.buzzer.off() #关闭蜂鸣器 + time.sleep(0.1) + + time.sleep(1) + + +if __name__ == "__main__": + main() diff --git a/src/Sensor/scripts/camera_calib.py b/src/Sensor/scripts/camera_calib.py new file mode 100644 index 0000000..be14516 --- /dev/null +++ b/src/Sensor/scripts/camera_calib.py @@ -0,0 +1,89 @@ +import numpy as np +import cv2 +import pickle + + + + + +def pixel2robot(p_x, p_y, Zc=260): + """ + 将像素坐标转换为机器人坐标系坐标 + + 参数: + p_x (int):像素坐标系x轴坐标 + p_y (int):像素坐标系y轴坐标 + + 返回值: + robot_coords (numpy.ndarray):机器人基坐标系下的坐标 + + 示例: + >>> pixel2robot(100, 200) + array([-51.464, -41.334, 774.52]) + """ + + # 摄像头内参矩阵 + camera_matrix = np.array([[9.751303247980034e+02, 0, 9.068156759228305e+02], + [0, 9.771159378738466e+02, 5.153786912293900e+02], + [0, 0, 1]]) + + # R = np.array([[-0.67004953, -0.74115346, 0.04153518], + # [0.73884813, -0.67127662, -0.05908594], + # [0.07167334, -0.00890232, 0.99738843]]) + # print(R) + + # T = np.array([0.06106497, -0.06272417, 0.7103077]) + + npzfile = np.load('camera_params.npz') + R = npzfile['R'] + T = npzfile['T'] + T = np.reshape(T, (3,)) + + # 336, 174 + u, v = p_x, p_y + + Zc = Zc + + Xc = (u - camera_matrix[0, 2]) * Zc / camera_matrix[0, 0] + Yc = (v - camera_matrix[1, 2]) * Zc / camera_matrix[1, 1] + + # 相机坐标系到标定板坐标系的转换 + camera_coords = np.array([Xc, Yc, Zc]) + base_coords = np.dot(R, camera_coords) + T + print(base_coords) + + taR = np.array([[0, -1, 0], + [-1, 0, 0], + [0, 0, 0]]) + taT = np.array([-22.73, -149.07, 82]) + # print(np.dot(taR, base_coords)) + base_coords = np.dot(taR, base_coords) + taT + + return base_coords + + +import cv2 +import numpy as np + + +camera_matrix = np.array([[9.751303247980034e+02, 0, 9.068156759228305e+02], + [0, 9.771159378738466e+02, 5.153786912293900e+02], + [0, 0, 1]]) +dist_coeffs = np.array([0.026868761843987, 0.042018062902688, 0, 0, 0]) + +def covert(point=[[0.0, 0.0]], z=260): + point = np.array(point, dtype=np.float) + pts_uv = cv2.undistortPoints(point, camera_matrix, dist_coeffs) * z + return pts_uv[0][0] + +print(covert([993,10],260)) +print(covert([554,559],260)) + + + +# if __name__ == '__main__': +# pixel2robot(993, 10) +# pixel2robot(554, 559) + + + diff --git a/src/Sensor/scripts/dc_motor.py b/src/Sensor/scripts/dc_motor.py new file mode 100755 index 0000000..9434892 --- /dev/null +++ b/src/Sensor/scripts/dc_motor.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 + +import hiwonder +import time + +""" +控制多个pwm舵机转动 +""" + +def main(): + while True: + #jetmax 上一共有3个直流马达接口, 最大输出电压为电源输入电压 + + #速度范围为-100~+100, 0为停止 + # + - 对应方向, 数值只能为整数 + + hiwonder.motor1.set_speed(100) #控制1号电机速度为100 + hiwonder.motor2.set_speed(-100) #控制2号电机速度为-100 + time.sleep(2) + + #你还可以通过getattr()来获取对应的对象进行操作 + def set_motor(id_, speed): + getattr(hiwonder, "motor%d"%id_).set_speed(speed) + + set_motor(1, 0) #控制1号电机速度为0 + set_motor(2, 0) #控制2号电机速度为0 + set_motor(3, 0) #控制3号电机速度为0 + + time.sleep(5) + + + +if __name__ == "__main__": + main() diff --git a/src/Sensor/scripts/digital_display.py b/src/Sensor/scripts/digital_display.py new file mode 100755 index 0000000..9eef48a --- /dev/null +++ b/src/Sensor/scripts/digital_display.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 + +import hiwonder +import time + +""" +将led点阵模块连接到jetmax 的GPIO2口 +""" + +# 字模数据 +font = {'0':0x3f,'1':0x06,'2':0x5b,'3':0x4f,'4':0x66,'5':0x6d,'6':0x7d,'7':0x07,'8':0x7f,'9':0x6f, '-': 0x40} + +def main(): + mtx = hiwonder.TM1640(4, 9) #4, 9 对应 clk, dio 引脚号 + mtx.gram = [0xFF] * 4 #gram用作点阵的显存, 共4个字节, 一个字节对应一位数字 + time.sleep(1) + + + #显示整数 + def display_int(num): + s = str(num) #将数转为字符串 + buf = [font[c] for c in s[:4]] #只显示数值的前4位数字 + mtx.gram = buf + if len(buf) < 4: #如果不够4位,前面填充0, 这样数字就会靠右显示 + buf_zero = [0] * (4 - len(buf)) + buf_zero.extend(buf) + mtx.gram = buf_zero + mtx.refresh() + for i in range(-1000,1222, 13): + display_int(i) + + #显示小数 + def display_float(num): + s = "{:0.1f}".format(num) #将数字转为字符串保留1位小数 + buf = [] + for c in s: + if c in font: + buf.append(font[c]) + else: + if c == '.': #如果是小数点, 将前面一位数字的显示增加小点 + buf[-1] = buf[-1] | 0x80 + mtx.gram = buf + if len(buf) < 4: #如果不够4位,前面填充0, 这样数字就会靠右显示 + buf_zero = [0] * (4 - len(buf)) + buf_zero.extend(buf) + mtx.gram = buf_zero + mtx.refresh() + + i = -10.0 + while i < 10.0: + display_float(i) + i += 0.1 + + while True: + display_int(int(hiwonder.sonar.get_distance())) + time.sleep(0.2) + +if __name__ == '__main__': + main() diff --git a/src/Sensor/scripts/face_expression_matrix.py b/src/Sensor/scripts/face_expression_matrix.py new file mode 100755 index 0000000..f686fe5 --- /dev/null +++ b/src/Sensor/scripts/face_expression_matrix.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python3 +import sys +import math +import rospy +import time +import queue +import threading +import cv2 +import numpy as np +import hiwonder +from sensor_msgs.msg import Image as RosImage + +from PIL import Image +import torch +from facenet_pytorch import MTCNN + +device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') +print(device) + +from FER import fer + +mtcnn = MTCNN(keep_all=True, min_face_size=50, factor=0.709, post_process=False, device=device) + +ROS_NODE_NAME = 'face_expression' +jetmax = hiwonder.JetMax() +image_queue = queue.Queue(maxsize=1) +mtx = hiwonder.TM1640(4, 9) +mtx.gram = [0xFF] * 16 +mtx.refresh() + +def display_expression(name): + expressions = { + 'Happy' : """---XX------XX--- + --X--X----X--X-- + -X----X--X----X- + ---------------- + ---------------- + ---X--------X--- + ----X------X---- + -----XXXXXX-----""".replace(' ', '').split('\n'), + + 'Angry' : """-XX----------XX- + --XX--------XX-- + ---XX------XX--- + ----XX----XX---- + ---------------- + ----XXXXXXXX---- + ---XX------XX--- + --XX--------XX--""".replace(' ', '').split('\n'), + + 'Sad' : """---XXX----XXX--- + --XX--------XX-- + XXX----------XXX + ---------------- + ---------------- + ----XXXXXXXX---- + --XX--------XX-- + -X------------X-""".replace(' ', '').split('\n') + } + if name in expressions: + e = expressions[name] + for y in range(8): + for x in range(16): + mtx.set_bit(x, y, 1 if e[y][x] == 'X' else 0) + else: + mtx.gram = [0] * 16 + mtx.refresh() + + + +class FaceExpression: + def __init__(self): + self.lock = threading.RLock() + self.servo_x = 500 + self.face_tracking = None + self.no_face_count = 0 + self.lost_target_count = 0 + self.is_running_face = False + self.fps = 0.0 + self.tic = time.time() + self.exp = '' + self.count = 0 + + +def show_faces(img, boxes, landmarks, color): + new_boxes = [] + new_landmarks = [] + for bb, ll in zip(boxes, landmarks): + x1 = int(hiwonder.misc.val_map(bb[0], 0, 160, 0, 640)) + y1 = int(hiwonder.misc.val_map(bb[1], 0, 160, 0, 480)) + x2 = int(hiwonder.misc.val_map(bb[2], 0, 160, 0, 640)) + y2 = int(hiwonder.misc.val_map(bb[3], 0, 160, 0, 480)) + cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) + new_boxes.append([x1, y1, x2, y2]) + landmarks_curr_face = [] + if len(landmarks): + for j in range(5): + lx = int(hiwonder.misc.val_map(ll[j][0], 0, 160, 0, 640)) + ly = int(hiwonder.misc.val_map(ll[j][1], 0, 160, 0, 480)) + cv2.circle(img, (lx, ly), 2, color, 2) + landmarks_curr_face.append([lx, ly]) + new_landmarks.append(landmarks_curr_face) + return img, new_boxes, new_landmarks + + + +def image_proc_a(image): + img_ret = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) + org_img1 = np.copy(image) + image = cv2.resize(image, (160, 160)) + boxes, _, landmarks = mtcnn.detect(Image.fromarray(image), landmarks=True) + if boxes is None: + return img_ret + boxes = list(boxes) + landmarks = list(landmarks) + + img_ret, boxes, landmarks = show_faces(img_ret, boxes, landmarks, (0, 255, 0)) + box = None + if state.face_tracking is None: + if len(boxes) > 0: + box = min(boxes, key=lambda b: math.sqrt(((b[2] + b[0]) / 2 - 320) ** 2 + ((b[3] + b[1]) / 2 - 240) ** 2)) + x1, y1, x2, y2 = box + center_x, center_y = int((x1 + x2) / 2), int((y1 + y2) / 2) + cv2.rectangle(img_ret, (x1, y1), (x2, y2), (255, 0, 0), 3) + cv2.circle(img_ret, (center_x, center_y), 2, (0, 255, 0), 4) + state.face_tracking = center_x, center_y + state.no_face_count = time.time() + 2 + else: + centers = [(int((box[2] + box[0]) / 2), int((box[3] + box[1]) / 2), box) for box in boxes] + get_face = False + if len(centers) > 0: + center_x, center_y = state.face_tracking + cv2.circle(img_ret, (center_x, center_y), 2, (255, 0, 0), 4) + min_dist_center = min(centers, key=lambda c: math.sqrt((c[0] - center_x) ** 2 + (c[1] - center_y) ** 2)) + new_center_x, new_center_y, box = min_dist_center + x1, y1, x2, y2 = box + dist = math.sqrt((new_center_x - center_x) ** 2 + (new_center_y - center_y) ** 2) + if dist < 250: + cv2.rectangle(img_ret, (x1, y1), (x2, y2), (0, 0, 255), 3) + cv2.circle(img_ret, (new_center_x, new_center_y), 2, (0, 0, 255), 4) + get_face = True + state.face_tracking = int(new_center_x), int(new_center_y) + state.no_face_count = time.time() + 0.2 + + if state.no_face_count < time.time(): + state.face_tracking = None + get_face = False + if get_face: + x1, y1, x2, y2 = box + x1 = 0 if x1 < 0 else 639 if x1 > 639 else x1 + x2 = 0 if x2 < 0 else 639 if x2 > 639 else x2 + y1 = 0 if y1 < 0 else 479 if y1 > 479 else y1 + y2 = 0 if y2 < 0 else 479 if y2 > 479 else y2 + + print(x1, y1, x2, y2) + face = org_img1[y1: y2, x1: x2] + cv2.imshow("face", cv2.cvtColor(face, cv2.COLOR_RGB2BGR)) + a = fer.fer(face) + cv2.putText(img_ret, a, (0, 200), 0, 1.6, (255, 50, 50), 5) + display_expression(a) + return img_ret + +def image_proc_b(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + image = image_proc_a(image) + toc = time.time() + curr_fps = 1.0 / (state.tic - toc) + state.fps = curr_fps if state.fps == 0.0 else (state.fps * 0.95 + curr_fps * 0.05) + state.tic = toc + cv2.imshow(ROS_NODE_NAME, image) + cv2.waitKey(1) + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + state = FaceExpression() + jetmax.go_home(1) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', RosImage, image_callback) + try: + while not rospy.is_shutdown(): + image_proc_b() + except Exception as e: + rospy.logerr(e) + print(e.__traceback__.tb_lineno) + sys.exit() diff --git a/src/Sensor/scripts/face_tracking.py b/src/Sensor/scripts/face_tracking.py new file mode 100755 index 0000000..988710f --- /dev/null +++ b/src/Sensor/scripts/face_tracking.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python3 +import math +import rospy +import time +import queue +import threading +from sensor_msgs.msg import Image as RosImage +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from std_srvs.srv import Empty +from object_tracking.srv import SetTarget, SetTargetResponse, SetTargetRequest +import cv2 +import numpy as np +import hiwonder +import sys +import Jetson.GPIO as GPIO +GPIO.setmode(GPIO.BCM) +GPIO.setup(9, GPIO.OUT) +GPIO.setup(4, GPIO.OUT) +GPIO.output(9, 0) +GPIO.output(4, 0) + +from PIL import Image +import torch +from facenet_pytorch import MTCNN, InceptionResnetV1 +device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') +print('Running on device: {}'.format(device)) +mtcnn = MTCNN(keep_all=True, min_face_size=50, factor=0.709, post_process=False, device=device) +ROS_NODE_NAME = 'face_tracking' +TARGET_PIXEL_X, TARGET_PIXEL_Y = 320, 240 + +class FaceTracking: + def __init__(self): + self.servo_x = 500 + self.servo_y = 500 + + self.face_x_pid = hiwonder.PID(0.09, 0.005, 0.005) + self.face_z_pid = hiwonder.PID(0.1, 0.0, 0.0) + self.tracking_face = None + self.no_face_count = 0 + self.lost_target_count = 0 + self.fan_on = False + + +def show_faces(img, boxes, landmarks, color): + new_boxes = [] + new_landmarks = [] + for bb, ll in zip(boxes, landmarks): + x1 = int(hiwonder.misc.val_map(bb[0], 0, 160, 0, 640)) + y1 = int(hiwonder.misc.val_map(bb[1], 0, 160, 0, 480)) + x2 = int(hiwonder.misc.val_map(bb[2], 0, 160, 0, 640)) + y2 = int(hiwonder.misc.val_map(bb[3], 0, 160, 0, 480)) + cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) + new_boxes.append([x1, y1, x2, y2]) + landmarks_curr_face = [] + if len(landmarks[0]): + for j in range(5): + lx = int(hiwonder.misc.val_map(ll[j][0], 0, 160, 0, 640)) + ly = int(hiwonder.misc.val_map(ll[j][1], 0, 160, 0, 480)) + cv2.circle(img, (lx, ly), 2, color, 4) + landmarks_curr_face.append([lx, ly]) + new_landmarks.append(landmarks_curr_face) + return img, new_boxes, new_landmarks + + +def fan_control(): + while True: + if state.fan_on: + GPIO.output(9, 0) + GPIO.output(4, 1) + time.sleep(0.01) + GPIO.output(9, 0) + GPIO.output(4, 0) + time.sleep(0.01) + else: + GPIO.output(9, 0) + GPIO.output(4, 0) + time.sleep(0.01) + + +def face_tracking(image): + ta = time.time() + org_img = np.copy(image) + image = cv2.resize(image, (160, 160)) + boxes, _, landmarks = mtcnn.detect(Image.fromarray(image), landmarks=True) + if boxes is not None: + boxes = boxes.tolist() + landmarks = landmarks.tolist() + org_img, boxes, landmarks = show_faces(org_img, boxes, landmarks, (0, 255, 0)) + else: + boxes = [] + + if state.tracking_face is None: + if len(boxes) > 0: + box = min(boxes, key=lambda b: math.sqrt(((b[2] + b[0]) / 2 - 320) ** 2 + ((b[3] + b[1]) / 2 - 240) ** 2)) + x1, y1, x2, y2 = box + org_img = cv2.rectangle(org_img, (x1, y1), (x2, y2), (255, 0, 0), 3) + center_x, center_y = int((x1 + x2) / 2), int((y1 + y2) / 2) + org_img = cv2.circle(org_img, (center_x, center_y), 2, (0, 255, 0), 4) + state.tracking_face = center_x, center_y + state.no_face_count = time.time() + 2 + state.face_x_pid.clear() + state.face_z_pid.clear() + else: + centers = [(int((box[2] + box[0]) / 2), int((box[3] + box[1]) / 2), box) for box in boxes] + get_face = False + if len(centers) > 0: + center_x, center_y = state.tracking_face + org_img = cv2.circle(org_img, (center_x, center_y), 2, (0, 0, 255), 4) + min_dist_center = min(centers, key=lambda c: math.sqrt((c[0] - center_x) ** 2 + (c[1] - center_y) ** 2)) + new_center_x, new_center_y, box = min_dist_center + x1, y1, x2, y2 = box + dist = math.sqrt((new_center_x - center_x) ** 2 + (new_center_y - center_y) ** 2) + if dist < 150: + org_img = cv2.rectangle(org_img, (x1, y1), (x2, y2), (255, 0, 0), 3) + org_img = cv2.circle(org_img, (new_center_x, new_center_y), 2, (255, 0, 0), 4) + get_face = True + state.tracking_face = int(new_center_x), int(new_center_y) + state.no_face_count = time.time() + 2 + if state.no_face_count < time.time(): + state.tracking_face = None + get_face = False + state.fan_on = False + print("FAN OFF") + + if get_face: + state.fan_on = True + center_x, center_y = state.tracking_face + x = center_x - 320 + if abs(x) > 30: + state.face_x_pid.SetPoint = 0 + state.face_x_pid.update(x) + state.servo_x += state.face_x_pid.output + jetmax.set_servo(1, int(state.servo_x), 0.02) + else: + state.face_x_pid.update(0) + + z = center_y - 240 + if abs(z) > 30: + state.face_z_pid.SetPoint = 0 + state.face_z_pid.update(z) + z = jetmax.position[2] + state.face_z_pid.output + jetmax.set_position((jetmax.position[0], jetmax.position[1], z), 0.02) + else: + state.face_z_pid.update(0) + print(center_x, center_y) + return org_img + +def image_proc(): + global mtcnn + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + image = face_tracking(image) + image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) + cv2.imshow("result", image) + cv2.waitKey(1) + + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + state = FaceTracking() + jetmax = hiwonder.JetMax() + jetmax.go_home() + rospy.sleep(1) + image_queue = queue.Queue(maxsize=1) + threading.Thread(target=fan_control, daemon=True).start() + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', RosImage, image_callback) # 订阅摄像头画面 + while not rospy.is_shutdown(): + image_proc() + diff --git a/src/Sensor/scripts/fan_control.py b/src/Sensor/scripts/fan_control.py new file mode 100755 index 0000000..0571b84 --- /dev/null +++ b/src/Sensor/scripts/fan_control.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +import time +import Jetson.GPIO as GPIO + +""" +控制风扇模块 +风扇模块上有独立的马达驱动电路, 需要使用两个io口来控制其正反转, 或者两个io口通过pwm控制其速度 +可以将风扇模块使用4pin 线连接到 jetmax 扩展板上的 GPIO2 上 +其对应的引脚是 gpio9, 和gpio4 +""" + +#初始化io口 +def init_fan(): + GPIO.setmode(GPIO.BCM) #设置gpio控制库为bcm模式 + GPIO.setup(9, GPIO.OUT) #将gpio 9 设置 输出 + GPIO.output(9, 0) + GPIO.setup(4, GPIO.OUT) #将gpio 9 设置 输出 + GPIO.output(4, 0) + + +def main(): + init_fan() + + # 通过两个io口的高低电平控制正反转 + # 两个io口均为低电平时 停止转动 + # 一高一低对应两个方向 + # 要控制速度, 就保持一个io口为低电平, 另一个输出pwm + + #正转100%速度 + GPIO.output(4, 1) + GPIO.output(9, 0) + time.sleep(1) + + #停止转动 + GPIO.output(9, 0) + GPIO.output(4, 0) + time.sleep(1) + + #反转 + GPIO.output(4, 0) + GPIO.output(9, 1) + time.sleep(1) + + + #停止转动 + GPIO.output(9, 0) + GPIO.output(4, 0) + time.sleep(1) + + + #要控制数度就要其中一个口输出pwm + # 例如50%占空比 + t = time.time() + 2 + while time.time() < t: + GPIO.output(4, 1) + GPIO.output(9, 0) + time.sleep(0.01) + GPIO.output(9, 0) + GPIO.output(4, 0) + time.sleep(0.01) + + + +if __name__ == "__main__": + main() diff --git a/src/Sensor/scripts/hand_gesture_tube.py b/src/Sensor/scripts/hand_gesture_tube.py new file mode 100755 index 0000000..bcb12ce --- /dev/null +++ b/src/Sensor/scripts/hand_gesture_tube.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import threading +import numpy as np +import rospy +import queue +from sensor_msgs.msg import Image +import hiwonder +import mediapipe as mp + +ROS_NODE_NAME = "hand_gesture_tube" +mtx = hiwonder.TM1640(4, 9) +mtx.gram = [0xFF] * 4 +mtx.refresh() + + +class HandGesture: + def __init__(self): + self.moving_color = None + self.target_colors = {} + self.lock = threading.RLock + self.position = 0, 0, 0 + self.runner = None + self.count = 0 + self.gesture_str = '' + + +ps = (-205, 0 + 10, 150), (-205, 0 + 10, 120), (-205, 0 + 10, 190) + + +def vector_2d_angle(v1, v2): + """ + Solve the angle between two vector + """ + v1_x = v1[0] + v1_y = v1[1] + v2_x = v2[0] + v2_y = v2[1] + try: + angle_ = math.degrees(math.acos( + (v1_x * v2_x + v1_y * v2_y) / (((v1_x ** 2 + v1_y ** 2) ** 0.5) * ((v2_x ** 2 + v2_y ** 2) ** 0.5)))) + except: + angle_ = 65535. + if angle_ > 180.: + angle_ = 65535. + return angle_ + + +def hand_angle(hand_): + """ + Obtain the angle of the corresponding hand-related vector, and determine the gesture according to the angle + """ + angle_list = [] + # ---------------------------- thumb + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[2][0])), (int(hand_[0][1]) - int(hand_[2][1]))), + ((int(hand_[3][0]) - int(hand_[4][0])), (int(hand_[3][1]) - int(hand_[4][1]))) + ) + angle_list.append(angle_) + # ---------------------------- index + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[6][0])), (int(hand_[0][1]) - int(hand_[6][1]))), + ((int(hand_[7][0]) - int(hand_[8][0])), (int(hand_[7][1]) - int(hand_[8][1]))) + ) + angle_list.append(angle_) + # ---------------------------- middle + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[10][0])), (int(hand_[0][1]) - int(hand_[10][1]))), + ((int(hand_[11][0]) - int(hand_[12][0])), (int(hand_[11][1]) - int(hand_[12][1]))) + ) + angle_list.append(angle_) + # ---------------------------- ring + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[14][0])), (int(hand_[0][1]) - int(hand_[14][1]))), + ((int(hand_[15][0]) - int(hand_[16][0])), (int(hand_[15][1]) - int(hand_[16][1]))) + ) + angle_list.append(angle_) + # ---------------------------- pink + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[18][0])), (int(hand_[0][1]) - int(hand_[18][1]))), + ((int(hand_[19][0]) - int(hand_[20][0])), (int(hand_[19][1]) - int(hand_[20][1]))) + ) + angle_list.append(angle_) + return angle_list + + +def h_gesture(angle_list): + """ + Use the angle of the corresponding hand-related to define the gesture + + """ + thr_angle = 65. + thr_angle_thumb = 53. + thr_angle_s = 49. + gesture_str = None + if 65535. not in angle_list: + if (angle_list[0] > thr_angle_thumb) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] > thr_angle): + gesture_str = "0" + elif (angle_list[0] > 5) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] > thr_angle): + gesture_str = "1" + elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] > thr_angle) and (angle_list[4] > thr_angle): + gesture_str = "2" + elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] < thr_angle_s) and (angle_list[4] > thr_angle): + gesture_str = "3" + elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] > thr_angle) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s): + gesture_str = "3" + elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s): + gesture_str = "4" + elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s): + gesture_str = "5" + elif (angle_list[0] < thr_angle_s) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] < thr_angle_s): + gesture_str = "6" + else: + gesture_str = None + return gesture_str + + +ngcs = { + 'one': 'gcode/1.ngc', + 'two': 'gcode/2.ngc', + 'three': 'gcode/3.ngc', + 'four': 'gcode/4.ngc', + 'five': 'gcode/5.ngc', + 'six': 'gcode/6.ngc', + 'hand_heart': 'ngcs/hand_heart.ngc', +} + + +def draw_num(num): + all_num = ['one', 'two', 'three', 'four', 'five', 'six', 'fist', 'hand_heart', 'nico-nico-ni', "OK"] + i = all_num.index(num) + if i < 6: + for i in range(i + 1): + hiwonder.buzzer.on() + rospy.sleep(0.1) + hiwonder.buzzer.off() + rospy.sleep(0.1) + else: + if i == 6: + hiwonder.buzer.on() + rospy.sleep(1) + hiwonder.buzer.off() + + +def image_proc_a(img): + img_ret = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) + if state.runner is not None: + cv2.putText(img, state.gesture_str, (0, 200), 0, 1.5, (100, 100, 255), 5) + return img_ret + + results = hands.process(img) + if results.multi_handedness: + for label in results.multi_handedness: + print(label) + if results.multi_hand_landmarks: + for hand_landmarks in results.multi_hand_landmarks: + # rospy.logdebug('hand_landmarks:', hand_landmarks) + mp_drawing.draw_landmarks(img_ret, hand_landmarks, mp_hands.HAND_CONNECTIONS) + hand_local = [] + for i in range(21): + x = hand_landmarks.landmark[i].x * img.shape[1] + y = hand_landmarks.landmark[i].y * img.shape[0] + hand_local.append((x, y)) + if hand_local: + angle_list = hand_angle(hand_local) + gesture_str = h_gesture(angle_list) + if gesture_str: + cv2.putText(img_ret, gesture_str, (0, 200), 0, 1.5, (100, 100, 255), 5) + n = int(gesture_str) + mtx.tube_display_int(n) + else: + mtx.gram = [0] * 4 + mtx.refresh() + return img_ret + +def image_proc_b(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + image = cv2.flip(image, 1) + image = image_proc_a(image) + image = cv2.resize(image, (1024, 768)) + cv2.imshow(ROS_NODE_NAME, image) + cv2.waitKey(1) + + + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + rospy.sleep(0.2) + state = HandGesture() + image_queue = queue.Queue(maxsize=1) + mp_drawing = mp.solutions.drawing_utils + mp_hands = mp.solutions.hands + hands = mp_hands.Hands( + static_image_mode=False, + max_num_hands=2, + min_detection_confidence=0.75, + min_tracking_confidence=0.5) + + jetmax = hiwonder.JetMax() + jetmax.go_home() + rospy.sleep(1) + hiwonder.motor2.set_speed(0) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback, queue_size=1) + while not rospy.is_shutdown(): + image_proc_b() + diff --git a/src/Sensor/scripts/img_cap.py b/src/Sensor/scripts/img_cap.py new file mode 100644 index 0000000..905047f --- /dev/null +++ b/src/Sensor/scripts/img_cap.py @@ -0,0 +1,67 @@ +import cv2 +import time + +cap = cv2.VideoCapture(0) +cap.set(6,cv2.VideoWriter.fourcc('M','J','P','G')) + +cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920) +cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080) + +ret, frame = cap.read() +cv2.imwrite(str(time.time()) + '.jpg', frame) + + + +# def SetPoints(windowname, img): +# """ +# 输入图片,打开该图片进行标记点,返回的是标记的几个点的字符串 +# """ +# print('(提示:单击需要标记的坐标,Enter确定,Esc跳过,其它重试。)') +# points = [] + +# def onMouse(event, x, y, flags, param): +# if event == cv2.EVENT_LBUTTONDOWN: +# cv2.circle(temp_img, (x, y), 10, (102, 217, 239), -1) +# points.append([x, y]) +# cv2.imshow(windowname, temp_img) + +# temp_img = img.copy() +# cv2.namedWindow(windowname) +# cv2.imshow(windowname, temp_img) +# cv2.setMouseCallback(windowname, onMouse) +# key = cv2.waitKey(0) +# if key == 13: # Enter +# print('坐标为:', points) +# del temp_img +# cv2.destroyAllWindows() +# return str(points) +# elif key == 27: # ESC +# print('跳过该张图片') +# del temp_img +# cv2.destroyAllWindows() +# return +# else: +# print('重试!') +# return SetPoints(windowname, img) + + + +# SetPoints('test', frame) + + + +# import json +# import requests + +# # Run inference on an image +# url = "https://api.ultralytics.com/v1/predict/MAyxSmPez5SZXdyspDvF" +# headers = {"x-api-key": "803cf64a0603764f0657e33bb0103f8a11ffc59567"} +# data = {"size": 640, "confidence": 0.25, "iou": 0.45} +# with open("test.jpg", "rb") as f: +# response = requests.post(url, headers=headers, data=data, files={"image": f}) + +# # Check for successful response +# response.raise_for_status() + +# # Print inference results +# print(json.dumps(response.json(), indent=2)) \ No newline at end of file diff --git a/src/Sensor/scripts/img_data_taker.py b/src/Sensor/scripts/img_data_taker.py new file mode 100644 index 0000000..e24736d --- /dev/null +++ b/src/Sensor/scripts/img_data_taker.py @@ -0,0 +1,56 @@ +import time +import hiwonder +import queue +import rospy +from sensor_msgs.msg import Image as RosImage +import numpy as np +import cv2 + +jetmax = hiwonder.JetMax() +sucker = hiwonder.Sucker() +ROS_NODE_NAME = 'image_data_taker' + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +def up_down(): + # for loop from 50 to 200 with 10 per step + for z in range(50, 200, 30): + jetmax.set_position((0, -200, z), 0.3) + rospy.sleep(5) + save_image() + +def save_image(): + try: + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) + cv2.imwrite(str(time.time()) + '.jpg', image) + except queue.Empty: + pass + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + jetmax = hiwonder.JetMax() + # jetmax.go_home() + image_queue = queue.Queue(maxsize=1) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', RosImage, image_callback) # 订阅摄像头画面 + rospy.sleep(3) + + + + # ros_image = image_queue.get(block=True) + # image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + # image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) + # rospy.loginfo(image) + + # cv2.imwrite('test.jpg', image) + print(jetmax.position) + # up_down() + save_image() + # jetmax.set_position((0, -100, 200), 1) \ No newline at end of file diff --git a/src/Sensor/scripts/kill_app_funcs.sh b/src/Sensor/scripts/kill_app_funcs.sh new file mode 100755 index 0000000..5f463f9 --- /dev/null +++ b/src/Sensor/scripts/kill_app_funcs.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +sudo kill -9 $(ps -elf|grep -v grep|grep python3|grep alphabetically|awk '{print $4}') >/dev/null 2>&1 +sudo systemctl stop alphabetically.service + +sudo kill -9 $(ps -elf|grep -v grep|grep python3|grep waste_classification|awk '{print $4}') >/dev/null 2>&1 +sudo systemctl stop waste_classification.service + +sudo kill -9 $(ps -elf|grep -v grep|grep python3|grep object_tracking|awk '{print $4}') >/dev/null 2>&1 +sudo systemctl stop object_tracking.service + +sudo kill -9 $(ps -elf|grep -v grep|grep python3|grep color_sorting|awk '{print $4}') >/dev/null 2>&1 +sudo systemctl stop color_sorting.service + + diff --git a/src/Sensor/scripts/mediapipe b/src/Sensor/scripts/mediapipe new file mode 120000 index 0000000..9d5750b --- /dev/null +++ b/src/Sensor/scripts/mediapipe @@ -0,0 +1 @@ +/usr/local/lib/python3.6/dist-packages/mediapipe \ No newline at end of file diff --git a/src/Sensor/scripts/models b/src/Sensor/scripts/models new file mode 120000 index 0000000..ec57a6d --- /dev/null +++ b/src/Sensor/scripts/models @@ -0,0 +1 @@ +/home/hiwonder/models \ No newline at end of file diff --git a/src/Sensor/scripts/multi_pwm_servo.py b/src/Sensor/scripts/multi_pwm_servo.py new file mode 100755 index 0000000..fa4bf7e --- /dev/null +++ b/src/Sensor/scripts/multi_pwm_servo.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 + +import hiwonder +import time + +""" +控制多个pwm舵机转动 +""" + +def main(): + while True: + #控制多个pwm舵机, 只需要将舵机对象的名在最后的数改为对应舵机号即可 + + hiwonder.pwm_servo1.set_position(90, 1) #控制1号舵机用1秒转动到90度位置 + hiwonder.pwm_servo2.set_position(90, 1) #控制2号舵机用1秒转动到90度位置 + time.sleep(2) + + #你还可以通过getattr()来获取对应的对象进行操作 + def set_pwm_servo(id_, pos, duration): + getattr(hiwonder, "pwm_servo%d"%id_).set_position(pos, duration) + + set_pwm_servo(1, 180, 1) #控制1号舵机用1秒转动到180度位置 + set_pwm_servo(2, 0, 2) #控制2号舵机用2秒转动到0度位置 + + time.sleep(3) + + + +if __name__ == "__main__": + main() diff --git a/src/Sensor/scripts/pwm_servo_control.py b/src/Sensor/scripts/pwm_servo_control.py new file mode 100755 index 0000000..ded59f9 --- /dev/null +++ b/src/Sensor/scripts/pwm_servo_control.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +import hiwonder +import time + +""" +控制pwm舵机转动 +""" + +def main(): + while True: + #控制1号pwm舵机 + hiwonder.pwm_servo1.set_position(90, 1) #用1秒转动到90度位置 + time.sleep(2) + hiwonder.pwm_servo1.set_position(180, 1) #用1秒转动到180度位置 + time.sleep(2) + hiwonder.pwm_servo1.set_position(0, 2) #用2秒转动到0度位置 + time.sleep(3) + + +if __name__ == "__main__": + main() diff --git a/src/Sensor/scripts/pwm_servo_speed.py b/src/Sensor/scripts/pwm_servo_speed.py new file mode 100755 index 0000000..69005fc --- /dev/null +++ b/src/Sensor/scripts/pwm_servo_speed.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 + +import hiwonder +import time + +""" +控制pwm舵机按速度转动 +""" + +def main(): + while True: + #控制1号pwm舵机 + hiwonder.pwm_servo1.set_position(90, 1) #用1秒转动到90度位置 + time.sleep(2) + #通过角速度计算舵机需要的运动时间 + # 控制舵机用20度每秒的速度从90度转动到180度 + t = (180 - 90) / 20 + hiwonder.pwm_servo1.set_position(180, t) + time.sleep(t + 1) + # 控制舵机用40度每秒的速度从180度转动到0度 + t = (180 - 0) / 40 + hiwonder.pwm_servo1.set_position(0, t) + time.sleep(t + 1) + + + + +if __name__ == "__main__": + main() diff --git a/src/Sensor/scripts/serial_port.py b/src/Sensor/scripts/serial_port.py new file mode 100755 index 0000000..b612433 --- /dev/null +++ b/src/Sensor/scripts/serial_port.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +import serial +import time + +def main(): + serialHandle = serial.Serial('/dev/ttyTHS1', 115200) #初始化串口为波特率115200 + + #演示控制串口收发数据, + #短接jetmax 的 rx, tx引脚(即扩增板上的UART口中间两根引脚) 即可在屏幕上看到打印 ‘abcdefg' + while True: + serialHandle.write(bytes("abcdefg", encoding='utf-8')) #向串口写入数据, 数据需要时bytes, bytearray + time.sleep(1) + + count = serialHandle.inWaiting() #获取串口接收缓存中接收到的数据的字节数 + recv_data = serialHandle.read(count) #将接收到的字节读取出来 + print(recv_data) + time.sleep(1) + + +if __name__=='__main__': + main() diff --git a/src/Sensor/scripts/serial_servo_control.py b/src/Sensor/scripts/serial_servo_control.py new file mode 100755 index 0000000..32f6d5b --- /dev/null +++ b/src/Sensor/scripts/serial_servo_control.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 + +import hiwonder +import time + +""" +jetmax上的舵机的位置数值范围为0~1000, 对应0~240度 +需要注意, 舵机的位置数值和时间数值都需要用整数 +""" + +def main(): + hiwonder.serial_servo.set_position(1, 1000, 3000) #让id为1的舵机用5000毫秒时间从当前位置运动到1000位置 + time.sleep(3) + hiwonder.serial_servo.set_position(1, 0, 8000) #让id为1的舵机用8000毫秒时间从当前位置运动到0位置 + time.sleep(8) + #如果我们需要用角度来控制的话可以将及角度转化为数值例如现在要转转动到180度位置 + p = 180 / 240 * 1000 + hiwonder.serial_servo.set_position(1, int(p), 4000) #这就是用4000毫秒从当前位置运动到 180度位置 + hiwonder.serial_servo.set_position(1, int(120 / 240 * 1000), 2000) #这就是用2000毫秒从当前位置运动到 120度位置 + + +if __name__ == "__main__": + main() diff --git a/src/Sensor/scripts/serial_servo_read.py b/src/Sensor/scripts/serial_servo_read.py new file mode 100755 index 0000000..46b04b8 --- /dev/null +++ b/src/Sensor/scripts/serial_servo_read.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 + +import hiwonder +import time + +""" +总线舵机支持读取舵机的多个参数及状态 +""" + +def main(): + while True: + id_ = 1 + print("ID: %d" % id_) + pos = hiwonder.serial_servo.read_position(id_) + print('Position:%d' % pos) + now_temp = hiwonder.serial_servo.read_temp(id_) + print('Temperature:%d°' % now_temp) + now_vin = hiwonder.serial_servo.read_vin(id_) + print('Voltage input:%dmv' % now_vin) + d = hiwonder.serial_servo.read_deviation(id_) + print('Deviation:%d' % d) + limit = hiwonder.serial_servo.read_angle_limit(id_) + print('Position range:%d-%d' % (limit[0], limit[1])) + vin = hiwonder.serial_servo.read_vin_limit(id_) + print('Voltage range:%dmv-%dmv' % (vin[0], vin[1])) + temp = hiwonder.serial_servo.read_temp_limit(id_) + print('Temperature limit:50°-%d°' % temp) + print("\n\n") + time.sleep(1) + + +if __name__ == "__main__": + main() diff --git a/src/Sensor/scripts/serial_servo_speed.py b/src/Sensor/scripts/serial_servo_speed.py new file mode 100755 index 0000000..8ca6bd0 --- /dev/null +++ b/src/Sensor/scripts/serial_servo_speed.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 + +import hiwonder +import time + +""" +如果需要用角速度来控制舵机的转动我们需要自己计算舵机从当前位置转动到目标位置的时间 +""" + +def main(): + #让id为1的舵机用500毫秒时间从当前位置运动到200位置, 并记下当前位置 + #记下当前位置是为了通过目标角速度计算到达目标位置需要的时间 + #当前位置也能通过与舵机通信来读取,读取较慢且麻烦,可以用变量记下来 + hiwonder.serial_servo.set_position(1, 200, 500) + time.sleep(2) + + #假如现在要用每秒50度的速度转到800位置可以这么计算 + angle = 200 / 1000 * 240 # 将当前位置数值转换为角度数值 + t_angle = 800 / 1000 * 240 # 将目标位置数值转换为角度数值 + th = angle - t_angle #计算当前角度与目标角度的差 + t = abs(th / 50) #通过角速度50 计算转到目标位置需要的时间, 我们要计算时间, 时间不能为负值 + hiwonder.serial_servo.set_position(1, 800, int(t * 1000)) #因为角速度为度每秒, 这里将秒转换为毫秒 + time.sleep(t) + + +if __name__ == "__main__": + while True: + main() + + + + diff --git a/src/Sensor/scripts/sonar.py b/src/Sensor/scripts/sonar.py new file mode 100755 index 0000000..20c2878 --- /dev/null +++ b/src/Sensor/scripts/sonar.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 + +import hiwonder + +import time + +""" +超声波灯光控制及距离读取 + +超声波模块需要连接到jetmax的I2C接口 +任意时刻只能连接一个超声波模块 +""" + +def main(): + # 超声波的灯光有有两种模式, 模式0 用户直接控制灯光发出某种颜色, 模式1控制灯光周期变化 + hiwonder.sonar.set_rgb_mode(0) #设置为模式0 + # 超声波的两个"眼睛" 对应两个灯用0, 1 表示 + hiwonder.sonar.set_color(0, 0xFF0000) #0 号灯设为 红色 0xFF0000 是要发出的灯光的RGB值 + hiwonder.sonar.set_color(1, 0x00FF00) #1号灯设为 绿色 + time.sleep(2) + + + hiwonder.sonar.set_rgb_mode(1) #设置为 模式1 + hiwonder.sonar.set_breath_cycle(0, 0, 0) #将0号灯的红色设置的呼吸亮灭周期设为0, 就是完全熄灭 + hiwonder.sonar.set_breath_cycle(0, 1, 0) #将0号灯的绿色设置的呼吸亮灭周期设为0, 就是完全熄灭 + hiwonder.sonar.set_breath_cycle(0, 2, 1000) #将0号灯的色蓝色设置的呼吸亮灭周期设为1000毫秒 + #这时候可以看到0号灯回以蓝色1000毫秒周期呼吸亮灭 + time.sleep(2) + hiwonder.sonar.set_breath_cycle(1, 0, 500) #将1号灯的红色设置的呼吸亮灭周期设为500毫秒 + hiwonder.sonar.set_breath_cycle(1, 1, 0) #将1号灯的绿色设置的呼吸亮灭周期设为0, 就是完全熄灭 + hiwonder.sonar.set_breath_cycle(1, 2, 1000) #将1号灯的色蓝色设置的呼吸亮灭周期设为1000毫秒 + #这时候可以看到1号灯回以蓝色1000毫秒周期呼吸亮灭,红色以500毫秒亮灭 + time.sleep(2) + + + #此外可以使用start_symphony来让rgb灯自行幻彩变化 + hiwonder.sonar.start_symphony() + + + distance = None + last_print_time = time.time() + while True: + d = hiwonder.sonar.get_distance() #读取超声波的距离, 单位为毫秒 + + #我们可以做点简单的滤波应对可能出现的跳变和错误数据 + if distance is None: + distance = d + else: + distance = distance * 0.6 + d * 0.4 #这次测量的距离权重0.4, 之前数值权重0.6 + + #1秒打印一次数据 + if last_print_time < time.time(): + last_print_time = time.time() + 1 + print(distance) + + #0.1秒读取一次超声波数据 + time.sleep(0.1) + + +if __name__ == "__main__": + main() diff --git a/src/Sensor/scripts/sonar_color.py b/src/Sensor/scripts/sonar_color.py new file mode 100755 index 0000000..203853d --- /dev/null +++ b/src/Sensor/scripts/sonar_color.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import time +import numpy as np +from sensor_msgs.msg import Image +import hiwonder +import threading +import rospy + +""" +17 超声波+识别抓取 (测距识别) +""" + +ROS_NODE_NAME = "color_detect" + + +def moving(block): + global runner + (x, y), r, color_name = block + if color_name == 'red': + hiwonder.sonar.set_color(0, 0xFF0000) + hiwonder.sonar.set_color(1, 0xFF0000) + if color_name == 'green': + hiwonder.sonar.set_color(0, 0x00FF00) + hiwonder.sonar.set_color(1, 0x00FF00) + if color_name == 'blue': + hiwonder.sonar.set_color(0, 0x0000FF) + hiwonder.sonar.set_color(1, 0x0000FF) + hiwonder.buzzer.on() + rospy.sleep(0.1) + hiwonder.buzzer.off() + rospy.sleep(1) + hiwonder.pwm_servo1.set_position(100, 0.5) + rospy.sleep(2) + if color_name == 'red': + jetmax.set_position((238, 80, 130), 2) + rospy.sleep(2) + elif color_name == 'green': + jetmax.set_position((238, 30, 130), 1.8) + rospy.sleep(1.8) + elif color_name == 'blue': + jetmax.set_position((238, -20, 130), 1.6) + rospy.sleep(1.6) + else: + pass + cur = list(jetmax.position) + cur[2] = 85 + jetmax.set_position(cur, 1) + hiwonder.pwm_servo1.set_position(130, 0.5) + rospy.sleep(1) + cur[2] = 150 + jetmax.set_position(cur, 1.2) + rospy.sleep(2) + jetmax.go_home(2) + rospy.sleep(2) + hiwonder.sonar.set_color(0, 0) + hiwonder.sonar.set_color(1, 0) + runner = None + +def image_proc(img): + global runner + img_h, img_w = img.shape[:2] + frame_gb = cv2.GaussianBlur(np.copy(img), (5, 5), 5) + frame_lab = cv2.cvtColor(frame_gb, cv2.COLOR_RGB2LAB) # 转换rgb到lab + + blocks = [] + frame_roi = frame_lab[0:280, 140:500] + cv2.line(img, (140, 0), (140, 280), (255, 0, 0), 2) + cv2.line(img, (140, 280), (500, 280), (255, 0, 0), 2) + cv2.line(img, (500, 280), (500, 0), (255, 0, 0), 2) + cv2.line(img, (500, 0), (140, 0), (255, 0, 0), 2) + cv2.putText(img, "D:{:0.2f}mm".format(distance), (0, 440), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (255, 0, 0), 2) + if runner is not None: + return img + + if distance < 70: + for color_name, color in target_colors.items(): # 遍历所有颜色阈值 + frame_mask = cv2.inRange(frame_roi, tuple(color['min']), tuple(color['max'])) + eroded = cv2.erode(frame_mask, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) + dilated = cv2.dilate(eroded, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) + contours = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] + contour_area = map(lambda c: (c, math.fabs(cv2.contourArea(c))), contours) + contour_area = list(filter(lambda c: c[1] > 1200, contour_area)) # 去除过小的色块 + + if len(contour_area) > 0: + for contour, area in contour_area: # Loop through all the contours found + (center_x, center_y), r = cv2.minEnclosingCircle(contour) + cv2.circle(img, (int(center_x + 140), int(center_y)), 1, hiwonder.COLORS[color_name.upper()], 5) + cv2.circle(img, (int(center_x + 140), int(center_y)), int(r), hiwonder.COLORS[color_name.upper()], 2) + cv2.putText(img, color_name.upper(), (int(center_x + 140), int(center_y)), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (255, 255, 255), 2) + + blocks.append(((center_x, center_y), r, color_name)) + if len(blocks) > 0: + block = max(blocks, key=lambda x: x[1]) + runner = threading.Thread(target=moving, args=(block,), daemon=True) + runner.start() + + cv2.line(img, (int(img_w / 2 - 10), int(img_h / 2)), (int(img_w / 2 + 10), int(img_h / 2)), (0, 255, 255), 2) + cv2.line(img, (int(img_w / 2), int(img_h / 2 - 10)), (int(img_w / 2), int(img_h / 2 + 10)), (0, 255, 255), 2) + return img + + +def image_callback(ros_image): + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = np.copy(image) + frame_result = image_proc(frame_result) + image_bgr = cv2.cvtColor(frame_result, cv2.COLOR_RGB2BGR) + cv2.imshow("result", image_bgr) + cv2.waitKey(1) + +def distance_update(): + global distance + t = time.time() + while True: + d = hiwonder.sonar.get_distance() + distance = d if distance is None else d * 0.4 + distance * 0.6 + if t < time.time(): + print("Distance:{:0.2f}mm".format(distance)) + t = time.time() + 1 + rospy.sleep(0.05) + + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + jetmax = hiwonder.JetMax() + jetmax.go_home() + hiwonder.pwm_servo1.set_position(130, 0.5) + rospy.sleep(1) + distance = None + runner = None + colors = rospy.get_param('/lab_config_manager/color_range_list', {}) + target_colors = {} + target_colors['red'] = colors['red'] + target_colors['green'] = colors['green'] + target_colors['blue'] = colors['blue'] + image_sub = rospy.Subscriber("/usb_cam/image_rect_color", Image, image_callback, queue_size=1) + sonar_thread = threading.Thread(target=distance_update, daemon=True) + sonar_thread.start() + hiwonder.sonar.set_color(0, 0x0) + hiwonder.sonar.set_color(1, 0x0) + try: + rospy.spin() + except KeyboardInterrupt: + sys.exit(0) diff --git a/src/Sensor/scripts/sonar_radar.py b/src/Sensor/scripts/sonar_radar.py new file mode 100755 index 0000000..4c73d8f --- /dev/null +++ b/src/Sensor/scripts/sonar_radar.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python3 +# encoding:utf-8 +import sys +import time +import numpy as np +from math import * +import threading +import multiprocessing +import matplotlib.pyplot as plt +import hiwonder + +jetmax = hiwonder.JetMax() + +turning_radius = 25 + +ax = [] # 定义一个 x 轴的空列表用来接收动态的数据 +ay = [] # 定义一个 y 轴的空列表用来接收动态的数据 +#传感器最大接收数值,距离大于600mm时超声波传感器易被干扰 +maximum_range=50 +time.sleep(3) + +hiwonder.sonar.set_rgb_mode(0) +hiwonder.sonar.start_symphony() # 设置超声波RGB颜色渐变模式 + +#旋转半径R +# 计算出在旋转半径为R、角度a时机械臂逆运动学算法输入参数 +def angle(a,R=turning_radius): + x=0.0 + y=0.0 + if a>=0 and a <=180: + if a==0: + x=R + y=0.0 + return x,y + elif a == 90: + x=0 + y=R + return x,y + elif a==180: + x=-R + y=0.0 + return x,y + else: + y= sin(pi/180*a)*R + x= y/tan(pi/180*a) + return x,y + else: + pass + +plt.ion() # 开启一个画图的窗口 +plt.xlim(-maximum_range, maximum_range) +plt.ylim(0, maximum_range) +plt.grid(True) + +end = 0 +start = 0 +noise = 0 +count = 0 +error = 20 +distance = 0 + +def two_dimensional_scatter_diagram(): + z=[0,0] + flag =1 + # 扫描角度 + # 步长越大越块相应的数据也越少 + step=2# + #机械臂运动速度 由于实时画图需要一定时间导致此值过小也不会太快而且会有卡顿感 + speed=50 + sp=speed/1000 + + Detection_Angle=180 + data = np.zeros(Detection_Angle+1, dtype = np.int) + x_y_data=np.zeros((Detection_Angle+1,2), dtype = np.float) + + z[0],z[1]=angle(0) + time.sleep(2.2) + + begin_time=0 + end_time=0 + jetmax.go_home() + time.sleep(1) + cur = list(jetmax.position) + cur[1] += 120 + jetmax.set_position(cur, 1) + time.sleep(1) + jetmax.set_joint(1, 30, 1) + time.sleep(1) + while True: + if flag: #flag控制机械臂左转后右转 + for j in range(0,Detection_Angle+1,step): #Detection_Angle控制探测角度 + z[0], z[1] = angle(j) + end_time = time.time() + run_time = end_time-begin_time + if sp>run_time: + time.sleep(abs(sp-run_time)*0.9) + jetmax.set_joint(1, 30 + j, sp) + begin_time = time.time() + data[j]=hiwonder.sonar.get_distance() / 10 + if data[j] > maximum_range: #当 + data[j]=maximum_range + x=z[0]*data[j]/turning_radius + y=z[1]*data[j]/turning_radius + print(data[j]) + ax.append(x)# 添加 i 到 x 轴的数据中 + ay.append(y) # 添加 i 的平方到 y 轴的数据中 + plt.xlim(-maximum_range, maximum_range) + plt.ylim(0, maximum_range) + plt.grid(True) + plt.plot(ax[-2:], ay[-2:]) + plt.pause(0.0000001)# 暂停一下 + flag = 0 # 切换转动方向 + plt.clf() + ax.clear() + ay.clear() + else: + for j in range(Detection_Angle,-1,-step): + z[0], z[1] = angle(j) + end_time = time.time() + run_time = end_time-begin_time + if sp>run_time: + time.sleep(abs(sp-run_time)*0.9) + jetmax.set_joint(1, 30 + j, sp) + begin_time = time.time() + data[j]=hiwonder.sonar.get_distance() / 10 + if data[j] > maximum_range: + data[j]=maximum_range + x=z[0]*data[j]/turning_radius + y=z[1]*data[j]/turning_radius + ax.append(x) # 添加 i 到 x 轴的数据中 + ay.append(y) # 添加 i 的平方到 y 轴的数据中 + plt.xlim(-maximum_range, maximum_range) + plt.ylim(0, maximum_range) + plt.grid(True) + plt.plot(ax[-2:], ay[-2:]) + plt.pause(0.000001) # 暂停一下 + flag = 1 + plt.clf() + ax.clear() + ay.clear() + +if __name__ == "__main__": + two_dimensional_scatter_diagram() + + + diff --git a/src/Sensor/scripts/stacking_main.py b/src/Sensor/scripts/stacking_main.py new file mode 100755 index 0000000..aaeaad3 --- /dev/null +++ b/src/Sensor/scripts/stacking_main.py @@ -0,0 +1,43 @@ +import sys +import math +import hiwonder +import time + + +jetmax = hiwonder.JetMax() +sucker = hiwonder.Sucker() +target_positions = [(238, 20, 80),(238, 20, 123),(238, 20, 166)] +if __name__ == '__main__': + jetmax.go_home() + sucker.set_state(True) + time.sleep(0.5) + sucker.release(3) + time.sleep(2) + overlay = 0 + + while(overlay<3): # Pick up the block + hiwonder.pwm_servo1.set_position(90 , 0.1) + jetmax.set_position((0, 80, 120), 1) + time.sleep(1) + sucker.set_state(True) # Turn on the air pump + jetmax.set_position((0, 80, 85 - 5), 1) + time.sleep(1) + + jetmax.set_position((0, 80, 180), 1) + time.sleep(1) + hiwonder.pwm_servo1.set_position(90, 0.1) + + # Go to the target position + (x, y, z) = target_positions[overlay] + jetmax.set_position((x, y, 180), 1) + time.sleep(1) + jetmax.set_position((x, y, z), 1) + time.sleep(1) + + # Put down the block + sucker.release(3) # Turn off the air pump + jetmax.set_position((x, y, 180), 1) + time.sleep(1) + jetmax.go_home() + time.sleep(1) + overlay = overlay+1 diff --git a/src/Sensor/scripts/suck_place_main.py b/src/Sensor/scripts/suck_place_main.py new file mode 100755 index 0000000..6d6a356 --- /dev/null +++ b/src/Sensor/scripts/suck_place_main.py @@ -0,0 +1,42 @@ +import sys +import math +import hiwonder +import time + + +jetmax = hiwonder.JetMax() +sucker = hiwonder.Sucker() +target_positions = (238, 20, 80) +if __name__ == '__main__': + jetmax.go_home() + sucker.set_state(True) + time.sleep(0.5) + sucker.release(3) + time.sleep(2) + + # Pick up the block + hiwonder.pwm_servo1.set_position(90 , 0.1) + jetmax.set_position((0, 80, 120), 1) + time.sleep(1) + sucker.set_state(True) # Turn on the air pump + jetmax.set_position((0, 80, 85 - 5), 1) + time.sleep(1) + + jetmax.set_position((0, 80, 180), 1) + time.sleep(1) + hiwonder.pwm_servo1.set_position(90, 0.1) + + # Go to the target position + (x, y, z) = target_positions[overlay] + jetmax.set_position((x, y, 180), 1) + time.sleep(1) + jetmax.set_position((x, y, z), 1) + time.sleep(1) + + # Put down the block + sucker.release(3) # Turn off the air pump + jetmax.set_position((x, y, 180), 1) + time.sleep(1) + jetmax.go_home() + time.sleep(1) + diff --git a/src/Sensor/scripts/test.py b/src/Sensor/scripts/test.py new file mode 100755 index 0000000..1ece235 --- /dev/null +++ b/src/Sensor/scripts/test.py @@ -0,0 +1,50 @@ +import sys +import math +import hiwonder +import time + + +jetmax = hiwonder.JetMax() +sucker = hiwonder.Sucker() +target_positions = (238, 20, 80) +if __name__ == '__main__': + jetmax.go_home() + cur_x, cur_y, cur_z = jetmax.position + print(cur_x, cur_y, cur_z) + sucker.set_state(True) + time.sleep(0.5) + sucker.release(3) + time.sleep(2) + hiwonder.pwm_servo2.set_position(0, 0.1) + time.sleep(1) + jetmax.set_position((100, -230, 50), 1) + time.sleep(1) + cur_x, cur_y, cur_z = jetmax.position + print(cur_x, cur_y, cur_z) + # Pick up the block +''' + hiwonder.pwm_servo1.set_position(90 , 0.1) + jetmax.set_position((0, 80, 120), 1) + time.sleep(1) + sucker.set_state(True) # Turn on the air pump + jetmax.set_position((0, 80, 85 - 5), 1) + time.sleep(1) + + jetmax.set_position((0, 80, 180), 1) + time.sleep(1) + hiwonder.pwm_servo1.set_position(90, 0.1) + + # Go to the target position + (x, y, z) = target_positions[overlay] + jetmax.set_position((x, y, 180), 1) + time.sleep(1) + jetmax.set_position((x, y, z), 1) + time.sleep(1) + + # Put down the block + sucker.release(3) # Turn off the air pump + jetmax.set_position((x, y, 180), 1) + time.sleep(1) + jetmax.go_home() + time.sleep(1) +''' diff --git a/src/Sensor/scripts/tm1640_led_matrix.py b/src/Sensor/scripts/tm1640_led_matrix.py new file mode 100755 index 0000000..e9a3a5c --- /dev/null +++ b/src/Sensor/scripts/tm1640_led_matrix.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 + +import hiwonder +import time + +""" +将led点阵模块连接到jetmax 的GPIO2口 +""" + + +def main(): + mtx = hiwonder.TM1640(4, 9) #4, 9 对应 clk, dio 引脚号 + mtx.gram = [0xFF] * 16 #gram用作点阵的显存, 共16个字节, 一个字节对应一列led点, 这里就是将所有点都点亮 + print(mtx.gram) + mtx.refresh() #设置了显存之后调用 refresh 将显存内容显示出来 + time.sleep(2) + + #可以使用set_bit来设置显存内某个点的亮灭 + # set_bit(x, y, 新状态) 0代表灭, 1代表亮 + for y in range(8): + for x in range(0, 16, 4): + mtx.set_bit(x, y, 0) + mtx.set_bit(x+1, y, 0) + mtx.set_bit(x+2, y, 0) + mtx.set_bit(x+3, y, 0) + mtx.refresh() + + #可以用字符来组成图画然后画出来 + smile = """__XXXX____XXXX__ + _X____X__X____X_ + ________________ + ________________ + ________________ + __X__________X__ + ___X________X___ + ____XXXXXXXX____""".replace(' ', '').split('\n') + print(smile) + for y in range(8): + for x in range(16): + mtx.set_bit(x, y, 1 if smile[y][x] == 'X' else 0) + mtx.refresh() + time.sleep(3) + + #清空屏幕 + mtx.gram = [0] * 16 + mtx.refresh() + + + + + +if __name__ == '__main__': + main() diff --git a/src/Sensor/scripts/touch_control.py b/src/Sensor/scripts/touch_control.py new file mode 100755 index 0000000..bb59b40 --- /dev/null +++ b/src/Sensor/scripts/touch_control.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +import os +import sys +import cv2 +import rospy +import numpy as np +import threading +import hiwonder +import Jetson.GPIO as GPIO +import time + +""" +触摸传感器控制臂 +短按执行一个动作 +连续短按连次就是复位 +长按机械臂向下运动,需要一定值后自动复位 +""" + +ROS_NODE_NAME = "touch_control" + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + GPIO.setmode(GPIO.BCM) + GPIO.setup(9, GPIO.IN) + jetmax = hiwonder.JetMax() + jetmax.go_home(2) + rospy.sleep(2) + last_state = 1 + press_time = time.time() + longpress_time = time.time() + short_count = 0 + next_short_time = time.time() + + def x_short(n): + print('短按%d次' % n) + if n == 1: + jetmax.set_position((jetmax.ORIGIN[0], jetmax.ORIGIN[1], 70), 1) + rospy.sleep(1.1) + jetmax.set_servo(1, int(210 / 240 * 1000), 1) + rospy.sleep(1.1) + pos = list(jetmax.position) + pos[2] += 100 + jetmax.set_position(pos, 1) + rospy.sleep(1.1) + jetmax.go_home(1) + rospy.sleep(1.1) + elif n == 2: + jetmax.go_home() + rospy.sleep(1.1) + else: + pass + + while not rospy.is_shutdown(): + + if next_short_time < time.time() and short_count > 0: #如果距离上次短按超过设定时间就执行短按动作 + x_short(short_count) + short_count = 0 + + current_state = GPIO.input(9) #获取当前状态 + if current_state != last_state: #新旧状态不同, 就是触摸按钮被操作了 + if current_state == 0: #如果新状态为0, 就是被按下的 + print("按钮被按下") + pressed_time = time.time() #记下被按下时的时刻 + longpress_time = pressed_time + else: #如果新状态为1, 就是被松开 + print("按钮被松开", end='') + if pressed_time == longpress_time: + print(", 是短按") + short_count += 1 + next_short_time = time.time() + 0.5 #0.5秒内按下第二次就是连按 + else: + print(", 是长按") + + else: #如果新旧状态相同, 就是没有操作按钮, 或者一直按着按钮 + if current_state == 0: #如果按钮是被按着的 + dur = time.time() - pressed_time #计算一下被按了多久 + if dur > 2: + print("按钮被长按") + longpress_time = time.time() + pos = list(jetmax.position) + pos[2] -= 2 + if pos[2] <= 60: + jetmax.go_home() + rospy.sleep(1.1) + else: + jetmax.set_position(pos, 0.05) + last_state = current_state #将新状态存起来 + time.sleep(0.05) #50毫秒刷新一次按钮状态 + + + diff --git a/src/Sensor/scripts/touch_sensor.py b/src/Sensor/scripts/touch_sensor.py new file mode 100755 index 0000000..b6bb250 --- /dev/null +++ b/src/Sensor/scripts/touch_sensor.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 + +import Jetson.GPIO as GPIO +import time + +""" +触摸传感器读取实验 +触摸传感器是简单的数字io传感器, 只要读取对应IO口的电平变化即可 + +这里我们把传感器连接到jetmax的GPIO2接口上, 读取gpio9 引脚的电平即可获取到触摸传感器的状态 +根据状态可以判断长按断按等 + +需要注意当触摸传感器没被按下时输出高电平, 被按下输出低电平 +""" + + +def main(): + #初始化io口 + GPIO.setmode(GPIO.BCM) + GPIO.setup(9, GPIO.IN) + last_state = 1 + press_time = time.time() + longpress_time = time.time() + while True: + current_state = GPIO.input(9) #获取当前状态 + if current_state != last_state: #新旧状态不同, 就是触摸按钮被操作了 + if current_state == 0: #如果新状态为0, 就是被按下的 + print("按钮被按下") + pressed_time = time.time() #记下被按下时的时刻 + longpress_time = pressed_time + else: #如果新状态为1, 就是被松开 + print("按钮被松开", end='') + if pressed_time == longpress_time: + print(", 是短按") + else: + print(", 是长按") + + else: #如果新旧状态相同, 就是没有操作按钮, 或者一直按着按钮 + if current_state == 0: #如果按钮是被按着的 + dur = time.time() - pressed_time #计算一下被按了多久 + if dur > 2 and longpress_time < time.time(): #按住超过2秒就是长按, longpress_time 控制每秒打印一次长按时间 + print("按钮被长按, 按了%d秒" % dur ) + longpress_time = time.time() + 1 + last_state = current_state #将新状态存起来 + time.sleep(0.05) #50毫秒刷新一次按钮状态 + +if __name__ == '__main__': + main() diff --git a/src/Sensor/scripts/tts.py b/src/Sensor/scripts/tts.py new file mode 100755 index 0000000..1d588e3 --- /dev/null +++ b/src/Sensor/scripts/tts.py @@ -0,0 +1,35 @@ +import smbus2 #调用树莓派IIC库 +import time +import os + +class TTS: + + address = None + TTS_MODULE_I2C_ADDR = 0x40 #传感器的IIC地址 + + def __init__(self, bus=1): + self.address = self.TTS_MODULE_I2C_ADDR + self.bus = smbus2.SMBus(bus) + + def TTSModuleSpeak(self, sign, words): + head = [0xFD,0x00,0x00,0x01,0x00] #文本播放命令 + wordslist = words.encode("gb2312") #将文本编码格式设为GB2312 + signdata = sign.encode("gb2312") + length = len(signdata) + len(wordslist) + 2 + head[1] = length >> 8 + head[2] = length + head.extend(list(signdata)) + head.extend(list(wordslist)) + write = smbus2.i2c_msg.write(self.address, head) + self.bus.i2c_rdwr(write) + time.sleep(0.05) + +if __name__ == '__main__': + v = TTS() + #[h?]设置单词发音方式,0为自动判断单词发音方式,1为字母发音方式,2为单词发音方式 + #[v?]设置音量,音量范围为0-10,10为最大音量。 + v.TTSModuleSpeak("[h0][v10][m3]","你好,我是语音合成模块") + time.sleep(3) # 必要延时,等待播放完成 + v.TTSModuleSpeak("[v8][m3]", "你好,我是语音合成模块") + time.sleep(3) + v.TTSModuleSpeak("[v3][m3]", "你好,我是语音合成模块") diff --git a/src/chassis/CMakeLists.txt b/src/chassis/CMakeLists.txt new file mode 100644 index 0000000..d14abd2 --- /dev/null +++ b/src/chassis/CMakeLists.txt @@ -0,0 +1,206 @@ +cmake_minimum_required(VERSION 3.0.2) +project(chassis) + +## 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 + rospy + std_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 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 +# ) + +################################################ +## 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 chassis +# CATKIN_DEPENDS roscpp rospy std_msgs +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( +# include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/chassis.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/chassis_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_chassis.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/chassis/package.xml b/src/chassis/package.xml new file mode 100644 index 0000000..6dea8fe --- /dev/null +++ b/src/chassis/package.xml @@ -0,0 +1,68 @@ + + + chassis + 0.0.0 + The chassis package + + + + + hiwonder + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + roscpp + rospy + std_msgs + roscpp + rospy + std_msgs + roscpp + rospy + std_msgs + + + + + + + + diff --git a/src/chassis/scripts/.drawing_steer.py b/src/chassis/scripts/.drawing_steer.py new file mode 100755 index 0000000..600b95e --- /dev/null +++ b/src/chassis/scripts/.drawing_steer.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python3 +import sys +import time +import math +import signal +import hiwonder +import threading +from PyQt5.QtCore import Qt, QPoint, QRect +from PyQt5.QtWidgets import QApplication, QWidget +from PyQt5.QtGui import QPainter, QPixmap, QColor,QPen,QFont + +# 画线行驶 + +# 实例化底盘驱动库 +chassis = hiwonder.MecanumChassis() + +# 角度转换函数 +def azimuthAngle(p1, p2): + x1 = p1[0] + y1 = -p1[1] + x2 = p2[0] + y2 = -p2[1] + + angle = math.degrees(math.atan2(y2 - y1, x2 - x1)) + if angle < 0: + angle = 360 + angle + + return angle + +class Winform(QWidget): + def __init__(self, parent=None): + super(Winform, self).__init__(parent) + self.setWindowTitle("绘图画板") + self.pix = QPixmap() # 实例化一个 QPixmap 对象 + self.lastPoint = QPoint() # 起始点 + self.endPoint = QPoint() # 终点 + self.initUi() + self.pp = QPainter(self.pix) + self.runner = None + self.num = 1 + self.st = True + self.coords = [] + + def initUi(self): + # 窗口大小设置为600*500 + self.resize(800, 600) + # 画布大小为400*400,背景为白色 + self.pix = QPixmap(800, 600) + self.pix.fill(Qt.white) + + # 重绘的复写函数 主要在这里绘制 + def paintEvent(self, event): + # 根据鼠标指针前后两个位置绘制直线 + self.pp.setPen(QPen(QColor(0, 0, 0),3)) + self.pp.drawLine(self.lastPoint, self.endPoint) + # 让前一个坐标值等于后一个坐标值, + # 这样就能实现画出连续的线 + self.lastPoint = self.endPoint + painter = QPainter(self) + painter.drawPixmap(0, 0, self.pix) # 在画布上画出 + + # 鼠标按压事件 + def mousePressEvent(self, event): + # 鼠标左键按下 + if event.button() == Qt.LeftButton: + if self.st: + self.lastPoint = event.pos() + self.endPoint = self.lastPoint + self.st = False + else: + self.endPoint = event.pos() + # 进行重新绘制 + self.update() + x, y = (event.pos().x(), event.pos().y()) + self.coords.append((x,y)) + self.pp.setPen(QPen(QColor(255, 0, 0),3)) + self.pp.drawEllipse(x-7, y-7, 14, 14) + self.pp.drawText(x,y-12,str(self.num)) + self.num += 1 + self.update() + + # 鼠标右键按下 + elif event.button() == Qt.RightButton: + if self.runner is None: + if len(self.coords) > 0: + self.runner = threading.Thread(target=move, daemon=True) + self.runner.start() + +# 移动控制函数 +def move(): + #print(form.coords) + form.pp.setPen(QPen(QColor(0, 255, 0),3)) + form.pp.drawEllipse(form.coords[0][0]-7, form.coords[0][1]-7, 14, 14) + form.update() #更新显示 + for i in range(len(form.coords)-1): #逐一运行所有线段 + x1 = form.coords[i][0] + x2 = form.coords[i+1][0] + y1 = form.coords[i][1] + y2 = form.coords[i+1][1] + dx = x2 - x1 + dy = y2 - y1 + D = int(math.sqrt((dx**2)+(dy**2))) + angle = int(azimuthAngle(form.coords[i], form.coords[i+1])) #计算偏转角 + print('D:',D, 'angle:',angle) + + form.pp.setPen(QPen(QColor(0, 0, 255),3)) #设置正在运行的线段为蓝色 + form.pp.drawLine(x1,y1, x2,y2) + form.update() #更新显示 + chassis.set_velocity(100,angle,0) #驱动底盘电机 + t = D / 80 + time.sleep(t) + chassis.set_velocity(0,0,0) # 停止移动 + time.sleep(0.02) + + form.pp.setPen(QPen(QColor(0, 255, 0),3)) #设置运行过了的线段为绿色 + form.pp.drawLine(x1,y1, x2,y2) + form.pp.drawEllipse(x2-7, y2-7, 14, 14) + form.update() #更新显示 + + form.pp.setPen(QPen(QColor(0, 255, 0),3)) + form.pp.drawEllipse(form.coords[-1][0]-7, form.coords[-1][1]-7, 14, 14) + form.update() + print('Finish') + time.sleep(0.8) + form.runner = None + form.coords.clear() + QPainter.eraseRect(form.pp, QRect(0, 0, 800, 600)) #清除内容 + form.update() + form.num = 1 + form.st = True + + +# 停止运行函数 +def shutdown(signum, frame): + print('shutdown') + chassis.set_velocity(0,0,0) + sys.exit() + +signal.signal(signal.SIGINT, shutdown) + + +if __name__ == "__main__": + app = QApplication(sys.argv) + form = Winform() + form.show() + sys.exit(app.exec_()) + + diff --git a/src/chassis/scripts/fingertip_control.py b/src/chassis/scripts/fingertip_control.py new file mode 100755 index 0000000..9c4149f --- /dev/null +++ b/src/chassis/scripts/fingertip_control.py @@ -0,0 +1,326 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import rospy +import queue +import signal +import hiwonder +import threading +import numpy as np +import mediapipe as mp +import numpy.linalg as LA +from sensor_msgs.msg import Image +from PyQt5.QtCore import Qt, QPoint, QRect +from PyQt5.QtWidgets import QApplication, QWidget +from PyQt5.QtGui import QPainter, QPixmap, QColor,QPen,QFont +from matplotlib import pyplot as plt + +# 指尖控制 + +ROS_NODE_NAME = "fingertip_control" + +class HandGesture: + def __init__(self): + self.moving_color = None + self.target_colors = {} + self.lock = threading.RLock + self.position = 0, 0, 0 + self.runner = None + self.count = 0 + self.gesture_str = '' + self.servo_x = 500 + self.last_coord = (0,0) + self.locus_coord = [] + self.pid_x = hiwonder.PID(0.10, 0, 0.01) + self.pid_z = hiwonder.PID(0.13, 0, 0.015) + +# 求两个向量夹角 +def vector_2d_angle(v1, v2): + """ + Solve the angle between two vector + """ + v1_x = v1[0] + v1_y = v1[1] + v2_x = v2[0] + v2_y = v2[1] + try: + angle_ = math.degrees(math.acos( + (v1_x * v2_x + v1_y * v2_y) / (((v1_x ** 2 + v1_y ** 2) ** 0.5) * ((v2_x ** 2 + v2_y ** 2) ** 0.5)))) + except: + angle_ = 65535. + if angle_ > 180.: + angle_ = 65535. + return angle_ + + +def hand_angle(hand_): + """ + Obtain the angle of the corresponding hand-related vector, and determine the gesture according to the angle + """ + angle_list = [] + # ---------------------------- thumb + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[2][0])), (int(hand_[0][1]) - int(hand_[2][1]))), + ((int(hand_[3][0]) - int(hand_[4][0])), (int(hand_[3][1]) - int(hand_[4][1]))) + ) + angle_list.append(angle_) + # ---------------------------- index + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[6][0])), (int(hand_[0][1]) - int(hand_[6][1]))), + ((int(hand_[7][0]) - int(hand_[8][0])), (int(hand_[7][1]) - int(hand_[8][1]))) + ) + angle_list.append(angle_) + # ---------------------------- middle + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[10][0])), (int(hand_[0][1]) - int(hand_[10][1]))), + ((int(hand_[11][0]) - int(hand_[12][0])), (int(hand_[11][1]) - int(hand_[12][1]))) + ) + angle_list.append(angle_) + # ---------------------------- ring + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[14][0])), (int(hand_[0][1]) - int(hand_[14][1]))), + ((int(hand_[15][0]) - int(hand_[16][0])), (int(hand_[15][1]) - int(hand_[16][1]))) + ) + angle_list.append(angle_) + # ---------------------------- pink + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[18][0])), (int(hand_[0][1]) - int(hand_[18][1]))), + ((int(hand_[19][0]) - int(hand_[20][0])), (int(hand_[19][1]) - int(hand_[20][1]))) + ) + angle_list.append(angle_) + return angle_list + + +def h_gesture(angle_list): + """ + Use the angle of the corresponding hand-related to define the gesture + + """ + thr_angle = 65. + thr_angle_thumb = 53. + thr_angle_s = 49. + gesture_str = None + if 65535. not in angle_list: + if (angle_list[0] > thr_angle_thumb) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] > thr_angle): + gesture_str = "fist" + elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] > thr_angle): + gesture_str = "hand_heart" + elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] < thr_angle_s): + gesture_str = "nico-nico-ni" + elif (angle_list[0] < thr_angle_s) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] > thr_angle): + gesture_str = "hand_heart" + elif (angle_list[0] > 5) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] > thr_angle): + gesture_str = "one" + elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] > thr_angle) and (angle_list[4] > thr_angle): + gesture_str = "two" + elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] < thr_angle_s) and (angle_list[4] > thr_angle): + gesture_str = "three" + elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] > thr_angle) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s): + gesture_str = "OK" + elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s): + gesture_str = "four" + elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s): + gesture_str = "five" + elif (angle_list[0] < thr_angle_s) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] < thr_angle_s): + gesture_str = "six" + else: + "none" + + return gesture_str + +def curvature(x,y): + """ + input : the coordinate of the three point + output : the curvature and norm direction + """ + t_a = LA.norm([x[1]-x[0],y[1]-y[0]]) + t_b = LA.norm([x[2]-x[1],y[2]-y[1]]) + + M = np.array([ + [1, -t_a, t_a**2], + [1, 0, 0 ], + [1, t_b, t_b**2]]) + + a = np.matmul(LA.inv(M),x) + b = np.matmul(LA.inv(M),y) + kappa = 2*(a[2]*b[1]-b[2]*a[1])/(a[1]**2.+b[1]**2.)**(1.5) + + return kappa, [b[1],-a[1]]/np.sqrt(a[1]**2.+b[1]**2.) + +def move(*args): + x = [] + y = [] + l = len(args) + if l >= 5: + for i in range(0,l,int(l/2)-1): + x.append(args[i][0]) + y.append(args[i][1]) + + if len(x) >= 3: + try: + k,b = curvature(x,y) #计算指尖轨迹曲率 + except: + state.runner = None + return + + if abs(k) > 0.03 and abs(k) < 1: # 指尖轨迹为弧形 + hiwonder.buzzer.on() #打开蜂鸣器 + rospy.sleep(0.1) + hiwonder.buzzer.off() #关闭蜂鸣器 + if k > 0: # 逆时针转 + chassis.set_velocity(0,0,30) + rospy.sleep(5.8) + chassis.set_velocity(0,0,0) + else: # 顺时针转 + chassis.set_velocity(0,0,-30) + rospy.sleep(5.8) + chassis.set_velocity(0,0,0) + + elif abs(k) < 0.01: # 指尖轨迹为直线 + dx = x[0] - x[2] + dy = y[0] - y[2] + if abs(dx) > 50 > abs(dy): + hiwonder.buzzer.on() #打开蜂鸣器 + rospy.sleep(0.1) + hiwonder.buzzer.off() #关闭蜂鸣器 + if dx > 0: # 向左横移 + chassis.set_velocity(60,0,0) + rospy.sleep(2) + chassis.set_velocity(0,0,0) + else: # 向右横移 + chassis.set_velocity(60,180,0) + rospy.sleep(2) + chassis.set_velocity(0,0,0) + + elif abs(dy) > 50 > abs(dx): + hiwonder.buzzer.on() #打开蜂鸣器 + rospy.sleep(0.1) + hiwonder.buzzer.off() #关闭蜂鸣器 + if dy > 0: # 向前移动 + chassis.set_velocity(60,90,0) + rospy.sleep(2) + chassis.set_velocity(0,0,0) + else: # 向后移动 + chassis.set_velocity(60,270,0) + rospy.sleep(2) + chassis.set_velocity(0,0,0) + else: + for i in range(2): + hiwonder.buzzer.on() #打开蜂鸣器 + rospy.sleep(0.1) + hiwonder.buzzer.off() #关闭蜂鸣器 + rospy.sleep(0.1) + else: + for i in range(2): + hiwonder.buzzer.on() #打开蜂鸣器 + rospy.sleep(0.1) + hiwonder.buzzer.off() #关闭蜂鸣器 + rospy.sleep(0.1) + + state.runner = None + +# 图像处理函数 +def image_proc(img): + ret_img = np.copy(img) + if state.runner is not None: + return ret_img + + results = hands.process(img) + + if results.multi_hand_landmarks: + for hand_landmarks in results.multi_hand_landmarks: + mp_drawing.draw_landmarks(ret_img, hand_landmarks, mp_hands.HAND_CONNECTIONS) + hand_local = [(landmark.x * ret_img.shape[1], landmark.y * ret_img.shape[0]) for landmark in hand_landmarks.landmark] + if hand_local: + angle_list = hand_angle(hand_local) + gesture_str = h_gesture(angle_list) + cv2.putText(ret_img, gesture_str, (10, 50), 0, 1.5, (100, 200, 255), 3) + if gesture_str == 'one': + x, y = hand_local[8] + x1, y1 = state.last_coord + if abs(x-x1) >= 5 or abs(y-y1) >= 5: + if x1 == 0 and y1 == 0: + x1, y1 = x, y + state.last_coord = hand_local[8] + state.locus_coord.append((int(x),int(y))) + + elif gesture_str == 'five': + if state.locus_coord: + #print(state.locus_coord) + if state.runner is None: + state.runner = threading.Thread(target=move, args=state.locus_coord, daemon=True) + state.runner.start() + state.locus_coord.clear() + + if state.locus_coord is not None: + for i in range(1,len(state.locus_coord)): + cv2.line(ret_img, state.locus_coord[i-1], state.locus_coord[i], (255,0,100), 5) + + else: + state.count = 0 + + return ret_img + +# 图像转换和显示 +def image_proc_b(): + image = image_queue.get(block=True) + image = image_proc(image) + image = cv2.resize(image, (640, 480)) + image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) + cv2.imshow(ROS_NODE_NAME, image) + cv2.waitKey(1) + +# 图像回调函数 +def image_callback(ros_image): + try: + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + image = cv2.flip(image, 1) + image_queue.put_nowait(image) + except: + pass + +# 停止运行函数 +def shutdown(signum, frame): + print('shutdown') + sys.exit() + +signal.signal(signal.SIGINT, shutdown) + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + rospy.sleep(0.2) + state = HandGesture() + image_queue = queue.Queue(maxsize=1) + mp_drawing = mp.solutions.drawing_utils + mp_hands = mp.solutions.hands + hands = mp_hands.Hands( + static_image_mode=False, + max_num_hands=1, + min_detection_confidence=0.70, + min_tracking_confidence=0.1) + + chassis = hiwonder.MecanumChassis() + jetmax = hiwonder.JetMax() + jetmax.go_home() + rospy.sleep(1) + hiwonder.motor2.set_speed(0) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback, queue_size=1) + + while True: + try: + image_proc_b() + except Exception as e: + print(e) + sys.exit() diff --git a/src/chassis/scripts/object_tracking.py b/src/chassis/scripts/object_tracking.py new file mode 100755 index 0000000..eafa036 --- /dev/null +++ b/src/chassis/scripts/object_tracking.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python3 +import cv2 +import sys +import math +import time +import rospy +import queue +import signal +import hiwonder +import threading +import numpy as np +from sensor_msgs.msg import Image + +# 目标追踪 + +ROS_NODE_NAME = 'object_tracking' + +DEFAULT_X, DEFAULT_Y, DEFAULT_Z = 0, 100 + 8.14, 0 +ORG_PIXEL_X, ORG_PIXEL_Y = 320, 240 +# 实例化 +en_mot = hiwonder.motor.EncoderMotorController(1, 3) +hiwonder.pwm_servo1.set_position(50, 100) + + +class BallTracking: + # 初始化 + def __init__(self): + self.lock = threading.RLock() + self.servo_x = 500 + self.servo_y = 500 + + self.color_x_pid = hiwonder.PID(0.12, 0.001, 0.005) + self.color_y_pid = hiwonder.PID(0.15, 0.001, 0.0005) + + self.target_color_range = None + self.target_color_name = None + self.last_color_circle = None + self.lost_target_count = 0 + + self.is_running = False + + self.fps = 0.0 + self.tic = time.time() + +# 图像处理和追踪控制函数 +def ball_tracking(image): + org_image = np.copy(image) + image = cv2.resize(image, (320, 240)) + image = cv2.cvtColor(image, cv2.COLOR_RGB2LAB) # RGB转LAB空间 + image = cv2.GaussianBlur(image, (5, 5), 5) + + with state.lock: + target_color_range = state.target_color_range + target_color_name = state.target_color_name + + if target_color_range is not None: + mask = cv2.inRange(image, tuple(target_color_range['min']), tuple(target_color_range['max'])) # 二值化 + eroded = cv2.erode(mask, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) # 腐蚀 + dilated = cv2.dilate(eroded, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) # 膨胀 + contours = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] # 找出轮廓 + contour_area = map(lambda c: (c, math.fabs(cv2.contourArea(c))), contours) # 计算各个轮廓的面积 + contour_area = list(filter(lambda c: c[1] > 100, contour_area)) # 剔除>面积过小的轮廓 + circle = None + if len(contour_area) > 0: + if state.last_color_circle is None: + contour, area = max(contour_area, key=lambda c_a: c_a[1]) + circle = cv2.minEnclosingCircle(contour) + else: + (last_x, last_y), last_r = state.last_color_circle + circles = map(lambda c: cv2.minEnclosingCircle(c[0]), contour_area) + circle_dist = list(map(lambda c: (c, math.sqrt(((c[0][0] - last_x) ** 2) + ((c[0][1] - last_y) ** 2))), + circles)) + circle, dist = min(circle_dist, key=lambda c: c[1]) + if dist < 100: + circle = circle + + if circle is not None: + state.lost_target_count = 0 + (x, y), r = circle + x = x / 320 * 640 + y = y / 240 * 480 + r = r / 320 * 640 + org_image = cv2.circle(org_image, (int(x), int(y)), int(r), (255, 0, 0), 2) + vx = 0 + vy = 0 + vw = 0 + if abs(x - ORG_PIXEL_X) > 30: # 左右方向上的PID处理 + state.color_x_pid.update(x - ORG_PIXEL_X) + vx = state.color_x_pid.output # PID输出 + #print(circle) + if abs(r - 50) > 10: # 前后方向上的PID处理 + if r - 50 < 0: + state.color_y_pid.setKp(1.2) + else: + state.color_y_pid.setKp(0.8) + state.color_y_pid.update(r - 50) + vy = -state.color_y_pid.output # PID输出 + # 计算合速度 + vw1 = vy - vx + vw * (1 + 2) + vw2 = vy + vx - vw * (1 + 2) + vw3 = vy - vx - vw * (1 + 2) + vw4 = vy + vx + vw * (1 + 2) + + vw1 = 100 if vw1 > 100 else vw1 #限制速度最大最小值 + vw2 = 100 if vw1 > 100 else vw2 + vw3 = 100 if vw1 > 100 else vw3 + vw4 = 100 if vw1 > 100 else vw4 + vw1 = -100 if vw1 < -100 else vw1 + vw2 = -100 if vw1 < -100 else vw2 + vw3 = -100 if vw1 < -100 else vw3 + vw4 = -100 if vw1 < -100 else vw4 + + en_mot.set_speed(int(vw1), 1) #驱动底盘电机 + en_mot.set_speed(int(-vw4), 2) + en_mot.set_speed(int(-vw2), 3) + en_mot.set_speed(int(vw3), 4) + + else: + state.lost_target_count += 1 + if state.lost_target_count > 2: + state.color_x_pid.update(0) + state.color_y_pid.update(0) + en_mot.set_speed(int(0), 1) + en_mot.set_speed(int(0), 2) + en_mot.set_speed(int(0), 3) + en_mot.set_speed(int(0), 4) + state.lost_target_count = 0 + state.last_color_circle = None + return org_image + +# 图像回调函数 +def image_callback(ros_image): + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = ball_tracking(image) + toc = time.time() + curr_fps = 1.0 / (state.tic - toc) + state.fps = curr_fps if state.fps == 0.0 else (state.fps * 0.95 + curr_fps * 0.05) + state.tic = toc + frame_result = cv2.cvtColor(frame_result, cv2.COLOR_RGB2BGR) + cv2.imshow(ROS_NODE_NAME, frame_result) + cv2.waitKey(1) + +# 设置追踪目标颜色函数 +def set_target(color_name): + color_ranges = rospy.get_param('/lab_config_manager/color_range_list', {}) + rospy.logdebug(color_ranges) + with state.lock: + if color_name in color_ranges: + state.target_color_name = color_name + state.target_color_range = color_ranges[color_name] + else: + state.target_color_name = None + state.target_color_range = None + +# 关闭函数 +def shutdown(signum, frame): + print('shutdown') + motor.set_speed(0, 1) + motor.set_speed(0, 2) + motor.set_speed(0, 3) + motor.set_speed(0, 4) + sys.exit() + +signal.signal(signal.SIGINT, shutdown) + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + state = BallTracking() + jetmax = hiwonder.JetMax() + jetmax.set_position((0, -130, 0), 1.5) + rospy.sleep(1.5) + image_queue = queue.Queue(maxsize=3) + set_target('ball') + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) # 订阅摄像头画面 + try: + rospy.spin() + except: + sys.exit(0) diff --git a/src/chassis/scripts/patrol_sorting.py b/src/chassis/scripts/patrol_sorting.py new file mode 100755 index 0000000..9874584 --- /dev/null +++ b/src/chassis/scripts/patrol_sorting.py @@ -0,0 +1,443 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import time +import math +import rospy +import queue +import signal +import hiwonder +import apriltag +import threading +import numpy as np +import mediapipe as mp +from sensor_msgs.msg import Image +from PyQt5.QtCore import Qt, QPoint, QRect +from PyQt5.QtWidgets import QApplication, QWidget +from PyQt5.QtGui import QPainter, QPixmap, QColor,QPen,QFont + +# 巡线分拣 + +ROS_NODE_NAME = "patrol_sorting" + +TAG_SIZE = 33.30 +# 实例化 +Misc = hiwonder.misc +chassis = hiwonder.MecanumChassis() +motor = hiwonder.motor.EncoderMotorController(1, 3) +at_detector = apriltag.Detector(apriltag.DetectorOptions(families='tag36h11')) + +# 放置坐标 +TARGET_POSITIONS = { + 1: (-100, -180, 0), + 2: ( 0, -180, 0), + 3: ( 100, -180, 0)} + +TRACKING_POSITION = (0, -120, 120) + + +class TrackingSorting: + # 初始化 + def __init__(self): + self.speed = 30 + self.count = 0 + self.skip = 'line' + self.tag_id = None + self.centerX = 320 + self.st = False + self.line_state = True + self.sorting_state = False + self.moving_block = None + self.line_centerx = -1 + self.line_centery = -1 + self.line_breadth = 0 + self.camera_params = None + self.pid_x = hiwonder.PID(0.18, 0.001, 0.02) + + # 加载相机内参 + def load_camera_params(self): + self.camera_params = rospy.get_param('/camera_cal/block_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + + +#机器人跟踪线程 +def move(): + rospy.sleep(8) + while True: + if state.line_centerx != -1 and state.line_state: #巡线 + dx = state.line_centerx - state.centerX # 目标线条横坐标与画面中心横坐标比较,相差比较大说明机器人偏离了 + if abs(dx) > 10: + state.pid_x.SetPoint = 0 + else: + state.pid_x.SetPoint = dx + # 通过PID算法进行纠正 + state.pid_x.update(dx) + deflection = int(state.pid_x.output) + # 把基础速度和纠正速度进行合成,最终输出到四个电机上 + motor.set_speed(-state.speed + deflection, 1) + motor.set_speed( state.speed - deflection, 2) + motor.set_speed( state.speed + deflection, 3) + motor.set_speed(-state.speed - deflection, 4) + rospy.sleep(0.01) + + if state.line_breadth > 120: # 通过判断线条宽度来检测到横线 + + if state.line_centery >= 380: + motor.set_speed(5, 1) + motor.set_speed(-5, 2) + motor.set_speed(-5, 3) + motor.set_speed(5, 4) + elif state.line_centery <= 370: + motor.set_speed(-5, 1) + motor.set_speed(5, 2) + motor.set_speed(5, 3) + motor.set_speed(-5, 4) + else: + state.line_breadth = 0 + state.skip = 'apriltag' # 切换到apriltag处理阶段 + state.line_state = False + motor.set_speed(0, 1) # 停止电机运行 + motor.set_speed(0, 2) + motor.set_speed(0, 3) + motor.set_speed(0, 4) + rospy.sleep(0.01) + + + elif state.skip == 'apriltag': + jetmax.go_home(2,3) + rospy.sleep(2) + if state.sorting_state: #放置标签木块阶段 + x, y, z = TARGET_POSITIONS[state.tag_id] #读取放置坐标 + dx, dy, _ = camera_to_world(state.K, state.R, state.T, p)[0][0] + new_x, new_y = x + dx, y + dy + arm_angle = math.atan(new_y / new_x) * 180 / math.pi + if arm_angle > 0: + arm_angle = (90 - arm_angle) + elif arm_angle < 0: + arm_angle = (-90 - arm_angle) + else: + pass + + if state.tag_id != 2: + hiwonder.pwm_servo1.set_position(90 - arm_angle, 0.1) #设置角度补偿 + jetmax.set_position((x, y, z), 1.5) #放置标签木块 + rospy.sleep(1.5) + sucker.release(3) + jetmax.set_position(TRACKING_POSITION, 1) #机械臂回到巡线位置 + hiwonder.pwm_servo1.set_position(90, 0.5) + rospy.sleep(1) + motor.set_speed( 20, 1) #后退一段距离 + motor.set_speed(-20, 2) + motor.set_speed(-20, 3) + motor.set_speed( 20, 4) + rospy.sleep(1) + motor.set_speed(-30, 1) #原地左转掉头 + motor.set_speed( 30, 2) + motor.set_speed(-30, 3) + motor.set_speed( 30, 4) + rospy.sleep(2.6) + motor.set_speed(0, 1) + motor.set_speed(0, 2) + motor.set_speed(0, 3) + motor.set_speed(0, 4) + + state.line_breadth = 0 + state.skip = 'line' + state.line_state = True + state.sorting_state = False + rospy.sleep(0.6) + + elif not state.sorting_state and state.st: #识别并抓取标签木块阶段 + jetmax.go_home(2,3) #机械臂回到检测位置 + rospy.sleep(2) + tag = state.moving_block + params = np.array([state.K[0][0], state.K[1][1], state.K[0][2], state.K[1][2]]) + pose_mtx, a, b = at_detector.detection_pose(tag, camera_params=params, tag_size=TAG_SIZE) + angle = rotation_mtx_to_euler(pose_mtx)[2] * (180 / math.pi) + cur_x, cur_y, cur_z = jetmax.position + rect_x, rect_y = state.moving_block.center + p = np.asarray([rect_x, rect_y]).reshape((1, 1, 2)) + x, y, _ = camera_to_world(state.K, state.R, state.T, p)[0][0] + if angle < -45: # ccw -45 ~ -90 + angle = -(-90 - angle) + if angle > 45: + angle = -(90 - angle) + + new_x, new_y = cur_x + x, cur_y + y + arm_angle = math.atan(new_y / new_x) * 180 / math.pi + if arm_angle > 0: + arm_angle = (90 - arm_angle) + elif arm_angle < 0: + arm_angle = (-90 - arm_angle) + else: + pass + angle = angle + -arm_angle + dist = math.sqrt(x * x + y * y + 120 * 120) + t = dist / 140 + hiwonder.pwm_servo1.set_position(90 + angle, 0.1) #设置角度补偿,使木块放正 + jetmax.set_position((new_x, new_y, 50), t) #移动到木块上方 + rospy.sleep(t + 0.1) + sucker.set_state(True) #打开气泵 + jetmax.set_position((new_x, new_y, -15), 1) #吸取木块 + rospy.sleep(1) + jetmax.set_position(TRACKING_POSITION, 1) #机械臂回到巡线位置 + rospy.sleep(1) + hiwonder.pwm_servo1.set_position(90, 0.5) + motor.set_speed( 20, 1) #后退一段距离 + motor.set_speed(-20, 2) + motor.set_speed(-20, 3) + motor.set_speed( 20, 4) + rospy.sleep(1) + motor.set_speed(-30, 1) #原地左转掉头 + motor.set_speed( 30, 2) + motor.set_speed(-30, 3) + motor.set_speed( 30, 4) + rospy.sleep(2.6) + motor.set_speed(0, 1) + motor.set_speed(0, 2) + motor.set_speed(0, 3) + motor.set_speed(0, 4) + + state.line_breadth = 0 + state.st = False + state.skip = 'line' + state.line_state = True + state.sorting_state = True + rospy.sleep(0.6) + + else: + motor.set_speed(0, 1) + motor.set_speed(0, 2) + motor.set_speed(0, 3) + motor.set_speed(0, 4) + rospy.sleep(0.01) + +#作为子线程开启 +th = threading.Thread(target=move) +th.setDaemon(True) +th.start() + +# 画面像素坐标转换现实坐标函数 +def camera_to_world(cam_mtx, r, t, img_points): + inv_k = np.asmatrix(cam_mtx).I + r_mat = np.zeros((3, 3), dtype=np.float64) + cv2.Rodrigues(r, r_mat) + # invR * T + inv_r = np.asmatrix(r_mat).I # 3*3 + transPlaneToCam = np.dot(inv_r, np.asmatrix(t)) # 3*3 dot 3*1 = 3*1 + world_pt = [] + coords = np.zeros((3, 1), dtype=np.float64) + for img_pt in img_points: + coords[0][0] = img_pt[0][0] + coords[1][0] = img_pt[0][1] + coords[2][0] = 1.0 + worldPtCam = np.dot(inv_k, coords) # 3*3 dot 3*1 = 3*1 + # [x,y,1] * invR + worldPtPlane = np.dot(inv_r, worldPtCam) # 3*3 dot 3*1 = 3*1 + # zc + scale = transPlaneToCam[2][0] / worldPtPlane[2][0] + # zc * [x,y,1] * invR + scale_worldPtPlane = np.multiply(scale, worldPtPlane) + # [X,Y,Z]=zc*[x,y,1]*invR - invR*T + worldPtPlaneReproject = np.asmatrix(scale_worldPtPlane) - np.asmatrix(transPlaneToCam) # 3*1 dot 1*3 = 3*3 + pt = np.zeros((3, 1), dtype=np.float64) + pt[0][0] = worldPtPlaneReproject[0][0] + pt[1][0] = worldPtPlaneReproject[1][0] + pt[2][0] = 0 + world_pt.append(pt.T.tolist()) + return world_pt + +def rotation_mtx_to_euler(R): + sy = math.sqrt(R[0, 0] * R[0, 0] + R[1, 0] * R[1, 0]) + singular = sy < 1e-6 + if not singular: + x = math.atan2(R[2, 1], R[2, 2]) + y = math.atan2(-R[2, 0], sy) + z = math.atan2(R[1, 0], R[0, 0]) + else: + x = math.atan2(-R[1, 2], R[1, 1]) + y = math.atan2(-R[2, 0], sy) + z = 0 + return np.array([x, y, z]) + + +# apriltag检测函数 +def Apriltag(img): + + frame_gray = cv2.cvtColor(np.copy(img), cv2.COLOR_RGB2GRAY) + tags = at_detector.detect(frame_gray) + for tag in tags: + corners = tag.corners.reshape(1, -1, 2).astype(int) + center = tag.center.astype(int) + cv2.drawContours(img, corners, -1, (255, 0, 0), 3) + cv2.circle(img, tuple(center), 5, (255, 255, 0), 10) + cv2.putText(img, "id:%d" % tag.tag_id,(center[0], center[1] - 5), + cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2) + + if len(tags) > 0: + if state.moving_block is None: + state.moving_block = tags[0] + else: + new_tag = tags[0] + if new_tag.tag_id != state.moving_block.tag_id: + state.count = 0 + state.st = False + else: + state.count += 1 + if state.count > 20: + state.count = 0 + if not state.sorting_state and not state.st: + state.st = True + state.tag_id = new_tag.tag_id + + state.moving_block = tags[0] + else: + state.count = 0 + state.st = False + if state.moving_block is not None: + state.moving_block = None + img_h, img_w = img.shape[:2] + cv2.line(img, (int(img_w / 2 - 10), int(img_h / 2)), (int(img_w / 2 + 10), int(img_h / 2)), (0, 255, 255), 2) + cv2.line(img, (int(img_w / 2), int(img_h / 2 - 10)), (int(img_w / 2), int(img_h / 2 + 10)), (0, 255, 255), 2) + return img + +# 找出面积最大的轮廓 +# 参数为要比较的轮廓的列表 +def getAreaMaxContour(contours, area_min=10): + contour_area_temp = 0 + contour_area_max = 0 + area_max_contour = None + for c in contours: # 历遍所有轮廓 + contour_area_temp = math.fabs(cv2.contourArea(c)) # 计算轮廓面积 + if contour_area_temp > contour_area_max: + contour_area_max = contour_area_temp + if contour_area_temp >= area_min: # 只有在面积大于设定值时,最大面积的轮廓才是有效的,以过滤干扰 + area_max_contour = c + return area_max_contour, contour_area_max # 返回最大的轮廓 + +size = (640, 480) +roi = [ (220, 260, 0, 640, 0.1), + (280, 320, 0, 640, 0.4), + (340, 420, 0, 640, 0.5)] +roi_h1 = roi[0][0] +roi_h2 = roi[1][0] - roi[0][0] +roi_h3 = roi[2][0] - roi[1][0] +roi_h_list = [roi_h1, roi_h2, roi_h3] + +#巡线视觉处理函数 +def line_patrol(img_draw, color = 'red'): + + n = 0 + center_ = [] + weight_sum = 0 + centroid_x_sum = 0 + img_h, img_w = img_draw.shape[:2] + frame_resize = cv2.resize(img_draw, size, interpolation=cv2.INTER_NEAREST) + frame_gb = cv2.GaussianBlur(frame_resize, (3, 3), 3) + + #将图像分割成上中下三个部分,这样处理速度会更快,更精确 + for r in roi: + area_max = 0 + areaMaxContour = 0 + roi_h = roi_h_list[n] + n += 1 + blobs = frame_gb[r[0]:r[1], r[2]:r[3]] + frame_lab = cv2.cvtColor(blobs, cv2.COLOR_RGB2LAB) # 将图像转换到LAB空间 + frame_mask = cv2.inRange(frame_lab, tuple(target_colors[color]['min']), tuple(target_colors[color]['max'])) #对原图像和掩模进行位运算 + opened = cv2.morphologyEx(frame_mask, cv2.MORPH_OPEN, np.ones((6, 6), np.uint8)) # 开运算 + closed = cv2.morphologyEx(opened, cv2.MORPH_CLOSE, np.ones((6, 6), np.uint8)) # 闭运算 + cnts = cv2.findContours(closed , cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_L1)[-2]#找出所有轮廓 + cnt_large, area = getAreaMaxContour(cnts)#找到最大面积的轮廓 + if cnt_large is not None:#如果轮廓不为空 + rect = cv2.minAreaRect(cnt_large)#最小外接矩形 + box = np.int0(cv2.boxPoints(rect))#最小外接矩形的四个顶点 + for i in range(4): + box[i, 1] = box[i, 1] + (n - 1)*roi_h + roi[0][0] + box[i, 1] = int(Misc.val_map(box[i, 1], 0, size[1], 0, img_h)) + for i in range(4): + box[i, 0] = int(Misc.val_map(box[i, 0], 0, size[0], 0, img_w)) + + cv2.drawContours(img_draw, [box], -1, (0,0,255,255), 2)#画出四个点组成的矩形 + #获取矩形的对角点 + pt1_x, pt1_y = box[0, 0], box[0, 1] + pt3_x, pt3_y = box[2, 0], box[2, 1] + state.line_breadth = abs(pt3_x-pt1_x) + center_x, center_y = (pt1_x + pt3_x) / 2, (pt1_y + pt3_y) / 2 #中心点 + cv2.circle(img_draw, (int(center_x), int(center_y)), 5, (0,0,255), -1) #画出中心点 + center_.append([center_x, center_y]) + #按权重不同对上中下三个中心点进行求和 + centroid_x_sum += center_x * r[4] + weight_sum += r[4] + + if weight_sum is not 0: + state.line_centery = int(center_y) + state.line_centerx = int(centroid_x_sum / weight_sum) #求最终得到的中心点 + cv2.circle(img_draw, (state.line_centerx, int(center_y)), 10, (0,255,255), -1) #画出中心 + + else: + state.line_centerx = -1 + state.line_centery = -1 + + return img_draw + + +def image_proc(): + image = image_queue.get(block=True) + image = np.copy(image) + if state.skip == 'line': + image = line_patrol(image) #巡线检测 + elif state.skip == 'apriltag': + image = Apriltag(image) #标签检测 + image = cv2.resize(image, size) + image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) + cv2.imshow(ROS_NODE_NAME, image) #显示画面 + cv2.waitKey(1) + + +def image_callback(ros_image): + try: + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + if state.skip == 'line': + image = cv2.flip(image, 1) + image_queue.put_nowait(image) + + except: + pass + + +def shutdown(signum, frame): + print('shutdown') + rospy.sleep(0.5) + motor.set_speed(0, 1) + motor.set_speed(0, 2) + motor.set_speed(0, 3) + motor.set_speed(0, 4) + sys.exit() + +signal.signal(signal.SIGINT, shutdown) + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + rospy.sleep(0.2) + state = TrackingSorting() + state.load_camera_params() + image_queue = queue.Queue(maxsize=1) + + jetmax = hiwonder.JetMax() + sucker = hiwonder.Sucker() + jetmax.go_home(2,3) + rospy.sleep(2) + jetmax.set_position(TRACKING_POSITION, 1) + target_colors = rospy.get_param('/lab_config_manager/color_range_list', {}) + del[target_colors['white']] + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback, queue_size=1) + + while True: + try: + image_proc() + except Exception as e: + print(e) + sys.exit() diff --git a/src/jetmax_buildin_funcs/.gitignore b/src/jetmax_buildin_funcs/.gitignore new file mode 100644 index 0000000..1cd53e9 --- /dev/null +++ b/src/jetmax_buildin_funcs/.gitignore @@ -0,0 +1,132 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + + +*.trt diff --git a/src/jetmax_buildin_funcs/README.md b/src/jetmax_buildin_funcs/README.md new file mode 100644 index 0000000..0cea7ef --- /dev/null +++ b/src/jetmax_buildin_funcs/README.md @@ -0,0 +1 @@ +# jetmax_buildin_funcs \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/alphabetically/CMakeLists.txt b/src/jetmax_buildin_funcs/alphabetically/CMakeLists.txt new file mode 100644 index 0000000..116fdef --- /dev/null +++ b/src/jetmax_buildin_funcs/alphabetically/CMakeLists.txt @@ -0,0 +1,207 @@ +cmake_minimum_required(VERSION 3.0.2) +project(alphabetically) + +## 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 + message_generation + rospy + std_msgs + std_srvs +) + +## 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 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 +# ) + +################################################ +## 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 alphabetically +# CATKIN_DEPENDS message_generation rospy std_msgs std_srvs +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( +# include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/alphabetically.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/alphabetically_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_alphabetically.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/jetmax_buildin_funcs/alphabetically/install_pycuda.sh b/src/jetmax_buildin_funcs/alphabetically/install_pycuda.sh new file mode 100644 index 0000000..578ad60 --- /dev/null +++ b/src/jetmax_buildin_funcs/alphabetically/install_pycuda.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# +# Reference for installing 'pycuda': https://wiki.tiker.net/PyCuda/Installation/Linux/Ubuntu + +set -e + +if ! which nvcc > /dev/null; then + echo "ERROR: nvcc not found" + exit +fi + +arch=$(uname -m) +folder=${HOME}/src +mkdir -p $folder + +echo "** Install requirements" +sudo apt-get install -y build-essential python3-dev +sudo apt-get install -y libboost-python-dev libboost-thread-dev +sudo pip3 install setuptools + +boost_pylib=$(basename /usr/lib/${arch}-linux-gnu/libboost_python*-py3?.so) +boost_pylibname=${boost_pylib%.so} +boost_pyname=${boost_pylibname/lib/} + +echo "** Download pycuda-2019.1.2 sources" +pushd $folder +if [ ! -f pycuda-2019.1.2.tar.gz ]; then + wget https://files.pythonhosted.org/packages/5e/3f/5658c38579b41866ba21ee1b5020b8225cec86fe717e4b1c5c972de0a33c/pycuda-2019.1.2.tar.gz +fi + +echo "** Build and install pycuda-2019.1.2" +CPU_CORES=$(nproc) +echo "** cpu cores available: " $CPU_CORES +tar xzvf pycuda-2019.1.2.tar.gz +cd pycuda-2019.1.2 +python3 ./configure.py --python-exe=/usr/bin/python3 --cuda-root=/usr/local/cuda --cudadrv-lib-dir=/usr/lib/${arch}-linux-gnu --boost-inc-dir=/usr/include --boost-lib-dir=/usr/lib/${arch}-linux-gnu --boost-python-libname=${boost_pyname} --boost-thread-libname=boost_thread --no-use-shipped-boost +make -j$CPU_CORES +python3 setup.py build +sudo python3 setup.py install + +popd + +python3 -c "import pycuda; print('pycuda version:', pycuda.VERSION)" diff --git a/src/jetmax_buildin_funcs/alphabetically/package.xml b/src/jetmax_buildin_funcs/alphabetically/package.xml new file mode 100644 index 0000000..6b512fe --- /dev/null +++ b/src/jetmax_buildin_funcs/alphabetically/package.xml @@ -0,0 +1,69 @@ + + + alphabetically + 0.0.0 + The alphabetically package + + + + + hiwonder + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + message_generation + rospy + std_msgs + std_srvs + rospy + std_msgs + std_srvs + rospy + std_msgs + std_srvs + + + + + + + + diff --git a/src/jetmax_buildin_funcs/alphabetically/scripts/alphabetically_main.py b/src/jetmax_buildin_funcs/alphabetically/scripts/alphabetically_main.py new file mode 100755 index 0000000..8584134 --- /dev/null +++ b/src/jetmax_buildin_funcs/alphabetically/scripts/alphabetically_main.py @@ -0,0 +1,497 @@ +#!/usr/bin/env python3 +import os +import sys +import cv2 +import math +import time +import queue +import random +import threading +import numpy as np +import rospy +import hiwonder +from sensor_msgs.msg import Image +from std_msgs.msg import Bool +from std_srvs.srv import Empty +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse +from jetmax_control.msg import SetServo +from yolov5_tensorrt import Yolov5TensorRT + +ROS_NODE_NAME = "alphabetically" +IMAGE_SIZE = 640, 480 # 输入图片尺寸 + +CHARACTERS_ENGINE_PATH = os.path.join(sys.path[0], 'characters_v5_160.trt') # 字母模型路径 +CHARACTER_LABELS = tuple([i for i in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ']) # 字母分类名称 +CHARACTER_NUM = 26 + +NUMBERS_ENGINE_PATH = os.path.join(sys.path[0], 'numbers_v5_160.trt') # 数字模型路径 +NUMBERS_LABELS = tuple([i for i in '0123456789+-*/=']) # 数字分类数值的名称 +NUMBERS_NUM = 15 # 分类总个数 + +TRT_INPUT_SIZE = 160 # trt输入尺寸 +# 随机颜色, 用于结果框出 +COLORS = tuple([tuple([random.randint(10, 255) for j in range(3)]) for i in range(CHARACTER_NUM + NUMBERS_NUM)]) + +GOAL_POSITIONS = ( + (-230, -85, 55, 17), (-230, -40, 55, 7), (-230, 5, 55, -3), (-230, 50, 55, -13), + (-185, -85, 55, 20), (-185, -40, 55, 10), (-185, 5, 55, -3), (-185, 50, 55, -13), + (-140, -85, 55, 30), (-140, -40, 55, 15), (-140, 5, 55, -5), (-140, 50, 55, -18), +) + + +def camera_to_world(cam_mtx, r, t, img_points): + inv_k = np.asmatrix(cam_mtx).I + r_mat = np.zeros((3, 3), dtype=np.float64) + cv2.Rodrigues(r, r_mat) + # invR * T + inv_r = np.asmatrix(r_mat).I # 3*3 + transPlaneToCam = np.dot(inv_r, np.asmatrix(t)) # 3*3 dot 3*1 = 3*1 + world_pt = [] + coords = np.zeros((3, 1), dtype=np.float64) + for img_pt in img_points: + coords[0][0] = img_pt[0][0] + coords[1][0] = img_pt[0][1] + coords[2][0] = 1.0 + worldPtCam = np.dot(inv_k, coords) # 3*3 dot 3*1 = 3*1 + # [x,y,1] * invR + worldPtPlane = np.dot(inv_r, worldPtCam) # 3*3 dot 3*1 = 3*1 + # zc + scale = transPlaneToCam[2][0] / worldPtPlane[2][0] + # zc * [x,y,1] * invR + scale_worldPtPlane = np.multiply(scale, worldPtPlane) + # [X,Y,Z]=zc*[x,y,1]*invR - invR*T + worldPtPlaneReproject = np.asmatrix(scale_worldPtPlane) - np.asmatrix(transPlaneToCam) # 3*1 dot 1*3 = 3*3 + pt = np.zeros((3, 1), dtype=np.float64) + pt[0][0] = worldPtPlaneReproject[0][0] + pt[1][0] = worldPtPlaneReproject[1][0] + pt[2][0] = 0 + world_pt.append(pt.T.tolist()) + return world_pt + + +class Alphabetically: + def __init__(self): + self.running_mode = 0 + self.moving_box = None + self.image_sub = None + self.heartbeat_timer = None + self.runner = None + self.moving_count = 0 + self.count = 0 + self.lock = threading.RLock() + self.fps_t0 = time.time() + self.fps = 0 + self.camera_params = None + self.enable_moving = False + self.K = None + self.R = None + self.T = None + + """ + 重置需要的变量 + """ + def reset(self): + self.running_mode = 0 + self.enable_moving = False + self.moving_box = None + self.moving_count = 0 + self.image_sub = None + self.heartbeat_timer = None + self.runner = None + self.count = 0 + self.fps_t0 = time.time() + self.fps = 0 + + """ + 读取相机内参 + """ + def load_camera_params(self): + self.camera_params = rospy.get_param('/camera_cal/card_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + + +""" +移动卡片 +""" +def moving(): + try: + c_x, c_y, cls_id, cls_conf = state.moving_box # 获取要移动的卡片在图上的位置 + cur_x, cur_y, cur_z = jetmax.position # 吸嘴的当前坐标 + + # 计算卡片在现实世界的中吸嘴中心(外参标定的时候用吸嘴标定的)的坐标 + x, y, _ = camera_to_world(state.K, state.R, state.T, np.array([c_x, c_y]).reshape((1, 1, 2)))[0][0] + + t = math.sqrt(x * x + y * y + 120 * 120) / 120 # 计算卡片位置的距离, 通过距离/速度=时间, 计算用多少时间到达卡片位置 + new_x, new_y = cur_x + x, cur_y + y # 计算卡片位置相对于机械臂基座的坐标 + nn_new_x = new_x + 15 + arm_angle = math.atan(new_y / new_x) * 180 / math.pi # 计算机械臂到达新位置后相对与中轴的偏转角度, 后边我们放置卡片的时候给小舵机旋转给偏回来 + if arm_angle > 0: + arm_angle = (90 - arm_angle) + elif arm_angle < 0: + arm_angle = (-90 - arm_angle) + else: + pass + # 机械臂分步运行到卡片位置 + jetmax.set_position((nn_new_x, new_y, 70), t) + rospy.sleep(t) + jetmax.set_position((new_x, new_y, 70), 0.3) + rospy.sleep(t + 0.6) + + # 下降,吸取 + sucker.set_state(True) + jetmax.set_position((new_x, new_y, 50), 0.8) + rospy.sleep(0.85) + + # 根据顺序查表获取要放到哪里, 并抬起机械臂 + x, y, z, angle = GOAL_POSITIONS[state.moving_count] + cur_x, cur_y, cur_z = jetmax.position + jetmax.set_position((cur_x, cur_y, 100), 0.8) + rospy.sleep(0.8) + + # 控制小舵机旋转卡片,使卡片角度能够跟吸取之前的放置角度一样 + hiwonder.pwm_servo1.set_position(90 + angle + arm_angle, 0.1) + cur_x, cur_y, cur_z = jetmax.position + # 计算当前位置到目标位置的距离以控制速度 + t = math.sqrt((cur_x - x) ** 2 + (cur_y - y) ** 2) / 150 + # 控制机械臂到达目标上方 + jetmax.set_position((x, y, z + 30), t) + rospy.sleep(t) + + # 控制机械臂到达目标位置 + jetmax.set_position((x, y, z), 0.8) + rospy.sleep(0.8) + + #释放 + sucker.release(3) + #抬起 + jetmax.set_position((x, y, z + 30), 0.8) + rospy.sleep(0.1) + #小舵机恢复 + hiwonder.pwm_servo1.set_position(90, 0.4) + rospy.sleep(0.8) + + finally: + sucker.release(3) + cur_x, cur_y, cur_z = jetmax.position + # 计算当期位置和默认位置的距离以控制速度 + t = math.sqrt((cur_x - jetmax.ORIGIN[0]) ** 2 + (cur_y - jetmax.ORIGIN[1]) ** 2) / 120 + # 回到默认位置 + jetmax.go_home(t) + # 小舵机恢复, 多次恢复是因为,上面的恢复可能因为异常而未被执行 + hiwonder.pwm_servo1.set_position(90, 0.2) + rospy.sleep(t + 0.2) + with state.lock: # 清理运行标识,让程序继续下次操作 + state.moving_box = None + state.moving_count += 1 # 累计摆放的个数,以记录放到哪里去 + if state.moving_count >= len(GOAL_POSITIONS): + state.moving_count = 0 + state.runner = None + print("FINISHED") + + +""" +字母图像处理 +""" +def image_proc_chars(img_in): + if state.runner is not None: # 如果有搬运动作在执行就不进行识别 + return img_in + result_image = img_in + outputs = yolov5_chars.detect(np.copy(img_in)) # 调用yolov5 进行识别 + boxes, confs, classes = yolov5_chars.post_process(img_in, outputs, 0.65) # 对 yolov5 的网络输出进行后处理, 获取最终结果 + cards = [] + width, height = IMAGE_SIZE + # 遍历识别出的结果 + for box, cls_id, cls_conf in zip(boxes, classes, confs): + x1 = box[0] / TRT_INPUT_SIZE * width + y1 = box[1] / TRT_INPUT_SIZE * height + x2 = box[2] / TRT_INPUT_SIZE * width + y2 = box[3] / TRT_INPUT_SIZE * height + cards.append((x1, y1, x2, y2, cls_id, cls_conf)) + # 画面中框出识别的的卡片并加上显示 + cv2.putText(img_in, CHARACTER_LABELS[cls_id] + " " + str(float(cls_conf))[:4], + (int(x1), int(y1) - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, COLORS[cls_id], 2) + cv2.rectangle(result_image, (int(x1), int(y1)), (int(x2), int(y2)), COLORS[cls_id], 3) + + if len(cards) == 0: # 没有识别到 + state.count = 0 + state.moving_box = None + else: # 识别到 + if state.moving_box is None: # 上一帧没有识别到, 要进行多次识别以防误触发 + moving_box = min(cards, key=lambda x: x[4]) # 所有识别到的卡片中 id 最小的 + x1, y1, x2, y2, cls_id, cls_conf = moving_box + c_x, c_y = (x1 + x2) / 2, (y1 + y2) / 2 # 框的中心 + state.moving_box = c_x, c_y, cls_id, cls_conf # 记录这个卡片的位置等参数 + cv2.circle(result_image, (int(c_x), int(c_y)), 1, (255, 0, 0), 30) # 画出中心 + state.count = 0 + else: # 上一帧有识别到 + l_c_x, l_c_y, l_cls_id, _ = state.moving_box + # 遍历所有新识别到的卡片 + cards = [((x1 + x2) / 2, + (y1 + y2) / 2, + cls_id, cls_conf) for x1, y1, x2, y2, cls_id, cls_conf in cards] + # 找出与上一帧记录的目标卡片距离最近的卡片 + distances = [math.sqrt((l_c_x - c_x) ** 2 + (l_c_y - c_y) ** 2) for c_x, c_y, _, _ in cards] + new_moving_box = min(zip(distances, cards), key=lambda x: x[0]) + _, (c_x, c_y, cls_id, cls_conf) = new_moving_box + # 画出两次的中心 + cv2.circle(result_image, (int(l_c_x), int(l_c_y)), 1, (0, 255, 0), 30) + cv2.circle(result_image, (int(c_x), int(c_y)), 1, (255, 0, 0), 30) + if cls_id == l_cls_id and state.enable_moving: # 如果两次id相同就是正确识别 + state.moving_box = c_x, c_y, cls_id, cls_conf + state.count += 1 + if state.count > 20: # 连续20帧识别到就开始搬运卡片 + state.runner = threading.Thread(target=moving, daemon=True) + state.runner.start() + else: + state.moving_box = None + return result_image + +""" +数字卡片识别 +整体过程跟字母卡片相同, 只是用的模型不同 +""" +def image_proc_nums(img_in): + if state.runner is not None: + return img_in + result_image = img_in + outputs = yolov5_nums.detect(np.copy(img_in)) + boxes, confs, classes = yolov5_nums.post_process(img_in, outputs, 0.65) + cards = [] + width, height = IMAGE_SIZE + + for box, cls_id, cls_conf in zip(boxes, classes, confs): + x1 = box[0] / TRT_INPUT_SIZE * width + y1 = box[1] / TRT_INPUT_SIZE * height + x2 = box[2] / TRT_INPUT_SIZE * width + y2 = box[3] / TRT_INPUT_SIZE * height + cards.append((x1, y1, x2, y2, cls_id, cls_conf)) + result_image = cv2.putText(img_in, NUMBERS_LABELS[cls_id] + " " + str(float(cls_conf))[:4], + (int(x1), int(y1) - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, + COLORS[CHARACTER_NUM + cls_id], 2) + result_image = cv2.rectangle(result_image, (int(x1), int(y1)), (int(x2), int(y2)), + COLORS[CHARACTER_NUM + cls_id], 3) + + if len(cards) == 0: + state.count = 0 + state.moving_box = None + else: + if state.moving_box is None: + moving_box = min(cards, key=lambda x: x[4]) + x1, y1, x2, y2, cls_id, cls_conf = moving_box + c_x, c_y = (x1 + x2) / 2, (y1 + y2) / 2 + state.moving_box = c_x, c_y, cls_id, cls_conf + result_image = cv2.circle(result_image, (int(c_x), int(c_y)), 1, (255, 0, 0), 30) + state.count = 0 + else: + l_c_x, l_c_y, l_cls_id, _ = state.moving_box + cards = [((x1 + x2) / 2, + (y1 + y2) / 2, + cls_id, cls_conf) for x1, y1, x2, y2, cls_id, cls_conf in cards] + distances = [math.sqrt((l_c_x - c_x) ** 2 + (l_c_y - c_y) ** 2) for c_x, c_y, _, _ in cards] + new_moving_box = min(zip(distances, cards), key=lambda x: x[0]) + _, (c_x, c_y, cls_id, cls_conf) = new_moving_box + result_image = cv2.circle(result_image, (int(l_c_x), int(l_c_y)), 1, (0, 255, 0), 30) + result_image = cv2.circle(result_image, (int(c_x), int(c_y)), 1, (255, 0, 0), 30) + if cls_id == l_cls_id and state.enable_moving: + state.moving_box = c_x, c_y, cls_id, cls_conf + state.count += 1 + if state.count > 20: + state.runner = threading.Thread(target=moving, daemon=True) + state.runner.start() + else: + state.moving_box = None + return result_image + + +def show_fps(img, fps): + """显示fps""" + font = cv2.FONT_HERSHEY_PLAIN + line = cv2.LINE_AA + fps_text = 'FPS: {:.2f}'.format(fps) + cv2.putText(img, fps_text, (11, 20), font, 1.0, (32, 32, 32), 4, line) + cv2.putText(img, fps_text, (10, 20), font, 1.0, (240, 240, 240), 1, line) + return img + + +""" +总的图像处理函数 +会根据设置状态决定调用数字卡片识别还是字母卡片识别或是不识别 +这个函数会在while循环中调用, 而不是直接被ros topic 的回调触发是因为 pycuda 要求相关调用必须在同一个线程中 +所以 ros topic 回调只会将接收到的图片放入一个队列而不会直接处理图片。 image_proc 会循环处理该队列 +""" +def image_proc(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + with state.lock: + if state.running_mode == 1: + result_img = image_proc_chars(image) + elif state.running_mode == 2: + result_img = image_proc_nums(image) + else: + result_img = image + # fps cal + fps_t1 = time.time() + fps_cur = (1.0 / (fps_t1 - state.fps_t0)) + state.fps = fps_cur if state.fps == 0.0 else (state.fps * 0.8 + fps_cur * 0.2) + state.fps_t0 = fps_t1 + # show_fps(result_img, state.fps) + # + rgb_image = result_img.tostring() + ros_image.data = rgb_image + image_pub.publish(ros_image) + + +""" +相机画面topic的回调 +只会将接收到的画面推入队列 +""" +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +""" +启动服务 +程序进入就绪状态,准备运行,但不做识别 +""" +def enter_func(msg): + rospy.loginfo("enter") + exit_func(msg) + jetmax.go_home() + state.reset() + state.load_camera_params() + state.image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) + return TriggerResponse(success=True) + + +""" +退出服务 +程序取消对相机topic的订阅 +""" +def exit_func(msg): + rospy.loginfo("exit") + try: + state.heartbeat_timer.cancel() + except: + pass + with state.lock: + state.running_mode = 0 + # 取消订阅 + if isinstance(state.image_sub, rospy.Subscriber): + rospy.loginfo('unregister image') + state.image_sub.unregister() + state.image_sub = None + # 等待正在运行的搬运动作完成 + if isinstance(state.runner, threading.Thread): + state.runner.join() + # 调用服务让机械臂回到初始位置 + rospy.ServiceProxy('/jetmax/go_home', Empty)() + rospy.Publisher('/jetmax/end_effector/sucker/command', Bool, queue_size=1).publish(data=False) + rospy.Publisher('/jetmax/end_effector/servo1/command', SetServo, queue_size=1).publish(data=90, duration=0.5) + return TriggerResponse(success=True) + + +def heartbeat_timeout_cb(): + rospy.loginfo("heartbeat timeout. exiting...") + rospy.ServiceProxy('/%s/exit' % ROS_NODE_NAME, Trigger) + + +def heartbeat_srv_cb(msg: SetBoolRequest): + try: + state.heartbeat_timer.cancel() + except: + pass + rospy.logdebug("Heartbeat") + if msg.data: + state.heartbeat_timer = threading.Timer(5, heartbeat_timeout_cb) + state.heartbeat_timer.start() + return SetBoolResponse(success=msg.data) + + +""" +开始字母卡片识别 +""" +def set_char_running_cb(msg): + with state.lock: + if msg.data: + # 如果当前模式不是字母识别模式(1), 就设为字母识别模式 + if state.running_mode != 1: + state.running_mode = 1 + state.moving_count = 0 + state.enable_moving = False + # 如果已经是字母识别模式就切换识别开关 + else: + if state.enable_moving: + state.enable_moving = False + else: + state.enable_moving = True + else: + if state.running_mode == 1: + state.running_mode = 0 + state.enable_moving = False + return [True, ''] + + +""" +开始识别数字卡片 +""" +def set_num_running_cb(msg): + with state.lock: + if msg.data: + # 如果 当前运行模式不是识别数字就改为识别数字 + if state.running_mode != 2: + state.running_mode = 2 + state.moving_count = 0 + state.enable_moving = False + # 如果是识别数字, 就控制开关识别 + else: + if state.enable_moving: + state.enable_moving = False + else: + state.enable_moving = True + else: + if state.running_mode == 2: + state.running_mode = 0 + state.enable_moving = False + return [True, ''] + + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) # 初始化节点 + state = Alphabetically() # 初始化相关参数 + state.load_camera_params() # 读取相机内参 + if state.camera_params is None: + rospy.logerr("Can not load camera parameters") + sys.exit(-1) + # 建立字母、数字识别器 + yolov5_chars = Yolov5TensorRT(CHARACTERS_ENGINE_PATH, TRT_INPUT_SIZE, CHARACTER_NUM) + yolov5_nums = Yolov5TensorRT(NUMBERS_ENGINE_PATH, TRT_INPUT_SIZE, NUMBERS_NUM) + # 图像队列 + image_queue = queue.Queue(maxsize=1) + # 机器人的控制接口 + jetmax = hiwonder.JetMax() + sucker = hiwonder.Sucker() + + # 相关topic的订阅和发布注册 + image_pub = rospy.Publisher('/%s/image_result' % ROS_NODE_NAME, Image, queue_size=1) # register result image pub + enter_srv = rospy.Service('/%s/enter' % ROS_NODE_NAME, Trigger, enter_func) + exit_srv = rospy.Service('/%s/exit' % ROS_NODE_NAME, Trigger, exit_func) + char_running_srv = rospy.Service('/%s/set_running_char' % ROS_NODE_NAME, SetBool, set_char_running_cb) + num_running_srv = rospy.Service('/%s/set_running_num' % ROS_NODE_NAME, SetBool, set_num_running_cb) + heartbeat_srv = rospy.Service('/%s/heartbeat' % ROS_NODE_NAME, SetBool, heartbeat_srv_cb) + + while True: + try: + image_proc() # 循环处理图片 + if rospy.is_shutdown(): + break + except KeyboardInterrupt: + rospy.signal_shutdown("custom shutdown") + break diff --git a/src/jetmax_buildin_funcs/alphabetically/scripts/yolov5_tensorrt.py b/src/jetmax_buildin_funcs/alphabetically/scripts/yolov5_tensorrt.py new file mode 100644 index 0000000..e60e029 --- /dev/null +++ b/src/jetmax_buildin_funcs/alphabetically/scripts/yolov5_tensorrt.py @@ -0,0 +1,207 @@ +import cv2 +import sys +import os +import tensorrt as trt +import pycuda.autoinit +import pycuda.driver as cuda +import numpy as np +import math + + +# Simple helper data class that's a little nicer to use than a 2-tuple. +class HostDeviceMem: + def __init__(self, host_mem, device_mem): + self.host = host_mem + self.device = device_mem + + def __str__(self): + return "Host:\n" + str(self.host) + "\nDevice:\n" + str(self.device) + + def __repr__(self): + return self.__str__() + + +def sigmoid_v(array): + return np.reciprocal(np.exp(-array) + 1.0) + + +def sigmoid(x): + return 1 / (1 + math.exp(-x)) + + +def non_max_suppression(boxes, confs, classes, iou_thres=0.6): + x1 = boxes[:, 0] + y1 = boxes[:, 1] + x2 = boxes[:, 2] + y2 = boxes[:, 3] + areas = (x2 - x1 + 1) * (y2 - y1 + 1) + order = confs.flatten().argsort()[::-1] + keep = [] + while order.size > 0: + i = order[0] + keep.append(i) + xx1 = np.maximum(x1[i], x1[order[1:]]) + yy1 = np.maximum(y1[i], y1[order[1:]]) + xx2 = np.minimum(x2[i], x2[order[1:]]) + yy2 = np.minimum(y2[i], y2[order[1:]]) + w = np.maximum(0.0, xx2 - xx1 + 1) + h = np.maximum(0.0, yy2 - yy1 + 1) + inter = w * h + ovr = inter / (areas[i] + areas[order[1:]] - inter) + inds = np.where(ovr <= iou_thres)[0] + order = order[inds + 1] + boxes = boxes[keep] + confs = confs[keep] + classes = classes[keep] + return boxes, confs, classes + + +def xywh2xyxy(x): + # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right + y = np.zeros_like(x) + y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x + y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y + y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x + y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y + return y + + +def nms(pred, iou_thres=0.6): + boxes = xywh2xyxy(pred[..., 0:4]) + # best class only + confs = np.amax(pred[:, 5:], 1, keepdims=True) + classes = np.argmax(pred[:, 5:], axis=-1) + return non_max_suppression(boxes, confs, classes) + + +def make_grid(nx, ny): + """ + Create scaling tensor based on box location + Source: https://github.com/ultralytics/yolov5/blob/master/models/yolo.py + Arguments + nx: x-axis num boxes + ny: y-axis num boxes + Returns + grid: tensor of shape (1, 1, nx, ny, 80) + """ + nx_vec = np.arange(nx) + ny_vec = np.arange(ny) + yv, xv = np.meshgrid(ny_vec, nx_vec) + grid = np.stack((yv, xv), axis=2) + grid = grid.reshape(1, 1, ny, nx, 2) + return grid + + +def pre_process(img_in, w, h): + img_in = cv2.resize(img_in, (w, h), interpolation=cv2.INTER_LINEAR) + # img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + # img = img.transpose((2, 0, 1)).astype(np.float16) + img_in = np.transpose(img_in, (2, 0, 1)).astype(np.float32) + img_in = np.expand_dims(img_in, axis=0) + img_in /= 255.0 + img_in = np.ascontiguousarray(img_in) + return img_in + + +class Yolov5TensorRT: + def __init__(self, model, input_size, classes_num): + # load tensorrt engine + self.input_size = input_size + TRT_LOGGER = trt.Logger(trt.Logger.INFO) + with open(model, 'rb') as f, trt.Runtime(TRT_LOGGER) as runtime: + engine = runtime.deserialize_cuda_engine(f.read()) + self.context = engine.create_execution_context() + # allocate memory + inputs, outputs, bindings = [], [], [] + stream = cuda.Stream() + for binding in engine: + size = trt.volume(engine.get_binding_shape(binding)) + dtype = trt.nptype(engine.get_binding_dtype(binding)) + host_mem = cuda.pagelocked_empty(size, dtype) + device_mem = cuda.mem_alloc(host_mem.nbytes) + bindings.append(int(device_mem)) + if engine.binding_is_input(binding): + inputs.append(HostDeviceMem(host_mem, device_mem)) + else: + outputs.append(HostDeviceMem(host_mem, device_mem)) + # save to class + self.inputs = inputs + self.outputs = outputs + self.bindings = bindings + self.stream = stream + # post processing config + self.strides = np.array([8., 16., 32.]) + anchors = np.array([ + [[10, 13], [16, 30], [33, 23]], + [[30, 61], [62, 45], [59, 119]], + [[116, 90], [156, 198], [373, 326]], + ]) + self.nl = len(anchors) + self.nc = classes_num # classes + self.no = self.nc + 5 # outputs per anchor + self.na = len(anchors[0]) + a = anchors.copy().astype(np.float32) + a = a.reshape(self.nl, -1, 2) + self.anchors = a.copy() + self.anchor_grid = a.copy().reshape(self.nl, 1, -1, 1, 1, 2) + self.output_shapes = [ + (1, 3, int(input_size / 8), int(input_size / 8), self.nc + 5), + (1, 3, int(input_size / 16), int(input_size / 16), self.nc + 5), + (1, 3, int(input_size / 32), int(input_size / 32), self.nc + 5) + ] + + def detect(self, img): + shape_orig_WH = (img.shape[1], img.shape[0]) + resized = pre_process(img, self.input_size, self.input_size) + outputs = self.inference(resized) + # reshape from flat to (1, 3, x, y, 85) + reshaped = [] + for output, shape in zip(outputs, self.output_shapes): + reshaped.append(output.reshape(shape)) + return reshaped + + def inference(self, img): + # copy img to input memory + # self.inputs[0]['host'] = np.ascontiguousarray(img) + self.inputs[0].host = np.ravel(img) + # transfer data to the gpu + [cuda.memcpy_htod_async(inp.device, inp.host, self.stream) for inp in self.inputs] + # run inference + self.context.execute_async_v2(bindings=self.bindings, stream_handle=self.stream.handle) + # fetch outputs from gpu + [cuda.memcpy_dtoh_async(out.host, out.device, self.stream) for out in self.outputs] + # synchronize stream + self.stream.synchronize() + return [out.host for out in self.outputs] + + def post_process(self, image, outputs, conf_thres=0.2): + """ + Transforms raw output into boxes, confs, classes + Applies NMS thresholding on bounding boxes and confs + Parameters: + output: raw output tensor + Returns: + boxes: x1,y1,x2,y2 tensor (dets, 4) + confs: class * obj prob tensor (dets, 1) + classes: class type tensor (dets, 1) + """ + scaled = [] + grids = [] + for out in outputs: + out = sigmoid_v(out) + _, _, width, height, _ = out.shape + grid = make_grid(width, height) + grids.append(grid) + scaled.append(out) + z = [] + for out, grid, stride, anchor in zip(scaled, grids, self.strides, self.anchor_grid): + _, _, width, height, _ = out.shape + out[..., 0:2] = (out[..., 0:2] * 2. - 0.5 + grid) * stride + out[..., 2:4] = (out[..., 2:4] * 2) ** 2 * anchor + + out = out.reshape((1, 3 * width * height, self.no)) + z.append(out) + pred = np.concatenate(z, 1) + xc = pred[..., 4] > conf_thres + pred = pred[xc] + return nms(pred) diff --git a/src/jetmax_buildin_funcs/camera_cal/CMakeLists.txt b/src/jetmax_buildin_funcs/camera_cal/CMakeLists.txt new file mode 100644 index 0000000..a120c32 --- /dev/null +++ b/src/jetmax_buildin_funcs/camera_cal/CMakeLists.txt @@ -0,0 +1,207 @@ +cmake_minimum_required(VERSION 3.0.2) +project(camera_cal) + +## 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 + rospy + std_msgs + std_srvs + message_generation + ) + +## 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 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 camera_cal + # CATKIN_DEPENDS rospy std_msg std_srv + # DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( + # include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/camera_cal.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/camera_cal_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_camera_cal.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/jetmax_buildin_funcs/camera_cal/config/camera_cal.yaml b/src/jetmax_buildin_funcs/camera_cal/config/camera_cal.yaml new file mode 100644 index 0000000..88c5670 --- /dev/null +++ b/src/jetmax_buildin_funcs/camera_cal/config/camera_cal.yaml @@ -0,0 +1,6 @@ +{block_params: {K: [[426.06805419921875, 0.0, 358.14440625582574], [0.0, 476.2198791503906, + 261.69051045566994], [0.0, 0.0, 1.0]], R: [[0.014497004068009021], [3.1197489580999527], + [0.15923718839096457]], T: [[-1.5661642742070736], [26.222952395045404], [152.85165237730655]]}, + card_params: {K: [[426.06805419921875, 0.0, 358.14440625582574], [0.0, 476.2198791503906, + 261.69051045566994], [0.0, 0.0, 1.0]], R: [[0.014497003492974753], [3.1197489541728882], + [0.1592372216838362]], T: [[-2.293080108280113], [22.153922262973335], [192.63749559392045]]}} diff --git a/src/jetmax_buildin_funcs/camera_cal/launch/camera_cal.launch b/src/jetmax_buildin_funcs/camera_cal/launch/camera_cal.launch new file mode 100644 index 0000000..d9ea8a6 --- /dev/null +++ b/src/jetmax_buildin_funcs/camera_cal/launch/camera_cal.launch @@ -0,0 +1,10 @@ + + + + + + config_file_path: "/home/hiwonder/ros/src/camera_cal/config/camera_cal.yaml" + + + + diff --git a/src/jetmax_buildin_funcs/camera_cal/package.xml b/src/jetmax_buildin_funcs/camera_cal/package.xml new file mode 100644 index 0000000..d8d154d --- /dev/null +++ b/src/jetmax_buildin_funcs/camera_cal/package.xml @@ -0,0 +1,68 @@ + + + camera_cal + 0.0.0 + The camera_cal package + + + + + hiwonder + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + rospy + std_msg + std_srv + rospy + std_msg + std_srv + rospy + std_msg + std_srv + + + + + + + + diff --git a/src/jetmax_buildin_funcs/camera_cal/scripts/camera_cal_main.py b/src/jetmax_buildin_funcs/camera_cal/scripts/camera_cal_main.py new file mode 100755 index 0000000..21a3c4e --- /dev/null +++ b/src/jetmax_buildin_funcs/camera_cal/scripts/camera_cal_main.py @@ -0,0 +1,335 @@ +#!/usr/bin/env python3 +import os +import sys +import cv2 +import threading +import rospy +import numpy as np +import yaml +import hiwonder +import apriltag +from sensor_msgs.msg import Image +from jetmax_control.msg import SetJetMax +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from std_srvs.srv import Empty +from sensor_msgs.msg import CameraInfo + +ROS_NODE_NAME = "camera_cal" +at_detector = apriltag.Detector(apriltag.DetectorOptions(families='tag36h11')) # apriltag检测器 + +# apriltag 中心在原点的情况下, 中心及四个角的坐标 +marker_corners = np.asarray([[0, 0, 40], # 40为木块高度 + [16.65, -16.65, 40], # TAG_SIZE = 33.30mm + [-16.65, -16.65, 40], + [-16.65, 16.65, 40], + [16.65, 16.65, 40]], + dtype=np.float64) + +# 对不同高度的物体(卡片和木块)我们直接用不同高度算出不同的的参数 +marker_corners_block = np.copy(marker_corners) +marker_corners_block[:, 2] = marker_corners_block[:, 2] - 40 +jetmax = hiwonder.JetMax() + +class State: + def __init__(self): + self.lock = threading.RLock() + # 读取摄像头内参 + with open('/home/hiwonder/.ros/camera_info/head_camera.yaml') as f: + camera_params = yaml.load(f.read()) + K_ = np.asarray([camera_params['camera_matrix']['data']]).reshape((3, 3)) + self.D = np.asarray(camera_params['distortion_coefficients']['data']) + self.K = cv2.getOptimalNewCameraMatrix(K_, self.D, (640, 480), 0, (640, 480))[0] + self.heartbeat_timer = None + self.image_sub = None + self.is_running = False + self.enter = False + self.R = None + self.T = None + self.R_40 = None + self.T_40 = None + + """ + 重置变量 + """ + def reset(self): + self.is_running = False + self.enter = False + self.R = None + self.T = None + self.R_40 = None + self.T_40 = None + + +""" +像素坐标转换为世界坐标 +""" +def camera_to_world(cam_mtx, r, t, img_points): + inv_k = np.asmatrix(cam_mtx).I + r_mat = np.zeros((3, 3), dtype=np.float64) + cv2.Rodrigues(r, r_mat) + # invR * T + inv_r = np.asmatrix(r_mat).I # 3*3 + transPlaneToCam = np.dot(inv_r, np.asmatrix(t)) # 3*3 dot 3*1 = 3*1 + world_pt = [] + coords = np.zeros((3, 1), dtype=np.float64) + for img_pt in img_points: + coords[0][0] = img_pt[0][0] + coords[1][0] = img_pt[0][1] + coords[2][0] = 1.0 + worldPtCam = np.dot(inv_k, coords) # 3*3 dot 3*1 = 3*1 + # [x,y,1] * invR + worldPtPlane = np.dot(inv_r, worldPtCam) # 3*3 dot 3*1 = 3*1 + # zc + scale = transPlaneToCam[2][0] / worldPtPlane[2][0] + # zc * [x,y,1] * invR + scale_worldPtPlane = np.multiply(scale, worldPtPlane) + # [X,Y,Z]=zc*[x,y,1]*invR - invR*T + worldPtPlaneReproject = np.asmatrix(scale_worldPtPlane) - np.asmatrix(transPlaneToCam) # 3*1 dot 1*3 = 3*3 + pt = np.zeros((3, 1), dtype=np.float64) + pt[0][0] = worldPtPlaneReproject[0][0] + pt[1][0] = worldPtPlaneReproject[1][0] + pt[2][0] = 0 + world_pt.append(pt.T.tolist()) + return world_pt + + +def image_proc(img): + frame_gray = cv2.cvtColor(np.copy(img), cv2.COLOR_RGB2GRAY) + tags = at_detector.detect(frame_gray) # 识别apriltag + for tag in tags: + center = np.array(tag.center).astype(int) # 中心点坐标 + if tag.tag_id == 1: # 只有 id 为 1 的tag做标定 + corners = tag.corners.reshape(1, -1, 2).astype(np.float32) + pts = np.insert(corners[0], 0, values=tag.center, axis=0) + with state.lock: + # 计算卡片情况下相机二维坐标与世界三维坐标的转换关系 + rtl, new_r, new_t = cv2.solvePnP(marker_corners, pts, state.K, None) + if rtl: + # 有简单的滤波避免跳动带来的影响 + state.R = new_r if state.R is None else state.R * 0.95 + new_r * 0.05 + state.T = new_t if state.T is None else state.T * 0.95 + new_t * 0.05 + + # 计算木块情况下相机二维坐标与世界三维坐标的转换关系 + rtl, new_r, new_t = cv2.solvePnP(marker_corners_block, pts, state.K, None) + if rtl: + # 有简单的滤波避免跳动带来的影响 + state.R_40 = new_r if state.R_40 is None else state.R_40 * 0.95 + new_r * 0.05 + state.T_40 = new_t if state.T_40 is None else state.T_40 * 0.95 + new_t * 0.05 + + if state.R is not None:# 有成功计算到转换关系的情况下 + # 用计算得到的转换关系和实际物理坐标反算出标签四个角在画面上的理论像素位置, + # 如果理论像素位置和识别到的标签实际像素位置重合就是计算得到的转换关系符合实际情况,就是准确的 + img_pts, jac = cv2.projectPoints(marker_corners, state.R, state.T, state.K, None) + else: + img_pts = [] + corners = corners.astype(int) + # 彩色画出标签的四个角和中心 + cv2.circle(img, tuple(corners[0][0]), 5, (255, 0, 0), 12) + cv2.circle(img, tuple(corners[0][1]), 5, (0, 255, 0), 12) + cv2.circle(img, tuple(corners[0][2]), 5, (0, 0, 255), 12) + cv2.circle(img, tuple(corners[0][3]), 5, (0, 255, 255), 12) + cv2.circle(img, tuple(center), 5, (255, 255, 0), 12) + cv2.putText(img, "id:%d" % tag.tag_id, + (center[0], center[1] - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2) + # 黑色画出反算出的理论像素位置 + # 黑色彩色重合就是有效了 + for i, c in enumerate(img_pts): + cv2.circle(img, tuple(c.astype(int)[0]), 3, (0, 0, 0), 4) + else: + with state.lock: + # 对于其他id不为1的标签,我们用得到的转换关系计算他们的世界坐标,并显示在画面上 + # 这样也可以测量实际位置和显示的位置是否一致判断标定的准确性。 + if state.R_40 is not None: + w = camera_to_world(state.K, state.R_40, state.T_40, + center.reshape((1, 1, 2)))[0][0] + else: + w = 0, 0, 0 + cv2.putText(img, "id:{} x:{:.2f} y:{:.2f}".format(tag.tag_id, w[0], w[1]), + (center[0] - 20, center[1] - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2) + return img + + +def image_callback(ros_image): + if state.enter is True: + # 将ros格式图转换为opencv格式 + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = image.copy() + with state.lock: + # 进行识别处理 + frame_result = image_proc(frame_result) + # 发布结果图像 + rgb_image = frame_result.tostring() + ros_image.data = rgb_image + image_pub.publish(ros_image) + +""" +进入服务 +""" +def enter_func(msg): + rospy.loginfo("enter object tracking") + exit_func(msg) + state.reset() + state.enter = True + return TriggerResponse(success=True) + +""" +退出服务 +""" +def exit_func(msg): + rospy.loginfo("exit object tracking") + state.is_running = False + state.enter = False + try: + state.heartbeat_timer.cancel() + except: + pass + #if isinstance(state.image_sub, rospy.Subscriber): + # rospy.loginfo('unregister image') + # state.image_sub.unregister() + # state.image_sub = None + rospy.ServiceProxy('/jetmax/go_home', Empty)() + #up_cb(msg) + return TriggerResponse(success=True) + +""" +开始/停止标定 +""" +def set_running(msg: SetBoolRequest): + rospy.loginfo('set running' + str(msg)) + with state.lock: + state.is_running = msg.data + return [True, ''] + + +def heartbeat_timeout_cb(): + rospy.loginfo('heartbeat timeout. exiting') + rospy.ServiceProxy('/%s/exit' % ROS_NODE_NAME, Trigger)() + + +def heartbeat_srv_cb(msg: SetBoolRequest): + try: + state.heartbeat_timer.cancel() + except: + pass + rospy.logdebug("Heartbeat") + if msg.data: + state.heartbeat_timer = threading.Timer(5, heartbeat_timeout_cb) + state.heartbeat_timer.start() + return SetBoolResponse(success=msg.data) + +""" +将当前的标定数据保存到文件中 +""" +def save_cb(msg): + rospy.loginfo("save") + with state.lock: + card_params = { + "K": state.K.tolist(), + "R": state.R.tolist(), + "T": state.T.tolist() + } + block_params = { + "K": state.K.tolist(), + "R": state.R_40.tolist(), + "T": state.T_40.tolist() + } + s = yaml.dump({ + 'card_params': card_params, + 'block_params': block_params, + }, default_flow_style=True) + rospy.set_param('~card_params', card_params) + rospy.set_param('~block_params', block_params) + with open(os.path.join(sys.path[0], '../config/camera_cal.yaml'), 'w') as f: + f.write(s) + return [True, ''] + +""" +机械臂上升抬起回调 +""" +def up_cb(msg: TriggerRequest): + try: + stepper = hiwonder.Stepper(1) + except: + stepper = None + try: + chassis = hiwonder.MecanumChassis() + except: + chassis = None + # 根据不同形态设置不同的高度 + if stepper: + jetmax.go_home(2,2) + elif chassis: + jetmax.go_home(2,3) + else: + jetmax.go_home(2) + + return [True, ''] + +""" +机械臂下降回调 +""" +def down_cb(msg): + try: + stepper = hiwonder.Stepper(1) + except: + stepper = None + try: + chassis = hiwonder.MecanumChassis() + except: + chassis = None + # 根据不同形态设置不同的高度 + if stepper: + dn = 160 + elif chassis: + dn = 190 + else: + dn = 110 + + jetmax_pub.publish(SetJetMax( + x=hiwonder.JetMax.ORIGIN[0], + y=hiwonder.JetMax.ORIGIN[1], + z=hiwonder.JetMax.ORIGIN[2] - dn, + duration=2 + )) + + return [True, ''] + +""" +订阅相机内参发布topic的回调 +将收到的内参保存到变量中 +""" +def camera_cb(msg): + new_k = np.asarray(msg.K).reshape((3, 3)) + new_d = np.asarray(msg.D) + new_k = cv2.getOptimalNewCameraMatrix(new_k, new_d, (640, 480), 0, (640, 480))[0] + with state.lock: + state.K = new_k + state.D = new_d + + +if __name__ == '__main__': + state = State() + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + rospy.sleep(0.2) + # 订阅相机图像 + state.image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) + # 机械臂控制topic + jetmax_pub = rospy.Publisher('/jetmax/command', SetJetMax, queue_size=1) + # 画面发布图像 + image_pub = rospy.Publisher('/%s/image_result' % ROS_NODE_NAME, Image, queue_size=1) # register image publisher + # 相机参数topic + camera_info_sub = rospy.Subscriber('/usb_cam/camera_info', CameraInfo, camera_cb, queue_size=1) + # 注册各个服务 + enter_srv = rospy.Service('/%s/enter' % ROS_NODE_NAME, Trigger, enter_func) + exit_srv = rospy.Service('/%s/exit' % ROS_NODE_NAME, Trigger, exit_func) + running_srv = rospy.Service('/%s/set_running' % ROS_NODE_NAME, SetBool, set_running) + up_srv = rospy.Service('/%s/up' % ROS_NODE_NAME, Trigger, up_cb) + down_srv = rospy.Service('/%s/down' % ROS_NODE_NAME, Trigger, down_cb) + save_srv = rospy.Service('/%s/save' % ROS_NODE_NAME, Trigger, save_cb) + heartbeat_srv = rospy.Service('/%s/heartbeat' % ROS_NODE_NAME, SetBool, heartbeat_srv_cb) + try: + rospy.spin() + except KeyboardInterrupt: + print("Shutting down") + sys.exit(0) diff --git a/src/jetmax_buildin_funcs/color_sorting/CMakeLists.txt b/src/jetmax_buildin_funcs/color_sorting/CMakeLists.txt new file mode 100644 index 0000000..7100730 --- /dev/null +++ b/src/jetmax_buildin_funcs/color_sorting/CMakeLists.txt @@ -0,0 +1,206 @@ +cmake_minimum_required(VERSION 3.0.2) +project(color_sorting) + +## 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 + message_generation + rospy + std_msgs + std_srvs +) + +## 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 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 + SetTarget.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 + ) + +################################################ +## 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 color_sorting +# CATKIN_DEPENDS rospy std_msgs std_srvs +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( +# include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/color_sorting.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/color_sorting_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_color_sorting.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/jetmax_buildin_funcs/color_sorting/package.xml b/src/jetmax_buildin_funcs/color_sorting/package.xml new file mode 100644 index 0000000..a0df2a8 --- /dev/null +++ b/src/jetmax_buildin_funcs/color_sorting/package.xml @@ -0,0 +1,70 @@ + + + color_sorting + 1.0.0 + The color_sorting package + + + + + hiwonder + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + rospy + std_msgs + std_srvs + message_generation + rospy + std_msgs + std_srvs + message_generation + rospy + std_msgs + std_srvs + + + + + + + + diff --git a/src/jetmax_buildin_funcs/color_sorting/scripts/color_sorting_main.py b/src/jetmax_buildin_funcs/color_sorting/scripts/color_sorting_main.py new file mode 100755 index 0000000..fe2f323 --- /dev/null +++ b/src/jetmax_buildin_funcs/color_sorting/scripts/color_sorting_main.py @@ -0,0 +1,457 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import threading +import numpy as np +import rospy +from sensor_msgs.msg import Image +from std_msgs.msg import Bool +from std_srvs.srv import Empty +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from color_sorting.srv import SetTarget, SetTargetResponse, SetTargetRequest +from std_msgs.msg import Bool +from jetmax_control.msg import SetServo +import hiwonder + + +ROS_NODE_NAME = "color_sorting" +IMAGE_PROC_SIZE = 640, 480 + + +# 色块中心在原点上时 中心及四个点的坐标 +unit_block_corners = np.asarray([[0, 0, 0], + [19.5, -19.5, 0], # TAG_SIZE = 33.30mm + [-19.5, -19.5, 0], + [-19.5, 19.5, 0], + [19.5, 19.5, 0]], + dtype=np.float64) +unit_block_img_pts = None + + +def camera_to_world(cam_mtx, r, t, img_points): + inv_k = np.asmatrix(cam_mtx).I + r_mat = np.zeros((3, 3), dtype=np.float64) + cv2.Rodrigues(r, r_mat) + # invR * T + inv_r = np.asmatrix(r_mat).I # 3*3 + transPlaneToCam = np.dot(inv_r, np.asmatrix(t)) # 3*3 dot 3*1 = 3*1 + world_pt = [] + coords = np.zeros((3, 1), dtype=np.float64) + for img_pt in img_points: + coords[0][0] = img_pt[0][0] + coords[1][0] = img_pt[0][1] + coords[2][0] = 1.0 + worldPtCam = np.dot(inv_k, coords) # 3*3 dot 3*1 = 3*1 + # [x,y,1] * invR + worldPtPlane = np.dot(inv_r, worldPtCam) # 3*3 dot 3*1 = 3*1 + # zc + scale = transPlaneToCam[2][0] / worldPtPlane[2][0] + # zc * [x,y,1] * invR + scale_worldPtPlane = np.multiply(scale, worldPtPlane) + # [X,Y,Z]=zc*[x,y,1]*invR - invR*T + worldPtPlaneReproject = np.asmatrix(scale_worldPtPlane) - np.asmatrix(transPlaneToCam) # 3*1 dot 1*3 = 3*3 + pt = np.zeros((3, 1), dtype=np.float64) + pt[0][0] = worldPtPlaneReproject[0][0] + pt[1][0] = worldPtPlaneReproject[1][0] + pt[2][0] = 0 + world_pt.append(pt.T.tolist()) + return world_pt + + +class ColorSortingState: + def __init__(self): + self.target_colors = {} + self.target_positions = { + 'red': ((235, -23, 85), -5), + 'green': ((235, -23 + 52, 85), 8), + 'blue': ((235, -23 + 52 * 2, 85), 18) + } + self.heartbeat_timer = None + self.is_running = False + self.image_sub = None + self.moving_color = None + self.lock = threading.RLock() + self.runner = None + self.count = 0 + self.camera_params = None + self.K = None + self.R = None + self.T = None + self.WIDTH = None + + """ + 重置部分需要的变量 + """ + def reset(self): + self.target_colors = {} + self.is_running = False + self.moving_color = None + self.count = 0 + + """ + 读取相机参数 + """ + def load_camera_params(self): + global unit_block_img_pts + self.camera_params = rospy.get_param('/camera_cal/block_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + # 计算色块中心在原点时四个角在图像上对应的坐标 + img_pts, jac = cv2.projectPoints(unit_block_corners, self.R, self.T, self.K, None) + unit_block_img_pts = img_pts.reshape(5, 2) + l_p1 = unit_block_img_pts[-1] + l_p2 = unit_block_img_pts[-2] + # 计算色块在画面上的宽度 + self.WIDTH = math.sqrt((l_p1[0] - l_p2[0]) ** 2 + (l_p1[1] - l_p2[1]) ** 2) + print(unit_block_img_pts) + + +""" +搬运色块 +""" +def moving(): + rect, box, color_name = state.moving_color + cur_x, cur_y, cur_z = jetmax.position + try: + #sucker.set_state(True) + # 将识别到的色块在画面上的坐标转为相对与吸嘴的xy偏移 + x, y, _ = camera_to_world(state.K, state.R, state.T, np.array(rect[0]).reshape((1, 1, 2)))[0][0] + # Calculate the distance between the current position and the target position to control the movement speed + # 计算用140速从吸嘴当前位置移动到色块中心需要的时间 + t = math.sqrt(x * x + y * y + 120 * 120) / 140 + + # 色块的旋转角度 + angle = rect[2] # + if angle < -45: # ccw -45 ~ -90 + angle = -(-90 - angle) + + # 色块相对于机械臂基座的坐标 + new_x, new_y = cur_x + x, cur_y + y + nn_new_x = new_x + 15 + + # 吸嘴在色块的位置的时候机械臂相对与中轴的旋转角, 用来控制小舵机旋转色块以摆正色块 + arm_angle = math.atan(new_y / new_x) * 180 / math.pi + if arm_angle > 0: + arm_angle = (90 - arm_angle) + elif arm_angle < 0: + arm_angle = (-90 - arm_angle) + else: + pass + + angle = angle + -arm_angle # 色块本身 + 机械臂的旋转角度 + + # 运动到色块位置并将色块吸取 + hiwonder.pwm_servo1.set_position(90 + angle, 0.1) + jetmax.set_position((nn_new_x, new_y, 120), t) + rospy.sleep(t) + jetmax.set_position((new_x, new_y, 120), 0.3) + rospy.sleep(0.4) + sucker.set_state(True) # 启动气泵,吸气 + jetmax.set_position((new_x, new_y, 85 - 5), 1) + rospy.sleep(1.05) + + cur_x, cur_y, cur_z = jetmax.position + jetmax.set_position((cur_x, cur_y, 180), 0.8) + rospy.sleep(0.8) + hiwonder.pwm_servo1.set_position(90, 0.1) + + # 运动到目标位置 + (x, y, z), angle = state.target_positions[color_name] + cur_x, cur_y, cur_z = jetmax.position + t = math.sqrt(((cur_x - x) ** 2 + (cur_y - y) ** 2)) / 180.0 + hiwonder.pwm_servo1.set_position(90 + angle, 0.5) + jetmax.set_position((x, y, 180), t) + rospy.sleep(t) + jetmax.set_position((x, y, 180), 0.3) + rospy.sleep(0.4) + jetmax.set_position((x, y, z), 1) + rospy.sleep(1) + + # 释放色块 + sucker.release(3) # 关泵,放气 + jetmax.set_position((x, y, 140), 0.8) # 抬起机械臂 + rospy.sleep(0.8) + except Exception as e: + rospy.logerr("ERROR") + finally: + # Go home + sucker.release(3) + hiwonder.pwm_servo1.set_position(90, 0.5) # 小舵机回到中位 + jetmax.go_home(2) # 机械臂回到初始位置 + rospy.sleep(2.5) + # 清理标志, 开始下次识别 + state.moving_color = None + state.runner = None + +""" +计算 a点和b点的连线上距离a点距离为r的且在a点b点中间的点的坐标 +""" +def point_xy(pt_a, pt_b, r): + x_a, y_a = pt_a + x_b, y_b = pt_b + if x_a == x_b: + return x_a, y_a + (r / abs((y_b - y_a))) * (y_b - y_a) + k = (y_a - y_b) / (x_a - x_b) + b = y_a - k * x_a + A = k ** 2 + 1 + B = 2 * ((b - y_a) * k - x_a) + C = (b - y_a) ** 2 + x_a ** 2 - r ** 2 + x1 = (-B + math.sqrt(B ** 2 - 4 * A * C)) / (2 * A) + x2 = (-B - math.sqrt(B ** 2 - 4 * A * C)) / (2 * A) + y1 = k * x1 + b + y2 = k * x2 + b + dist_1 = math.sqrt((x1 - x_b) ** 2 + (y1 - y_b) ** 2) + dist_2 = math.sqrt((x2 - x_b) ** 2 + (y2 - y_b) ** 2) + if dist_1 <= dist_2: + return x1, y1 + else: + return x2, y2 + + +""" +图像处理 +""" +def image_proc(img): + if state.runner is not None: + return img + img_h, img_w = img.shape[:2] + frame_gb = cv2.GaussianBlur(np.copy(img), (5, 5), 5) # 高斯录播 + frame_lab = cv2.cvtColor(frame_gb, cv2.COLOR_RGB2LAB) # 转换为 lab 空间 + + blocks = [] + for color_name, color in state.target_colors.items(): # 遍历所有目标颜色, 识别画面中的色块 + frame_mask = cv2.inRange(frame_lab, tuple(color['min']), tuple(color['max'])) # 二值化 + eroded = cv2.erode(frame_mask, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) # 腐蚀 + dilated = cv2.dilate(eroded, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) # 膨胀 + contours = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] # 获取二值图中的所有外轮廓 + contour_area = map(lambda c: (c, math.fabs(cv2.contourArea(c))), contours) # 计算所有轮廓的面积 + contour_area = list(filter(lambda c: c[1] > 1000, contour_area)) # 去掉面积太小的轮廓 + + # 有识别到符合要求的轮廓 + if len(contour_area) > 0: + for contour, area in contour_area: # 遍历所有识别到的符合要求的轮廓 + rect = cv2.minAreaRect(contour) # 获取轮廓最小外接矩形 + center_x, center_y = rect[0] + box = cv2.boxPoints(rect) # 最小外接矩形的四个角的坐标 + box_list = box.tolist() + box = np.int0(box) + + # 计算正确的上表面的中心点 + # 计算色块上表面的中心在画面上的坐标 + # 因为相机视角原因,当木块放在地图边缘时,相机会看到色块的侧面导致不能正确获取目块上表面的中心坐标 + # 这里做些处理。 + # 取识别到的色块距离画面中心最远的一个角,以这个角的两条边认为是木块上表面的两条边 + # 取计算到的木块在画面中的理论宽度作为腰长,对角线作为底边形成一个等腰三角形,认为底边的中点就是木块上表面的中心坐标 + ap = max(box_list, key=lambda p: math.sqrt((p[0] - state.K[0][2]) ** 2 + (p[1] - state.K[1][2]) ** 2)) + index_ap = box_list.index(ap) + p1 = box_list[index_ap - 1 if index_ap - 1 >= 0 else 3] + p2 = box_list[index_ap + 1 if index_ap + 1 <= 3 else 0] + n_p1 = point_xy(ap, p1, state.WIDTH) + n_p2 = point_xy(ap, p2, state.WIDTH) + + c_x, c_y = None, None + if n_p1 and n_p2: + x_1, y_1 = n_p1 + x_2, y_2 = n_p2 + c_x = (x_1 + x_2) / 2 + c_y = (y_1 + y_2) / 2 + # 画出三角形三个点 + cv2.circle(img, (int(n_p1[0]), int(n_p1[1])), 2, (255, 255, 0), 10) + cv2.circle(img, (int(n_p2[0]), int(n_p2[1])), 2, (255, 255, 0), 10) + cv2.circle(img, (int(c_x), int(c_y)), 2, (0, 0, 0), 10) + + # 画出识别到的色块 + cv2.circle(img, (int(ap[0]), int(ap[1])), 2, (0, 255, 255), 10) + cv2.drawContours(img, [box], -1, hiwonder.COLORS[color_name.upper()], 2) + cv2.circle(img, (int(center_x), int(center_y)), 1, hiwonder.COLORS[color_name.upper()], 5) + rect = list(rect) + if c_x: + rect[0] = c_x, c_y + else: + rect[0] = (center_x, center_y) + blocks.append((rect, box, color_name)) + + # 如果正确识别到的色块数量不为0 + if len(blocks) > 0: + # 上一帧没有识别到色块 + if state.moving_color is None: + # 选择识别到的最大的色块存下来, 作为目标 + state.moving_color = max(blocks, key=lambda tmp: tmp[0][1][0] * tmp[0][1][1]) + # 上一帧识别到色块并已经记下来 + else: + # 找到距离上一帧记下的色块最近的色块 + rect, _, _ = state.moving_color + moving_x, moving_y = rect[0] + blocks = list(map(lambda tmp: (tmp, math.sqrt((moving_x - tmp[0][0][0]) ** 2 + + (moving_y - tmp[0][0][1]) ** 2)), blocks)) + blocks.sort(key=lambda tmp: tmp[1]) + moving_color, _ = blocks[0] + x, y = moving_color[0][0] + # 用白色画出目标色块 + cv2.drawContours(img, [moving_color[1]], -1, (255, 255, 255), 2) + cv2.circle(img, (int(x), int(y)), 1, (255, 255, 255), 5) + + state.count += 1 + if state.count > 5: # 连续5帧符合要求, 开始记录对目标位置进行滤波 + rect, box, color_name = moving_color + (x, y), (w, h), angle = rect + (o_x, o_y), _, o_angle = state.moving_color[0] + # 对 识别到的色块坐标做简单滤波 + o_x = x * 0.2 + o_x * 0.8 + o_y = y * 0.2 + o_y * 0.8 + o_angle = angle * 0.2 + o_angle * 0.8 + rect = (o_x, o_y), (w, h), o_angle + moving_color = rect, box, color_name + if state.count > 30: # 连续30帧符合要求, 开始搬运色块 + state.count = 0 + state.moving_color = moving_color + state.runner = threading.Thread(target=moving, daemon=True) # Move block + state.runner.start() + state.moving_color = moving_color + else: + state.moving_color = None + state.count = 0 + + # 画中心十字架 + cv2.line(img, (int(img_w / 2 - 10), int(img_h / 2)), (int(img_w / 2 + 10), int(img_h / 2)), (0, 255, 255), 2) + cv2.line(img, (int(img_w / 2), int(img_h / 2 - 10)), (int(img_w / 2), int(img_h / 2 + 10)), (0, 255, 255), 2) + return img + + +""" +相机画面的ros topic 回调这个函数,对画面进行识别处理 +""" +def image_callback(ros_image): + # 将ros图片转换为opencv图片 + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = np.copy(image) + with state.lock: + # 如果开启运行, 就进行识别 + if state.is_running: + frame_result = image_proc(frame_result) + rgb_image = frame_result.tostring() + ros_image.data = rgb_image + image_pub.publish(ros_image) # 发布结果图片 + + +""" +启动服务, 程序订阅相机话题,但是不做识别 +""" +def enter_func(msg): + rospy.loginfo("Enter color sorting") + exit_func(msg) + jetmax.go_home() + state.reset() + state.load_camera_params() + state.image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) + return TriggerResponse(success=True) + + +""" +退出服务, 程序取消对相机话题的订阅 +""" +def exit_func(msg): + rospy.loginfo("Exit color sorting") + state.is_running = False + try: + state.heartbeat_timer.cancel() + except: + pass + if isinstance(state.runner, threading.Thread): # If the arm is moving, wait for it to complete + state.runner.join() + try: + state.image_sub.unregister() + except: + pass + finally: + state.image_sub = None + rospy.ServiceProxy('/jetmax/go_home', Empty)() + rospy.Publisher('/jetmax/end_effector/sucker/command', Bool, queue_size=1).publish(data=False) + rospy.Publisher('/jetmax/end_effector/servo1/command', SetServo, queue_size=1).publish(data=90, duration=0.5) + return TriggerResponse(success=True) + + +""" +启动运行,运行标志置位 +""" +def set_running(msg: SetBoolRequest): + rospy.loginfo('Set running' + str(msg)) + if msg.data: + state.is_running = True + else: + state.is_running = False + return SetBoolResponse() + + +""" +设置目标颜色 +""" +def set_target_cb(msg: SetTargetRequest): + try: + if msg.is_enable: + # 获取颜色阈值列表 + color_ranges = rospy.get_param('/lab_config_manager/color_range_list', {}) + with state.lock: + # 从列表中找出对应阈值并设为目标阈值 + state.target_colors[msg.color_name] = color_ranges[msg.color_name] + rospy.logdebug('set target color ' + str(msg)) + else: + with state.lock: + del (state.target_colors[msg.color_name]) + rospy.loginfo('disable target color: ' + msg.color_name) + except Exception as e: + rospy.logerr(e) + return SetTargetResponse(success=False, message=str(e)) + return SetTargetResponse(success=True) + + +def heartbeat_timeout_cb(): + rospy.loginfo('Heartbeat timeout. exiting') + rospy.ServiceProxy('/%s/exit' % ROS_NODE_NAME, Trigger)() + + +def heartbeat_srv_cb(msg: SetBoolRequest): + """ + Heartbeat callback. A timer will be set, and the exit service will be called when the time is reached + + """ + rospy.logdebug("Heartbeat") + try: + state.heartbeat_timer.cancel() + except: + pass + if msg.data: + state.heartbeat_timer = threading.Timer(5, heartbeat_timeout_cb) + state.heartbeat_timer.start() + return SetBoolResponse(success=msg.data) + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + state = ColorSortingState() + # 读取相机参数 + state.load_camera_params() + if state.camera_params is None: + rospy.logerr("Can not load camera params") + sys.exit(-1) + + # 机械臂控制接口 + jetmax = hiwonder.JetMax() + sucker = hiwonder.Sucker() + rospy.sleep(0.2) + + # 订阅/发布相关话题, 注册服务 + image_pub = rospy.Publisher('/%s/image_result' % ROS_NODE_NAME, Image, queue_size=1) # register image publisher + enter_srv = rospy.Service('/%s/enter' % ROS_NODE_NAME, Trigger, enter_func) + exit_srv = rospy.Service('/%s/exit' % ROS_NODE_NAME, Trigger, exit_func) + running_srv = rospy.Service('/%s/set_running' % ROS_NODE_NAME, SetBool, set_running) + set_target_srv = rospy.Service('/%s/set_target' % ROS_NODE_NAME, SetTarget, set_target_cb) + heartbeat_srv = rospy.Service('/%s/heartbeat' % ROS_NODE_NAME, SetBool, heartbeat_srv_cb) + try: + rospy.spin() + except KeyboardInterrupt: + sys.exit(0) diff --git a/src/jetmax_buildin_funcs/color_sorting/srv/SetTarget.srv b/src/jetmax_buildin_funcs/color_sorting/srv/SetTarget.srv new file mode 100644 index 0000000..bc50337 --- /dev/null +++ b/src/jetmax_buildin_funcs/color_sorting/srv/SetTarget.srv @@ -0,0 +1,5 @@ +string color_name +bool is_enable +--- +bool success +string message \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/dataset_capture/CMakeLists.txt b/src/jetmax_buildin_funcs/dataset_capture/CMakeLists.txt new file mode 100644 index 0000000..03ff85f --- /dev/null +++ b/src/jetmax_buildin_funcs/dataset_capture/CMakeLists.txt @@ -0,0 +1,205 @@ +cmake_minimum_required(VERSION 3.0.2) +project(dataset_capture) + +## 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 + rospy + std_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 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 +# ) + +################################################ +## 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 dataset_capture +# CATKIN_DEPENDS rospy std_msgs +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( +# include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/dataset_capture.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/dataset_capture_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_dataset_capture.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/jetmax_buildin_funcs/dataset_capture/camera.svg b/src/jetmax_buildin_funcs/dataset_capture/camera.svg new file mode 100644 index 0000000..7f0dc25 --- /dev/null +++ b/src/jetmax_buildin_funcs/dataset_capture/camera.svg @@ -0,0 +1,137 @@ + + + + +camera +Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/jetmax_buildin_funcs/dataset_capture/package.xml b/src/jetmax_buildin_funcs/dataset_capture/package.xml new file mode 100644 index 0000000..44e202c --- /dev/null +++ b/src/jetmax_buildin_funcs/dataset_capture/package.xml @@ -0,0 +1,65 @@ + + + dataset_capture + 0.0.0 + The dataset_capture package + + + + + lucas + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + rospy + std_msgs + rospy + std_msgs + rospy + std_msgs + + + + + + + + diff --git a/src/jetmax_buildin_funcs/dataset_capture/scripts/camera.ui b/src/jetmax_buildin_funcs/dataset_capture/scripts/camera.ui new file mode 100644 index 0000000..b9a6566 --- /dev/null +++ b/src/jetmax_buildin_funcs/dataset_capture/scripts/camera.ui @@ -0,0 +1,196 @@ + + + MainWindow + + + + 0 + 0 + 418 + 392 + + + + + 0 + 0 + + + + + 418 + 392 + + + + + 418 + 392 + + + + Camera + + + + + 10 + + + + + + 0 + 30 + + + + + 400 + 300 + + + + QFrame::StyledPanel + + + + + + + + + + 12 + + + QLayout::SetDefaultConstraint + + + + + Directory : + + + + + + + + 0 + 0 + + + + + 16777215 + 300 + + + + /home/hiwonder/Pictures + + + + + + + + 0 + 35 + + + + + 67 + 30 + + + + Select + + + + + + + + + 6 + + + QLayout::SetFixedSize + + + 0 + + + 0 + + + + + Prefix name: + + + + + + + + 16777215 + 16777215 + + + + Camera + + + + + + + Start Index: + + + + + + + + 36 + 16777215 + + + + 1 + + + + + + + + 0 + 35 + + + + + 67 + 30 + + + + Save + + + + + + + + + + + diff --git a/src/jetmax_buildin_funcs/dataset_capture/scripts/camera_ui.py b/src/jetmax_buildin_funcs/dataset_capture/scripts/camera_ui.py new file mode 100644 index 0000000..bca11ba --- /dev/null +++ b/src/jetmax_buildin_funcs/dataset_capture/scripts/camera_ui.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file './camera.ui' +# +# Created by: PyQt5 UI code generator 5.15.4 +# +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(418, 392) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth()) + MainWindow.setSizePolicy(sizePolicy) + MainWindow.setMinimumSize(QtCore.QSize(418, 392)) + MainWindow.setMaximumSize(QtCore.QSize(418, 392)) + self.centralwidget = QtWidgets.QWidget(MainWindow) + self.centralwidget.setObjectName("centralwidget") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.centralwidget) + self.verticalLayout_2.setSpacing(10) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.label_img = QtWidgets.QLabel(self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(30) + sizePolicy.setHeightForWidth(self.label_img.sizePolicy().hasHeightForWidth()) + self.label_img.setSizePolicy(sizePolicy) + self.label_img.setMinimumSize(QtCore.QSize(400, 300)) + self.label_img.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.label_img.setText("") + self.label_img.setObjectName("label_img") + self.verticalLayout_2.addWidget(self.label_img) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) + self.horizontalLayout.setSpacing(12) + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(self.centralwidget) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.lineEdit_path = QtWidgets.QLineEdit(self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lineEdit_path.sizePolicy().hasHeightForWidth()) + self.lineEdit_path.setSizePolicy(sizePolicy) + self.lineEdit_path.setMaximumSize(QtCore.QSize(16777215, 300)) + self.lineEdit_path.setObjectName("lineEdit_path") + self.horizontalLayout.addWidget(self.lineEdit_path) + self.pushButton_select = QtWidgets.QPushButton(self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(35) + sizePolicy.setHeightForWidth(self.pushButton_select.sizePolicy().hasHeightForWidth()) + self.pushButton_select.setSizePolicy(sizePolicy) + self.pushButton_select.setMaximumSize(QtCore.QSize(67, 30)) + self.pushButton_select.setObjectName("pushButton_select") + self.horizontalLayout.addWidget(self.pushButton_select) + self.verticalLayout_2.addLayout(self.horizontalLayout) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setSizeConstraint(QtWidgets.QLayout.SetFixedSize) + self.horizontalLayout_2.setContentsMargins(0, 0, -1, -1) + self.horizontalLayout_2.setSpacing(6) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.label_2 = QtWidgets.QLabel(self.centralwidget) + self.label_2.setObjectName("label_2") + self.horizontalLayout_2.addWidget(self.label_2) + self.lineEdit_prefix = QtWidgets.QLineEdit(self.centralwidget) + self.lineEdit_prefix.setMaximumSize(QtCore.QSize(16777215, 16777215)) + self.lineEdit_prefix.setObjectName("lineEdit_prefix") + self.horizontalLayout_2.addWidget(self.lineEdit_prefix) + self.label_3 = QtWidgets.QLabel(self.centralwidget) + self.label_3.setObjectName("label_3") + self.horizontalLayout_2.addWidget(self.label_3) + self.lineEdit_index = QtWidgets.QLineEdit(self.centralwidget) + self.lineEdit_index.setMaximumSize(QtCore.QSize(36, 16777215)) + self.lineEdit_index.setObjectName("lineEdit_index") + self.horizontalLayout_2.addWidget(self.lineEdit_index) + self.pushButton_save = QtWidgets.QPushButton(self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(35) + sizePolicy.setHeightForWidth(self.pushButton_save.sizePolicy().hasHeightForWidth()) + self.pushButton_save.setSizePolicy(sizePolicy) + self.pushButton_save.setMaximumSize(QtCore.QSize(67, 30)) + self.pushButton_save.setObjectName("pushButton_save") + self.horizontalLayout_2.addWidget(self.pushButton_save) + self.verticalLayout_2.addLayout(self.horizontalLayout_2) + MainWindow.setCentralWidget(self.centralwidget) + + self.retranslateUi(MainWindow) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "Camera")) + self.label.setText(_translate("MainWindow", "Directory : ")) + self.lineEdit_path.setText(_translate("MainWindow", "/home/hiwonder/Pictures")) + self.pushButton_select.setText(_translate("MainWindow", "Select")) + self.label_2.setText(_translate("MainWindow", "Prefix name:")) + self.lineEdit_prefix.setText(_translate("MainWindow", "Camera")) + self.label_3.setText(_translate("MainWindow", "Start Index:")) + self.lineEdit_index.setText(_translate("MainWindow", "1")) + self.pushButton_save.setText(_translate("MainWindow", "Save")) diff --git a/src/jetmax_buildin_funcs/dataset_capture/scripts/main.py b/src/jetmax_buildin_funcs/dataset_capture/scripts/main.py new file mode 100755 index 0000000..838af62 --- /dev/null +++ b/src/jetmax_buildin_funcs/dataset_capture/scripts/main.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +import os +import sys +from PyQt5.QtGui import QImage, QPixmap +from PyQt5.QtWidgets import QMainWindow, QApplication, QFileDialog +from camera_ui import * +from PIL import Image +import rospy +import numpy as np +from sensor_msgs.msg import Image as RosImage + + +class MainWindow(QMainWindow, Ui_MainWindow): + def __init__(self): + super(MainWindow, self).__init__() + self.setupUi(self) + icon_path = os.path.join(sys.path[0], '../camera.svg') + self.setWindowIcon(QtGui.QIcon(icon_path)) + rospy.init_node('dataset_capture', anonymous=False) # 初始化节点 + # 订阅相机topic + self.image_sub = rospy.Subscriber('/usb_cam/image_rect_color', RosImage, self.image_callback) + # 两个按钮信号槽连接 + self.pushButton_select.clicked.connect(self.select_folder) + self.pushButton_save.clicked.connect(self.save_picture) + self.snapshot = None + + # 保存按钮调用 + def save_picture(self): + if self.snapshot is not None: + image = Image.fromarray(self.snapshot) + filename = self.lineEdit_prefix.text() + save_path = self.lineEdit_path.text() + index = self.lineEdit_index.text() + index = int(index) + while os.path.exists(os.path.join(save_path, filename + '_' + str(index) + '.jpg')): + index += 1 + # 保存图片 + image.save(os.path.join(save_path, filename + '_' + str(index) + '.jpg'), quality=100) + + # 选择保存路径 + def select_folder(self): + s = str(QFileDialog.getExistingDirectory(self, "Select Directory")) + if s: + self.lineEdit_path.setText(s) + + # 相机画面回调 + def image_callback(self, ros_image): + # 将图片转为qt的格式并缩放显示出来 + frame = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + self.snapshot = frame + img = QImage(frame.data, ros_image.width, ros_image.height, QImage.Format_RGB888).scaled(400, 300) + self.label_img.setPixmap(QPixmap.fromImage(img)) + + +if __name__ == "__main__": + app = QApplication(sys.argv) + win = MainWindow() + win.show() + sys.exit(app.exec_()) diff --git a/src/jetmax_buildin_funcs/jetmax_control/CMakeLists.txt b/src/jetmax_buildin_funcs/jetmax_control/CMakeLists.txt new file mode 100644 index 0000000..d49fad4 --- /dev/null +++ b/src/jetmax_buildin_funcs/jetmax_control/CMakeLists.txt @@ -0,0 +1,214 @@ +cmake_minimum_required(VERSION 3.0.2) +project(jetmax_control) + +## 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 + rospy + std_msgs + actionlib_msgs + message_generation + ) + +## 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 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 + Mecanum.msg + JetMax.msg + SetServo.msg + SetJoint.msg + SetJetMax.msg +) + +## Generate services in the 'srv' folder +add_service_files( + FILES + ActionSetList.srv + ActionSetFileOp.srv + # Service1.srv + # Service2.srv +) + +## Generate actions in the 'action' folder +add_action_files( + FILES + ActionSetRaw.action + # Action1.action + # Action2.action +) + +## Generate added messages and services with any dependencies listed here +generate_messages( + DEPENDENCIES + std_msgs + actionlib_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 jetmax_control + CATKIN_DEPENDS rospy std_msgs message_runtime actionlib_msgs + # DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( + # include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/jetmax_control.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/jetmax_control_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_jetmax_control.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/jetmax_buildin_funcs/jetmax_control/action/ActionSetRaw.action b/src/jetmax_buildin_funcs/jetmax_control/action/ActionSetRaw.action new file mode 100644 index 0000000..36dab78 --- /dev/null +++ b/src/jetmax_buildin_funcs/jetmax_control/action/ActionSetRaw.action @@ -0,0 +1,7 @@ +string data +uint32 repeat +--- +bool result +--- +uint32 index +uint32 count \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/jetmax_control/msg/JetMax.msg b/src/jetmax_buildin_funcs/jetmax_control/msg/JetMax.msg new file mode 100644 index 0000000..0568251 --- /dev/null +++ b/src/jetmax_buildin_funcs/jetmax_control/msg/JetMax.msg @@ -0,0 +1,12 @@ +float32 x +float32 y +float32 z +float32 joint1 +float32 joint2 +float32 joint3 +float32 servo1 +float32 servo2 +float32 servo3 +float32 pwm1 +float32 pwm2 +bool sucker diff --git a/src/jetmax_buildin_funcs/jetmax_control/msg/Mecanum.msg b/src/jetmax_buildin_funcs/jetmax_control/msg/Mecanum.msg new file mode 100644 index 0000000..63ea8f9 --- /dev/null +++ b/src/jetmax_buildin_funcs/jetmax_control/msg/Mecanum.msg @@ -0,0 +1,3 @@ +float32 velocity +float32 direction +float32 angular_rate \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/jetmax_control/msg/SetJetMax.msg b/src/jetmax_buildin_funcs/jetmax_control/msg/SetJetMax.msg new file mode 100644 index 0000000..8b77d3c --- /dev/null +++ b/src/jetmax_buildin_funcs/jetmax_control/msg/SetJetMax.msg @@ -0,0 +1,4 @@ +float32 x +float32 y +float32 z +float32 duration \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/jetmax_control/msg/SetJoint.msg b/src/jetmax_buildin_funcs/jetmax_control/msg/SetJoint.msg new file mode 100644 index 0000000..99587e1 --- /dev/null +++ b/src/jetmax_buildin_funcs/jetmax_control/msg/SetJoint.msg @@ -0,0 +1,2 @@ +float32 data +float32 duration \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/jetmax_control/msg/SetServo.msg b/src/jetmax_buildin_funcs/jetmax_control/msg/SetServo.msg new file mode 100644 index 0000000..ab6e9ca --- /dev/null +++ b/src/jetmax_buildin_funcs/jetmax_control/msg/SetServo.msg @@ -0,0 +1,2 @@ +uint16 data +float32 duration \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/jetmax_control/msg/Sucker.msg b/src/jetmax_buildin_funcs/jetmax_control/msg/Sucker.msg new file mode 100644 index 0000000..aed19c3 --- /dev/null +++ b/src/jetmax_buildin_funcs/jetmax_control/msg/Sucker.msg @@ -0,0 +1 @@ +bool state \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/jetmax_control/msg/SuckerState.msg b/src/jetmax_buildin_funcs/jetmax_control/msg/SuckerState.msg new file mode 100644 index 0000000..f7cabb9 --- /dev/null +++ b/src/jetmax_buildin_funcs/jetmax_control/msg/SuckerState.msg @@ -0,0 +1 @@ +bool data \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/jetmax_control/package.xml b/src/jetmax_buildin_funcs/jetmax_control/package.xml new file mode 100644 index 0000000..89e376f --- /dev/null +++ b/src/jetmax_buildin_funcs/jetmax_control/package.xml @@ -0,0 +1,69 @@ + + + jetmax_control + 0.0.0 + The jetmax_control package + + + + + lucas + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + message_generation + actionlib_msgs + rospy + std_msgs + rospy + std_msgs + actionlib_msgs + rospy + std_msgs + message_runtime + + + + + + + + diff --git a/src/jetmax_buildin_funcs/jetmax_control/scripts/.jetmax_control_main.py.swp b/src/jetmax_buildin_funcs/jetmax_control/scripts/.jetmax_control_main.py.swp new file mode 100644 index 0000000..f6d155d Binary files /dev/null and b/src/jetmax_buildin_funcs/jetmax_control/scripts/.jetmax_control_main.py.swp differ diff --git a/src/jetmax_buildin_funcs/jetmax_control/scripts/action_set.py b/src/jetmax_buildin_funcs/jetmax_control/scripts/action_set.py new file mode 100644 index 0000000..365372b --- /dev/null +++ b/src/jetmax_buildin_funcs/jetmax_control/scripts/action_set.py @@ -0,0 +1,132 @@ +import asyncio +import threading +import hiwonder +import os +import json +import actionlib +from jetmax_control.msg import ActionSetRawAction, ActionSetRawFeedback, ActionSetRawActionGoal, ActionSetRawResult +from jetmax_control.srv import ActionSetList, ActionSetListResponse +from jetmax_control.srv import ActionSetFileOp, ActionSetFileOpResponse +from std_srvs.srv import Trigger +import rospy + + +class ActionSetRunner: + def __init__(self, jetmax, sucker): + self._running = None + self._loop = asyncio.new_event_loop() + self._lock = threading.RLock() + self._jetmax = jetmax + self._sucker = sucker + self.action_set_online = actionlib.SimpleActionServer('/jetmax/actionset_online', ActionSetRawAction, + self.run_online, + auto_start=False) + threading.Thread(target=self._start_loop, daemon=True).start() + self.action_set_online.start() + self.get_actionset_list_srv = rospy.Service('/jetmax/actionset/get_actionset_list', ActionSetList, + self.get_action_list_cb) + self.remove_actionset_srv = rospy.Service('/jetmax/actionset/remove_actionset', ActionSetFileOp, + self.remove_actionset_cb) + self.save_actionset_srv = rospy.Service('/jetmax/actionset/save_actionset', ActionSetFileOp, + self.save_actionset_cb) + self.read_actionset_srv = rospy.Service('/jetmax/actionset/read_actionset', ActionSetFileOp, + self.read_actionset_cb) + + def get_action_list_cb(self, req): + for root, dirs, files in os.walk('/home/hiwonder/ActionSets'): + print(root) + print(dirs) + print(files) + files = list(map(lambda n: n[:-5], files)) + return ActionSetListResponse(action_sets=files) + + def save_actionset_cb(self, req): + with open(os.path.join('/home/hiwonder/ActionSets', req.file_name + '.json'), 'w') as f: + print(req.data) + f.write(req.data) + return [True, ''] + + def read_actionset_cb(self, req): + try: + with open(os.path.join('/home/hiwonder/ActionSets', req.file_name + '.json')) as f: + data = json.load(f) + return [True, json.dumps(data)] + except Exception as e: + return [False, str(e)] + + def remove_actionset_cb(self, req): + os.remove(os.path.join('/home/hiwonder/ActionSets', req.file_name + '.json')) + return [True, ''] + + def run_online(self, msg): + repeat = msg.repeat + action_set = json.loads(msg.data) + success = True + count = 0 + print(action_set) + for i in range(repeat): + if success: + for action in action_set['data']: + duration = action['duration'] + position = action['position'] + pwm1, pwm2 = action['pwm_servos'] + sucker = True if action['sucker'] else False + self._jetmax.set_position(position, duration) + hiwonder.pwm_servo1.set_position(pwm1, duration) + hiwonder.pwm_servo2.set_position(pwm2, duration) + if self._sucker.get_state() != sucker: + self._sucker.set_state(sucker) + rospy.sleep(duration) + if self.action_set_online.is_preempt_requested(): + rospy.loginfo('run online: Preempted') + self.action_set_online.set_preempted() + success = False + break + self.action_set_online.publish_feedback(ActionSetRawFeedback(index=i + 1, count=count)) + count += 1 + if success: + self.action_set_online.set_succeeded(ActionSetRawResult(True)) + + def _start_loop(self): + asyncio.set_event_loop(self._loop) + self._loop.run_forever() + + async def run_action_set_a(self, action_set, repeat): + for i in range(repeat): + for action in action_set['data']: + duration = action['duration'] + position = action['position'] + pwm1, pwm2 = action['pwm_servos'] + sucker = action['sucker'] + self._jetmax.set_position(position, duration) + hiwonder.pwm_servo1.set_position(pwm1, duration) + hiwonder.pwm_servo2.set_position(pwm2, duration) + self._sucker.set_state(True if sucker != 0 else False) + await asyncio.sleep(duration) + + def run_action_set(self, action_set, repeat, block=False, callback=None): + with self._lock: + self.stop_action_set() + self._running = asyncio.run_coroutine_threadsafe(self.run_action_set_a(action_set, repeat), self._loop) + if block: + self._running.result() + self._running = None + else: + if callable(callback): + self._loop.call_soon_threadsafe(self._running.add_done_callback, callback) + return self._running + + def run_action_set_str(self, action_set_str, repeat, block): + action_set = json.loads(action_set_str) + self.run_action_set(action_set, repeat, block) + + def run_action_set_file(self, path, repeat, block): + with open(path) as f: + action_set = json.load(f) + self.run_action_set(action_set, repeat, block) + + def stop_action_set(self): + with self._lock: + if self._running: + self._loop.call_soon_threadsafe(self._running.cancel) + self._running = None diff --git a/src/jetmax_buildin_funcs/jetmax_control/scripts/jetmax_control_main.py b/src/jetmax_buildin_funcs/jetmax_control/scripts/jetmax_control_main.py new file mode 100755 index 0000000..b1067ce --- /dev/null +++ b/src/jetmax_buildin_funcs/jetmax_control/scripts/jetmax_control_main.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python3 +import actionlib +import rospy +from jetmax_control.msg import Mecanum +from jetmax_control.msg import JetMax as JetMaxState +from jetmax_control.msg import SetServo, SetJoint, SetJetMax +from std_msgs.msg import UInt8, UInt16, Float32, Bool +from std_srvs.srv import Empty +import hiwonder +import threading +import action_set + + +# import jetmax_control_joystick as joystick + + +class JetMaxControl: + def __init__(self): + rospy.init_node('jetmax_control', anonymous=True) + self.pwm_servos = [hiwonder.pwm_servo1, hiwonder.pwm_servo2] + + """ + 麦轮相关的topic + """ + try: + self.chassis = hiwonder.MecanumChassis() + self.mecanum_pub = rospy.Publisher('/jetmax/mecanum/status', Mecanum, queue_size=1) + self.mecanum_sub = rospy.Subscriber('/jetmax/mecanum/command', Mecanum, + queue_size=1, + callback=lambda msg: self.chassis.set_velocity(msg.velocity, + msg.direction, + msg.angular_rate)) + except Exception: + self.chassis = None + self.mecanum_sub = None + self.mecanum_pub = None + + """ + 机械臂相关的topic + """ + self.jetmax = hiwonder.JetMax() + # 机械臂末端位置控制topic + self.jetmax_pub = rospy.Publisher('/jetmax/status', JetMaxState, queue_size=1) + self.jetmax_sub = rospy.Subscriber('/jetmax/command', SetJetMax, + queue_size=1, + callback=lambda msg: self.jetmax.set_position((msg.x, msg.y, msg.z), + msg.duration)) + # 机械臂末端带速度的位置控制 topic + self.jetmax_speed_sub = rospy.Subscriber('/jetmax/speed_command', SetJetMax, + queue_size=1, + callback=lambda msg: self.jetmax.set_position_with_speed( + (msg.x, msg.y, msg.z), max(msg.duration, 0.001))) + # 机械臂末端相对位置控制topic + self.jetmax_relative_sub = rospy.Subscriber('/jetmax/relative_command', SetJetMax, + queue_size=1, + callback=lambda msg: self.jetmax.set_position_relatively( + (msg.x, msg.y, msg.z), msg.duration)) + + self.jetmax_joint_pubs = [] + self.jetmax_joint_subs = [] + self.jetmax_servo_pubs = [] + self.jetmax_servo_subs = [] + self.jetmax_servo_speed_subs = [] + # 机械臂各个关节的topic + for i in range(1, 4): + joint_pub = rospy.Publisher('/jetmax/joint{}/status'.format(i), Float32, queue_size=1) + joint_cmd = rospy.Subscriber('/jetmax/joint{}/command'.format(i), SetJoint, + queue_size=1, + callback_args=i, + callback=lambda msg, joint_id: self.jetmax.set_joint(joint_id, + msg.data, + msg.duration)) + servo_pub = rospy.Publisher('/jetmax/servo{}/status'.format(i), UInt16, queue_size=1) + servo_cmd = rospy.Subscriber('/jetmax/servo{}/command'.format(i), SetServo, + queue_size=1, + callback_args=i, + callback=lambda msg, servo_id: self.jetmax.set_servo(servo_id, + msg.data, + msg.duration)) + servo_speed_cmd = rospy.Subscriber('/jetmax/servo{}/speed_command'.format(i), SetServo, + queue_size=1, + callback_args=i, + callback=lambda msg, servo_id: self.jetmax.set_servo_with_speed( + servo_id, + msg.data, + msg.duration)) + self.jetmax_joint_pubs.append(joint_pub) + self.jetmax_joint_subs.append(joint_cmd) + self.jetmax_servo_pubs.append(servo_pub) + self.jetmax_servo_subs.append(servo_cmd) + self.jetmax_servo_speed_subs.append(servo_speed_cmd) + + """ + 末端执行器的topic + """ + self.end_effector_servo_pubs = [] + self.end_effector_servo_subs = [] + # 末端的几个小的topic + for i in range(1, 3): + pub = rospy.Publisher('/jetmax/end_effector/servo{}/status'.format(i), UInt8, queue_size=1) + cmd = rospy.Subscriber('/jetmax/end_effector/servo{}/command'.format(i), SetServo, + queue_size=1, + callback_args=i - 1, + callback=lambda msg, servo_id: self.pwm_servos[servo_id].set_position(msg.data, + msg.duration)) + self.end_effector_servo_pubs.append(pub) + self.end_effector_servo_subs.append(cmd) + + self.sucker = hiwonder.Sucker() + # 末端吸嘴的topic + self.sucker_pub = rospy.Publisher('/jetmax/end_effector/sucker/status', Bool, queue_size=1) + self.sucker_sub = rospy.Subscriber('/jetmax/end_effector/sucker/command', Bool, + queue_size=1, + callback=lambda msg: self.sucker.set_state(msg.data)) + + # 回初始位置的topic + self.go_home_srv = rospy.Service('/jetmax/go_home', Empty, self.go_home) + self.action_set = action_set.ActionSetRunner(self.jetmax, self.sucker) + + self.rate = rospy.Rate(10) # 10hz + self.go_home() # 让机械臂回初始位置 + + def go_home(self, req=None): + self.jetmax.go_home(2) + return [] + + def update(self): + while not rospy.is_shutdown(): + """ + 更新麦轮底盘的状态 + """ + if self.chassis: + mecanum_status = Mecanum( + velocity=self.chassis.velocity, + direction=self.chassis.direction, + angular_rate=self.chassis.angular_rate + ) + self.mecanum_pub.publish(mecanum_status) + + """ + 更新末端执行器的状态 + """ + pwm_servo_states = [] + for i in range(2): + servo_state = UInt8(data=int(self.pwm_servos[i].get_position())) + self.end_effector_servo_pubs[i].publish(servo_state) + pwm_servo_states.append(servo_state) + self.sucker_pub.publish(self.sucker.get_state()) + + """ + 更新机械臂的状态 + """ + servo_states = [] + joint_states = [] + for i in range(3): + servo_state = int(self.jetmax.servos[i]) + joint_state = self.jetmax.joints[i] + self.jetmax_servo_pubs[i].publish(UInt16(data=servo_state)) + self.jetmax_joint_pubs[i].publish(Float32(data=joint_state)) + servo_states.append(servo_state) + joint_states.append(joint_state) + x, y, z = self.jetmax.position + self.jetmax_pub.publish(JetMaxState( + x=x, y=y, z=z, + joint1=joint_states[0], joint2=joint_states[1], joint3=joint_states[2], + servo1=servo_states[0], servo2=servo_states[1], servo3=servo_states[2], + pwm1=hiwonder.pwm_servo1.get_position(), pwm2=hiwonder.pwm_servo2.get_position(), + sucker=self.sucker.get_state() + )) + + self.rate.sleep() + + +if __name__ == '__main__': + jetmax = JetMaxControl() + # joystick.jetmax = jetmax.jetmax + # joystick.sucker = jetmax.sucker + try: + # threading.Thread(target=joystick.joystick_loop, daemon=True).start() + jetmax.update() + except rospy.ROSInterruptException: + pass diff --git a/src/jetmax_buildin_funcs/jetmax_control/srv/ActionSetFileOp.srv b/src/jetmax_buildin_funcs/jetmax_control/srv/ActionSetFileOp.srv new file mode 100644 index 0000000..cebfa51 --- /dev/null +++ b/src/jetmax_buildin_funcs/jetmax_control/srv/ActionSetFileOp.srv @@ -0,0 +1,5 @@ +string file_name +string data +--- +bool success +string message \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/jetmax_control/srv/ActionSetList.srv b/src/jetmax_buildin_funcs/jetmax_control/srv/ActionSetList.srv new file mode 100644 index 0000000..8a6a94c --- /dev/null +++ b/src/jetmax_buildin_funcs/jetmax_control/srv/ActionSetList.srv @@ -0,0 +1,2 @@ +--- +string[] action_sets \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/lab_config/CMakeLists.txt b/src/jetmax_buildin_funcs/lab_config/CMakeLists.txt new file mode 100644 index 0000000..39cffbb --- /dev/null +++ b/src/jetmax_buildin_funcs/lab_config/CMakeLists.txt @@ -0,0 +1,211 @@ +cmake_minimum_required(VERSION 3.0.2) +project(lab_config) + +## 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 + rospy + std_msgs + message_generation + ) + +## 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 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 + ChangeRange.srv + StashRange.srv + GetRange.srv + GetAllColorName.srv + + # 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 lab_config + # CATKIN_DEPENDS other_catkin_pkg + # DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( + # include + # ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/lab_config.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/lab_config_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_lab_config.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/jetmax_buildin_funcs/lab_config/config/lab_config.yaml b/src/jetmax_buildin_funcs/lab_config/config/lab_config.yaml new file mode 100644 index 0000000..a18c601 --- /dev/null +++ b/src/jetmax_buildin_funcs/lab_config/config/lab_config.yaml @@ -0,0 +1,73 @@ +color_range_list: + ball: + max: + - 180 + - 180 + - 150 + min: + - 0 + - 160 + - 0 + black: + max: + - 45 + - 150 + - 150 + min: + - 0 + - 100 + - 100 + blue: + max: + - 233 + - 134 + - 121 + min: + - 58 + - 88 + - 0 + green: + max: + - 255 + - 103 + - 195 + min: + - 86 + - 11 + - 15 + red: + max: + - 242 + - 255 + - 255 + min: + - 76 + - 157 + - 98 + tennis: + max: + - 255 + - 116 + - 181 + min: + - 19 + - 79 + - 140 + white: + max: + - 255 + - 155 + - 155 + min: + - 110 + - 100 + - 100 + yellow: + max: + - 255 + - 177 + - 184 + min: + - 195 + - 110 + - 146 diff --git a/src/jetmax_buildin_funcs/lab_config/config/lab_config.yaml.bak b/src/jetmax_buildin_funcs/lab_config/config/lab_config.yaml.bak new file mode 100644 index 0000000..ad6c9d3 --- /dev/null +++ b/src/jetmax_buildin_funcs/lab_config/config/lab_config.yaml.bak @@ -0,0 +1,64 @@ +color_range_list: + black: + max: + - 45 + - 150 + - 150 + min: + - 0 + - 100 + - 100 + blue: + max: + - 255 + - 172 + - 97 + min: + - 44 + - 120 + - 56 + green: + max: + - 255 + - 113 + - 154 + min: + - 45 + - 11 + - 15 + red: + max: + - 242 + - 174 + - 205 + min: + - 48 + - 151 + - 135 + tennis: + max: + - 255 + - 116 + - 181 + min: + - 19 + - 79 + - 140 + white: + max: + - 255 + - 155 + - 155 + min: + - 110 + - 100 + - 100 + yellow: + max: + - 255 + - 177 + - 184 + min: + - 195 + - 110 + - 146 diff --git a/src/jetmax_buildin_funcs/lab_config/lab.ico b/src/jetmax_buildin_funcs/lab_config/lab.ico new file mode 100644 index 0000000..9859e66 Binary files /dev/null and b/src/jetmax_buildin_funcs/lab_config/lab.ico differ diff --git a/src/jetmax_buildin_funcs/lab_config/launch/lab_config_manager.launch b/src/jetmax_buildin_funcs/lab_config/launch/lab_config_manager.launch new file mode 100644 index 0000000..4bb4b95 --- /dev/null +++ b/src/jetmax_buildin_funcs/lab_config/launch/lab_config_manager.launch @@ -0,0 +1,11 @@ + + + + + + kernel_erode: 5 + kernel_dilate: 5 + + + + \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/lab_config/package.xml b/src/jetmax_buildin_funcs/lab_config/package.xml new file mode 100644 index 0000000..947fb0c --- /dev/null +++ b/src/jetmax_buildin_funcs/lab_config/package.xml @@ -0,0 +1,59 @@ + + + lab_config + 0.0.0 + The lab_config package + + + + + ubuntu + + + + + + TODO + + + + + + + + + + + + + + + + + + + rospy + + + + + message_generation + + message_generation + + + + message_runtime + + + + + catkin + + + + + + + + diff --git a/src/jetmax_buildin_funcs/lab_config/scripts/add_color_dialog.py b/src/jetmax_buildin_funcs/lab_config/scripts/add_color_dialog.py new file mode 100644 index 0000000..b2a79a9 --- /dev/null +++ b/src/jetmax_buildin_funcs/lab_config/scripts/add_color_dialog.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'add_color_dialog.ui' +# +# Created by: PyQt5 UI code generator 5.15.2 +# +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(300, 120) + Dialog.setMinimumSize(QtCore.QSize(300, 120)) + Dialog.setMaximumSize(QtCore.QSize(300, 120)) + self.lineEdit = QtWidgets.QLineEdit(Dialog) + self.lineEdit.setGeometry(QtCore.QRect(140, 30, 120, 34)) + self.lineEdit.setObjectName("lineEdit") + self.pushButton_cancel = QtWidgets.QPushButton(Dialog) + self.pushButton_cancel.setGeometry(QtCore.QRect(30, 80, 99, 30)) + self.pushButton_cancel.setObjectName("pushButton_cancel") + self.pushButton_ok = QtWidgets.QPushButton(Dialog) + self.pushButton_ok.setGeometry(QtCore.QRect(170, 80, 99, 30)) + self.pushButton_ok.setObjectName("pushButton_ok") + self.label = QtWidgets.QLabel(Dialog) + self.label.setGeometry(QtCore.QRect(40, 36, 91, 20)) + self.label.setObjectName("label") + + self.retranslateUi(Dialog) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "新增颜色")) + self.pushButton_cancel.setText(_translate("Dialog", "取消")) + self.pushButton_ok.setText(_translate("Dialog", "确定")) + self.label.setText(_translate("Dialog", "Color Name:")) diff --git a/src/jetmax_buildin_funcs/lab_config/scripts/add_color_dialog.ui b/src/jetmax_buildin_funcs/lab_config/scripts/add_color_dialog.ui new file mode 100644 index 0000000..830ae24 --- /dev/null +++ b/src/jetmax_buildin_funcs/lab_config/scripts/add_color_dialog.ui @@ -0,0 +1,80 @@ + + + Dialog + + + + 0 + 0 + 300 + 120 + + + + + 300 + 120 + + + + + 300 + 120 + + + + 新增颜色 + + + + + 140 + 30 + 120 + 34 + + + + + + + 30 + 80 + 99 + 30 + + + + 取消 + + + + + + 170 + 80 + 99 + 30 + + + + 确定 + + + + + + 40 + 36 + 91 + 20 + + + + Color Name: + + + + + + diff --git a/src/jetmax_buildin_funcs/lab_config/scripts/lab_config_client.py b/src/jetmax_buildin_funcs/lab_config/scripts/lab_config_client.py new file mode 100755 index 0000000..eea539f --- /dev/null +++ b/src/jetmax_buildin_funcs/lab_config/scripts/lab_config_client.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 +import sys +import threading + +import rospy +from PyQt5.QtGui import QImage, QPixmap +from PyQt5.QtWidgets import QMainWindow, QApplication, QDialog, QMessageBox +from vid import VideoCapture +from lab_config_client_proxy_local import LabConfigProxy +from ui import * +import add_color_dialog +import time + + +class MainWindow(QMainWindow, Ui_Form): + def __init__(self): + super(MainWindow, self).__init__() + self.setupUi(self) + self.last_range_max = [999, 999, 999] + self.last_range_min = [999, 999, 999] + self.lab_config_proxy = LabConfigProxy() + self.org_video = VideoCapture('/usb_cam/image_raw') + self.result_video = VideoCapture('/lab_config_manager/image_result') + self.lab_config_proxy.enter_func() + + self.org_video.new_img_signal.connect(lambda frame: self.label_orign.setPixmap(QPixmap.fromImage(frame))) + self.result_video.new_img_signal.connect(lambda frame: self.label_process.setPixmap(QPixmap.fromImage(frame))) + self.comboBox_color.currentTextChanged.connect(self.set_slider_by_combobox) + self.horizontalSlider_LMax.valueChanged.connect(lambda value: self.label_LMax.setNum(value)) + self.horizontalSlider_LMin.valueChanged.connect(lambda value: self.label_LMin.setNum(value)) + self.horizontalSlider_AMax.valueChanged.connect(lambda value: self.label_AMax.setNum(value)) + self.horizontalSlider_AMin.valueChanged.connect(lambda value: self.label_AMin.setNum(value)) + self.horizontalSlider_BMax.valueChanged.connect(lambda value: self.label_BMax.setNum(value)) + self.horizontalSlider_BMin.valueChanged.connect(lambda value: self.label_BMin.setNum(value)) + self.pushButton_Apply.clicked.connect(self.apply_current_range) + self.pushButton_labWrite.clicked.connect(self.save_ranges_to_disk) + self.pushButton_AddColor.clicked.connect(self.add_color) + self.update_color_names() + self.range_update_timer = threading.Timer(0.05, self.update_current_range) + self.range_update_timer.start() + + def closeEvent(self, event): + del (self.org_video) + del (self.result_video) + self.range_update_timer.cancel() + self.lab_config_proxy.heartbeat_timer.cancel() + time.sleep(1) + + def apply_current_range(self): + rsl = self.lab_config_proxy.apply_current_range(self.comboBox_color.currentText()) + if rsl['success']: + QMessageBox.information(self, "Apply color range", "Successed!") + else: + QMessageBox.information(self, "Apply color range", "Failed") + + def save_ranges_to_disk(self): + self.lab_config_proxy.apply_current_range(self.comboBox_color.currentText()) + rsl = self.lab_config_proxy.save_ranges_to_disk() + if rsl['success']: + QMessageBox.information(self, "Save to disk", "Successed!") + else: + QMessageBox.information(self, "Save to disk", "Failed") + + def add_color(self): + dialog = QDialog() + dialog_ui = add_color_dialog.Ui_Dialog() + dialog_ui.setupUi(dialog) + + def get_color_name(): + color_name = dialog_ui.lineEdit.text() + self.lab_config_proxy.apply_current_range(color_name) + self.comboBox_color.addItem(color_name) + self.comboBox_color.setCurrentText(color_name) + dialog.close() + + dialog_ui.pushButton_ok.clicked.connect(get_color_name) + dialog_ui.pushButton_cancel.clicked.connect(dialog.close) + dialog.exec_() + + def update_current_range(self): + range_max = list((int(n) for n in (self.label_LMax.text(), self.label_AMax.text(), self.label_BMax.text()))) + range_min = list((int(n) for n in (self.label_LMin.text(), self.label_AMin.text(), self.label_BMin.text()))) + if not (range_max == self.last_range_max and range_min == self.last_range_min): + self.lab_config_proxy.set_current_range(range_min, range_max) + self.last_range_max = range_max + self.last_range_min = range_min + self.range_update_timer = threading.Timer(0.05, self.update_current_range) + self.range_update_timer.start() + + def update_color_names(self): + names = self.lab_config_proxy.get_all_color_name() + names.sort() + self.comboBox_color.addItems(names) + + def set_slider_states(self, range_min, range_max): + self.horizontalSlider_LMin.setSliderPosition(range_min[0]) + self.horizontalSlider_AMin.setSliderPosition(range_min[1]) + self.horizontalSlider_BMin.setSliderPosition(range_min[2]) + self.horizontalSlider_LMax.setSliderPosition(range_max[0]) + self.horizontalSlider_AMax.setSliderPosition(range_max[1]) + self.horizontalSlider_BMax.setSliderPosition(range_max[2]) + + def set_slider_by_combobox(self, msg): + rsl = self.lab_config_proxy.get_range_by_name(msg) + self.set_slider_states(rsl['min'], rsl['max']) + self.lab_config_proxy.set_current_range(rsl['min'], rsl['max']) + + +if __name__ == "__main__": + app = QApplication(sys.argv) + win = MainWindow() + win.show() + sys.exit(app.exec_()) diff --git a/src/jetmax_buildin_funcs/lab_config/scripts/lab_config_client_proxy_local.py b/src/jetmax_buildin_funcs/lab_config/scripts/lab_config_client_proxy_local.py new file mode 100644 index 0000000..c9f2a0c --- /dev/null +++ b/src/jetmax_buildin_funcs/lab_config/scripts/lab_config_client_proxy_local.py @@ -0,0 +1,50 @@ +import rospy +import threading +import std_srvs.srv +import lab_config.srv + + +class LabConfigProxy: + def __init__(self): + self.heartbeat_timer = None + self.node = rospy.init_node('lab_config_client', log_level=rospy.INFO) + + def heartbeat(self): + proxy = rospy.ServiceProxy('/lab_config_manager/heartbeat', std_srvs.srv.SetBool) + proxy(True) + self.heartbeat_timer = threading.Timer(2, self.heartbeat) + self.heartbeat_timer.start() + + def enter_func(self): + proxy = rospy.ServiceProxy('/lab_config_manager/enter', std_srvs.srv.Trigger) + proxy() + self.heartbeat() + + def exit_func(self): + proxy = rospy.ServiceProxy('/lab_config_manager/exit', std_srvs.srv.Trigger) + proxy() + self.heartbeat_timer.cancel() + + def get_all_color_name(self): + proxy = rospy.ServiceProxy('/lab_config_manager/get_all_color_name', lab_config.srv.GetAllColorName) + ret = proxy() + return ret.color_names + + def get_range_by_name(self, name): + proxy = rospy.ServiceProxy('/lab_config_manager/get_range', lab_config.srv.GetRange) + ret: lab_config.srv.GetRangeResponse = proxy(name) + return dict(min=list(ret.min), max=list(ret.max)) + + def set_current_range(self, range_min, range_max): + proxy = rospy.ServiceProxy('/lab_config_manager/change_range', lab_config.srv.ChangeRange) + ret = proxy(min=range_min, max=range_max) + return ret + + def apply_current_range(self, name): + proxy = rospy.ServiceProxy('/lab_config_manager/stash_range', lab_config.srv.StashRange) + ret = proxy(color_name=name) + return ret + + def save_ranges_to_disk(self): + proxy = rospy.ServiceProxy('/lab_config_manager/save_to_disk', std_srvs.srv.Trigger) + proxy() diff --git a/src/jetmax_buildin_funcs/lab_config/scripts/lab_config_manager.py b/src/jetmax_buildin_funcs/lab_config/scripts/lab_config_manager.py new file mode 100755 index 0000000..9957c85 --- /dev/null +++ b/src/jetmax_buildin_funcs/lab_config/scripts/lab_config_manager.py @@ -0,0 +1,210 @@ +#!/usr/bin/env python3 +import os +import sys +import cv2 +import rospy +import yaml +import numpy as np +from threading import RLock, Timer +from sensor_msgs.msg import Image +from std_srvs.srv import Trigger, SetBool, TriggerResponse, SetBoolResponse +from lab_config.srv import StashRange, GetRange, ChangeRange, GetAllColorName +from lab_config.srv import StashRangeResponse, GetRangeResponse, ChangeRangeResponse, GetAllColorNameResponse +from std_srvs.srv import Empty + +lock = RLock() +image_sub = None +image_pub = None +kernel_erode = 3 +kernel_dilate = 3 +color_ranges = {} +current_range = {'min': [0, 0, 0], 'max': [100, 100, 100]} +config_file_path = os.path.join(sys.path[0], "../config/lab_config.yaml") +heartbeat_timer = None +sub_ed = False + + +def image_callback(ros_image): + """ + 画面订阅回调 + :params ros_image: + """ + range_ = current_range + # 将ros图片转换为opencv格式 + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + # 缩放为 400x300 分辨率 + image_resize = cv2.resize(image, (400, 300), interpolation=cv2.INTER_NEAREST) + # 转换将lab色彩空间 + frame_result = cv2.cvtColor(image_resize, cv2.COLOR_RGB2LAB) + # 高斯滤波 + frame_result = cv2.GaussianBlur(frame_result, (3, 3), 3) + mask = cv2.inRange(frame_result, tuple(range_['min']), tuple(range_['max'])) # 对原图像和掩模进行位运算 + eroded = cv2.erode(mask, cv2.getStructuringElement(cv2.MORPH_RECT, (kernel_erode, kernel_erode))) + dilated = cv2.dilate(eroded, cv2.getStructuringElement(cv2.MORPH_RECT, (kernel_dilate, kernel_dilate))) + + # 将二值图转换为 rgb 格式来发布, 对于修改相关参数到图像的实际参数(我们给他缩放了) + rgb_image = cv2.cvtColor(dilated, cv2.COLOR_GRAY2RGB).tostring() + ros_image.data = rgb_image + ros_image.height = 300 + ros_image.width = 400 + ros_image.step = ros_image.width * 3 + image_pub.publish(ros_image) + + +def enter_func(msg): + rospy.loginfo(msg) + global lock, image_sub, sub_ed + with lock: + if not sub_ed: + image_sub = rospy.Subscriber('/usb_cam/image_raw', Image, image_callback) + sub_ed = True + rospy.ServiceProxy('/usb_cam/start_capture', Empty)() + return [True, ''] + + +def exit_func(msg): + rospy.loginfo(msg) + global lock, image_sub, sub_ed + with lock: + try: + image_sub.unregister() + sub_ed = False + except: + pass + + return [True, ''] + + + +def set_running(msg): + rospy.loginfo(msg) + return [True, 'set_running'] + + +""" +将当前的所有颜色阈值列表存储到文件中 +""" +def save_to_disk_srv_cb(msg): + rospy.loginfo(msg) + global lock, color_ranges + + with lock: + cf = {"color_range_list": color_ranges.copy()} + rospy.loginfo(cf) + s = yaml.dump(cf, default_flow_style=False) + with open(config_file_path, 'w') as f: + f.write(s) + rsp = TriggerResponse() + rsp.success = True + + return rsp + +""" +通过颜色名称获取阈值范围 +""" +def get_range_srv_cb(msg): + rospy.loginfo(msg) + global lock, color_ranges + + ranges = rospy.get_param('~color_range_list', color_ranges) + rsp = GetRangeResponse() + if msg.color_name in ranges: + rsp.success = True + rsp.min = ranges[msg.color_name]['min'] + rsp.max = ranges[msg.color_name]['max'] + else: + rsp.success = False + with lock: + color_ranges = ranges + + return rsp + + +""" +改变当前的阈值范围 +""" +def change_range_srv_cb(msg): + rospy.loginfo(msg) + global current_range + + with lock: + current_range = dict(min=list(msg.min), max=list(msg.max)) + rsp = ChangeRangeResponse() + rsp.success = True + + return rsp + + +""" +将当前的阈值范围保存为参数服务器中指定颜色名称的阈值 +""" +def stash_range_srv_cb(msg): + rospy.loginfo(msg) + global lock, color_ranges, current_range + + ranges = rospy.get_param('~color_range_list', color_ranges) + with lock: + ranges[msg.color_name] = current_range.copy() + rospy.set_param('~color_range_list', ranges) + color_ranges = ranges + rsp = StashRangeResponse() + rsp.success = True + + return rsp + +""" +获取当前存在的所有颜色阈值范围的颜色名称 +""" +def get_all_color_name_srv_cb(msg): + rospy.loginfo(msg) + global lock, color_ranges, current_range + ranges = rospy.get_param('~color_range_list', color_ranges) + color_names = list(ranges.keys()) + return GetAllColorNameResponse(color_names=color_names) + +def heartbeat_timeout_cb(): + rospy.loginfo("heartbeat timeout. exiting...") + rospy.ServiceProxy('/lab_config_manager/exit', Trigger)() + +def heartbeat_srv_cb(msg): + rospy.loginfo(msg) + global heartbeat_timer + if isinstance(heartbeat_timer, Timer): + heartbeat_timer.cancel() + rospy.logdebug("Heartbeat") + if msg.data: + heartbeat_timer = Timer(5, heartbeat_timeout_cb) + heartbeat_timer.start() + else: + if isinstance(heartbeat_timer, Timer): + heartbeat_timer.cancel() + return SetBoolResponse(success=True) + + +if __name__ == '__main__': + rospy.init_node('lab_config_manager', log_level=rospy.DEBUG) + color_ranges = rospy.get_param('~color_range_list', {}) + kernel_erode = rospy.get_param('~kernel_erode', 3) + kernel_dilate = rospy.get_param('~kernel_dilate', 3) + config_file_path = rospy.get_param('~config_file_path', config_file_path) + + if 'red' in color_ranges: + current_range = color_ranges['red'] + + image_pub = rospy.Publisher('/lab_config_manager/image_result', Image, queue_size=1) + enter_srv = rospy.Service('/lab_config_manager/enter', Trigger, enter_func) + exit_srv = rospy.Service('/lab_config_manager/exit', Trigger, exit_func) + running_srv = rospy.Service('/lab_config_manager/set_running', SetBool, set_running) + + save_to_disk_srv = rospy.Service('lab_config_manager/save_to_disk', Trigger, save_to_disk_srv_cb) + get_color_range_srv = rospy.Service('lab_config_manager/get_range', GetRange, get_range_srv_cb) + change_range_srv = rospy.Service('lab_config_manager/change_range', ChangeRange, change_range_srv_cb) + stash_range_srv = rospy.Service('lab_config_manager/stash_range', StashRange, stash_range_srv_cb) + get_all_color_name_srv = rospy.Service('/lab_config_manager/get_all_color_name', GetAllColorName, + get_all_color_name_srv_cb) + heartbeat_srv = rospy.Service('lab_config_manager/heartbeat', SetBool, heartbeat_srv_cb) + + try: + rospy.spin() + except KeyboardInterrupt: + print("Shutting down") diff --git a/src/jetmax_buildin_funcs/lab_config/scripts/ui.py b/src/jetmax_buildin_funcs/lab_config/scripts/ui.py new file mode 100644 index 0000000..74c2ed6 --- /dev/null +++ b/src/jetmax_buildin_funcs/lab_config/scripts/ui.py @@ -0,0 +1,237 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'ui.ui' +# +# Created by: PyQt5 UI code generator 5.15.2 +# +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.setWindowModality(QtCore.Qt.NonModal) + Form.setEnabled(True) + Form.resize(950, 620) + Form.setMinimumSize(QtCore.QSize(0, 0)) + Form.setMaximumSize(QtCore.QSize(950, 620)) + font = QtGui.QFont() + font.setFamily("Arial") + font.setPointSize(11) + Form.setFont(font) + Form.setFocusPolicy(QtCore.Qt.NoFocus) + Form.setContextMenuPolicy(QtCore.Qt.NoContextMenu) + Form.setAcceptDrops(False) + Form.setAutoFillBackground(False) + Form.setStyleSheet("background-color: rgb(255, 255, 255);") + self.tabWidget = QtWidgets.QTabWidget(Form) + self.tabWidget.setGeometry(QtCore.QRect(0, 10, 950, 600)) + font = QtGui.QFont() + font.setFamily("黑体") + font.setPointSize(12) + self.tabWidget.setFont(font) + self.tabWidget.setObjectName("tabWidget") + self.tab = QtWidgets.QWidget() + self.tab.setObjectName("tab") + self.label_8 = QtWidgets.QLabel(self.tab) + self.label_8.setGeometry(QtCore.QRect(620, 10, 141, 31)) + font = QtGui.QFont() + font.setFamily("黑体") + font.setPointSize(16) + self.label_8.setFont(font) + self.label_8.setAlignment(QtCore.Qt.AlignCenter) + self.label_8.setObjectName("label_8") + self.widget_12 = QtWidgets.QWidget(self.tab) + self.widget_12.setGeometry(QtCore.QRect(40, 380, 385, 161)) + self.widget_12.setStyleSheet("#widget_12 {border:1px solid #242424;\n" +"border-color: rgb(200, 200, 200);}") + self.widget_12.setObjectName("widget_12") + self.label_25 = QtWidgets.QLabel(self.widget_12) + self.label_25.setGeometry(QtCore.QRect(5, 30, 15, 31)) + font = QtGui.QFont() + font.setFamily("黑体") + font.setPointSize(14) + self.label_25.setFont(font) + self.label_25.setAlignment(QtCore.Qt.AlignCenter) + self.label_25.setObjectName("label_25") + self.label_26 = QtWidgets.QLabel(self.widget_12) + self.label_26.setGeometry(QtCore.QRect(5, 80, 15, 31)) + font = QtGui.QFont() + font.setFamily("黑体") + font.setPointSize(14) + self.label_26.setFont(font) + self.label_26.setAlignment(QtCore.Qt.AlignCenter) + self.label_26.setObjectName("label_26") + self.label_27 = QtWidgets.QLabel(self.widget_12) + self.label_27.setGeometry(QtCore.QRect(5, 133, 15, 21)) + font = QtGui.QFont() + font.setFamily("黑体") + font.setPointSize(14) + self.label_27.setFont(font) + self.label_27.setAlignment(QtCore.Qt.AlignCenter) + self.label_27.setObjectName("label_27") + self.horizontalSlider_LMin = QtWidgets.QSlider(self.widget_12) + self.horizontalSlider_LMin.setGeometry(QtCore.QRect(20, 35, 169, 22)) + self.horizontalSlider_LMin.setMaximum(255) + self.horizontalSlider_LMin.setPageStep(1) + self.horizontalSlider_LMin.setOrientation(QtCore.Qt.Horizontal) + self.horizontalSlider_LMin.setObjectName("horizontalSlider_LMin") + self.horizontalSlider_AMin = QtWidgets.QSlider(self.widget_12) + self.horizontalSlider_AMin.setGeometry(QtCore.QRect(20, 85, 169, 22)) + self.horizontalSlider_AMin.setMaximum(255) + self.horizontalSlider_AMin.setPageStep(1) + self.horizontalSlider_AMin.setOrientation(QtCore.Qt.Horizontal) + self.horizontalSlider_AMin.setObjectName("horizontalSlider_AMin") + self.horizontalSlider_BMin = QtWidgets.QSlider(self.widget_12) + self.horizontalSlider_BMin.setGeometry(QtCore.QRect(20, 135, 169, 22)) + self.horizontalSlider_BMin.setMaximum(255) + self.horizontalSlider_BMin.setPageStep(1) + self.horizontalSlider_BMin.setOrientation(QtCore.Qt.Horizontal) + self.horizontalSlider_BMin.setObjectName("horizontalSlider_BMin") + self.label_LMin = QtWidgets.QLabel(self.widget_12) + self.label_LMin.setGeometry(QtCore.QRect(80, 10, 51, 20)) + font = QtGui.QFont() + font.setFamily("黑体") + font.setPointSize(14) + self.label_LMin.setFont(font) + self.label_LMin.setAlignment(QtCore.Qt.AlignCenter) + self.label_LMin.setObjectName("label_LMin") + self.label_AMin = QtWidgets.QLabel(self.widget_12) + self.label_AMin.setGeometry(QtCore.QRect(80, 60, 51, 21)) + font = QtGui.QFont() + font.setFamily("黑体") + font.setPointSize(14) + self.label_AMin.setFont(font) + self.label_AMin.setAlignment(QtCore.Qt.AlignCenter) + self.label_AMin.setObjectName("label_AMin") + self.label_BMin = QtWidgets.QLabel(self.widget_12) + self.label_BMin.setGeometry(QtCore.QRect(80, 110, 51, 21)) + font = QtGui.QFont() + font.setFamily("黑体") + font.setPointSize(14) + self.label_BMin.setFont(font) + self.label_BMin.setAlignment(QtCore.Qt.AlignCenter) + self.label_BMin.setObjectName("label_BMin") + self.horizontalSlider_LMax = QtWidgets.QSlider(self.widget_12) + self.horizontalSlider_LMax.setGeometry(QtCore.QRect(210, 35, 169, 22)) + self.horizontalSlider_LMax.setMaximum(255) + self.horizontalSlider_LMax.setPageStep(1) + self.horizontalSlider_LMax.setProperty("value", 255) + self.horizontalSlider_LMax.setOrientation(QtCore.Qt.Horizontal) + self.horizontalSlider_LMax.setObjectName("horizontalSlider_LMax") + self.horizontalSlider_AMax = QtWidgets.QSlider(self.widget_12) + self.horizontalSlider_AMax.setGeometry(QtCore.QRect(210, 85, 169, 22)) + self.horizontalSlider_AMax.setMaximum(255) + self.horizontalSlider_AMax.setPageStep(1) + self.horizontalSlider_AMax.setProperty("value", 255) + self.horizontalSlider_AMax.setOrientation(QtCore.Qt.Horizontal) + self.horizontalSlider_AMax.setObjectName("horizontalSlider_AMax") + self.horizontalSlider_BMax = QtWidgets.QSlider(self.widget_12) + self.horizontalSlider_BMax.setGeometry(QtCore.QRect(210, 135, 169, 22)) + self.horizontalSlider_BMax.setMaximum(255) + self.horizontalSlider_BMax.setPageStep(1) + self.horizontalSlider_BMax.setProperty("value", 255) + self.horizontalSlider_BMax.setOrientation(QtCore.Qt.Horizontal) + self.horizontalSlider_BMax.setObjectName("horizontalSlider_BMax") + self.label_LMax = QtWidgets.QLabel(self.widget_12) + self.label_LMax.setGeometry(QtCore.QRect(270, 10, 51, 20)) + font = QtGui.QFont() + font.setFamily("黑体") + font.setPointSize(14) + self.label_LMax.setFont(font) + self.label_LMax.setAlignment(QtCore.Qt.AlignCenter) + self.label_LMax.setObjectName("label_LMax") + self.label_AMax = QtWidgets.QLabel(self.widget_12) + self.label_AMax.setGeometry(QtCore.QRect(270, 60, 51, 20)) + font = QtGui.QFont() + font.setFamily("黑体") + font.setPointSize(14) + self.label_AMax.setFont(font) + self.label_AMax.setAlignment(QtCore.Qt.AlignCenter) + self.label_AMax.setObjectName("label_AMax") + self.label_BMax = QtWidgets.QLabel(self.widget_12) + self.label_BMax.setGeometry(QtCore.QRect(270, 110, 51, 20)) + font = QtGui.QFont() + font.setFamily("黑体") + font.setPointSize(14) + self.label_BMax.setFont(font) + self.label_BMax.setAlignment(QtCore.Qt.AlignCenter) + self.label_BMax.setObjectName("label_BMax") + self.widget_15 = QtWidgets.QWidget(self.tab) + self.widget_15.setGeometry(QtCore.QRect(450, 380, 85, 161)) + self.widget_15.setStyleSheet("#widget_15 {border:1px solid #242424;\n" +"border-color: rgb(200, 200, 200);}") + self.widget_15.setObjectName("widget_15") + self.comboBox_color = QtWidgets.QComboBox(self.widget_15) + self.comboBox_color.setGeometry(QtCore.QRect(7, 10, 69, 22)) + self.comboBox_color.setObjectName("comboBox_color") + self.pushButton_labWrite = QtWidgets.QPushButton(self.widget_15) + self.pushButton_labWrite.setGeometry(QtCore.QRect(5, 83, 75, 30)) + font = QtGui.QFont() + font.setFamily("黑体") + font.setPointSize(14) + self.pushButton_labWrite.setFont(font) + self.pushButton_labWrite.setStyleSheet("QPushButton{background-color: rgb(255, 165, 0);}\n" +"QPushButton:hover{background-color: rgb(255, 210, 0);}\n" +"QPushButton{border-radius:5px;}") + self.pushButton_labWrite.setObjectName("pushButton_labWrite") + self.pushButton_Apply = QtWidgets.QPushButton(self.widget_15) + self.pushButton_Apply.setGeometry(QtCore.QRect(5, 43, 75, 30)) + font = QtGui.QFont() + font.setFamily("黑体") + font.setPointSize(14) + self.pushButton_Apply.setFont(font) + self.pushButton_Apply.setStyleSheet("QPushButton{background-color: rgb(255, 165, 0);}\n" +"QPushButton:hover{background-color: rgb(255, 210, 0);}\n" +"QPushButton{border-radius:5px;}") + self.pushButton_Apply.setObjectName("pushButton_Apply") + self.pushButton_AddColor = QtWidgets.QPushButton(self.widget_15) + self.pushButton_AddColor.setGeometry(QtCore.QRect(5, 123, 75, 30)) + font = QtGui.QFont() + font.setFamily("黑体") + font.setPointSize(14) + self.pushButton_AddColor.setFont(font) + self.pushButton_AddColor.setStyleSheet("QPushButton{background-color: rgb(255, 165, 0);}\n" +"QPushButton:hover{background-color: rgb(255, 210, 0);}\n" +"QPushButton{border-radius:5px;}") + self.pushButton_AddColor.setObjectName("pushButton_AddColor") + self.label_process = QtWidgets.QLabel(self.tab) + self.label_process.setGeometry(QtCore.QRect(50, 50, 400, 300)) + self.label_process.setText("") + self.label_process.setObjectName("label_process") + self.label_orign = QtWidgets.QLabel(self.tab) + self.label_orign.setGeometry(QtCore.QRect(500, 50, 400, 300)) + self.label_orign.setText("") + self.label_orign.setObjectName("label_orign") + self.widget_15.raise_() + self.widget_12.raise_() + self.label_8.raise_() + self.label_process.raise_() + self.label_orign.raise_() + self.tabWidget.addTab(self.tab, "") + + self.retranslateUi(Form) + self.tabWidget.setCurrentIndex(0) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "LAB_Tool 1.0")) + self.label_8.setText(_translate("Form", "400x300")) + self.label_25.setText(_translate("Form", "L")) + self.label_26.setText(_translate("Form", "A")) + self.label_27.setText(_translate("Form", "B")) + self.label_LMin.setText(_translate("Form", "0")) + self.label_AMin.setText(_translate("Form", "0")) + self.label_BMin.setText(_translate("Form", "0")) + self.label_LMax.setText(_translate("Form", "255")) + self.label_AMax.setText(_translate("Form", "255")) + self.label_BMax.setText(_translate("Form", "255")) + self.pushButton_labWrite.setText(_translate("Form", "Save")) + self.pushButton_Apply.setText(_translate("Form", "Apply")) + self.pushButton_AddColor.setText(_translate("Form", "Add")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("Form", "Camera")) diff --git a/src/jetmax_buildin_funcs/lab_config/scripts/ui.ui b/src/jetmax_buildin_funcs/lab_config/scripts/ui.ui new file mode 100644 index 0000000..8f4e712 --- /dev/null +++ b/src/jetmax_buildin_funcs/lab_config/scripts/ui.ui @@ -0,0 +1,566 @@ + + + Form + + + Qt::NonModal + + + true + + + + 0 + 0 + 950 + 620 + + + + + 0 + 0 + + + + + 950 + 620 + + + + + Arial + 11 + + + + Qt::NoFocus + + + Qt::NoContextMenu + + + false + + + LAB_Tool 1.0 + + + false + + + background-color: rgb(255, 255, 255); + + + + + 0 + 10 + 950 + 600 + + + + + 黑体 + 12 + + + + 0 + + + + Camera + + + + + 620 + 10 + 141 + 31 + + + + + 黑体 + 16 + + + + 400x300 + + + Qt::AlignCenter + + + + + + 40 + 380 + 385 + 161 + + + + #widget_12 {border:1px solid #242424; +border-color: rgb(200, 200, 200);} + + + + + 5 + 30 + 15 + 31 + + + + + 黑体 + 14 + + + + L + + + Qt::AlignCenter + + + + + + 5 + 80 + 15 + 31 + + + + + 黑体 + 14 + + + + A + + + Qt::AlignCenter + + + + + + 5 + 133 + 15 + 21 + + + + + 黑体 + 14 + + + + B + + + Qt::AlignCenter + + + + + + 20 + 35 + 169 + 22 + + + + 255 + + + 1 + + + Qt::Horizontal + + + + + + 20 + 85 + 169 + 22 + + + + 255 + + + 1 + + + Qt::Horizontal + + + + + + 20 + 135 + 169 + 22 + + + + 255 + + + 1 + + + Qt::Horizontal + + + + + + 80 + 10 + 51 + 20 + + + + + 黑体 + 14 + + + + 0 + + + Qt::AlignCenter + + + + + + 80 + 60 + 51 + 21 + + + + + 黑体 + 14 + + + + 0 + + + Qt::AlignCenter + + + + + + 80 + 110 + 51 + 21 + + + + + 黑体 + 14 + + + + 0 + + + Qt::AlignCenter + + + + + + 210 + 35 + 169 + 22 + + + + 255 + + + 1 + + + 255 + + + Qt::Horizontal + + + + + + 210 + 85 + 169 + 22 + + + + 255 + + + 1 + + + 255 + + + Qt::Horizontal + + + + + + 210 + 135 + 169 + 22 + + + + 255 + + + 1 + + + 255 + + + Qt::Horizontal + + + + + + 270 + 10 + 51 + 20 + + + + + 黑体 + 14 + + + + 255 + + + Qt::AlignCenter + + + + + + 270 + 60 + 51 + 20 + + + + + 黑体 + 14 + + + + 255 + + + Qt::AlignCenter + + + + + + 270 + 110 + 51 + 20 + + + + + 黑体 + 14 + + + + 255 + + + Qt::AlignCenter + + + + + + + 450 + 380 + 85 + 161 + + + + #widget_15 {border:1px solid #242424; +border-color: rgb(200, 200, 200);} + + + + + 7 + 10 + 69 + 22 + + + + + + + 5 + 83 + 75 + 30 + + + + + 黑体 + 14 + + + + QPushButton{background-color: rgb(255, 165, 0);} +QPushButton:hover{background-color: rgb(255, 210, 0);} +QPushButton{border-radius:5px;} + + + Save + + + + + + 5 + 43 + 75 + 30 + + + + + 黑体 + 14 + + + + QPushButton{background-color: rgb(255, 165, 0);} +QPushButton:hover{background-color: rgb(255, 210, 0);} +QPushButton{border-radius:5px;} + + + Apply + + + + + + 5 + 123 + 75 + 30 + + + + + 黑体 + 14 + + + + QPushButton{background-color: rgb(255, 165, 0);} +QPushButton:hover{background-color: rgb(255, 210, 0);} +QPushButton{border-radius:5px;} + + + Add + + + + + + + 50 + 50 + 400 + 300 + + + + + + + + + + 500 + 50 + 400 + 300 + + + + + + + widget_15 + widget_12 + label_8 + label_process + label_orign + + + + + + diff --git a/src/jetmax_buildin_funcs/lab_config/scripts/vid.py b/src/jetmax_buildin_funcs/lab_config/scripts/vid.py new file mode 100644 index 0000000..eef2e56 --- /dev/null +++ b/src/jetmax_buildin_funcs/lab_config/scripts/vid.py @@ -0,0 +1,22 @@ +from PyQt5.QtCore import pyqtSignal, QObject +from PyQt5.QtGui import QImage, QPixmap +import rospy +import numpy as np +from sensor_msgs.msg import Image + + +class VideoCapture(QObject): + new_img_signal = pyqtSignal(QImage) + + def __init__(self, path): + super(VideoCapture, self).__init__() + self.path = path + self.image_sub = rospy.Subscriber(self.path, Image, self.image_callback) + + def __del__(self): + self.image_sub.unregister() + + def image_callback(self, ros_image): + frame = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + img = QImage(frame.data, ros_image.width, ros_image.height, QImage.Format_RGB888).scaled(320, 240) + self.new_img_signal.emit(img) diff --git a/src/jetmax_buildin_funcs/lab_config/srv/ChangeRange.srv b/src/jetmax_buildin_funcs/lab_config/srv/ChangeRange.srv new file mode 100644 index 0000000..52940dc --- /dev/null +++ b/src/jetmax_buildin_funcs/lab_config/srv/ChangeRange.srv @@ -0,0 +1,5 @@ +int16[] min +int16[] max +--- +bool success +string message \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/lab_config/srv/GetAllColorName.srv b/src/jetmax_buildin_funcs/lab_config/srv/GetAllColorName.srv new file mode 100644 index 0000000..94443e0 --- /dev/null +++ b/src/jetmax_buildin_funcs/lab_config/srv/GetAllColorName.srv @@ -0,0 +1,2 @@ +--- +string[] color_names \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/lab_config/srv/GetRange.srv b/src/jetmax_buildin_funcs/lab_config/srv/GetRange.srv new file mode 100644 index 0000000..ca87564 --- /dev/null +++ b/src/jetmax_buildin_funcs/lab_config/srv/GetRange.srv @@ -0,0 +1,5 @@ +string color_name +--- +bool success +int16[] min +int16[] max \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/lab_config/srv/StashRange.srv b/src/jetmax_buildin_funcs/lab_config/srv/StashRange.srv new file mode 100644 index 0000000..6bcd7fc --- /dev/null +++ b/src/jetmax_buildin_funcs/lab_config/srv/StashRange.srv @@ -0,0 +1,4 @@ +string color_name +--- +bool success +string message diff --git a/src/jetmax_buildin_funcs/object_tracking/CMakeLists.txt b/src/jetmax_buildin_funcs/object_tracking/CMakeLists.txt new file mode 100644 index 0000000..f855f06 --- /dev/null +++ b/src/jetmax_buildin_funcs/object_tracking/CMakeLists.txt @@ -0,0 +1,206 @@ +cmake_minimum_required(VERSION 3.0.2) +project(object_tracking) + +## 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 + message_generation + rospy + std_msgs + std_srvs + ) + +## 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 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 + SetTarget.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 +) + +################################################ +## 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 object_tracking + # CATKIN_DEPENDS messages_generation rospy std_msgs std_srvs + # DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( + # include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/object_tracking.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/object_tracking_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_object_tracking.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/jetmax_buildin_funcs/object_tracking/package.xml b/src/jetmax_buildin_funcs/object_tracking/package.xml new file mode 100644 index 0000000..d2f52dc --- /dev/null +++ b/src/jetmax_buildin_funcs/object_tracking/package.xml @@ -0,0 +1,71 @@ + + + object_tracking + 0.0.0 + The object_tracking package + + + + + lucas + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + message_generation + rospy + std_msgs + std_srvs + message_generation + rospy + std_msgs + std_srvs + message_generation + rospy + std_msgs + std_srvs + + + + + + + + diff --git a/src/jetmax_buildin_funcs/object_tracking/scripts/object_tracking_main.py b/src/jetmax_buildin_funcs/object_tracking/scripts/object_tracking_main.py new file mode 100755 index 0000000..ef02db8 --- /dev/null +++ b/src/jetmax_buildin_funcs/object_tracking/scripts/object_tracking_main.py @@ -0,0 +1,453 @@ +#!/usr/bin/env python3 +import math +import rospy +import time +import queue +import threading +from sensor_msgs.msg import Image +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from std_srvs.srv import Empty +from object_tracking.srv import SetTarget, SetTargetResponse, SetTargetRequest +import cv2 +import numpy as np +import hiwonder +import sys + +# 人脸识别需要的库 +sys.path.append("/home/hiwonder/tensorrt_demos") +from utils.mtcnn import TrtMtcnn + +mtcnn = TrtMtcnn() # mtcnn 人脸识别网络实例画 + +image_queue = queue.Queue(maxsize=3) # 图像队列 + +ROS_NODE_NAME = 'object_tracking' +DEFAULT_X, DEFAULT_Y, DEFAULT_Z = 0, 138 + 8.14, 84 + 128.4 +TARGET_PIXEL_X, TARGET_PIXEL_Y = 320, 240 + + + +class ObjectTracking: + def __init__(self): + self.image_sub = None + self.heartbeat_timer = None + self.lock = threading.RLock() + self.servo_x = 500 + self.servo_y = 500 + + # 人脸追踪 pid + self.face_x_pid = hiwonder.PID(0.09, 0.01, 0.015) + self.face_z_pid = hiwonder.PID(0.16, 0.0, 0.0) + + # 颜色追踪 pid + self.color_x_pid = hiwonder.PID(0.07, 0.01, 0.0015) + self.color_y_pid = hiwonder.PID(0.08, 0.008, 0.001) + + self.tracking_face = None + self.no_face_count = 0 + + self.target_color_range = None + self.target_color_name = None + self.last_color_circle = None + self.lost_target_count = 0 + + self.is_running_color = False + self.is_running_face = False + + self.fps = 0.0 + self.tic = time.time() + + """ + 重置变量 + """ + def reset(self): + self.tracking_face = None + self.image_sub = None + self.heartbeat_timer = None + self.tracking_face_encoding = None + self.no_face_count = 0 + self.servo_x = 500 + self.servo_y = 500 + + self.last_color_circle = None + self.lost_target_count = 0 + + self.is_running_color = False + self.is_running_face = False + + self.tic = time.time() + + +# 识别及机械臂操作的接口对象 +state = ObjectTracking() +jetmax = hiwonder.JetMax() +sucker = hiwonder.Sucker() + + +# 初始化, 机械臂回初位 +def init(): + state.reset() + sucker.set_state(False) + jetmax.go_home(1) + +""" +总的图像处理函数 +会根据设置状态决定人脸追踪还是颜色追踪 +这个函数会在while循环中调用, 而不是直接被ros topic 的回调触发是因为 pycuda 要求相关调用必须在同一个线程中 +所以 ros topic 回调只会将接收到的图片放入一个队列而不会直接处理图片。 image_proc 会循环处理该队列 +""" +def image_proc(): + # 从队列中获取新的图像 + ros_image = image_queue.get(block=True) + # 将ros图像转换为opencv图像 + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + if state.is_running_face: + image = face_tracking(image) # 人脸追踪 + elif state.is_running_color: + image = color_tracking(image) # 颜色追踪 + else: + pass + # 计算帧率 + toc = time.time() + curr_fps = 1.0 / (state.tic - toc) + state.fps = curr_fps if state.fps == 0.0 else (state.fps * 0.95 + curr_fps * 0.05) + state.tic = toc + # 发布结果图像 + rgb_image = image.tostring() + ros_image.data = rgb_image + image_pub.publish(ros_image) + + +def color_tracking(image): + org_image = np.copy(image) + image = cv2.resize(image, (320, 240)) # 缩放一下减少计算量 + image = cv2.cvtColor(image, cv2.COLOR_RGB2LAB) # RGB转LAB空间 + image = cv2.GaussianBlur(image, (5, 5), 5) + + with state.lock: + target_color_range = state.target_color_range + target_color_name = state.target_color_name + + if target_color_range is not None: + mask = cv2.inRange(image, tuple(target_color_range['min']), tuple(target_color_range['max'])) # 二值化 + eroded = cv2.erode(mask, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) # 腐蚀 + dilated = cv2.dilate(eroded, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) # 膨胀 + contours = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] # 找出轮廓 + contour_area = map(lambda c: (c, math.fabs(cv2.contourArea(c))), contours) # 计算各个轮廓的面积 + contour_area = list(filter(lambda c: c[1] > 200, contour_area)) # 剔除面积过小的轮廓 + circle = None + + if len(contour_area) > 0: + # 上一帧没有识别到色块 + if state.last_color_circle is None: + contour, area = max(contour_area, key=lambda c_a: c_a[1]) + circle = cv2.minEnclosingCircle(contour) # 最小外接圆 + else: + # 上一帧有识别到色块 + (last_x, last_y), last_r = state.last_color_circle + # 计算新的色块与旧色块的中心距离, 如果太大就认为误识别。放弃这次结果当没有识别到 + circles = map(lambda c: cv2.minEnclosingCircle(c[0]), contour_area) + circle_dist = list(map(lambda c: (c, math.sqrt(((c[0][0] - last_x) ** 2) + ((c[0][1] - last_y) ** 2))), + circles)) + circle, dist = min(circle_dist, key=lambda c: c[1]) + if dist < 50: + circle = circle + + if circle is not None: + state.lost_target_count = 0 + (c_x, c_y), c_r = circle + # 将识别到的坐标重新映射回原始图像大小 + c_x = hiwonder.misc.val_map(c_x, 0, 320, 0, 640) + c_y = hiwonder.misc.val_map(c_y, 0, 240, 0, 480) + c_r = hiwonder.misc.val_map(c_r, 0, 320, 0, 640) + + # x 轴 pid 更新 + x = c_x - TARGET_PIXEL_X + if abs(x) > 30: # 误差在一定范围内就认为到达 + state.color_x_pid.SetPoint = 0 + state.color_x_pid.update(x) + state.servo_x += state.color_x_pid.output + else: + state.color_x_pid.update(0) + + # y 轴 pid 更新 + y = c_y - TARGET_PIXEL_Y + if abs(y) > 30: # 误差在一定范围内就认为到达 + state.color_y_pid.SetPoint = 0 + state.color_y_pid.update(y) + state.servo_y -= state.color_y_pid.output + else: + state.color_y_pid.update(0) + # 对舵机范围做限制 + if state.servo_y < 350: + state.servo_y = 350 + if state.servo_y > 650: + state.servo_y = 650 + + # 执行新的目标位置 + jetmax.set_servo(1, int(state.servo_x), duration=0.02) + jetmax.set_servo(2, int(state.servo_y), duration=0.02) + color_name = target_color_name.upper() + # 画面显示识别结果 + org_image = cv2.circle(org_image, (int(c_x), int(c_y)), int(c_r), hiwonder.COLORS[color_name], 3) + state.last_color_circle = circle + else: + # 超过一定次数没有识别到就清理标志重新识别 + state.lost_target_count += 1 + if state.lost_target_count > 15: + state.lost_target_count = 0 + state.last_color_circle = None + return org_image + +""" +画面中显示人脸 +并返回人脸识别到的相关坐标在原图上的对应坐标 +""" +def show_faces(img, boxes, landmarks, color): + new_boxes = [] + new_landmarks = [] + for bb, ll in zip(boxes, landmarks): + # 将坐标映射回原图坐标 + x1 = int(hiwonder.misc.val_map(bb[0], 0, 400, 0, 640)) + y1 = int(hiwonder.misc.val_map(bb[1], 0, 300, 0, 480)) + x2 = int(hiwonder.misc.val_map(bb[2], 0, 400, 0, 640)) + y2 = int(hiwonder.misc.val_map(bb[3], 0, 300, 0, 480)) + # 画出 外框 + cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) + new_boxes.append([x1, y1, x2, y2]) + landmarks_curr_face = [] + if len(landmarks): + # 画出关键点 + for j in range(5): + # 将坐标映射回原图坐标 + lx = int(hiwonder.misc.val_map(ll[j], 0, 400, 0, 640)) + ly = int(hiwonder.misc.val_map(ll[j + 5], 0, 300, 0, 480)) + cv2.circle(img, (lx, ly), 2, color, 2) + landmarks_curr_face.append([lx, ly]) + new_landmarks.append(landmarks_curr_face) + return img, new_boxes, new_landmarks + + +def face_tracking(image): + global mtcnn + ta = time.time() + org_img = np.copy(image) + image = cv2.resize(image, (400, 300)) # 缩放一下减少计算量 + + boxes, landmarks = mtcnn.detect(image, minsize=40) # 调用 mtcnn 进行人脸识别 + org_img, boxes, landmarks = show_faces(org_img, boxes, landmarks, (0, 255, 0)) # 显示人脸 + + # 上一帧没有识别到人脸 + if state.tracking_face is None: + if len(boxes) > 0: # 如果识别到人脸就找出距离画面中心最近的人脸来追踪 + box = min(boxes, key=lambda b: math.sqrt(((b[2] + b[0]) / 2 - 320) ** 2 + ((b[3] + b[1]) / 2 - 240) ** 2)) + x1, y1, x2, y2 = box + # 用红色单独画出要追踪的人脸 + org_img = cv2.rectangle(org_img, (x1, y1), (x2, y2), (255, 0, 0), 3) + center_x, center_y = int((x1 + x2) / 2), int((y1 + y2) / 2) + org_img = cv2.circle(org_img, (center_x, center_y), 2, (0, 255, 0), 4) + # 记录要追踪的人脸的坐标 + state.tracking_face = center_x, center_y + state.no_face_count = time.time() + 2 + # 清理pid控制器 + state.face_x_pid.clear() + state.face_z_pid.clear() + else: # 上一帧识别到了人脸 + # 计算所有识别到的人脸的中心坐标 + centers = [(int((box[2] + box[0]) / 2), int((box[3] + box[1]) / 2), box) for box in boxes] + get_face = False + # 找出距离上一帧识别到的人脸最近的人脸 + if len(centers) > 0: + center_x, center_y = state.tracking_face + org_img = cv2.circle(org_img, (center_x, center_y), 2, (0, 0, 255), 4) + min_dist_center = min(centers, key=lambda c: math.sqrt((c[0] - center_x) ** 2 + (c[1] - center_y) ** 2)) + new_center_x, new_center_y, box = min_dist_center + x1, y1, x2, y2 = box + dist = math.sqrt((new_center_x - center_x) ** 2 + (new_center_y - center_y) ** 2) + # 像素距离小于一定值才认为是同一张人脸, 超过就当没识别到 + if dist < 150: + org_img = cv2.rectangle(org_img, (x1, y1), (x2, y2), (255, 0, 0), 3) + org_img = cv2.circle(org_img, (new_center_x, new_center_y), 2, (255, 0, 0), 4) + get_face = True + state.tracking_face = int(new_center_x), int(new_center_y) + state.no_face_count = time.time() + 2 + # 判断是否超过一定时间没有识别要追踪的人脸 + if state.no_face_count < time.time(): + state.tracking_face = None + + # 本帧中识别到了要追踪的人脸 + if get_face: + center_x, center_y = state.tracking_face + x = center_x - 320 + # 更新 x 轴 pid控制器 + if abs(x) > 30: + state.face_x_pid.SetPoint = 0 + state.face_x_pid.update(x) + state.servo_x += state.face_x_pid.output + jetmax.set_servo(1, int(state.servo_x), 0.08) + else: + state.face_x_pid.update(0) + + # 更新 z 轴 pid 控制器 + z = center_y - 240 + if abs(z) > 30: + state.face_z_pid.SetPoint = 0 + state.face_z_pid.update(z) + z = jetmax.position[2] + state.face_z_pid.output + jetmax.set_position([jetmax.position[0], jetmax.position[1], z], 0.08) + else: + state.face_z_pid.update(0) + return org_img + + +""" +相机画面topic的回调 +只会将接收到的画面推入队列 +""" +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +""" +启动服务 +程序进入就绪状态,准备运行,但不做识别 +""" +def enter_func(msg): + rospy.loginfo("enter object tracking") + exit_func(msg) # 先退出一次, 简化过程 + rospy.sleep(0.1) + init() # 初始化位置及状态 + state.target_color_range = None + state.target_color_name = None + state.image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) # 订阅摄像头画面 + rospy.ServiceProxy('/usb_cam/start_capture', Empty)() + return [True, ''] + + +def reset(): + exit_func(TriggerRequest()) # 先退出一次, 简化过程 + rospy.sleep(0.1) + init() # 初始化位置及状态 + state.image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) # 订阅摄像头画面 + rospy.ServiceProxy('/usb_cam/start_capture', Empty)() + +""" +退出服务 +程序取消对相机topic的订阅 +""" +def exit_func(msg): + rospy.loginfo("exit object tracking") + state.is_running_color = False + state.is_running_face = False + try: + state.heartbeat_timer.cancel() + except: + pass + try: # 注销图像节点的订阅, 这样回调就不会被调用了 + rospy.loginfo('unregister image') + state.image_sub.unregister() + except: + pass + finally: + state.image_sub = None + return TriggerResponse(success=True) + + +""" +开始颜色追踪 +""" +def set_running_color_cb(msg: SetBoolRequest): + reset() + if msg.data: + rospy.loginfo("start running color tracking") + state.is_running_face = False + state.is_running_color = True + else: + rospy.loginfo("stop running color tracking") + state.is_running_color = False + return SetBoolResponse(success=True) + + +""" +开始人脸追踪 +""" +def set_running_face_cb(msg: SetBoolRequest): + reset() + if msg.data: + rospy.loginfo("start running face tracking") + state.is_running_color = False + state.is_running_face = True + else: + rospy.loginfo("stop running face tracking") + state.is_running_face = False + return [True, ''] + + +def heartbeat_timeout_cb(): + rospy.loginfo("heartbeat timeout. exiting...") + rospy.ServiceProxy('/%s/exit' % ROS_NODE_NAME, Trigger)() + + +def heartbeat_srv_cb(msg: SetBoolRequest): + """ + 心跳回调.会设置一个定时器,当定时到达后会调用退出服务退出玩法处理 + :params msg: 服务调用参数, std_srv SetBool + """ + rospy.logdebug("Heartbeat") + try: + state.heartbeat_timer.cancel() + except: + pass + if msg.data: + state.heartbeat_timer = threading.Timer(20, heartbeat_timeout_cb) + state.heartbeat_timer.start() + return SetBoolResponse(success=msg.data) + + +""" +设置要追踪的目标颜色 +""" +def set_target_cb(msg: SetTargetRequest): + # 获取颜色阈值列表 + color_ranges = rospy.get_param('/lab_config_manager/color_range_list', {}) + rospy.logdebug(color_ranges) + with state.lock: + if msg.color_name in color_ranges: + # 从阈值列表中找到目标阈值, 并设置目标 + state.target_color_name = msg.color_name + state.target_color_range = color_ranges[msg.color_name] + return [True, ''] + else: + state.target_color_name = None + state.target_color_range = None + return [False, ''] + + +if __name__ == '__main__': + # 初始化节点 + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + # 初始化程序资源 + init() + + # topic订阅/发布注册,服务注册 + image_pub = rospy.Publisher('/%s/image_result' % ROS_NODE_NAME, Image, queue_size=1) # register result image pub + enter_srv = rospy.Service('/%s/enter' % ROS_NODE_NAME, Trigger, enter_func) + exit_srv = rospy.Service('/%s/exit' % ROS_NODE_NAME, Trigger, exit_func) + color_running_srv = rospy.Service('/%s/set_running_color' % ROS_NODE_NAME, SetBool, set_running_color_cb) + face_running_srv = rospy.Service('/%s/set_running_face' % ROS_NODE_NAME, SetBool, set_running_face_cb) + set_target_srv = rospy.Service("/%s/set_target" % ROS_NODE_NAME, SetTarget, set_target_cb) + heartbeat_srv = rospy.Service('/%s/heartbeat' % ROS_NODE_NAME, SetBool, heartbeat_srv_cb) + hiwonder.buzzer.on() + rospy.sleep(0.2) + hiwonder.buzzer.off() + while True: + try: + image_proc() # 循环处理图像 + if rospy.is_shutdown(): + break + except KeyboardInterrupt: + break diff --git a/src/jetmax_buildin_funcs/object_tracking/scripts/object_tracking_main.py.back b/src/jetmax_buildin_funcs/object_tracking/scripts/object_tracking_main.py.back new file mode 100644 index 0000000..f8de022 --- /dev/null +++ b/src/jetmax_buildin_funcs/object_tracking/scripts/object_tracking_main.py.back @@ -0,0 +1,237 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import rospy +import time +import queue +import threading +from sensor_msgs.msg import Image +from std_srvs.srv import Empty +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from std_msgs.msg import Bool +from jetmax_control.msg import SetServo +from object_tracking.srv import SetTarget, SetTargetResponse, SetTargetRequest +import hiwonder +import numpy as np + +ROS_NODE_NAME = 'object_tracking' +TARGET_PIXEL_X, TARGET_PIXEL_Y = 320, 240 + + +class ObjectTracking: + def __init__(self): + self.heartbeat_timer = None + self.lock = threading.Lock() + self.servo_x = 500 + self.servo_y = 500 + + self.color_x_pid = hiwonder.PID(0.07, 0.01, 0.0015) + self.color_y_pid = hiwonder.PID(0.08, 0.008, 0.001) + + self.target_color_range = None + self.target_color_name = None + self.last_color_circle = None + self.lost_target_count = 0 + + self.is_running = False + self.entered = False + + self.fps = 0.0 + self.tic = time.time() + + def reset(self): + self.heartbeat_timer = None + self.is_running = False + self.servo_x = 500 + self.servo_y = 500 + self.last_color_circle = None + self.lost_target_count = 0 + self.tic = time.time() + self.target_color_range = None + self.target_color_name = None + self.last_color_circle = None + + +state = ObjectTracking() +jetmax = hiwonder.JetMax() + + + + +def color_tracking(image): + global TARGET_PIXEL_X, TARGET_PIXEL_Y + org_image = np.copy(image) + image = cv2.resize(image, (320, 240)) + image = cv2.cvtColor(image, cv2.COLOR_RGB2LAB) # RGB转LAB空间 + image = cv2.GaussianBlur(image, (5, 5), 5) + + target_color_range = state.target_color_range + target_color_name = state.target_color_name + + if target_color_range is not None: + mask = cv2.inRange(image, tuple(target_color_range['min']), tuple(target_color_range['max'])) # 二值化 + eroded = cv2.erode(mask, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) # 腐蚀 + dilated = cv2.dilate(eroded, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) # 膨胀 + contours = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] # 找出轮廓 + contour_area = map(lambda c: (c, math.fabs(cv2.contourArea(c))), contours) # 计算各个轮廓的面积 + contour_area = list(filter(lambda c: c[1] > 300, contour_area)) # 剔除面积过小的轮廓 + circle = None + if len(contour_area) > 0: + if state.last_color_circle is None: + contour, area = max(contour_area, key=lambda c_a: c_a[1]) + circle = cv2.minEnclosingCircle(contour) + else: + (last_x, last_y), last_r = state.last_color_circle + circles = map(lambda c: cv2.minEnclosingCircle(c[0]), contour_area) + circle_dist = list(map(lambda c: (c, math.sqrt(((c[0][0] - last_x) ** 2) + ((c[0][1] - last_y) ** 2))), + circles)) + circle, dist = min(circle_dist, key=lambda c: c[1]) + if dist < 50: + circle = circle + + if circle is not None: + # 可以使用极坐标进行定位, 这里不用精确计算坐标,直接控制两个舵机来定位 + state.lost_target_count = 0 + (c_x, c_y), c_r = circle + c_x = hiwonder.misc.val_map(c_x, 0, 320, 0, 640) + c_y = hiwonder.misc.val_map(c_y, 0, 240, 0, 480) + c_r = hiwonder.misc.val_map(c_r, 0, 320, 0, 640) + + x = c_x - TARGET_PIXEL_X + if abs(x) > 30: + state.color_x_pid.SetPoint = 0 + state.color_x_pid.update(x) + state.servo_x += state.color_x_pid.output + else: + state.color_x_pid.update(0) + + y = c_y - TARGET_PIXEL_Y + if abs(y) > 30: + state.color_y_pid.SetPoint = 0 + state.color_y_pid.update(y) + state.servo_y -= state.color_y_pid.output + else: + state.color_y_pid.update(0) + if state.servo_y < 350: + state.servo_y = 350 + if state.servo_y > 650: + state.servo_y = 650 + jetmax.set_servo(1, int(state.servo_x), duration=0.02) + jetmax.set_servo(2, int(state.servo_y), duration=0.02) + color_name = target_color_name.upper() + org_image = cv2.circle(org_image, (int(c_x), int(c_y)), int(c_r), hiwonder.COLORS[color_name], 3) + state.last_color_circle = circle + else: + state.lost_target_count += 1 + if state.lost_target_count > 15: + state.lost_target_count = 0 + state.last_color_circle = None + return org_image + + +def image_callback(ros_image): + if not state.entered: + rospy.sleep(0.1) + return + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = image + with state.lock: + if state.is_running: + frame_result = color_tracking(np.copy(image)) + toc = time.time() + curr_fps = 1.0 / (state.tic - toc) + state.fps = curr_fps if state.fps == 0.0 else (state.fps * 0.95 + curr_fps * 0.05) + state.tic = toc + rgb_image = frame_result.tostring() + ros_image.data = rgb_image + image_pub.publish(ros_image) + + +def enter_func(msg): + rospy.loginfo("enter object tracking") + exit_func(msg) # 先退出一次, 简化过程 + with state.lock: + state.reset() + state.entered = True + return [True, ''] + + + +def exit_func(msg): + rospy.loginfo("exit object tracking") + if isinstance(state.heartbeat_timer, threading.Timer): + state.heartbeat_timer.cancel() + with state.lock: + state.entered = False + state.is_running = False + rospy.ServiceProxy('/jetmax/go_home', Empty)() + rospy.Publisher('/jetmax/end_effector/sucker/command', Bool, queue_size=1).publish(data=False) + rospy.Publisher('/jetmax/end_effector/servo1/command', SetServo, queue_size=1).publish(data=90, duration=0.5) + return TriggerResponse(success=True) + + +def set_running_color_cb(msg: SetBoolRequest): + rospy.loginfo("start running color tracking") + if isinstance(state.heartbeat_timer, threading.Timer): + state.heartbeat_timer.cancel() + with state.lock: + state.reset() + state.is_running = msg.data + if not msg.data: + jetmax.go_home() + rospy.sleep(0.1) + return [True, ''] + + +def heartbeat_timeout_cb(): + rospy.loginfo("heartbeat timeout. exiting...") + rospy.ServiceProxy('/%s/exit' % ROS_NODE_NAME, Trigger)() + + +def heartbeat_srv_cb(msg: SetBoolRequest): + if isinstance(state.heartbeat_timer, threading.Timer): + state.heartbeat_timer.cancel() + rospy.logdebug("Heartbeat") + if msg.data: + state.heartbeat_timer = threading.Timer(5, heartbeat_timeout_cb) + state.heartbeat_timer.start() + else: + if isinstance(state.heartbeat_timer, threading.Timer): + state.heartbeat_timer.cancel() + return SetBoolResponse(success=msg.data) + + +def set_target_cb(msg: SetTargetRequest): + color_ranges = rospy.get_param('/lab_config_manager/color_range_list', {}) + rospy.logdebug(color_ranges) + with state.lock: + if msg.color_name in color_ranges: + state.target_color_name = msg.color_name + state.target_color_range = color_ranges[msg.color_name] + return [True, ''] + else: + state.target_color_name = None + state.target_color_range = None + return [False, ''] + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + state.reset() + TARGET_PIXEL_X, TARGET_PIXEL_Y, _, _ = rospy.get_param('/camera_cal/block', (320, 240)) + print(TARGET_PIXEL_X, TARGET_PIXEL_Y) + + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback, queue_size=1) # 订阅摄像头画面 + image_pub = rospy.Publisher('/%s/image_result' % ROS_NODE_NAME, Image, queue_size=2) # register result image pub + enter_srv = rospy.Service('/%s/enter' % ROS_NODE_NAME, Trigger, enter_func) + exit_srv = rospy.Service('/%s/exit' % ROS_NODE_NAME, Trigger, exit_func) + color_running_srv = rospy.Service('/%s/set_running_color' % ROS_NODE_NAME, SetBool, set_running_color_cb) + set_running_srv = rospy.Service('/%s/set_running' % ROS_NODE_NAME, SetBool, set_running_color_cb) + set_target_srv = rospy.Service("/%s/set_target" % ROS_NODE_NAME, SetTarget, set_target_cb) + heartbeat_srv = rospy.Service('/%s/heartbeat' % ROS_NODE_NAME, SetBool, heartbeat_srv_cb) + try: + rospy.spin() + except: + sys.exit(0) diff --git a/src/jetmax_buildin_funcs/object_tracking/scripts/object_tracking_main.py.facenet_bak b/src/jetmax_buildin_funcs/object_tracking/scripts/object_tracking_main.py.facenet_bak new file mode 100755 index 0000000..b992f27 --- /dev/null +++ b/src/jetmax_buildin_funcs/object_tracking/scripts/object_tracking_main.py.facenet_bak @@ -0,0 +1,394 @@ +#!/usr/bin/env python3 +import math +import rospy +import time +import queue +import threading +from sensor_msgs.msg import Image as RosImage +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from std_srvs.srv import Empty +from object_tracking.srv import SetTarget, SetTargetResponse, SetTargetRequest +import cv2 +import numpy as np +import hiwonder +import sys +import Jetson.GPIO as GPIO +GPIO.setmode(GPIO.BCM) +GPIO.setup(9, GPIO.OUT) +GPIO.setup(4, GPIO.OUT) +GPIO.output(9, 0) +GPIO.output(4, 0) + + +from PIL import Image +import torch +from facenet_pytorch import MTCNN, InceptionResnetV1 +device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') +print('Running on device: {}'.format(device)) +mtcnn = None + + +image_queue = queue.Queue(maxsize=1) +ROS_NODE_NAME = 'object_tracking' +DEFAULT_X, DEFAULT_Y, DEFAULT_Z = 0, 138 + 8.14, 84 + 128.4 +TARGET_PIXEL_X, TARGET_PIXEL_Y = 320, 240 + + +class ObjectTracking: + def __init__(self): + self.image_sub = None + self.heartbeat_timer = None + self.lock = threading.RLock() + self.servo_x = 500 + self.servo_y = 500 + + self.face_x_pid = hiwonder.PID(0.09, 0.005, 0.005) + self.face_z_pid = hiwonder.PID(0.1, 0.0, 0.0) + + self.color_x_pid = hiwonder.PID(0.07, 0.01, 0.0015) + self.color_y_pid = hiwonder.PID(0.08, 0.008, 0.001) + + self.tracking_face = None + self.no_face_count = 0 + + self.target_color_range = None + self.target_color_name = None + self.last_color_circle = None + self.lost_target_count = 0 + + self.is_running_color = False + self.is_running_face = False + + self.fps = 0.0 + self.tic = time.time() + + def reset(self): + self.tracking_face = None + self.image_sub = None + self.heartbeat_timer = None + self.tracking_face_encoding = None + self.no_face_count = 0 + self.servo_x = 500 + self.servo_y = 500 + + self.last_color_circle = None + self.lost_target_count = 0 + + self.is_running_color = False + self.is_running_face = False + + self.tic = time.time() + + +state = ObjectTracking() +jetmax = hiwonder.JetMax() +sucker = hiwonder.Sucker() + + +def init(): + state.reset() + sucker.set_state(False) + jetmax.go_home(1) + + +def image_proc(): + global mtcnn + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + if state.is_running_face: + if mtcnn is None: + mtcnn = MTCNN(keep_all=True, min_face_size=50, factor=0.709, post_process=False, device=device) + image = face_tracking(image) + elif state.is_running_color: + image = color_tracking(image) + else: + pass + toc = time.time() + curr_fps = 1.0 / (state.tic - toc) + state.fps = curr_fps if state.fps == 0.0 else (state.fps * 0.95 + curr_fps * 0.05) + state.tic = toc + rgb_image = image.tostring() + ros_image.data = rgb_image + image_pub.publish(ros_image) + + +def color_tracking(image): + org_image = np.copy(image) + image = cv2.resize(image, (320, 240)) + image = cv2.cvtColor(image, cv2.COLOR_RGB2LAB) # RGB转LAB空间 + image = cv2.GaussianBlur(image, (5, 5), 5) + + with state.lock: + target_color_range = state.target_color_range + target_color_name = state.target_color_name + + if target_color_range is not None: + mask = cv2.inRange(image, tuple(target_color_range['min']), tuple(target_color_range['max'])) # 二值化 + eroded = cv2.erode(mask, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) # 腐蚀 + dilated = cv2.dilate(eroded, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) # 膨胀 + contours = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] # 找出轮廓 + contour_area = map(lambda c: (c, math.fabs(cv2.contourArea(c))), contours) # 计算各个轮廓的面积 + contour_area = list(filter(lambda c: c[1] > 200, contour_area)) # 剔除面积过小的轮廓 + circle = None + if len(contour_area) > 0: + if state.last_color_circle is None: + contour, area = max(contour_area, key=lambda c_a: c_a[1]) + circle = cv2.minEnclosingCircle(contour) + else: + (last_x, last_y), last_r = state.last_color_circle + circles = map(lambda c: cv2.minEnclosingCircle(c[0]), contour_area) + circle_dist = list(map(lambda c: (c, math.sqrt(((c[0][0] - last_x) ** 2) + ((c[0][1] - last_y) ** 2))), + circles)) + circle, dist = min(circle_dist, key=lambda c: c[1]) + if dist < 50: + circle = circle + + if circle is not None: + state.lost_target_count = 0 + (c_x, c_y), c_r = circle + c_x = hiwonder.misc.val_map(c_x, 0, 320, 0, 640) + c_y = hiwonder.misc.val_map(c_y, 0, 240, 0, 480) + c_r = hiwonder.misc.val_map(c_r, 0, 320, 0, 640) + + x = c_x - TARGET_PIXEL_X + if abs(x) > 30: + state.color_x_pid.SetPoint = 0 + state.color_x_pid.update(x) + state.servo_x += state.color_x_pid.output + else: + state.color_x_pid.update(0) + + y = c_y - TARGET_PIXEL_Y + if abs(y) > 30: + state.color_y_pid.SetPoint = 0 + state.color_y_pid.update(y) + state.servo_y -= state.color_y_pid.output + else: + state.color_y_pid.update(0) + if state.servo_y < 350: + state.servo_y = 350 + if state.servo_y > 650: + state.servo_y = 650 + jetmax.set_servo(1, int(state.servo_x), duration=0.02) + jetmax.set_servo(2, int(state.servo_y), duration=0.02) + color_name = target_color_name.upper() + org_image = cv2.circle(org_image, (int(c_x), int(c_y)), int(c_r), hiwonder.COLORS[color_name], 3) + state.last_color_circle = circle + else: + state.lost_target_count += 1 + if state.lost_target_count > 15: + state.lost_target_count = 0 + state.last_color_circle = None + return org_image + + +def show_faces(img, boxes, landmarks, color): + new_boxes = [] + new_landmarks = [] + for bb, ll in zip(boxes, landmarks): + x1 = int(hiwonder.misc.val_map(bb[0], 0, 160, 0, 640)) + y1 = int(hiwonder.misc.val_map(bb[1], 0, 160, 0, 480)) + x2 = int(hiwonder.misc.val_map(bb[2], 0, 160, 0, 640)) + y2 = int(hiwonder.misc.val_map(bb[3], 0, 160, 0, 480)) + cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) + new_boxes.append([x1, y1, x2, y2]) + landmarks_curr_face = [] + if len(landmarks[0]): + for j in range(5): + lx = int(hiwonder.misc.val_map(ll[j][0], 0, 160, 0, 640)) + ly = int(hiwonder.misc.val_map(ll[j][1], 0, 160, 0, 480)) + cv2.circle(img, (lx, ly), 2, color, 4) + landmarks_curr_face.append([lx, ly]) + new_landmarks.append(landmarks_curr_face) + return img, new_boxes, new_landmarks + + +def face_tracking(image): + ta = time.time() + org_img = np.copy(image) + image = cv2.resize(image, (160, 160)) + boxes, _, landmarks = mtcnn.detect(Image.fromarray(image), landmarks=True) + if boxes is not None: + boxes = boxes.tolist() + landmarks = landmarks.tolist() + org_img, boxes, landmarks = show_faces(org_img, boxes, landmarks, (0, 255, 0)) + else: + boxes = [] + + if state.tracking_face is None: + if len(boxes) > 0: + box = min(boxes, key=lambda b: math.sqrt(((b[2] + b[0]) / 2 - 320) ** 2 + ((b[3] + b[1]) / 2 - 240) ** 2)) + x1, y1, x2, y2 = box + org_img = cv2.rectangle(org_img, (x1, y1), (x2, y2), (255, 0, 0), 3) + center_x, center_y = int((x1 + x2) / 2), int((y1 + y2) / 2) + org_img = cv2.circle(org_img, (center_x, center_y), 2, (0, 255, 0), 4) + state.tracking_face = center_x, center_y + state.no_face_count = time.time() + 2 + state.face_x_pid.clear() + state.face_z_pid.clear() + else: + centers = [(int((box[2] + box[0]) / 2), int((box[3] + box[1]) / 2), box) for box in boxes] + get_face = False + if len(centers) > 0: + center_x, center_y = state.tracking_face + org_img = cv2.circle(org_img, (center_x, center_y), 2, (0, 0, 255), 4) + min_dist_center = min(centers, key=lambda c: math.sqrt((c[0] - center_x) ** 2 + (c[1] - center_y) ** 2)) + new_center_x, new_center_y, box = min_dist_center + x1, y1, x2, y2 = box + dist = math.sqrt((new_center_x - center_x) ** 2 + (new_center_y - center_y) ** 2) + if dist < 150: + org_img = cv2.rectangle(org_img, (x1, y1), (x2, y2), (255, 0, 0), 3) + org_img = cv2.circle(org_img, (new_center_x, new_center_y), 2, (255, 0, 0), 4) + get_face = True + state.tracking_face = int(new_center_x), int(new_center_y) + state.no_face_count = time.time() + 2 + if state.no_face_count < time.time(): + state.tracking_face = None + get_face = False + GPIO.output(4, 0) + + if get_face: + GPIO.output(4, 1) + center_x, center_y = state.tracking_face + x = center_x - 320 + if abs(x) > 30: + state.face_x_pid.SetPoint = 0 + state.face_x_pid.update(x) + state.servo_x += state.face_x_pid.output + jetmax.set_servo(1, int(state.servo_x), 0.02) + else: + state.face_x_pid.update(0) + + z = center_y - 240 + if abs(z) > 30: + state.face_z_pid.SetPoint = 0 + state.face_z_pid.update(z) + z = jetmax.position[2] + state.face_z_pid.output + jetmax.set_position((jetmax.position[0], jetmax.position[1], z), 0.02) + else: + state.face_z_pid.update(0) + return org_img + + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +def enter_func(msg): + rospy.loginfo("enter object tracking") + exit_func(msg) # 先退出一次, 简化过程 + rospy.sleep(0.1) + init() # 初始化位置及状态 + state.target_color_range = None + state.target_color_name = None + state.image_sub = rospy.Subscriber('/usb_cam/image_rect_color', RosImage, image_callback, queue_size=1) # 订阅摄像头画面 + rospy.ServiceProxy('/usb_cam/start_capture', Empty)() + return [True, ''] + + +def reset(): + exit_func(TriggerRequest()) # 先退出一次, 简化过程 + rospy.sleep(0.1) + init() # 初始化位置及状态 + state.image_sub = rospy.Subscriber('/usb_cam/image_rect_color', RosImage, image_callback) # 订阅摄像头画面 + rospy.ServiceProxy('/usb_cam/start_capture', Empty)() + + +def exit_func(msg): + rospy.loginfo("exit object tracking") + state.is_running_color = False + state.is_running_face = False + if isinstance(state.heartbeat_timer, threading.Timer): + state.heartbeat_timer.cancel() + if isinstance(state.image_sub, rospy.Subscriber): # 注销图像节点的订阅, 这样回调就不会被调用了 + rospy.loginfo('unregister image') + state.image_sub.unregister() + state.image_sub = None + return TriggerResponse(success=True) + + +def set_running_color_cb(msg: SetBoolRequest): + reset() + if msg.data: + rospy.loginfo("start running color tracking") + state.is_running_face = False + state.is_running_color = True + else: + rospy.loginfo("stop running color tracking") + state.is_running_color = False + return SetBoolResponse(success=True) + + +def set_running_face_cb(msg: SetBoolRequest): + reset() + if msg.data: + rospy.loginfo("start running face tracking") + state.is_running_color = False + state.is_running_face = True + else: + rospy.loginfo("stop running face tracking") + state.is_running_face = False + return [True, ''] + + +def heartbeat_timeout_cb(): + rospy.loginfo("heartbeat timeout. exiting...") + rospy.ServiceProxy('/%s/exit' % ROS_NODE_NAME, Trigger)() + + +def heartbeat_srv_cb(msg: SetBoolRequest): + """ + 心跳回调.会设置一个定时器,当定时到达后会调用退出服务退出玩法处理 + :params msg: 服务调用参数, std_srv SetBool + """ + if isinstance(state.heartbeat_timer, threading.Timer): + state.heartbeat_timer.cancel() + rospy.logdebug("Heartbeat") + if msg.data: + state.heartbeat_timer = threading.Timer(15, heartbeat_timeout_cb) + state.heartbeat_timer.start() + else: + if isinstance(state.heartbeat_timer, threading.Timer): + state.heartbeat_timer.cancel() + return SetBoolResponse(success=msg.data) + + +def set_target_cb(msg: SetTargetRequest): + color_ranges = rospy.get_param('/lab_config_manager/color_range_list', {}) + rospy.logdebug(color_ranges) + with state.lock: + if msg.color_name in color_ranges: + state.target_color_name = msg.color_name + state.target_color_range = color_ranges[msg.color_name] + return [True, ''] + else: + state.target_color_name = None + state.target_color_range = None + return [False, ''] + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + init() + + image_pub = rospy.Publisher('/%s/image_result' % ROS_NODE_NAME, RosImage, queue_size=1) # register result image pub + enter_srv = rospy.Service('/%s/enter' % ROS_NODE_NAME, Trigger, enter_func) + exit_srv = rospy.Service('/%s/exit' % ROS_NODE_NAME, Trigger, exit_func) + color_running_srv = rospy.Service('/%s/set_running_color' % ROS_NODE_NAME, SetBool, set_running_color_cb) + face_running_srv = rospy.Service('/%s/set_running_face' % ROS_NODE_NAME, SetBool, set_running_face_cb) + set_target_srv = rospy.Service("/%s/set_target" % ROS_NODE_NAME, SetTarget, set_target_cb) + heartbeat_srv = rospy.Service('/%s/heartbeat' % ROS_NODE_NAME, SetBool, heartbeat_srv_cb) + hiwonder.buzzer.on() + rospy.sleep(0.2) + hiwonder.buzzer.off() + while True: + try: + image_proc() + if rospy.is_shutdown(): + break + except KeyboardInterrupt: + break diff --git a/src/jetmax_buildin_funcs/object_tracking/srv/SetTarget.srv b/src/jetmax_buildin_funcs/object_tracking/srv/SetTarget.srv new file mode 100644 index 0000000..d1f0c8f --- /dev/null +++ b/src/jetmax_buildin_funcs/object_tracking/srv/SetTarget.srv @@ -0,0 +1,4 @@ +string color_name +--- +bool success +string message \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/palletizing/CMakeLists.txt b/src/jetmax_buildin_funcs/palletizing/CMakeLists.txt new file mode 100644 index 0000000..85def5d --- /dev/null +++ b/src/jetmax_buildin_funcs/palletizing/CMakeLists.txt @@ -0,0 +1,206 @@ +cmake_minimum_required(VERSION 3.0.2) +project(palletizing) + +## 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 + message_generation + rospy + std_msgs + std_srvs +) + +## 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 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 +# SetTarget.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 +) + +################################################ +## 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 palletizing + CATKIN_DEPENDS messages_runtime rospy std_msgs std_srvs +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( +# include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/palletizing.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/palletizing_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_palletizing.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/jetmax_buildin_funcs/palletizing/package.xml b/src/jetmax_buildin_funcs/palletizing/package.xml new file mode 100644 index 0000000..e591b86 --- /dev/null +++ b/src/jetmax_buildin_funcs/palletizing/package.xml @@ -0,0 +1,73 @@ + + + palletizing + 0.0.0 + The palletizing package + + + + + hiwonder + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + message_generation + messages_runtime + rospy + std_msgs + std_srvs + message_generation + messages_runtime + rospy + std_msgs + std_srvs + messages_runtime + rospy + std_msgs + std_srvs + + + + + + + + diff --git a/src/jetmax_buildin_funcs/palletizing/scripts/palletizing_main.py b/src/jetmax_buildin_funcs/palletizing/scripts/palletizing_main.py new file mode 100755 index 0000000..0a5ff50 --- /dev/null +++ b/src/jetmax_buildin_funcs/palletizing/scripts/palletizing_main.py @@ -0,0 +1,355 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import time +import rospy +import numpy as np +import threading +from sensor_msgs.msg import Image +from std_msgs.msg import Bool +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from std_srvs.srv import Empty +from jetmax_control.msg import SetServo +import hiwonder +import apriltag +import yaml + +ROS_NODE_NAME = "palletizing" +IMAGE_PROC_SIZE = 640, 480 +TAG_SIZE = 33.30 +TARGET_POSITIONS = (((235, -75, 85), -18), ((235, -75, 125), -18), ((235, -75, 173), -18)) + +jetmax = hiwonder.JetMax() # 机械臂控制接口 +sucker = hiwonder.Sucker() # 吸嘴控制接口 + +# apriltag 识别器 +at_detector = apriltag.Detector(apriltag.DetectorOptions(families='tag36h11')) + + +""" +将像素坐标转换为世界坐标 +""" +def camera_to_world(cam_mtx, r, t, img_points): + inv_k = np.asmatrix(cam_mtx).I + r_mat = np.zeros((3, 3), dtype=np.float64) + cv2.Rodrigues(r, r_mat) + # invR * T + inv_r = np.asmatrix(r_mat).I # 3*3 + transPlaneToCam = np.dot(inv_r, np.asmatrix(t)) # 3*3 dot 3*1 = 3*1 + world_pt = [] + coords = np.zeros((3, 1), dtype=np.float64) + for img_pt in img_points: + coords[0][0] = img_pt[0][0] + coords[1][0] = img_pt[0][1] + coords[2][0] = 1.0 + worldPtCam = np.dot(inv_k, coords) # 3*3 dot 3*1 = 3*1 + # [x,y,1] * invR + worldPtPlane = np.dot(inv_r, worldPtCam) # 3*3 dot 3*1 = 3*1 + # zc + scale = transPlaneToCam[2][0] / worldPtPlane[2][0] + # zc * [x,y,1] * invR + scale_worldPtPlane = np.multiply(scale, worldPtPlane) + # [X,Y,Z]=zc*[x,y,1]*invR - invR*T + worldPtPlaneReproject = np.asmatrix(scale_worldPtPlane) - np.asmatrix(transPlaneToCam) # 3*1 dot 1*3 = 3*3 + pt = np.zeros((3, 1), dtype=np.float64) + pt[0][0] = worldPtPlaneReproject[0][0] + pt[1][0] = worldPtPlaneReproject[1][0] + pt[2][0] = 0 + world_pt.append(pt.T.tolist()) + return world_pt + + +class Palletizing: + def __init__(self): + self.is_running = False + self.moving_block = None + self.image_sub = None + self.heartbeat_timer = None + self.runner = None + self.count = 0 + self.level = 0 + self.lock = threading.RLock() + self.camera_params = None + self.K = None + self.R = None + self.T = None + + """ + 重置相关变量 + """ + def reset(self): + self.is_running = False + self.moving_block = None + self.image_sub = None + self.heartbeat_timer = None + self.runner = None + self.count = 0 + self.level = 0 + + """ + 读取相机参数 + """ + def load_camera_params(self): + self.camera_params = rospy.get_param('/camera_cal/block_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + + +""" +旋转矩阵转为欧拉角 +""" +def rotation_mtx_to_euler(R): + sy = math.sqrt(R[0, 0] * R[0, 0] + R[1, 0] * R[1, 0]) + singular = sy < 1e-6 + if not singular: + x = math.atan2(R[2, 1], R[2, 2]) + y = math.atan2(-R[2, 0], sy) + z = math.atan2(R[1, 0], R[0, 0]) + else: + x = math.atan2(-R[1, 2], R[1, 1]) + y = math.atan2(-R[2, 0], sy) + z = 0 + return np.array([x, y, z]) + + +""" +搬运木块进行码垛 +""" +def moving(): + try: + tag = state.moving_block + # 相机参数,整理成需要的格式 + params = np.array([state.K[0][0], state.K[1][1], state.K[0][2], state.K[1][2]]) + # 获取识别到的tag的世界位姿 + pose_mtx, a, b = at_detector.detection_pose(tag, camera_params=params, tag_size=TAG_SIZE) + angle = rotation_mtx_to_euler(pose_mtx)[2] * (180 / math.pi) # 获取标签的旋转角 + + cur_x, cur_y, cur_z = jetmax.position # 当前位置 + rect_x, rect_y = state.moving_block.center # 要码垛的标签的中心像素坐标 + # 要码垛的标签的中心世界坐标 + p = np.asarray([rect_x, rect_y]).reshape((1, 1, 2)) + w = camera_to_world(state.K, state.R, state.T, p)[0][0] + x, y, _ = w + print(w) + if angle < -45: # ccw -45 ~ -90 + angle = -(-90 - angle) + if angle > 45: + angle = -(90 - angle) + + new_x, new_y = cur_x + x, cur_y + y + new_x = new_x * 1.05 + nn_new_x = new_x + 15 + # 机械臂在码垛的标签位置时,机械臂相对于中轴的偏移角度 + arm_angle = math.atan(new_y / new_x) * 180 / math.pi + if arm_angle > 0: + arm_angle = (90 - arm_angle) + elif arm_angle < 0: + arm_angle = (-90 - arm_angle) + else: + pass + + angle = angle + -arm_angle + + dist = math.sqrt(x * x + y * y + 120 * 120) + t = dist / 140 + hiwonder.pwm_servo1.set_position(90 + angle, 0.1) + jetmax.set_position((nn_new_x, new_y, 120), t) + rospy.sleep(t + 0.1) + jetmax.set_position((new_x, new_y, 120), 0.3) + rospy.sleep(0.4) + + # 吸起 + sucker.set_state(True) + jetmax.set_position((new_x, new_y, 85 - 5), 1) + rospy.sleep(1) + + cur_x, cur_y, cur_z = jetmax.position + (x, y, z), angle = TARGET_POSITIONS[state.level] + # 到目标位置上方 + jetmax.set_position((cur_x, cur_y, 200 + 4), 0.8) + rospy.sleep(0.8) + + # 根据记录码垛到第几个确定高度 + state.level += 1 + if state.level == 3: + state.level = 0 + + hiwonder.pwm_servo1.set_position(90 + angle, 0.5) + cur_x, cur_y, cur_z = jetmax.position + t = math.sqrt((cur_x - x) ** 2 + (cur_y - y) ** 2) / 120 + jetmax.set_position((x, y + 10, 200), t) + rospy.sleep(t) + jetmax.set_position((x, y, 200), 0.3) + rospy.sleep(0.4) + + # 到达目标位置 + jetmax.set_position((x, y, z), 1) + rospy.sleep(1) + + # 关闭气泵、放气 + sucker.release(3) + jetmax.set_position((x, y, 205), 1) + rospy.sleep(0.5) + + finally: + # Go home + sucker.release(3) + hiwonder.pwm_servo1.set_position(90, 0.5) # 小舵机复位 + rospy.sleep(0.5) + jetmax.go_home(1.5) # 回到初始位置 + rospy.sleep(1.5) + with state.lock: + # 完成过程清理相关标志, 继续下一次识别 + state.moving_block = None + state.runner = None + + +""" +图像识别处理 +""" +def image_proc(img): + if state.runner is not None: # 如果正在搬运码垛过程中就不进行识别 + return img + frame_gray = cv2.cvtColor(np.copy(img), cv2.COLOR_RGB2GRAY) # 转为灰度图 + tags = at_detector.detect(frame_gray) # 识别 apriltag + for tag in tags: + corners = tag.corners.reshape(1, -1, 2).astype(int) # 识别到的标签的四个角的坐标, 转换为((x, y), (x, y)....)形状方便使用 + center = tag.center.astype(int) # 识别到的标签的中心坐标 + cv2.drawContours(img, corners, -1, (255, 0, 0), 3) # 框出标签 + cv2.circle(img, tuple(center), 5, (255, 255, 0), 10) # 画出中心 + cv2.putText(img, "id:%d" % tag.tag_id, # 显示 id等文字 + (center[0], center[1] - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2) + if len(tags) > 0: + if state.moving_block is None: + state.moving_block = tags[0] # tags 的顺序就是按id从小到大排列的, 直接取第一个就是id最小的 + else: + new_tag = tags[0] + if new_tag.tag_id != state.moving_block.tag_id: + state.count = 0 + else: + state.count += 1 + if state.count > 50: # 连续50帧识别到标签就开始搬运码垛过程 + state.count = 0 + state.runner = threading.Thread(target=moving, daemon=True) + state.runner.start() + state.moving_block = tags[0] + else: + state.count = 0 + if state.moving_block is not None: + state.moving_block = None + img_h, img_w = img.shape[:2] + + # 画中心十字 + cv2.line(img, (int(img_w / 2 - 10), int(img_h / 2)), (int(img_w / 2 + 10), int(img_h / 2)), (0, 255, 255), 2) + cv2.line(img, (int(img_w / 2), int(img_h / 2 - 10)), (int(img_w / 2), int(img_h / 2 + 10)), (0, 255, 255), 2) + return img + + +""" +相机画面topic回调 +""" +def image_callback(ros_image): + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = image.copy() + with state.lock: + if state.is_running: + frame_result = image_proc(frame_result) # 对图像进行处理 + # 发布处理结果图像 + rgb_image = frame_result.tostring() + ros_image.data = rgb_image + image_pub.publish(ros_image) + + +""" +进入服务 +""" +def enter_func(msg): + rospy.loginfo("Enter color palletizing") + exit_func(msg) + jetmax.go_home() + state.reset() + state.load_camera_params() # 读取相机参数 + state.image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) # 订阅相机画面 + return TriggerResponse(success=True) + + +""" +退出服务 +""" +def exit_func(msg): + rospy.loginfo("Exit color palletizing") + state.is_running = False + try: + state.heartbeat_timer.cancel() + except: + pass + if isinstance(state.runner, threading.Thread): + state.runner.join() + if isinstance(state.image_sub, rospy.Subscriber): + state.image_sub.unregister() + state.image_sub = None + rospy.ServiceProxy('/jetmax/go_home', Empty)() + rospy.Publisher('/jetmax/end_effector/sucker/command', Bool, queue_size=1).publish(data=False) + rospy.Publisher('/jetmax/end_effector/servo1/command', SetServo, queue_size=1).publish(data=90, duration=0.5) + return TriggerResponse(success=True) + + +""" +启动/停止码垛 +""" +def set_running(msg: SetBoolRequest): + # True为启动,False为停止 + if msg.data: + rospy.loginfo("Start running color palletizing") + state.is_running = True + state.level = 0 + else: + rospy.loginfo("stop running object tracking") + state.is_running = False + return SetBoolResponse(success=True) + + +def heartbeat_timeout_cb(): + rospy.loginfo("Heartbeat timeout. exiting...") + rospy.ServiceProxy('/%s/exit' % ROS_NODE_NAME, Trigger)() + + +def heartbeat_srv_cb(msg: SetBoolRequest): + """ + Heartbeat callback. A timer will be set, and the exit service will be called when the time is reached + + """ + try: + state.heartbeat_timer.cancel() + except: + pass + rospy.logdebug("Heartbeat") + if msg.data: + state.heartbeat_timer = threading.Timer(5, heartbeat_timeout_cb) + state.heartbeat_timer.start() + return SetBoolResponse(success=msg.data) + + +if __name__ == '__main__': + state = Palletizing() + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) # 初始化节点 + # 读取相机参数 + state.load_camera_params() + if state.camera_params is None: + rospy.logerr('Can not load camera parameters') + sys.exit(-1) + + # topic 的订阅/发布注册, 相关服务的注册 + image_pub = rospy.Publisher('/%s/image_result' % ROS_NODE_NAME, Image, queue_size=1) # Register result image pub + enter_srv = rospy.Service('/%s/enter' % ROS_NODE_NAME, Trigger, enter_func) + exit_srv = rospy.Service('/%s/exit' % ROS_NODE_NAME, Trigger, exit_func) + running_srv = rospy.Service('/%s/set_running' % ROS_NODE_NAME, SetBool, set_running) + heartbeat_srv = rospy.Service('/%s/heartbeat' % ROS_NODE_NAME, SetBool, heartbeat_srv_cb) + try: + rospy.spin() + except KeyboardInterrupt: + sys.exit(0) diff --git a/src/jetmax_buildin_funcs/palletizing/srv/SetTarget.srv b/src/jetmax_buildin_funcs/palletizing/srv/SetTarget.srv new file mode 100644 index 0000000..bc50337 --- /dev/null +++ b/src/jetmax_buildin_funcs/palletizing/srv/SetTarget.srv @@ -0,0 +1,5 @@ +string color_name +bool is_enable +--- +bool success +string message \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/remote_control/CMakeLists.txt b/src/jetmax_buildin_funcs/remote_control/CMakeLists.txt new file mode 100644 index 0000000..e246791 --- /dev/null +++ b/src/jetmax_buildin_funcs/remote_control/CMakeLists.txt @@ -0,0 +1,209 @@ +cmake_minimum_required(VERSION 3.0.2) +project(remote_control) + +## 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 + message_generation + rospy + std_msgs + std_srvs + ) + +## 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 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 + Status.msg +) + +## Generate services in the 'srv' folder +add_service_files( + FILES + ChangePosition.srv + SetChuck.srv + SetPosition.srv + SetPWMServo.srv + SetServo.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 +) + +################################################ +## 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 remote_control + # CATKIN_DEPENDS message_generation rospy std_msgs std_srvs + # DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( + # include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/remote_control.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/remote_control_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_remote_control.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/jetmax_buildin_funcs/remote_control/msg/Mecanum.msg b/src/jetmax_buildin_funcs/remote_control/msg/Mecanum.msg new file mode 100644 index 0000000..e69de29 diff --git a/src/jetmax_buildin_funcs/remote_control/msg/Mecanum.msgs b/src/jetmax_buildin_funcs/remote_control/msg/Mecanum.msgs new file mode 100644 index 0000000..e69de29 diff --git a/src/jetmax_buildin_funcs/remote_control/msg/Status.msg b/src/jetmax_buildin_funcs/remote_control/msg/Status.msg new file mode 100644 index 0000000..43d62a9 --- /dev/null +++ b/src/jetmax_buildin_funcs/remote_control/msg/Status.msg @@ -0,0 +1,11 @@ +int16 x +int16 y +int16 z +uint16 id1 +uint16 id2 +uint16 id3 +uint16 id4 +uint8 pwm1 +uint8 motor1 +uint8 motor2 + diff --git a/src/jetmax_buildin_funcs/remote_control/package.xml b/src/jetmax_buildin_funcs/remote_control/package.xml new file mode 100644 index 0000000..3a38910 --- /dev/null +++ b/src/jetmax_buildin_funcs/remote_control/package.xml @@ -0,0 +1,69 @@ + + + remote_control + 0.0.0 + The remote_control package + + + + + lucas + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + message_generation + rospy + std_msgs + std_srvs + rospy + std_msgs + std_srvs + rospy + std_msgs + std_srvs + + + + + + + + diff --git a/src/jetmax_buildin_funcs/remote_control/scripts/remote_control_joystick.py b/src/jetmax_buildin_funcs/remote_control/scripts/remote_control_joystick.py new file mode 100755 index 0000000..26682e2 --- /dev/null +++ b/src/jetmax_buildin_funcs/remote_control/scripts/remote_control_joystick.py @@ -0,0 +1,290 @@ +#!/usr/bin/env python3 +import os +import sys +import rospy +import threading +import numpy as np +import pygame as pg +from functools import partial +import hiwonder + +ROS_NODE_NAME = 'remote_control_joystick' +jetmax = hiwonder.JetMax() +sucker = hiwonder.Sucker() + +enable_control = True +os.environ["SDL_VIDEODRIVER"] = "dummy" # For use PyGame without opening a visible display +pg.display.init() + +PRESSED_ACTION_MAP = {} +HOLD_ACTION_MAP = {} +RELEASED_ACTION_MAP = {} +BUTTONS = ("CROSS", "CIRCLE", "None_1", "SQUARE", + "TRIANGLE", "None_2", "L1", "R1", + "L2", "R2", "SELECT", "START", "MODE", + "L_HAT_LEFT", "L_HAT_RIGHT", "L_HAT_DOWN", "L_HAT_UP", + "L_AXIS_LEFT", "L_AXIS_RIGHT", "L_AXIS_UP", "L_AXIS_DOWN", + "R_AXIS_LEFT", "R_AXIS_RIGHT", "R_AXIS_UP", "R_AXIS_DOWN") + +try: + stepper = hiwonder.Stepper(1) +except: + stepper = None +try: + chassis = hiwonder.MecanumChassis() +except: + chassis = None + + +servo1 = 90 + +def go_home(): + global enable_control, servo1 + enable_control = False + jetmax.go_home(1) + servo1 = 90 + hiwonder.pwm_servo1.set_position(servo1, 1) + sucker.release() + rospy.sleep(1) + if stepper: + stepper.go_home() + enable_control = True + +def set_slideway(pulse): + if stepper: + stepper.set_mode(stepper.SLEEP) + stepper.goto(pulse) + rospy.sleep(0.1) + +def stepper_unlock(): + if stepper: + stepper.set_mode(stepper.EN) + +def change_mode(new_mode, beep=True): + global PRESSED_ACTION_MAP, HOLD_ACTION_MAP, RELEASED_ACTION_MAP + if new_mode == 0: + if beep: + hiwonder.buzzer.on() + rospy.sleep(0.1) + hiwonder.buzzer.off() + PRESSED_ACTION_MAP = JOINT_MODE_PRESSED_ACTION_MAP + HOLD_ACTION_MAP = JOINT_MODE_HOLD_ACTION_MAP + RELEASED_ACTION_MAP = JOINT_RELEASED_ACTION_MAP + + elif new_mode == 1: + hiwonder.buzzer.on() + rospy.sleep(0.1) + hiwonder.buzzer.off() + rospy.sleep(0.05) + hiwonder.buzzer.on() + rospy.sleep(0.1) + hiwonder.buzzer.off() + PRESSED_ACTION_MAP = COORDINATE_MODE_PRESSED_ACTION_MAP + HOLD_ACTION_MAP = COORDINATE_MODE_HOLD_ACTION_MAP + RELEASED_ACTION_MAP = COORDINATE_MODE_RELEASED_ACTION_MAP + else: + pass + +def set_pwm_servo1(v, dur): + global servo1 + servo1 += v + servo1 = 180 if servo1 > 180 else servo1 + servo1 = 0 if servo1 < 0 else servo1 + hiwonder.pwm_servo1.set_position(servo1, dur) + +JOINT_MODE_PRESSED_ACTION_MAP = { + "START": go_home, + "SELECT": partial(change_mode, 1), + "L2": partial(sucker.suck), + "R2": partial(sucker.release), + "L_HAT_LEFT": partial(jetmax.set_servo_relatively, 1, 2, 0.05), + "L_HAT_RIGHT": partial(jetmax.set_servo_relatively, 1, -2, 0.05), + "L_HAT_UP": partial(jetmax.set_servo_relatively, 2, -2, 0.05), + "L_HAT_DOWN": partial(jetmax.set_servo_relatively, 2, 2, 0.05), + "TRIANGLE": partial(jetmax.set_servo_relatively, 3, -2, 0.05), + "CROSS": partial(jetmax.set_servo_relatively, 3, 2, 0.05), + "CIRCLE": partial(set_pwm_servo1, 2, 0), + "SQUARE": partial(set_pwm_servo1, -2, 0), + "R1": partial(set_slideway, 350), + "L1": partial(set_slideway, -350), +} + +JOINT_MODE_HOLD_ACTION_MAP = { + "L_HAT_LEFT": partial(jetmax.set_servo_relatively, 1, 8, 0.05), + "L_HAT_RIGHT": partial(jetmax.set_servo_relatively, 1, -8, 0.05), + "L_HAT_UP": partial(jetmax.set_servo_relatively, 2, -8, 0.05), + "L_HAT_DOWN": partial(jetmax.set_servo_relatively, 2, 8, 0.05), + "TRIANGLE": partial(jetmax.set_servo_relatively, 3, -8, 0.05), + "CROSS": partial(jetmax.set_servo_relatively, 3, 8, 0.05), + "CIRCLE": partial(set_pwm_servo1, 5, 0), + "SQUARE": partial(set_pwm_servo1, -5, 0), + "R1": partial(set_slideway, 500), + "L1": partial(set_slideway, -500), +} + +JOINT_RELEASED_ACTION_MAP = { + "R1": partial(stepper_unlock), + "L1": partial(stepper_unlock), +} + +COORDINATE_MODE_PRESSED_ACTION_MAP = { + "START": go_home, + "SELECT": partial(change_mode, 0), + "L2": partial(sucker.suck), + "R2": partial(sucker.release), + "CIRCLE": partial(set_pwm_servo1, 2, 0), + "SQUARE": partial(set_pwm_servo1, -2, 0), + "L_HAT_LEFT": partial(jetmax.set_position_relatively, (1, 0, 0), 0.05), + "L_HAT_RIGHT": partial(jetmax.set_position_relatively, (-1, 0, 0), 0.05), + "L_HAT_UP": partial(jetmax.set_position_relatively, (0, -1, 0), 0.05), + "L_HAT_DOWN": partial(jetmax.set_position_relatively, (0, 1, 0), 0.05), + "TRIANGLE": partial(jetmax.set_position_relatively, (0, 0, 1), 0.05), + "CROSS": partial(jetmax.set_position_relatively, (0, 0, -1), 0.05), + "R1": partial(set_slideway, 300), + "L1": partial(set_slideway, -300), +} + +COORDINATE_MODE_HOLD_ACTION_MAP = { + "CIRCLE": partial(set_pwm_servo1, 5, 0), + "SQUARE": partial(set_pwm_servo1, -5, 0), + "L_HAT_LEFT": partial(jetmax.set_position_relatively, (4, 0, 0), 0.05), + "L_HAT_RIGHT": partial(jetmax.set_position_relatively, (-4, 0, 0), 0.05), + "L_HAT_UP": partial(jetmax.set_position_relatively, (0, -4, 0), 0.05), + "L_HAT_DOWN": partial(jetmax.set_position_relatively, (0, 4, 0), 0.05), + "TRIANGLE": partial(jetmax.set_position_relatively, (0, 0, 4), 0.05), + "CROSS": partial(jetmax.set_position_relatively, (0, 0, -4), 0.05), + "R1": partial(set_slideway, 500), + "L1": partial(set_slideway, -500), +} + +COORDINATE_MODE_RELEASED_ACTION_MAP = { + "R1": partial(stepper_unlock), + "L1": partial(stepper_unlock), +} + + +class Joystick: + def __init__(self): + self.js = None + self.last_buttons = [0] * len(BUTTONS) + self.hold_count = [0] * len(BUTTONS) + self.lock = threading.Lock() + self.speed_x = 0 + self.speed_y = 0 + self.axis = [0,0,0,0] + self.chassis_en = False + threading.Thread(target=self.connect, daemon=True).start() + + def connect(self): + while True: + if os.path.exists("/dev/input/js0"): + with self.lock: + if self.js is None: + pg.joystick.init() + try: + self.js = pg.joystick.Joystick(0) + self.js.init() + except Exception as e: + rospy.logerr(e) + self.js = None + else: + with self.lock: + if self.js is not None: + self.js.quit() + self.js = None + rospy.sleep(0.2) + + def update_buttons(self): + global enable_control + with self.lock: + if self.js is None or not enable_control: + return + # update and read joystick data + pg.event.pump() + buttons = [self.js.get_button(i) for i in range(13)] + hat = list(self.js.get_hat(0)) + new_axis = [self.js.get_axis(i) for i in range(4)] + new_axis[0] = hiwonder.misc.val_map(new_axis[0], -1, 1, -200, 200) + new_axis[1] = hiwonder.misc.val_map(new_axis[1], -1, 1, 200, -200) + new_axis[2] = hiwonder.misc.val_map(new_axis[2], -1, 1, 60, -60) + new_axis[3] = hiwonder.misc.val_map(new_axis[3], -1, 1, 200, -200) + dax = abs(np.mean(new_axis) - np.mean(self.axis)) + if dax > 1: + self.axis = new_axis + self.chassis_en = True + else: + self.chassis_en = False + + hat.extend(new_axis) + # convert analog data to digital + for i in range(6): + buttons.extend([1 if hat[i] < -0.95 else 0, 1 if hat[i] > 0.95 else 0]) + # check what has changed in this update + buttons = np.array(buttons) + buttons_changed = np.bitwise_xor(self.last_buttons, buttons).tolist() + self.last_buttons = buttons # save buttons data + + if chassis and self.chassis_en: + speed = new_axis[1] + if not speed: + speed = new_axis[3] + v, d = chassis.translation(new_axis[0], speed, fake=True) + chassis.set_velocity(v, d, new_axis[2]) + + for i, button in enumerate(buttons_changed): + if button: # button state changed + if buttons[i]: + rospy.logdebug(BUTTONS[i] + " pressed") + self.hold_count[i] = 0 + button_name = BUTTONS[i] + if button_name in PRESSED_ACTION_MAP: + try: + PRESSED_ACTION_MAP[button_name]() + break + except Exception as e: + rospy.logerr(e) + else: + rospy.logdebug(BUTTONS[i] + " released") + button_name = BUTTONS[i] + if button_name in RELEASED_ACTION_MAP: + try: + RELEASED_ACTION_MAP[button_name]() + break + except Exception as e: + rospy.logerr(e) + else: + if buttons[i]: + if self.hold_count[i] < 3: # Better distinguish between short press and long press + self.hold_count[i] += 1 + else: + rospy.logdebug(BUTTONS[i] + " hold") + button_name = BUTTONS[i] + if button_name in HOLD_ACTION_MAP: + try: + HOLD_ACTION_MAP[button_name]() + break + except Exception as e: + rospy.logerr(e) + + + +js = Joystick() +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.INFO) + jetmax.go_home(1) + hiwonder.pwm_servo1.set_position(90, 1) + sucker.release() + rospy.sleep(1) + change_mode(0, beep=False) # Joint mode as the default mode + if stepper: + stepper.go_home() + stepper.set_mode(stepper.EN) + + while True: + try: + js.update_buttons() + rospy.sleep(0.05) + if rospy.is_shutdown(): + sys.exit(0) + except KeyboardInterrupt: + sys.exit(0) diff --git a/src/jetmax_buildin_funcs/remote_control/srv/ChangePosition.srv b/src/jetmax_buildin_funcs/remote_control/srv/ChangePosition.srv new file mode 100644 index 0000000..c44d0d0 --- /dev/null +++ b/src/jetmax_buildin_funcs/remote_control/srv/ChangePosition.srv @@ -0,0 +1,6 @@ +string axis_name +float32 change_value +float32 duration +--- +bool success +string message \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/remote_control/srv/GoHome.srv b/src/jetmax_buildin_funcs/remote_control/srv/GoHome.srv new file mode 100644 index 0000000..e69de29 diff --git a/src/jetmax_buildin_funcs/remote_control/srv/Se b/src/jetmax_buildin_funcs/remote_control/srv/Se new file mode 100644 index 0000000..e69de29 diff --git a/src/jetmax_buildin_funcs/remote_control/srv/SetChuck.srv b/src/jetmax_buildin_funcs/remote_control/srv/SetChuck.srv new file mode 100644 index 0000000..cf67b72 --- /dev/null +++ b/src/jetmax_buildin_funcs/remote_control/srv/SetChuck.srv @@ -0,0 +1,4 @@ +bool absorb +--- +bool success +string message \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/remote_control/srv/SetPWMServo.srv b/src/jetmax_buildin_funcs/remote_control/srv/SetPWMServo.srv new file mode 100644 index 0000000..98ee136 --- /dev/null +++ b/src/jetmax_buildin_funcs/remote_control/srv/SetPWMServo.srv @@ -0,0 +1,6 @@ +uint8 servo_id +float32 angle +float32 duration +--- +bool success +string message \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/remote_control/srv/SetPosition.srv b/src/jetmax_buildin_funcs/remote_control/srv/SetPosition.srv new file mode 100644 index 0000000..6b12fdd --- /dev/null +++ b/src/jetmax_buildin_funcs/remote_control/srv/SetPosition.srv @@ -0,0 +1,7 @@ +float32 x +float32 y +float32 z +float32 duration +--- +bool success +string message \ No newline at end of file diff --git a/src/jetmax_buildin_funcs/remote_control/srv/SetServo.srv b/src/jetmax_buildin_funcs/remote_control/srv/SetServo.srv new file mode 100644 index 0000000..c2bbc85 --- /dev/null +++ b/src/jetmax_buildin_funcs/remote_control/srv/SetServo.srv @@ -0,0 +1,6 @@ +uint8 servo_id +float32 angle +float32 duration +--- +bool success +string message diff --git a/src/jetmax_buildin_funcs/waste_classification/CMakeLists.txt b/src/jetmax_buildin_funcs/waste_classification/CMakeLists.txt new file mode 100644 index 0000000..de62752 --- /dev/null +++ b/src/jetmax_buildin_funcs/waste_classification/CMakeLists.txt @@ -0,0 +1,207 @@ +cmake_minimum_required(VERSION 3.0.2) +project(waste_classification) + +## 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 + message_generation + rospy + std_msgs + std_srvs +) + +## 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 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 +# ) + +################################################ +## 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 waste_classification +# CATKIN_DEPENDS message_generation rospy std_msgs std_srvs +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( +# include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/waste_classification.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/waste_classification_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_waste_classification.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/jetmax_buildin_funcs/waste_classification/package.xml b/src/jetmax_buildin_funcs/waste_classification/package.xml new file mode 100644 index 0000000..cadc0b3 --- /dev/null +++ b/src/jetmax_buildin_funcs/waste_classification/package.xml @@ -0,0 +1,71 @@ + + + waste_classification + 0.0.0 + The waste_classification package + + + + + lucas + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + message_generation + rospy + std_msgs + std_srvs + message_generation + rospy + std_msgs + std_srvs + message_generation + rospy + std_msgs + std_srvs + + + + + + + + diff --git a/src/jetmax_buildin_funcs/waste_classification/scripts/waste_classification_main.py b/src/jetmax_buildin_funcs/waste_classification/scripts/waste_classification_main.py new file mode 100755 index 0000000..999fa61 --- /dev/null +++ b/src/jetmax_buildin_funcs/waste_classification/scripts/waste_classification_main.py @@ -0,0 +1,385 @@ +#!/usr/bin/env python3 +import os +import sys +import cv2 +import math +import rospy +import numpy as np +import threading +import queue +import hiwonder +from sensor_msgs.msg import Image +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from std_srvs.srv import Empty +from std_msgs.msg import Bool +from jetmax_control.msg import SetServo +from yolov5_tensorrt import Yolov5TensorRT + +ROS_NODE_NAME = "waste_classification" + +# 垃圾分类模型 +TRT_ENGINE_PATH = os.path.join(sys.path[0], "waste_v5_160.trt") +# 模型输入尺寸 +TRT_INPUT_SIZE = 160 +# 模型所有分类名称 +TRT_CLASS_NAMES = ('Banana Peel', 'Broken Bones', 'Cigarette End', 'Disposable Chopsticks', + 'Ketchup', 'Marker', 'Oral Liquid Bottle', 'Plate', + 'Plastic Bottle', 'Storage Battery', 'Toothbrush', 'Umbrella') +# 模型分类个数 +TRT_NUM_CLASSES = 12 + +# 不同垃圾对应的类型 +WASTE_CLASSES = { + 'food_waste': ('Banana Peel', 'Broken Bones', 'Ketchup'), + 'hazardous_waste': ('Marker', 'Oral Liquid Bottle', 'Storage Battery'), + 'recyclable_waste': ('Plastic Bottle', 'Toothbrush', 'Umbrella'), + 'residual_waste': ('Plate', 'Cigarette End', 'Disposable Chopsticks'), +} + +# 框出识别结果时不同类型垃圾有不同的颜色 +COLORS = { + 'recyclable_waste': (0, 0, 255), + 'hazardous_waste': (255, 0, 0), + 'food_waste': (0, 255, 0), + 'residual_waste': (80, 80, 80) +} + +# 不同类型垃圾有不同的放置位置 +TARGET_POSITIONS = { + 'recyclable_waste': (163, -70, 65, 65), + 'hazardous_waste': (163, -23, 65, 85), + 'food_waste': (163, -23 + 52, 65, 100), + 'residual_waste': (163, -23 + 52 * 2, 65, 118) +} + + +""" +将像素坐标转换为世界坐标 +""" +def camera_to_world(cam_mtx, r, t, img_points): + inv_k = np.asmatrix(cam_mtx).I + r_mat = np.zeros((3, 3), dtype=np.float64) + cv2.Rodrigues(r, r_mat) + # invR * T + inv_r = np.asmatrix(r_mat).I # 3*3 + transPlaneToCam = np.dot(inv_r, np.asmatrix(t)) # 3*3 dot 3*1 = 3*1 + world_pt = [] + coords = np.zeros((3, 1), dtype=np.float64) + for img_pt in img_points: + coords[0][0] = img_pt[0][0] + coords[1][0] = img_pt[0][1] + coords[2][0] = 1.0 + worldPtCam = np.dot(inv_k, coords) # 3*3 dot 3*1 = 3*1 + # [x,y,1] * invR + worldPtPlane = np.dot(inv_r, worldPtCam) # 3*3 dot 3*1 = 3*1 + # zc + scale = transPlaneToCam[2][0] / worldPtPlane[2][0] + # zc * [x,y,1] * invR + scale_worldPtPlane = np.multiply(scale, worldPtPlane) + # [X,Y,Z]=zc*[x,y,1]*invR - invR*T + worldPtPlaneReproject = np.asmatrix(scale_worldPtPlane) - np.asmatrix(transPlaneToCam) # 3*1 dot 1*3 = 3*3 + pt = np.zeros((3, 1), dtype=np.float64) + pt[0][0] = worldPtPlaneReproject[0][0] + pt[1][0] = worldPtPlaneReproject[1][0] + pt[2][0] = 0 + world_pt.append(pt.T.tolist()) + return world_pt + + +class WasteClassification: + def __init__(self): + self.lock = threading.RLock() + self.is_running = False + self.moving_box = None + self.image_sub = None + self.heartbeat_timer = None + self.runner = None + self.count = 0 + self.camera_params = None + self.K = None + self.R = None + self.T = None + + """ + 重置相关变量 + """ + def reset(self): + self.is_running = False + self.moving_box = None + self.image_sub = None + self.heartbeat_timer = None + self.runner = None + self.count = 0 + + """ + 读取相机参数 + """ + def load_camera_params(self): + self.camera_params = rospy.get_param('/camera_cal/card_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + + +""" +吸取垃圾卡片并放到目标位置 +""" +def moving(): + try: + c_x, c_y, waste_class_name = state.moving_box # 要搬运的卡片的位置和分类类型 + cur_x, cur_y, cur_z = jetmax.position # 机械臂当前位置 + + # 将卡片的像素坐标转换为相对于吸嘴的物理坐标 + x, y, _ = camera_to_world(state.K, state.R, state.T, np.array([c_x, c_y]).reshape((1, 1, 2)))[0][0] + print("dist", x, y) + # 控速, 140mm/s的速度从当期位置移动到卡片上方140mm位置的用时 + t = math.sqrt(x * x + y * y + 140 * 140) / 140 + + # 卡片相对于机械臂基座的坐标 + new_x, new_y = cur_x + x, cur_y + y + nn_new_x = new_x + 15 + + # 机械臂在卡片位置时,机械臂相对于初始位置(中轴)的偏移角度 + # 后面我们用小舵机旋转相同角度来抵消这个偏移,使放置时的角度跟吸起时的角度一样 + arm_angle = math.atan(new_y / new_x) * 180 / math.pi + if arm_angle > 0: + arm_angle = (90 - arm_angle) + elif arm_angle < 0: + arm_angle = (-90 - arm_angle) + else: + pass + + # 机械臂去到卡片上方 + jetmax.set_position((nn_new_x, new_y, 70), t) + rospy.sleep(t) + jetmax.set_position((new_x, new_y, 70), 0.3) + rospy.sleep(0.4) + + # 吸起卡片 + sucker.set_state(True) + jetmax.set_position((new_x, new_y, 50 - 4), 0.8) + rospy.sleep(0.85) + + x, y, z, angle = TARGET_POSITIONS[waste_class_name] + cur_x, cur_y, cur_z = jetmax.position + jetmax.set_position((cur_x, cur_y, 140), 0.8) + rospy.sleep(0.8) + + # 机械臂到目标位置 + hiwonder.pwm_servo1.set_position(angle + arm_angle, 0.1) + cur_x, cur_y, cur_z = jetmax.position + t = math.sqrt((cur_x - x) ** 2 + (cur_y - y) ** 2) / 160 + jetmax.set_position((x, y, 120), t) + rospy.sleep(t) + jetmax.set_position((x, y, 120), 0.3) + rospy.sleep(0.4) + + jetmax.set_position((x, y, z), 0.8) + rospy.sleep(0.8) + + # 放下卡片 + sucker.release(3) + jetmax.set_position((x, y, z + 50), 0.8) + rospy.sleep(0.3) + hiwonder.pwm_servo1.set_position(90, 0.5) + rospy.sleep(0.8) + + finally: + cur_x, cur_y, cur_z = jetmax.position + # 计算140mm/s的速度从当前位置回到初始位置时间 + t = math.sqrt((cur_x - jetmax.ORIGIN[0]) ** 2 + (cur_y - jetmax.ORIGIN[1]) ** 2) / 140 + hiwonder.pwm_servo1.set_position(90, 0.5) # 小舵机复位 + # 回去初始位置 + jetmax.go_home(t) + rospy.sleep(t + 0.2) + # 清理标志,开始下一次识别搬运 + state.moving_box = None + state.runner = None + print("FINISHED") + + +def image_proc(): + # 从队列中获取新的图像 + ros_image = image_queue.get(block=True) + # 是否正在搬运,如果正在搬运就直接返回 + if state.is_running is False or state.runner is not None: + image_pub.publish(ros_image) # 原始图像直接发布 + return + # 将ros图像转换为 opencv 图像 + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + outputs = yolov5.detect(image) # yolov5 进行识别 + boxes, confs, classes = yolov5.post_process(image, outputs, 0.65) # 对网络输出结果进行后处理 + width = image.shape[1] + height = image.shape[0] + cards = [] + for box, cls_conf, cls_id in zip(boxes, confs, classes): + # 将结果映射回原图坐标 + x1 = int(box[0] / TRT_INPUT_SIZE * width) + y1 = int(box[1] / TRT_INPUT_SIZE * height) + x2 = int(box[2] / TRT_INPUT_SIZE * width) + y2 = int(box[3] / TRT_INPUT_SIZE * height) + waste_name = TRT_CLASS_NAMES[cls_id] # 获取垃圾名字 + waste_class_name = '' + for k, v in WASTE_CLASSES.items(): # 获取这个垃圾对应的分类 + if waste_name in v: + waste_class_name = k + break + cards.append((cls_conf, x1, y1, x2, y2, waste_class_name)) # 存起来已经识别到的卡片 + # 画面上框出卡片及相应的名称等数据的显示 + image = cv2.putText(image, waste_name + " " + str(float(cls_conf))[:4], (x1, y1 - 5), + cv2.FONT_HERSHEY_SIMPLEX, 0.7, COLORS[waste_class_name], 2) + # 不同分类的垃圾用不同的COLOR + image = cv2.rectangle(image, (x1, y1), (x2, y2), COLORS[waste_class_name], 3) + + # 没有识别到就清除相应标志,重新识别 + if len(cards) == 0: + state.count = 0 + state.moving_box = None + # 识别到 + else: + # 上一帧没有识别到 + if state.moving_box is None: + moving_box = max(cards, key=lambda card: card[0]) # 找出所有识别到的卡片中概率最大的卡片 + conf, x1, y1, x2, y2, waste_class_name = moving_box + c_x, c_y = (x1 + x2) / 2, (y1 + y2) / 2 + state.moving_box = c_x, c_y, waste_class_name # 存储这张概率最大的卡片作为将要搬运的目标卡片 + # 上一帧有识别到 + else: + # 找出帧中距离上帧识别到的卡片最近的卡片 + l_c_x, l_c_y, l_waste_class_name = state.moving_box + moving_box = min(cards, key=lambda card: math.sqrt((l_c_x - card[1]) ** 2 + (l_c_y - card[2]) ** 2)) + + conf, x1, y1, x2, y2, waste_class_name = moving_box + c_x, c_y = (x1 + x2) / 2, (y1 + y2) / 2 + + # 框出 + image = cv2.rectangle(image, (x1, y1), (x2, y2), (255, 255, 255), 6) + image = cv2.circle(image, (int(c_x), int(c_y)), 1, (255, 255, 255), 10) + + # 如果距离过大就认为误识别, 清理相关标志重新正确开始计数 + if math.sqrt((l_c_x - c_x) ** 2 + (l_c_y - c_y) ** 2) > 30: + state.count = 0 + else: + c_x = l_c_x * 0.2 + c_x * 0.8 + c_y = l_c_y * 0.2 + c_y * 0.8 + state.count += 1 + state.moving_box = c_x, c_y, waste_class_name + # 超过50次正确识别,就认为可靠,开始搬运 + if state.count > 50: + state.count = 0 + state.runner = threading.Thread(target=moving, daemon=True) + state.runner.start() + # 发布结果画面 + rgb_image = image.tostring() + ros_image.data = rgb_image + image_pub.publish(ros_image) + +""" +相机画面topic的回调 +只会将接收到的画面推入队列 +""" +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +""" +进入服务 +订阅相机topic, 但是不进行识别 +""" +def enter_func(msg): + rospy.loginfo("enter") + exit_func(msg) + jetmax.go_home() + state.reset() + state.load_camera_params() + state.image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) + return TriggerResponse(success=True) + + +""" +退出服务 +取消对相机topic的订阅 +""" +def exit_func(msg): + rospy.loginfo("exit") + state.is_running = False + try: + state.heartbeat_timer.cancel() + except: + pass + if isinstance(state.runner, threading.Thread): + state.runner.join() + if isinstance(state.image_sub, rospy.Subscriber): + rospy.loginfo('unregister image') + state.image_sub.unregister() + rospy.ServiceProxy('/jetmax/go_home', Empty)() + rospy.Publisher('/jetmax/end_effector/sucker/command', Bool, queue_size=1).publish(data=False) + rospy.Publisher('/jetmax/end_effector/servo1/command', SetServo, queue_size=1).publish(data=90, duration=0.5) + return TriggerResponse(success=True) + + +""" +启动识别搬运 +""" +def set_running(msg: SetBoolRequest): + if msg.data: + rospy.loginfo("start running") + state.is_running = True + else: + rospy.loginfo("stop running") + state.is_running = False + return SetBoolResponse(success=True) + + +def heartbeat_timeout_cb(): + rospy.loginfo('heartbeat timeout. exiting...') + rospy.ServiceProxy('/%s/exit' % ROS_NODE_NAME, Trigger) + + +def heartbeat_srv_cb(msg: SetBoolRequest): + rospy.logdebug("Heartbeat") + try: + state.heartbeat_timer.cancel() + except: + pass + if msg.data: + state.heartbeat_timer = threading.Timer(5, heartbeat_timeout_cb) + state.heartbeat_timer.start() + return SetBoolResponse(success=msg.data) + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) # 初始化节点 + image_queue = queue.Queue(maxsize=2) + state = WasteClassification() + state.load_camera_params() # 读取相机参数 + if state.camera_params is None: + rospy.logerr("Can not load camera parameters") + sys.exit(-1) + + # 机器人控制接口 + jetmax = hiwonder.JetMax() # 机械臂 + sucker = hiwonder.Sucker() # 吸嘴 + + # yolov5 识别器 + yolov5 = Yolov5TensorRT(TRT_ENGINE_PATH, TRT_INPUT_SIZE, TRT_NUM_CLASSES) + + # 相关 topic 的订阅/发布注册, 服务注册 + image_pub = rospy.Publisher('/%s/image_result' % ROS_NODE_NAME, Image, queue_size=1) # register result image pub + enter_srv = rospy.Service('/%s/enter' % ROS_NODE_NAME, Trigger, enter_func) + exit_srv = rospy.Service('/%s/exit' % ROS_NODE_NAME, Trigger, exit_func) + running_srv = rospy.Service('/%s/set_running' % ROS_NODE_NAME, SetBool, set_running) + heartbeat_srv = rospy.Service('/%s/heartbeat' % ROS_NODE_NAME, SetBool, heartbeat_srv_cb) + while True: + try: + image_proc() # 循环处理图片 + if rospy.is_shutdown(): + break + except Exception as e: + rospy.logerr(e) + break diff --git a/src/jetmax_buildin_funcs/waste_classification/scripts/yolov5_tensorrt.py b/src/jetmax_buildin_funcs/waste_classification/scripts/yolov5_tensorrt.py new file mode 100644 index 0000000..e60e029 --- /dev/null +++ b/src/jetmax_buildin_funcs/waste_classification/scripts/yolov5_tensorrt.py @@ -0,0 +1,207 @@ +import cv2 +import sys +import os +import tensorrt as trt +import pycuda.autoinit +import pycuda.driver as cuda +import numpy as np +import math + + +# Simple helper data class that's a little nicer to use than a 2-tuple. +class HostDeviceMem: + def __init__(self, host_mem, device_mem): + self.host = host_mem + self.device = device_mem + + def __str__(self): + return "Host:\n" + str(self.host) + "\nDevice:\n" + str(self.device) + + def __repr__(self): + return self.__str__() + + +def sigmoid_v(array): + return np.reciprocal(np.exp(-array) + 1.0) + + +def sigmoid(x): + return 1 / (1 + math.exp(-x)) + + +def non_max_suppression(boxes, confs, classes, iou_thres=0.6): + x1 = boxes[:, 0] + y1 = boxes[:, 1] + x2 = boxes[:, 2] + y2 = boxes[:, 3] + areas = (x2 - x1 + 1) * (y2 - y1 + 1) + order = confs.flatten().argsort()[::-1] + keep = [] + while order.size > 0: + i = order[0] + keep.append(i) + xx1 = np.maximum(x1[i], x1[order[1:]]) + yy1 = np.maximum(y1[i], y1[order[1:]]) + xx2 = np.minimum(x2[i], x2[order[1:]]) + yy2 = np.minimum(y2[i], y2[order[1:]]) + w = np.maximum(0.0, xx2 - xx1 + 1) + h = np.maximum(0.0, yy2 - yy1 + 1) + inter = w * h + ovr = inter / (areas[i] + areas[order[1:]] - inter) + inds = np.where(ovr <= iou_thres)[0] + order = order[inds + 1] + boxes = boxes[keep] + confs = confs[keep] + classes = classes[keep] + return boxes, confs, classes + + +def xywh2xyxy(x): + # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right + y = np.zeros_like(x) + y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x + y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y + y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x + y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y + return y + + +def nms(pred, iou_thres=0.6): + boxes = xywh2xyxy(pred[..., 0:4]) + # best class only + confs = np.amax(pred[:, 5:], 1, keepdims=True) + classes = np.argmax(pred[:, 5:], axis=-1) + return non_max_suppression(boxes, confs, classes) + + +def make_grid(nx, ny): + """ + Create scaling tensor based on box location + Source: https://github.com/ultralytics/yolov5/blob/master/models/yolo.py + Arguments + nx: x-axis num boxes + ny: y-axis num boxes + Returns + grid: tensor of shape (1, 1, nx, ny, 80) + """ + nx_vec = np.arange(nx) + ny_vec = np.arange(ny) + yv, xv = np.meshgrid(ny_vec, nx_vec) + grid = np.stack((yv, xv), axis=2) + grid = grid.reshape(1, 1, ny, nx, 2) + return grid + + +def pre_process(img_in, w, h): + img_in = cv2.resize(img_in, (w, h), interpolation=cv2.INTER_LINEAR) + # img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + # img = img.transpose((2, 0, 1)).astype(np.float16) + img_in = np.transpose(img_in, (2, 0, 1)).astype(np.float32) + img_in = np.expand_dims(img_in, axis=0) + img_in /= 255.0 + img_in = np.ascontiguousarray(img_in) + return img_in + + +class Yolov5TensorRT: + def __init__(self, model, input_size, classes_num): + # load tensorrt engine + self.input_size = input_size + TRT_LOGGER = trt.Logger(trt.Logger.INFO) + with open(model, 'rb') as f, trt.Runtime(TRT_LOGGER) as runtime: + engine = runtime.deserialize_cuda_engine(f.read()) + self.context = engine.create_execution_context() + # allocate memory + inputs, outputs, bindings = [], [], [] + stream = cuda.Stream() + for binding in engine: + size = trt.volume(engine.get_binding_shape(binding)) + dtype = trt.nptype(engine.get_binding_dtype(binding)) + host_mem = cuda.pagelocked_empty(size, dtype) + device_mem = cuda.mem_alloc(host_mem.nbytes) + bindings.append(int(device_mem)) + if engine.binding_is_input(binding): + inputs.append(HostDeviceMem(host_mem, device_mem)) + else: + outputs.append(HostDeviceMem(host_mem, device_mem)) + # save to class + self.inputs = inputs + self.outputs = outputs + self.bindings = bindings + self.stream = stream + # post processing config + self.strides = np.array([8., 16., 32.]) + anchors = np.array([ + [[10, 13], [16, 30], [33, 23]], + [[30, 61], [62, 45], [59, 119]], + [[116, 90], [156, 198], [373, 326]], + ]) + self.nl = len(anchors) + self.nc = classes_num # classes + self.no = self.nc + 5 # outputs per anchor + self.na = len(anchors[0]) + a = anchors.copy().astype(np.float32) + a = a.reshape(self.nl, -1, 2) + self.anchors = a.copy() + self.anchor_grid = a.copy().reshape(self.nl, 1, -1, 1, 1, 2) + self.output_shapes = [ + (1, 3, int(input_size / 8), int(input_size / 8), self.nc + 5), + (1, 3, int(input_size / 16), int(input_size / 16), self.nc + 5), + (1, 3, int(input_size / 32), int(input_size / 32), self.nc + 5) + ] + + def detect(self, img): + shape_orig_WH = (img.shape[1], img.shape[0]) + resized = pre_process(img, self.input_size, self.input_size) + outputs = self.inference(resized) + # reshape from flat to (1, 3, x, y, 85) + reshaped = [] + for output, shape in zip(outputs, self.output_shapes): + reshaped.append(output.reshape(shape)) + return reshaped + + def inference(self, img): + # copy img to input memory + # self.inputs[0]['host'] = np.ascontiguousarray(img) + self.inputs[0].host = np.ravel(img) + # transfer data to the gpu + [cuda.memcpy_htod_async(inp.device, inp.host, self.stream) for inp in self.inputs] + # run inference + self.context.execute_async_v2(bindings=self.bindings, stream_handle=self.stream.handle) + # fetch outputs from gpu + [cuda.memcpy_dtoh_async(out.host, out.device, self.stream) for out in self.outputs] + # synchronize stream + self.stream.synchronize() + return [out.host for out in self.outputs] + + def post_process(self, image, outputs, conf_thres=0.2): + """ + Transforms raw output into boxes, confs, classes + Applies NMS thresholding on bounding boxes and confs + Parameters: + output: raw output tensor + Returns: + boxes: x1,y1,x2,y2 tensor (dets, 4) + confs: class * obj prob tensor (dets, 1) + classes: class type tensor (dets, 1) + """ + scaled = [] + grids = [] + for out in outputs: + out = sigmoid_v(out) + _, _, width, height, _ = out.shape + grid = make_grid(width, height) + grids.append(grid) + scaled.append(out) + z = [] + for out, grid, stride, anchor in zip(scaled, grids, self.strides, self.anchor_grid): + _, _, width, height, _ = out.shape + out[..., 0:2] = (out[..., 0:2] * 2. - 0.5 + grid) * stride + out[..., 2:4] = (out[..., 2:4] * 2) ** 2 * anchor + + out = out.reshape((1, 3 * width * height, self.no)) + z.append(out) + pred = np.concatenate(z, 1) + xc = pred[..., 4] > conf_thres + pred = pred[xc] + return nms(pred) diff --git a/src/jetmax_demos/.gitignore b/src/jetmax_demos/.gitignore new file mode 100644 index 0000000..b6e4761 --- /dev/null +++ b/src/jetmax_demos/.gitignore @@ -0,0 +1,129 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ diff --git a/src/jetmax_demos/CMakeLists.txt b/src/jetmax_demos/CMakeLists.txt new file mode 100644 index 0000000..e265bb4 --- /dev/null +++ b/src/jetmax_demos/CMakeLists.txt @@ -0,0 +1,204 @@ +cmake_minimum_required(VERSION 3.0.2) +project(jetmax_demos) + +## 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 + rospy +) + +## 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 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 jetmax_demos +# CATKIN_DEPENDS rospy +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( +# include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/jetmax_demos.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/jetmax_demos_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_jetmax_demos.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/jetmax_demos/README.md b/src/jetmax_demos/README.md new file mode 100644 index 0000000..d041883 --- /dev/null +++ b/src/jetmax_demos/README.md @@ -0,0 +1,9 @@ +# jetmax_demos + + + +## 1. Demonstration + +hand_gesture: https://www.youtube.com/watch?v=vrQrUa9UXr8&ab_channel=Hiwonder + + diff --git a/src/jetmax_demos/package.xml b/src/jetmax_demos/package.xml new file mode 100644 index 0000000..54a2b31 --- /dev/null +++ b/src/jetmax_demos/package.xml @@ -0,0 +1,62 @@ + + + jetmax_demos + 0.0.0 + The jetmax_demos package + + + + + lucas + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + rospy + rospy + rospy + + + + + + + + diff --git a/src/jetmax_demos/scripts/.kill_app_funcs.sh.swp b/src/jetmax_demos/scripts/.kill_app_funcs.sh.swp new file mode 100644 index 0000000..3e8157f Binary files /dev/null and b/src/jetmax_demos/scripts/.kill_app_funcs.sh.swp differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S010_004_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S010_004_00000017.png new file mode 100644 index 0000000..1ce86e6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S010_004_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S010_004_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S010_004_00000018.png new file mode 100644 index 0000000..a71f499 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S010_004_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S010_004_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S010_004_00000019.png new file mode 100644 index 0000000..423dbac Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S010_004_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S011_004_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S011_004_00000019.png new file mode 100644 index 0000000..42e97c3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S011_004_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S011_004_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S011_004_00000020.png new file mode 100644 index 0000000..20c5dff Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S011_004_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S011_004_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S011_004_00000021.png new file mode 100644 index 0000000..0f900d2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S011_004_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S014_003_00000028.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S014_003_00000028.png new file mode 100644 index 0000000..5f26938 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S014_003_00000028.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S014_003_00000029.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S014_003_00000029.png new file mode 100644 index 0000000..28cf5df Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S014_003_00000029.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S014_003_00000030.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S014_003_00000030.png new file mode 100644 index 0000000..5321c43 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S014_003_00000030.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S022_005_00000030.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S022_005_00000030.png new file mode 100644 index 0000000..f98882c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S022_005_00000030.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S022_005_00000031.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S022_005_00000031.png new file mode 100644 index 0000000..9a6b178 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S022_005_00000031.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S022_005_00000032.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S022_005_00000032.png new file mode 100644 index 0000000..531b789 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S022_005_00000032.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S026_003_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S026_003_00000013.png new file mode 100644 index 0000000..8b801c4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S026_003_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S026_003_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S026_003_00000014.png new file mode 100644 index 0000000..552efa6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S026_003_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S026_003_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S026_003_00000015.png new file mode 100644 index 0000000..849e05f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S026_003_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S028_001_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S028_001_00000022.png new file mode 100644 index 0000000..4d0e9e1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S028_001_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S028_001_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S028_001_00000023.png new file mode 100644 index 0000000..9265297 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S028_001_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S028_001_00000024.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S028_001_00000024.png new file mode 100644 index 0000000..b2b4874 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S028_001_00000024.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S029_001_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S029_001_00000017.png new file mode 100644 index 0000000..4f15fe0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S029_001_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S029_001_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S029_001_00000018.png new file mode 100644 index 0000000..a51933d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S029_001_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S029_001_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S029_001_00000019.png new file mode 100644 index 0000000..c976e3d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S029_001_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S032_003_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S032_003_00000015.png new file mode 100644 index 0000000..38a1c4c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S032_003_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S032_003_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S032_003_00000016.png new file mode 100644 index 0000000..ee3f4ae Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S032_003_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S032_003_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S032_003_00000017.png new file mode 100644 index 0000000..61db34e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S032_003_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S034_003_00000025.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S034_003_00000025.png new file mode 100644 index 0000000..79fa094 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S034_003_00000025.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S034_003_00000026.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S034_003_00000026.png new file mode 100644 index 0000000..433b377 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S034_003_00000026.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S034_003_00000027.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S034_003_00000027.png new file mode 100644 index 0000000..3e77ae3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S034_003_00000027.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S037_003_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S037_003_00000020.png new file mode 100644 index 0000000..c197ec0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S037_003_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S037_003_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S037_003_00000021.png new file mode 100644 index 0000000..311e92e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S037_003_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S037_003_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S037_003_00000022.png new file mode 100644 index 0000000..ed27c42 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S037_003_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S042_004_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S042_004_00000018.png new file mode 100644 index 0000000..f5ddf98 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S042_004_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S042_004_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S042_004_00000019.png new file mode 100644 index 0000000..de9cf62 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S042_004_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S042_004_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S042_004_00000020.png new file mode 100644 index 0000000..dbb62bc Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S042_004_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S045_005_00000028.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S045_005_00000028.png new file mode 100644 index 0000000..b4c5ede Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S045_005_00000028.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S045_005_00000029.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S045_005_00000029.png new file mode 100644 index 0000000..4dbe3e9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S045_005_00000029.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S045_005_00000030.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S045_005_00000030.png new file mode 100644 index 0000000..e224f4d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S045_005_00000030.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S050_004_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S050_004_00000019.png new file mode 100644 index 0000000..b42379b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S050_004_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S050_004_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S050_004_00000020.png new file mode 100644 index 0000000..3ae14eb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S050_004_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S050_004_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S050_004_00000021.png new file mode 100644 index 0000000..b339874 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S050_004_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S055_004_00000026.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S055_004_00000026.png new file mode 100644 index 0000000..98dd9c5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S055_004_00000026.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S055_004_00000027.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S055_004_00000027.png new file mode 100644 index 0000000..9cc69c3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S055_004_00000027.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S055_004_00000028.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S055_004_00000028.png new file mode 100644 index 0000000..10d74b2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S055_004_00000028.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S058_005_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S058_005_00000008.png new file mode 100644 index 0000000..497e35a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S058_005_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S058_005_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S058_005_00000009.png new file mode 100644 index 0000000..b2fb96e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S058_005_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S058_005_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S058_005_00000010.png new file mode 100644 index 0000000..1d5c798 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S058_005_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S066_005_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S066_005_00000009.png new file mode 100644 index 0000000..6b121df Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S066_005_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S066_005_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S066_005_00000010.png new file mode 100644 index 0000000..06d8995 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S066_005_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S066_005_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S066_005_00000011.png new file mode 100644 index 0000000..51a94cf Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S066_005_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S067_004_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S067_004_00000021.png new file mode 100644 index 0000000..71e3107 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S067_004_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S067_004_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S067_004_00000022.png new file mode 100644 index 0000000..1f334e2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S067_004_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S067_004_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S067_004_00000023.png new file mode 100644 index 0000000..0ea2c2a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S067_004_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S071_004_00000026.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S071_004_00000026.png new file mode 100644 index 0000000..917e5cb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S071_004_00000026.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S071_004_00000027.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S071_004_00000027.png new file mode 100644 index 0000000..ce96580 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S071_004_00000027.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S071_004_00000028.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S071_004_00000028.png new file mode 100644 index 0000000..cb3fdd6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S071_004_00000028.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S072_005_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S072_005_00000017.png new file mode 100644 index 0000000..19a0a73 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S072_005_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S072_005_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S072_005_00000018.png new file mode 100644 index 0000000..35b8ef9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S072_005_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S072_005_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S072_005_00000019.png new file mode 100644 index 0000000..275469e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S072_005_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S075_008_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S075_008_00000010.png new file mode 100644 index 0000000..ef0e953 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S075_008_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S075_008_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S075_008_00000011.png new file mode 100644 index 0000000..7e0785a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S075_008_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S075_008_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S075_008_00000012.png new file mode 100644 index 0000000..e25d214 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S075_008_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S082_005_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S082_005_00000015.png new file mode 100644 index 0000000..d958169 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S082_005_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S082_005_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S082_005_00000016.png new file mode 100644 index 0000000..c411dee Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S082_005_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S082_005_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S082_005_00000017.png new file mode 100644 index 0000000..abdc1cc Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S082_005_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S087_007_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S087_007_00000014.png new file mode 100644 index 0000000..ed4e61a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S087_007_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S087_007_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S087_007_00000015.png new file mode 100644 index 0000000..3b663ef Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S087_007_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S087_007_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S087_007_00000016.png new file mode 100644 index 0000000..12b13d4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S087_007_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S089_003_00000034.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S089_003_00000034.png new file mode 100644 index 0000000..a4c3334 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S089_003_00000034.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S089_003_00000035.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S089_003_00000035.png new file mode 100644 index 0000000..a520bc2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S089_003_00000035.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S089_003_00000036.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S089_003_00000036.png new file mode 100644 index 0000000..a8ceb9b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S089_003_00000036.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S090_007_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S090_007_00000012.png new file mode 100644 index 0000000..dc24aa1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S090_007_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S090_007_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S090_007_00000013.png new file mode 100644 index 0000000..5c7ac9a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S090_007_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S090_007_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S090_007_00000014.png new file mode 100644 index 0000000..2f66ae0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S090_007_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S092_003_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S092_003_00000012.png new file mode 100644 index 0000000..8d865b7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S092_003_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S092_003_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S092_003_00000013.png new file mode 100644 index 0000000..6f6cf90 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S092_003_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S092_003_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S092_003_00000014.png new file mode 100644 index 0000000..a95b12f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S092_003_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S100_005_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S100_005_00000021.png new file mode 100644 index 0000000..377d7c3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S100_005_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S100_005_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S100_005_00000022.png new file mode 100644 index 0000000..ae84a53 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S100_005_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S100_005_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S100_005_00000023.png new file mode 100644 index 0000000..6f4ee6e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S100_005_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S109_003_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S109_003_00000015.png new file mode 100644 index 0000000..410acc9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S109_003_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S109_003_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S109_003_00000016.png new file mode 100644 index 0000000..9157a7c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S109_003_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S109_003_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S109_003_00000017.png new file mode 100644 index 0000000..577fd19 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S109_003_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S111_006_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S111_006_00000008.png new file mode 100644 index 0000000..d8f771c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S111_006_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S111_006_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S111_006_00000009.png new file mode 100644 index 0000000..67db47b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S111_006_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S111_006_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S111_006_00000010.png new file mode 100644 index 0000000..a4fc390 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S111_006_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S112_005_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S112_005_00000015.png new file mode 100644 index 0000000..712d652 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S112_005_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S112_005_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S112_005_00000016.png new file mode 100644 index 0000000..2bbf953 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S112_005_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S112_005_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S112_005_00000017.png new file mode 100644 index 0000000..aa9382e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S112_005_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S113_008_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S113_008_00000021.png new file mode 100644 index 0000000..ff81d6e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S113_008_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S113_008_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S113_008_00000022.png new file mode 100644 index 0000000..44f6153 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S113_008_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S113_008_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S113_008_00000023.png new file mode 100644 index 0000000..e9ead3b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S113_008_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S117_006_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S117_006_00000008.png new file mode 100644 index 0000000..29ce59d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S117_006_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S117_006_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S117_006_00000009.png new file mode 100644 index 0000000..f4fde68 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S117_006_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S117_006_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S117_006_00000010.png new file mode 100644 index 0000000..f12ae80 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S117_006_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S119_008_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S119_008_00000016.png new file mode 100644 index 0000000..efc0c02 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S119_008_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S119_008_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S119_008_00000017.png new file mode 100644 index 0000000..3dbb787 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S119_008_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S119_008_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S119_008_00000018.png new file mode 100644 index 0000000..e04c787 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S119_008_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S126_008_00000027.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S126_008_00000027.png new file mode 100644 index 0000000..16a5741 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S126_008_00000027.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S126_008_00000028.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S126_008_00000028.png new file mode 100644 index 0000000..18f73b8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S126_008_00000028.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S126_008_00000029.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S126_008_00000029.png new file mode 100644 index 0000000..cc72676 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S126_008_00000029.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S127_010_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S127_010_00000016.png new file mode 100644 index 0000000..39696d4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S127_010_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S127_010_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S127_010_00000017.png new file mode 100644 index 0000000..39090fb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S127_010_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S127_010_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S127_010_00000018.png new file mode 100644 index 0000000..1dc3c64 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S127_010_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S129_006_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S129_006_00000008.png new file mode 100644 index 0000000..0424cca Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S129_006_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S129_006_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S129_006_00000009.png new file mode 100644 index 0000000..71f5bea Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S129_006_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S129_006_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S129_006_00000010.png new file mode 100644 index 0000000..3aa215e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S129_006_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S130_007_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S130_007_00000018.png new file mode 100644 index 0000000..793d0d7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S130_007_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S130_007_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S130_007_00000019.png new file mode 100644 index 0000000..1a52bd1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S130_007_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S130_007_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S130_007_00000020.png new file mode 100644 index 0000000..db54858 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S130_007_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S133_003_00000045.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S133_003_00000045.png new file mode 100644 index 0000000..6697fc2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S133_003_00000045.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S133_003_00000046.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S133_003_00000046.png new file mode 100644 index 0000000..e90bd86 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S133_003_00000046.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S133_003_00000047.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S133_003_00000047.png new file mode 100644 index 0000000..c2d2fa6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S133_003_00000047.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S134_003_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S134_003_00000009.png new file mode 100644 index 0000000..55fbc4e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S134_003_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S134_003_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S134_003_00000010.png new file mode 100644 index 0000000..ecae8ac Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S134_003_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S134_003_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S134_003_00000011.png new file mode 100644 index 0000000..990fcf5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S134_003_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S136_005_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S136_005_00000008.png new file mode 100644 index 0000000..ba02ea7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S136_005_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S136_005_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S136_005_00000009.png new file mode 100644 index 0000000..673efd0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S136_005_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S136_005_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S136_005_00000010.png new file mode 100644 index 0000000..dd962c4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S136_005_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S501_001_00000065.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S501_001_00000065.png new file mode 100644 index 0000000..c29963c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S501_001_00000065.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S501_001_00000066.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S501_001_00000066.png new file mode 100644 index 0000000..fbaadca Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S501_001_00000066.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S501_001_00000067.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S501_001_00000067.png new file mode 100644 index 0000000..f9d83a6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S501_001_00000067.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S502_001_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S502_001_00000014.png new file mode 100644 index 0000000..473e103 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S502_001_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S502_001_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S502_001_00000015.png new file mode 100644 index 0000000..88d1c96 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S502_001_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S502_001_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S502_001_00000016.png new file mode 100644 index 0000000..66f27af Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S502_001_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S503_001_00000069.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S503_001_00000069.png new file mode 100644 index 0000000..4400942 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S503_001_00000069.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S503_001_00000070.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S503_001_00000070.png new file mode 100644 index 0000000..473d515 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S503_001_00000070.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S503_001_00000071.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S503_001_00000071.png new file mode 100644 index 0000000..a82dc8f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S503_001_00000071.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S504_001_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S504_001_00000020.png new file mode 100644 index 0000000..2dddc73 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S504_001_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S504_001_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S504_001_00000021.png new file mode 100644 index 0000000..2195767 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S504_001_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S504_001_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S504_001_00000022.png new file mode 100644 index 0000000..1736a84 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S504_001_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S506_001_00000038.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S506_001_00000038.png new file mode 100644 index 0000000..3166c43 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S506_001_00000038.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S506_001_00000039.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S506_001_00000039.png new file mode 100644 index 0000000..9db7807 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S506_001_00000039.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S506_001_00000040.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S506_001_00000040.png new file mode 100644 index 0000000..2bb2c1b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S506_001_00000040.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S999_001_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S999_001_00000016.png new file mode 100644 index 0000000..432ae3e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S999_001_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S999_001_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S999_001_00000017.png new file mode 100644 index 0000000..a477454 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S999_001_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S999_001_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S999_001_00000018.png new file mode 100644 index 0000000..7cf2b8c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/anger/S999_001_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S138_008_00000007.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S138_008_00000007.png new file mode 100644 index 0000000..061a5ad Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S138_008_00000007.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S138_008_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S138_008_00000008.png new file mode 100644 index 0000000..0698d42 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S138_008_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S138_008_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S138_008_00000009.png new file mode 100644 index 0000000..2dd928a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S138_008_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S139_002_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S139_002_00000011.png new file mode 100644 index 0000000..5dc7daf Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S139_002_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S139_002_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S139_002_00000012.png new file mode 100644 index 0000000..dfa9b6d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S139_002_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S139_002_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S139_002_00000013.png new file mode 100644 index 0000000..de46dff Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S139_002_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S147_002_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S147_002_00000011.png new file mode 100644 index 0000000..2241626 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S147_002_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S147_002_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S147_002_00000012.png new file mode 100644 index 0000000..1bd0bd3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S147_002_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S147_002_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S147_002_00000013.png new file mode 100644 index 0000000..dfaefdf Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S147_002_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S148_002_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S148_002_00000013.png new file mode 100644 index 0000000..ab6c0d5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S148_002_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S148_002_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S148_002_00000014.png new file mode 100644 index 0000000..2208520 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S148_002_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S148_002_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S148_002_00000015.png new file mode 100644 index 0000000..fc9354e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S148_002_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S149_002_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S149_002_00000011.png new file mode 100644 index 0000000..c6bb2b4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S149_002_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S149_002_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S149_002_00000012.png new file mode 100644 index 0000000..bd90bb7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S149_002_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S149_002_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S149_002_00000013.png new file mode 100644 index 0000000..73e9bca Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S149_002_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S151_002_00000027.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S151_002_00000027.png new file mode 100644 index 0000000..359bc70 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S151_002_00000027.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S151_002_00000028.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S151_002_00000028.png new file mode 100644 index 0000000..fb86e2f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S151_002_00000028.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S151_002_00000029.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S151_002_00000029.png new file mode 100644 index 0000000..2cdd8dd Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S151_002_00000029.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S154_002_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S154_002_00000011.png new file mode 100644 index 0000000..97ce508 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S154_002_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S154_002_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S154_002_00000012.png new file mode 100644 index 0000000..9ef9372 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S154_002_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S154_002_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S154_002_00000013.png new file mode 100644 index 0000000..98ed53b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S154_002_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S155_002_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S155_002_00000010.png new file mode 100644 index 0000000..13c0496 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S155_002_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S155_002_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S155_002_00000011.png new file mode 100644 index 0000000..7d45d6f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S155_002_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S155_002_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S155_002_00000012.png new file mode 100644 index 0000000..73856b3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S155_002_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S156_002_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S156_002_00000019.png new file mode 100644 index 0000000..179aa45 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S156_002_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S156_002_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S156_002_00000020.png new file mode 100644 index 0000000..111a7c0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S156_002_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S156_002_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S156_002_00000021.png new file mode 100644 index 0000000..54ddfd8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S156_002_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S157_002_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S157_002_00000009.png new file mode 100644 index 0000000..8228323 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S157_002_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S157_002_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S157_002_00000010.png new file mode 100644 index 0000000..3cf74fc Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S157_002_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S157_002_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S157_002_00000011.png new file mode 100644 index 0000000..bb5c39a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S157_002_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S158_002_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S158_002_00000009.png new file mode 100644 index 0000000..2820ffc Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S158_002_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S158_002_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S158_002_00000010.png new file mode 100644 index 0000000..ae82984 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S158_002_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S158_002_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S158_002_00000011.png new file mode 100644 index 0000000..63305ee Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S158_002_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S160_006_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S160_006_00000008.png new file mode 100644 index 0000000..43a8159 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S160_006_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S160_006_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S160_006_00000009.png new file mode 100644 index 0000000..0db2491 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S160_006_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S160_006_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S160_006_00000010.png new file mode 100644 index 0000000..6d1dfa7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S160_006_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S502_002_00000007.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S502_002_00000007.png new file mode 100644 index 0000000..44a6adf Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S502_002_00000007.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S502_002_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S502_002_00000008.png new file mode 100644 index 0000000..4b3d6e8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S502_002_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S502_002_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S502_002_00000009.png new file mode 100644 index 0000000..566abdb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S502_002_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S503_002_00000006.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S503_002_00000006.png new file mode 100644 index 0000000..a7864ae Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S503_002_00000006.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S503_002_00000007.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S503_002_00000007.png new file mode 100644 index 0000000..3c15360 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S503_002_00000007.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S503_002_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S503_002_00000008.png new file mode 100644 index 0000000..6cbc1e5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S503_002_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S504_002_00000007.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S504_002_00000007.png new file mode 100644 index 0000000..ff8ddcf Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S504_002_00000007.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S504_002_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S504_002_00000008.png new file mode 100644 index 0000000..0fe8758 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S504_002_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S504_002_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S504_002_00000009.png new file mode 100644 index 0000000..401c792 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S504_002_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S505_002_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S505_002_00000019.png new file mode 100644 index 0000000..da71811 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S505_002_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S505_002_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S505_002_00000020.png new file mode 100644 index 0000000..aef1b48 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S505_002_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S505_002_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S505_002_00000021.png new file mode 100644 index 0000000..b181f8a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S505_002_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S506_002_00000007.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S506_002_00000007.png new file mode 100644 index 0000000..8635544 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S506_002_00000007.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S506_002_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S506_002_00000008.png new file mode 100644 index 0000000..ce8ac4b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S506_002_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S506_002_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S506_002_00000009.png new file mode 100644 index 0000000..0589244 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S506_002_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S895_002_00000005.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S895_002_00000005.png new file mode 100644 index 0000000..bec11ac Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S895_002_00000005.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S895_002_00000006.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S895_002_00000006.png new file mode 100644 index 0000000..ddb8d43 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S895_002_00000006.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S895_002_00000007.png b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S895_002_00000007.png new file mode 100644 index 0000000..7010384 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/contempt/S895_002_00000007.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S005_001_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S005_001_00000009.png new file mode 100644 index 0000000..82970e3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S005_001_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S005_001_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S005_001_00000010.png new file mode 100644 index 0000000..a5635a8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S005_001_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S005_001_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S005_001_00000011.png new file mode 100644 index 0000000..12dfbf3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S005_001_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S011_005_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S011_005_00000018.png new file mode 100644 index 0000000..054574c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S011_005_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S011_005_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S011_005_00000019.png new file mode 100644 index 0000000..5c20ad3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S011_005_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S011_005_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S011_005_00000020.png new file mode 100644 index 0000000..4d1b0c3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S011_005_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S022_006_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S022_006_00000015.png new file mode 100644 index 0000000..cd553d0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S022_006_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S022_006_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S022_006_00000016.png new file mode 100644 index 0000000..117c7ea Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S022_006_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S022_006_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S022_006_00000017.png new file mode 100644 index 0000000..0976760 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S022_006_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S032_005_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S032_005_00000014.png new file mode 100644 index 0000000..abd2528 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S032_005_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S032_005_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S032_005_00000015.png new file mode 100644 index 0000000..f30775a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S032_005_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S032_005_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S032_005_00000016.png new file mode 100644 index 0000000..c5d8df9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S032_005_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S035_005_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S035_005_00000017.png new file mode 100644 index 0000000..9ce3ab0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S035_005_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S035_005_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S035_005_00000018.png new file mode 100644 index 0000000..6d199ef Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S035_005_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S035_005_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S035_005_00000019.png new file mode 100644 index 0000000..36a4d05 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S035_005_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S044_006_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S044_006_00000017.png new file mode 100644 index 0000000..046faff Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S044_006_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S044_006_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S044_006_00000018.png new file mode 100644 index 0000000..0817b32 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S044_006_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S044_006_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S044_006_00000019.png new file mode 100644 index 0000000..5638bf9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S044_006_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S045_004_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S045_004_00000013.png new file mode 100644 index 0000000..8640edf Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S045_004_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S045_004_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S045_004_00000014.png new file mode 100644 index 0000000..c0b6d60 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S045_004_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S045_004_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S045_004_00000015.png new file mode 100644 index 0000000..5ea805a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S045_004_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S046_004_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S046_004_00000015.png new file mode 100644 index 0000000..e754b9f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S046_004_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S046_004_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S046_004_00000016.png new file mode 100644 index 0000000..03aa09f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S046_004_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S046_004_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S046_004_00000017.png new file mode 100644 index 0000000..e0d7926 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S046_004_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S051_003_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S051_003_00000016.png new file mode 100644 index 0000000..7378c03 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S051_003_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S051_003_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S051_003_00000017.png new file mode 100644 index 0000000..42dd43a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S051_003_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S051_003_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S051_003_00000018.png new file mode 100644 index 0000000..2d5ad0e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S051_003_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S052_006_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S052_006_00000011.png new file mode 100644 index 0000000..714c3c4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S052_006_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S052_006_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S052_006_00000012.png new file mode 100644 index 0000000..344c85d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S052_006_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S052_006_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S052_006_00000013.png new file mode 100644 index 0000000..ba71f51 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S052_006_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S054_004_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S054_004_00000022.png new file mode 100644 index 0000000..37ccebf Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S054_004_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S054_004_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S054_004_00000023.png new file mode 100644 index 0000000..bc266f3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S054_004_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S054_004_00000024.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S054_004_00000024.png new file mode 100644 index 0000000..9a168c9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S054_004_00000024.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S055_003_00000007.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S055_003_00000007.png new file mode 100644 index 0000000..54c717b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S055_003_00000007.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S055_003_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S055_003_00000008.png new file mode 100644 index 0000000..1d15d5b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S055_003_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S055_003_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S055_003_00000009.png new file mode 100644 index 0000000..100b63d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S055_003_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S056_002_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S056_002_00000008.png new file mode 100644 index 0000000..c0292d2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S056_002_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S056_002_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S056_002_00000009.png new file mode 100644 index 0000000..0b27c1c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S056_002_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S056_002_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S056_002_00000010.png new file mode 100644 index 0000000..0cfea9f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S056_002_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S057_003_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S057_003_00000013.png new file mode 100644 index 0000000..571d449 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S057_003_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S057_003_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S057_003_00000014.png new file mode 100644 index 0000000..3706dc1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S057_003_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S057_003_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S057_003_00000015.png new file mode 100644 index 0000000..938908a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S057_003_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S058_006_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S058_006_00000016.png new file mode 100644 index 0000000..a62fc7a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S058_006_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S058_006_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S058_006_00000017.png new file mode 100644 index 0000000..6795405 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S058_006_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S058_006_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S058_006_00000018.png new file mode 100644 index 0000000..a0833d4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S058_006_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S060_005_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S060_005_00000019.png new file mode 100644 index 0000000..dcc8260 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S060_005_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S060_005_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S060_005_00000020.png new file mode 100644 index 0000000..1f9e8a1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S060_005_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S060_005_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S060_005_00000021.png new file mode 100644 index 0000000..e73554d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S060_005_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S061_004_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S061_004_00000020.png new file mode 100644 index 0000000..7096ec4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S061_004_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S061_004_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S061_004_00000021.png new file mode 100644 index 0000000..cd0144a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S061_004_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S061_004_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S061_004_00000022.png new file mode 100644 index 0000000..d66e5a5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S061_004_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S062_005_00000027.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S062_005_00000027.png new file mode 100644 index 0000000..056572c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S062_005_00000027.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S062_005_00000028.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S062_005_00000028.png new file mode 100644 index 0000000..99eda63 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S062_005_00000028.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S062_005_00000029.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S062_005_00000029.png new file mode 100644 index 0000000..52f4687 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S062_005_00000029.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S065_005_00000006.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S065_005_00000006.png new file mode 100644 index 0000000..3df9170 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S065_005_00000006.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S065_005_00000007.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S065_005_00000007.png new file mode 100644 index 0000000..61cfaa5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S065_005_00000007.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S065_005_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S065_005_00000008.png new file mode 100644 index 0000000..68b7bee Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S065_005_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S067_006_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S067_006_00000009.png new file mode 100644 index 0000000..106b6bb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S067_006_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S067_006_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S067_006_00000010.png new file mode 100644 index 0000000..b008fc5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S067_006_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S067_006_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S067_006_00000011.png new file mode 100644 index 0000000..a23c636 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S067_006_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S068_005_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S068_005_00000019.png new file mode 100644 index 0000000..9a14542 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S068_005_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S068_005_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S068_005_00000020.png new file mode 100644 index 0000000..3ea7f4e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S068_005_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S068_005_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S068_005_00000021.png new file mode 100644 index 0000000..ce835be Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S068_005_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S069_003_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S069_003_00000009.png new file mode 100644 index 0000000..057e177 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S069_003_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S069_003_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S069_003_00000010.png new file mode 100644 index 0000000..892f11a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S069_003_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S069_003_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S069_003_00000011.png new file mode 100644 index 0000000..7b88769 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S069_003_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S070_005_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S070_005_00000014.png new file mode 100644 index 0000000..69c61c6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S070_005_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S070_005_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S070_005_00000015.png new file mode 100644 index 0000000..b971003 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S070_005_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S070_005_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S070_005_00000016.png new file mode 100644 index 0000000..15d8ce8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S070_005_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S071_006_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S071_006_00000012.png new file mode 100644 index 0000000..dd6eb61 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S071_006_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S071_006_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S071_006_00000013.png new file mode 100644 index 0000000..17e57e5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S071_006_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S071_006_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S071_006_00000014.png new file mode 100644 index 0000000..4ad3a63 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S071_006_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S073_006_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S073_006_00000012.png new file mode 100644 index 0000000..688ffa1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S073_006_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S073_006_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S073_006_00000013.png new file mode 100644 index 0000000..cc92546 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S073_006_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S073_006_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S073_006_00000014.png new file mode 100644 index 0000000..3d26246 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S073_006_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S074_004_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S074_004_00000016.png new file mode 100644 index 0000000..d3f8cdd Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S074_004_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S074_004_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S074_004_00000017.png new file mode 100644 index 0000000..98bb043 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S074_004_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S074_004_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S074_004_00000018.png new file mode 100644 index 0000000..468ae7c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S074_004_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S075_005_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S075_005_00000010.png new file mode 100644 index 0000000..2eb65a2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S075_005_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S075_005_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S075_005_00000011.png new file mode 100644 index 0000000..42aa3dc Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S075_005_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S075_005_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S075_005_00000012.png new file mode 100644 index 0000000..7192709 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S075_005_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S076_005_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S076_005_00000010.png new file mode 100644 index 0000000..d5462f0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S076_005_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S076_005_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S076_005_00000011.png new file mode 100644 index 0000000..de82c0e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S076_005_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S076_005_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S076_005_00000012.png new file mode 100644 index 0000000..7af8d9d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S076_005_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S077_006_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S077_006_00000012.png new file mode 100644 index 0000000..ac8a29d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S077_006_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S077_006_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S077_006_00000013.png new file mode 100644 index 0000000..e60cd81 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S077_006_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S077_006_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S077_006_00000014.png new file mode 100644 index 0000000..c355fc7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S077_006_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S078_007_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S078_007_00000011.png new file mode 100644 index 0000000..49fb8c6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S078_007_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S078_007_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S078_007_00000012.png new file mode 100644 index 0000000..f4815d0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S078_007_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S078_007_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S078_007_00000013.png new file mode 100644 index 0000000..3687db8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S078_007_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S079_002_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S079_002_00000010.png new file mode 100644 index 0000000..e0aa973 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S079_002_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S079_002_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S079_002_00000011.png new file mode 100644 index 0000000..faec888 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S079_002_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S079_002_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S079_002_00000012.png new file mode 100644 index 0000000..5c99fa7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S079_002_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S080_008_00000007.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S080_008_00000007.png new file mode 100644 index 0000000..a0dfc19 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S080_008_00000007.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S080_008_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S080_008_00000008.png new file mode 100644 index 0000000..a6002d1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S080_008_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S080_008_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S080_008_00000009.png new file mode 100644 index 0000000..d7e75a2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S080_008_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S081_008_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S081_008_00000009.png new file mode 100644 index 0000000..f764ea8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S081_008_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S081_008_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S081_008_00000010.png new file mode 100644 index 0000000..34cae2a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S081_008_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S081_008_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S081_008_00000011.png new file mode 100644 index 0000000..068968b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S081_008_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S082_007_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S082_007_00000008.png new file mode 100644 index 0000000..7eab7fb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S082_007_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S082_007_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S082_007_00000009.png new file mode 100644 index 0000000..127a4cf Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S082_007_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S082_007_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S082_007_00000010.png new file mode 100644 index 0000000..221fa3b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S082_007_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S085_004_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S085_004_00000015.png new file mode 100644 index 0000000..55197f2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S085_004_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S085_004_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S085_004_00000016.png new file mode 100644 index 0000000..58d256a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S085_004_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S085_004_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S085_004_00000017.png new file mode 100644 index 0000000..ab5c2ed Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S085_004_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S087_004_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S087_004_00000010.png new file mode 100644 index 0000000..4f6258a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S087_004_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S087_004_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S087_004_00000011.png new file mode 100644 index 0000000..7e25fc4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S087_004_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S087_004_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S087_004_00000012.png new file mode 100644 index 0000000..ce29324 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S087_004_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S088_004_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S088_004_00000018.png new file mode 100644 index 0000000..27be15a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S088_004_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S088_004_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S088_004_00000019.png new file mode 100644 index 0000000..e7b6697 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S088_004_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S088_004_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S088_004_00000020.png new file mode 100644 index 0000000..dff8fb3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S088_004_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S090_006_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S090_006_00000009.png new file mode 100644 index 0000000..298f346 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S090_006_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S090_006_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S090_006_00000010.png new file mode 100644 index 0000000..4f6246e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S090_006_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S090_006_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S090_006_00000011.png new file mode 100644 index 0000000..b40b4ea Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S090_006_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S095_006_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S095_006_00000011.png new file mode 100644 index 0000000..891b14d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S095_006_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S095_006_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S095_006_00000012.png new file mode 100644 index 0000000..6d8b8c2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S095_006_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S095_006_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S095_006_00000013.png new file mode 100644 index 0000000..7946cec Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S095_006_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S096_003_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S096_003_00000010.png new file mode 100644 index 0000000..6761ee8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S096_003_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S096_003_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S096_003_00000011.png new file mode 100644 index 0000000..72eb7a3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S096_003_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S096_003_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S096_003_00000012.png new file mode 100644 index 0000000..4e30ad4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S096_003_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S097_004_00000028.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S097_004_00000028.png new file mode 100644 index 0000000..ab79acc Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S097_004_00000028.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S097_004_00000029.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S097_004_00000029.png new file mode 100644 index 0000000..b5156c3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S097_004_00000029.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S097_004_00000030.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S097_004_00000030.png new file mode 100644 index 0000000..e39b72c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S097_004_00000030.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S098_003_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S098_003_00000011.png new file mode 100644 index 0000000..b648afd Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S098_003_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S098_003_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S098_003_00000012.png new file mode 100644 index 0000000..3b307b2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S098_003_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S098_003_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S098_003_00000013.png new file mode 100644 index 0000000..9bab325 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S098_003_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S099_007_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S099_007_00000010.png new file mode 100644 index 0000000..0552d04 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S099_007_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S099_007_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S099_007_00000011.png new file mode 100644 index 0000000..428d05c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S099_007_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S099_007_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S099_007_00000012.png new file mode 100644 index 0000000..6a1d99f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S099_007_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S102_009_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S102_009_00000013.png new file mode 100644 index 0000000..0e7b2ae Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S102_009_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S102_009_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S102_009_00000014.png new file mode 100644 index 0000000..657b30e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S102_009_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S102_009_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S102_009_00000015.png new file mode 100644 index 0000000..284280a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S102_009_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S105_008_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S105_008_00000008.png new file mode 100644 index 0000000..a51e202 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S105_008_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S105_008_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S105_008_00000009.png new file mode 100644 index 0000000..a1e1a1c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S105_008_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S105_008_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S105_008_00000010.png new file mode 100644 index 0000000..b4d9baf Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S105_008_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S106_004_00000006.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S106_004_00000006.png new file mode 100644 index 0000000..6d2d16b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S106_004_00000006.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S106_004_00000007.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S106_004_00000007.png new file mode 100644 index 0000000..5a220d0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S106_004_00000007.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S106_004_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S106_004_00000008.png new file mode 100644 index 0000000..b6c0b48 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S106_004_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S107_005_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S107_005_00000009.png new file mode 100644 index 0000000..dd5bb84 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S107_005_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S107_005_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S107_005_00000010.png new file mode 100644 index 0000000..3144f10 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S107_005_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S107_005_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S107_005_00000011.png new file mode 100644 index 0000000..73c5c9f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S107_005_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S108_006_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S108_006_00000018.png new file mode 100644 index 0000000..548f02d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S108_006_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S108_006_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S108_006_00000019.png new file mode 100644 index 0000000..b2e420b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S108_006_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S108_006_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S108_006_00000020.png new file mode 100644 index 0000000..19f724b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S108_006_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S109_005_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S109_005_00000012.png new file mode 100644 index 0000000..97ea7c2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S109_005_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S109_005_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S109_005_00000013.png new file mode 100644 index 0000000..9c38bc8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S109_005_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S109_005_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S109_005_00000014.png new file mode 100644 index 0000000..09fd8c9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S109_005_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S111_007_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S111_007_00000012.png new file mode 100644 index 0000000..3d7bce0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S111_007_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S111_007_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S111_007_00000013.png new file mode 100644 index 0000000..d277ce2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S111_007_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S111_007_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S111_007_00000014.png new file mode 100644 index 0000000..e14bc03 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S111_007_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S116_006_00000005.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S116_006_00000005.png new file mode 100644 index 0000000..02d342f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S116_006_00000005.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S116_006_00000006.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S116_006_00000006.png new file mode 100644 index 0000000..13c5348 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S116_006_00000006.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S116_006_00000007.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S116_006_00000007.png new file mode 100644 index 0000000..f0024eb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S116_006_00000007.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S124_006_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S124_006_00000009.png new file mode 100644 index 0000000..d8a0780 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S124_006_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S124_006_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S124_006_00000010.png new file mode 100644 index 0000000..ddb9534 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S124_006_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S124_006_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S124_006_00000011.png new file mode 100644 index 0000000..137b147 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S124_006_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S125_008_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S125_008_00000008.png new file mode 100644 index 0000000..103d8cf Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S125_008_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S125_008_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S125_008_00000009.png new file mode 100644 index 0000000..ce60334 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S125_008_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S125_008_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S125_008_00000010.png new file mode 100644 index 0000000..1bd0ff1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S125_008_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S128_004_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S128_004_00000011.png new file mode 100644 index 0000000..1234840 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S128_004_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S128_004_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S128_004_00000012.png new file mode 100644 index 0000000..a0cc90c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S128_004_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S128_004_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S128_004_00000013.png new file mode 100644 index 0000000..4c07782 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S128_004_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S129_011_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S129_011_00000016.png new file mode 100644 index 0000000..09ae3b4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S129_011_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S129_011_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S129_011_00000017.png new file mode 100644 index 0000000..62d7f81 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S129_011_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S129_011_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S129_011_00000018.png new file mode 100644 index 0000000..0d111a4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S129_011_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S130_012_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S130_012_00000009.png new file mode 100644 index 0000000..7909b6d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S130_012_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S130_012_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S130_012_00000010.png new file mode 100644 index 0000000..47b8bff Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S130_012_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S130_012_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S130_012_00000011.png new file mode 100644 index 0000000..f1844c2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S130_012_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S131_010_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S131_010_00000016.png new file mode 100644 index 0000000..8e809b8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S131_010_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S131_010_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S131_010_00000017.png new file mode 100644 index 0000000..eaa1310 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S131_010_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S131_010_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S131_010_00000018.png new file mode 100644 index 0000000..920c087 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S131_010_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S132_005_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S132_005_00000014.png new file mode 100644 index 0000000..0c99888 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S132_005_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S132_005_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S132_005_00000015.png new file mode 100644 index 0000000..19e042d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S132_005_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S132_005_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S132_005_00000016.png new file mode 100644 index 0000000..e8687fd Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S132_005_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S134_008_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S134_008_00000011.png new file mode 100644 index 0000000..d921aeb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S134_008_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S134_008_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S134_008_00000012.png new file mode 100644 index 0000000..ed0f36c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S134_008_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S134_008_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S134_008_00000013.png new file mode 100644 index 0000000..da8c9ad Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/disgust/S134_008_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S011_003_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S011_003_00000012.png new file mode 100644 index 0000000..506241c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S011_003_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S011_003_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S011_003_00000013.png new file mode 100644 index 0000000..16f990c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S011_003_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S011_003_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S011_003_00000014.png new file mode 100644 index 0000000..0956c8c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S011_003_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S032_004_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S032_004_00000012.png new file mode 100644 index 0000000..e1e0ce6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S032_004_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S032_004_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S032_004_00000013.png new file mode 100644 index 0000000..0a824bc Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S032_004_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S032_004_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S032_004_00000014.png new file mode 100644 index 0000000..7dab887 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S032_004_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S046_003_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S046_003_00000014.png new file mode 100644 index 0000000..c81a573 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S046_003_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S046_003_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S046_003_00000015.png new file mode 100644 index 0000000..9d5b7f5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S046_003_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S046_003_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S046_003_00000016.png new file mode 100644 index 0000000..21e0277 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S046_003_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S050_001_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S050_001_00000015.png new file mode 100644 index 0000000..67950c4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S050_001_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S050_001_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S050_001_00000016.png new file mode 100644 index 0000000..907f6a2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S050_001_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S050_001_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S050_001_00000017.png new file mode 100644 index 0000000..b70697f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S050_001_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S054_002_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S054_002_00000013.png new file mode 100644 index 0000000..4a5928c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S054_002_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S054_002_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S054_002_00000014.png new file mode 100644 index 0000000..04fa0d0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S054_002_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S054_002_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S054_002_00000015.png new file mode 100644 index 0000000..4a9d592 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S054_002_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S055_006_00000006.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S055_006_00000006.png new file mode 100644 index 0000000..30d99bb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S055_006_00000006.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S055_006_00000007.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S055_006_00000007.png new file mode 100644 index 0000000..dbeab4f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S055_006_00000007.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S055_006_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S055_006_00000008.png new file mode 100644 index 0000000..8e5cfc4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S055_006_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S059_002_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S059_002_00000015.png new file mode 100644 index 0000000..6316c37 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S059_002_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S059_002_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S059_002_00000016.png new file mode 100644 index 0000000..d379e6d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S059_002_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S059_002_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S059_002_00000017.png new file mode 100644 index 0000000..5c316b7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S059_002_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S062_001_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S062_001_00000015.png new file mode 100644 index 0000000..df18ab1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S062_001_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S062_001_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S062_001_00000016.png new file mode 100644 index 0000000..b773e33 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S062_001_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S062_001_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S062_001_00000017.png new file mode 100644 index 0000000..bb6058f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S062_001_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S065_002_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S065_002_00000020.png new file mode 100644 index 0000000..41bcebd Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S065_002_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S065_002_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S065_002_00000021.png new file mode 100644 index 0000000..4965fda Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S065_002_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S065_002_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S065_002_00000022.png new file mode 100644 index 0000000..294231e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S065_002_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S068_004_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S068_004_00000008.png new file mode 100644 index 0000000..b870fff Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S068_004_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S068_004_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S068_004_00000009.png new file mode 100644 index 0000000..49a4309 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S068_004_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S068_004_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S068_004_00000010.png new file mode 100644 index 0000000..dc3407b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S068_004_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S074_001_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S074_001_00000018.png new file mode 100644 index 0000000..a8ee01f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S074_001_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S074_001_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S074_001_00000019.png new file mode 100644 index 0000000..aec4c94 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S074_001_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S074_001_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S074_001_00000020.png new file mode 100644 index 0000000..585e24f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S074_001_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S084_002_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S084_002_00000021.png new file mode 100644 index 0000000..862bb43 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S084_002_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S084_002_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S084_002_00000022.png new file mode 100644 index 0000000..52d43fe Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S084_002_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S084_002_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S084_002_00000023.png new file mode 100644 index 0000000..b67f7a9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S084_002_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S091_001_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S091_001_00000013.png new file mode 100644 index 0000000..50cedd4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S091_001_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S091_001_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S091_001_00000014.png new file mode 100644 index 0000000..714156e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S091_001_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S091_001_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S091_001_00000015.png new file mode 100644 index 0000000..6b041b2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S091_001_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S102_003_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S102_003_00000014.png new file mode 100644 index 0000000..9721a70 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S102_003_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S102_003_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S102_003_00000015.png new file mode 100644 index 0000000..ff30824 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S102_003_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S102_003_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S102_003_00000016.png new file mode 100644 index 0000000..6c5db30 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S102_003_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S117_003_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S117_003_00000012.png new file mode 100644 index 0000000..a6417b0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S117_003_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S117_003_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S117_003_00000013.png new file mode 100644 index 0000000..31a17ce Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S117_003_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S117_003_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S117_003_00000014.png new file mode 100644 index 0000000..20e0687 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S117_003_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S119_003_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S119_003_00000022.png new file mode 100644 index 0000000..10ba120 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S119_003_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S119_003_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S119_003_00000023.png new file mode 100644 index 0000000..1442f0d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S119_003_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S119_003_00000024.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S119_003_00000024.png new file mode 100644 index 0000000..1bf8c4a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S119_003_00000024.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S124_003_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S124_003_00000009.png new file mode 100644 index 0000000..b3e6ced Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S124_003_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S124_003_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S124_003_00000010.png new file mode 100644 index 0000000..42a2882 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S124_003_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S124_003_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S124_003_00000011.png new file mode 100644 index 0000000..32f09a0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S124_003_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S125_006_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S125_006_00000020.png new file mode 100644 index 0000000..1c01191 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S125_006_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S125_006_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S125_006_00000021.png new file mode 100644 index 0000000..6871f82 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S125_006_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S125_006_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S125_006_00000022.png new file mode 100644 index 0000000..0a64a55 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S125_006_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S132_003_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S132_003_00000021.png new file mode 100644 index 0000000..90ced43 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S132_003_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S132_003_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S132_003_00000022.png new file mode 100644 index 0000000..77bae6c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S132_003_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S132_003_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S132_003_00000023.png new file mode 100644 index 0000000..2b719b0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S132_003_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S138_001_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S138_001_00000010.png new file mode 100644 index 0000000..624ea32 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S138_001_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S138_001_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S138_001_00000011.png new file mode 100644 index 0000000..05d52eb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S138_001_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S138_001_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S138_001_00000012.png new file mode 100644 index 0000000..24a1609 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S138_001_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S501_004_00000054.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S501_004_00000054.png new file mode 100644 index 0000000..873b88f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S501_004_00000054.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S501_004_00000055.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S501_004_00000055.png new file mode 100644 index 0000000..43348bb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S501_004_00000055.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S501_004_00000056.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S501_004_00000056.png new file mode 100644 index 0000000..f3d7c0b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S501_004_00000056.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S502_004_00000050.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S502_004_00000050.png new file mode 100644 index 0000000..2fb749a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S502_004_00000050.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S502_004_00000051.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S502_004_00000051.png new file mode 100644 index 0000000..edcb459 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S502_004_00000051.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S502_004_00000052.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S502_004_00000052.png new file mode 100644 index 0000000..b0d2755 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S502_004_00000052.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S504_004_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S504_004_00000013.png new file mode 100644 index 0000000..417dd22 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S504_004_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S504_004_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S504_004_00000014.png new file mode 100644 index 0000000..8d744f3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S504_004_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S504_004_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S504_004_00000015.png new file mode 100644 index 0000000..6fce5eb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S504_004_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S506_004_00000036.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S506_004_00000036.png new file mode 100644 index 0000000..edc27a3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S506_004_00000036.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S506_004_00000037.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S506_004_00000037.png new file mode 100644 index 0000000..36ba6b6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S506_004_00000037.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S506_004_00000038.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S506_004_00000038.png new file mode 100644 index 0000000..4d09508 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S506_004_00000038.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S999_003_00000053.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S999_003_00000053.png new file mode 100644 index 0000000..dbd9ac1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S999_003_00000053.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S999_003_00000054.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S999_003_00000054.png new file mode 100644 index 0000000..f001ff2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S999_003_00000054.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S999_003_00000055.png b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S999_003_00000055.png new file mode 100644 index 0000000..82e877c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/fear/S999_003_00000055.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S010_006_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S010_006_00000013.png new file mode 100644 index 0000000..064cde5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S010_006_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S010_006_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S010_006_00000014.png new file mode 100644 index 0000000..953d9e5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S010_006_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S010_006_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S010_006_00000015.png new file mode 100644 index 0000000..ecd9ae3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S010_006_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S011_006_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S011_006_00000011.png new file mode 100644 index 0000000..3368287 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S011_006_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S011_006_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S011_006_00000012.png new file mode 100644 index 0000000..046c971 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S011_006_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S011_006_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S011_006_00000013.png new file mode 100644 index 0000000..ebd1f3e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S011_006_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S014_005_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S014_005_00000015.png new file mode 100644 index 0000000..84dd5b9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S014_005_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S014_005_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S014_005_00000016.png new file mode 100644 index 0000000..e07a88c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S014_005_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S014_005_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S014_005_00000017.png new file mode 100644 index 0000000..59b0aec Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S014_005_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S026_006_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S026_006_00000011.png new file mode 100644 index 0000000..155ff78 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S026_006_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S026_006_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S026_006_00000012.png new file mode 100644 index 0000000..25ac49c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S026_006_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S026_006_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S026_006_00000013.png new file mode 100644 index 0000000..f1e0389 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S026_006_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S032_006_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S032_006_00000014.png new file mode 100644 index 0000000..d29a125 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S032_006_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S032_006_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S032_006_00000015.png new file mode 100644 index 0000000..b1ed6e1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S032_006_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S032_006_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S032_006_00000016.png new file mode 100644 index 0000000..8cca2f1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S032_006_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S034_005_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S034_005_00000008.png new file mode 100644 index 0000000..3816007 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S034_005_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S034_005_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S034_005_00000009.png new file mode 100644 index 0000000..f71f579 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S034_005_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S034_005_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S034_005_00000010.png new file mode 100644 index 0000000..822e6df Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S034_005_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S035_006_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S035_006_00000016.png new file mode 100644 index 0000000..ee26180 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S035_006_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S035_006_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S035_006_00000017.png new file mode 100644 index 0000000..cd5df4b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S035_006_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S035_006_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S035_006_00000018.png new file mode 100644 index 0000000..0c5f5aa Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S035_006_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S037_006_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S037_006_00000019.png new file mode 100644 index 0000000..f93b1ed Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S037_006_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S037_006_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S037_006_00000020.png new file mode 100644 index 0000000..422ed3c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S037_006_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S037_006_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S037_006_00000021.png new file mode 100644 index 0000000..c8b9865 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S037_006_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S042_006_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S042_006_00000015.png new file mode 100644 index 0000000..5897185 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S042_006_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S042_006_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S042_006_00000016.png new file mode 100644 index 0000000..f5b4468 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S042_006_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S042_006_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S042_006_00000017.png new file mode 100644 index 0000000..fcf5751 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S042_006_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S044_003_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S044_003_00000012.png new file mode 100644 index 0000000..4d9c701 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S044_003_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S044_003_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S044_003_00000013.png new file mode 100644 index 0000000..7648b07 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S044_003_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S044_003_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S044_003_00000014.png new file mode 100644 index 0000000..cde0fee Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S044_003_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S050_006_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S050_006_00000021.png new file mode 100644 index 0000000..acf71c3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S050_006_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S050_006_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S050_006_00000022.png new file mode 100644 index 0000000..972df94 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S050_006_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S050_006_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S050_006_00000023.png new file mode 100644 index 0000000..7c36318 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S050_006_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S052_004_00000031.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S052_004_00000031.png new file mode 100644 index 0000000..27e29b4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S052_004_00000031.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S052_004_00000032.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S052_004_00000032.png new file mode 100644 index 0000000..97efb3e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S052_004_00000032.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S052_004_00000033.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S052_004_00000033.png new file mode 100644 index 0000000..b06aa27 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S052_004_00000033.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S053_004_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S053_004_00000022.png new file mode 100644 index 0000000..d9a8c27 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S053_004_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S053_004_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S053_004_00000023.png new file mode 100644 index 0000000..d029345 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S053_004_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S053_004_00000024.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S053_004_00000024.png new file mode 100644 index 0000000..8255909 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S053_004_00000024.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S055_005_00000043.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S055_005_00000043.png new file mode 100644 index 0000000..65175b5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S055_005_00000043.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S055_005_00000044.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S055_005_00000044.png new file mode 100644 index 0000000..975dcf0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S055_005_00000044.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S055_005_00000045.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S055_005_00000045.png new file mode 100644 index 0000000..2e7d151 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S055_005_00000045.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S056_004_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S056_004_00000018.png new file mode 100644 index 0000000..83b6b98 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S056_004_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S056_004_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S056_004_00000019.png new file mode 100644 index 0000000..192549d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S056_004_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S056_004_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S056_004_00000020.png new file mode 100644 index 0000000..88483eb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S056_004_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S057_006_00000031.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S057_006_00000031.png new file mode 100644 index 0000000..9d3774d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S057_006_00000031.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S057_006_00000032.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S057_006_00000032.png new file mode 100644 index 0000000..b734717 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S057_006_00000032.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S057_006_00000033.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S057_006_00000033.png new file mode 100644 index 0000000..e71eac4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S057_006_00000033.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S060_002_00000024.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S060_002_00000024.png new file mode 100644 index 0000000..0a2d93c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S060_002_00000024.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S060_002_00000025.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S060_002_00000025.png new file mode 100644 index 0000000..0761416 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S060_002_00000025.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S060_002_00000026.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S060_002_00000026.png new file mode 100644 index 0000000..984eb6e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S060_002_00000026.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S061_002_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S061_002_00000013.png new file mode 100644 index 0000000..4af1bb4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S061_002_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S061_002_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S061_002_00000014.png new file mode 100644 index 0000000..cf1a66c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S061_002_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S061_002_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S061_002_00000015.png new file mode 100644 index 0000000..4aaddda Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S061_002_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S062_004_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S062_004_00000022.png new file mode 100644 index 0000000..b3a946f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S062_004_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S062_004_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S062_004_00000023.png new file mode 100644 index 0000000..40cbd5b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S062_004_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S062_004_00000024.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S062_004_00000024.png new file mode 100644 index 0000000..e344e14 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S062_004_00000024.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S063_002_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S063_002_00000021.png new file mode 100644 index 0000000..a3c7944 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S063_002_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S063_002_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S063_002_00000022.png new file mode 100644 index 0000000..7369bbf Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S063_002_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S063_002_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S063_002_00000023.png new file mode 100644 index 0000000..03a7786 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S063_002_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S064_003_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S064_003_00000023.png new file mode 100644 index 0000000..3bd4526 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S064_003_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S064_003_00000024.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S064_003_00000024.png new file mode 100644 index 0000000..a4f3be2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S064_003_00000024.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S064_003_00000025.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S064_003_00000025.png new file mode 100644 index 0000000..3014d6f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S064_003_00000025.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S065_004_00000026.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S065_004_00000026.png new file mode 100644 index 0000000..96023b8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S065_004_00000026.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S065_004_00000027.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S065_004_00000027.png new file mode 100644 index 0000000..0d83d8f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S065_004_00000027.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S065_004_00000028.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S065_004_00000028.png new file mode 100644 index 0000000..74ba094 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S065_004_00000028.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S066_003_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S066_003_00000010.png new file mode 100644 index 0000000..c19043c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S066_003_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S066_003_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S066_003_00000011.png new file mode 100644 index 0000000..2164ce7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S066_003_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S066_003_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S066_003_00000012.png new file mode 100644 index 0000000..dc91d8e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S066_003_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S067_005_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S067_005_00000020.png new file mode 100644 index 0000000..5ca04d1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S067_005_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S067_005_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S067_005_00000021.png new file mode 100644 index 0000000..188a36b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S067_005_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S067_005_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S067_005_00000022.png new file mode 100644 index 0000000..38895d4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S067_005_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S068_002_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S068_002_00000013.png new file mode 100644 index 0000000..4dbcc74 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S068_002_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S068_002_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S068_002_00000014.png new file mode 100644 index 0000000..03dc5d8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S068_002_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S068_002_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S068_002_00000015.png new file mode 100644 index 0000000..27f1394 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S068_002_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S069_004_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S069_004_00000015.png new file mode 100644 index 0000000..832fd9b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S069_004_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S069_004_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S069_004_00000016.png new file mode 100644 index 0000000..89c7055 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S069_004_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S069_004_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S069_004_00000017.png new file mode 100644 index 0000000..94e570e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S069_004_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S070_003_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S070_003_00000015.png new file mode 100644 index 0000000..83c0425 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S070_003_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S070_003_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S070_003_00000016.png new file mode 100644 index 0000000..7645c22 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S070_003_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S070_003_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S070_003_00000017.png new file mode 100644 index 0000000..c278f8d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S070_003_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S071_005_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S071_005_00000019.png new file mode 100644 index 0000000..5fd06fc Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S071_005_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S071_005_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S071_005_00000020.png new file mode 100644 index 0000000..e0fde4c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S071_005_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S071_005_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S071_005_00000021.png new file mode 100644 index 0000000..8c0c6e3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S071_005_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S072_006_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S072_006_00000020.png new file mode 100644 index 0000000..45c56da Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S072_006_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S072_006_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S072_006_00000021.png new file mode 100644 index 0000000..f2c0c90 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S072_006_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S072_006_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S072_006_00000022.png new file mode 100644 index 0000000..40d464c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S072_006_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S074_005_00000041.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S074_005_00000041.png new file mode 100644 index 0000000..50b1250 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S074_005_00000041.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S074_005_00000042.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S074_005_00000042.png new file mode 100644 index 0000000..b941047 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S074_005_00000042.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S074_005_00000043.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S074_005_00000043.png new file mode 100644 index 0000000..36ee91e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S074_005_00000043.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S075_006_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S075_006_00000023.png new file mode 100644 index 0000000..ac06964 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S075_006_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S075_006_00000024.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S075_006_00000024.png new file mode 100644 index 0000000..c0bed1a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S075_006_00000024.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S075_006_00000025.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S075_006_00000025.png new file mode 100644 index 0000000..2688ce7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S075_006_00000025.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S076_006_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S076_006_00000017.png new file mode 100644 index 0000000..542072d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S076_006_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S076_006_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S076_006_00000018.png new file mode 100644 index 0000000..f53c61f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S076_006_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S076_006_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S076_006_00000019.png new file mode 100644 index 0000000..89f0582 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S076_006_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S078_004_00000025.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S078_004_00000025.png new file mode 100644 index 0000000..631177a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S078_004_00000025.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S078_004_00000026.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S078_004_00000026.png new file mode 100644 index 0000000..e61329f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S078_004_00000026.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S078_004_00000027.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S078_004_00000027.png new file mode 100644 index 0000000..8d1dcb6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S078_004_00000027.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S079_004_00000024.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S079_004_00000024.png new file mode 100644 index 0000000..41dc6be Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S079_004_00000024.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S079_004_00000025.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S079_004_00000025.png new file mode 100644 index 0000000..6d042d5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S079_004_00000025.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S079_004_00000026.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S079_004_00000026.png new file mode 100644 index 0000000..a4cea04 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S079_004_00000026.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S083_003_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S083_003_00000017.png new file mode 100644 index 0000000..55fd474 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S083_003_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S083_003_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S083_003_00000018.png new file mode 100644 index 0000000..f32ae6b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S083_003_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S083_003_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S083_003_00000019.png new file mode 100644 index 0000000..5bc5c85 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S083_003_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S085_002_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S085_002_00000012.png new file mode 100644 index 0000000..7f8bb7b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S085_002_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S085_002_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S085_002_00000013.png new file mode 100644 index 0000000..10caaaa Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S085_002_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S085_002_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S085_002_00000014.png new file mode 100644 index 0000000..cf3fb34 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S085_002_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S086_002_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S086_002_00000013.png new file mode 100644 index 0000000..793e5b2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S086_002_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S086_002_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S086_002_00000014.png new file mode 100644 index 0000000..c2766f5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S086_002_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S086_002_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S086_002_00000015.png new file mode 100644 index 0000000..6a48b86 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S086_002_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S087_005_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S087_005_00000010.png new file mode 100644 index 0000000..c09da5b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S087_005_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S087_005_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S087_005_00000011.png new file mode 100644 index 0000000..5c32f8f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S087_005_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S087_005_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S087_005_00000012.png new file mode 100644 index 0000000..fc52403 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S087_005_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S089_002_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S089_002_00000019.png new file mode 100644 index 0000000..2109539 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S089_002_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S089_002_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S089_002_00000020.png new file mode 100644 index 0000000..a4e9acb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S089_002_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S089_002_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S089_002_00000021.png new file mode 100644 index 0000000..59f7184 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S089_002_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S091_003_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S091_003_00000019.png new file mode 100644 index 0000000..f79353a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S091_003_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S091_003_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S091_003_00000020.png new file mode 100644 index 0000000..144865d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S091_003_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S091_003_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S091_003_00000021.png new file mode 100644 index 0000000..9c4dd93 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S091_003_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S092_004_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S092_004_00000022.png new file mode 100644 index 0000000..f570412 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S092_004_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S092_004_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S092_004_00000023.png new file mode 100644 index 0000000..749802e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S092_004_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S092_004_00000024.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S092_004_00000024.png new file mode 100644 index 0000000..72d5bf3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S092_004_00000024.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S093_004_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S093_004_00000014.png new file mode 100644 index 0000000..3425b4b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S093_004_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S093_004_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S093_004_00000015.png new file mode 100644 index 0000000..bcb649b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S093_004_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S093_004_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S093_004_00000016.png new file mode 100644 index 0000000..8c34b7f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S093_004_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S094_004_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S094_004_00000010.png new file mode 100644 index 0000000..7e4d111 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S094_004_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S094_004_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S094_004_00000011.png new file mode 100644 index 0000000..701faa3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S094_004_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S094_004_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S094_004_00000012.png new file mode 100644 index 0000000..7e4fb8c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S094_004_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S095_007_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S095_007_00000019.png new file mode 100644 index 0000000..f104d57 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S095_007_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S095_007_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S095_007_00000020.png new file mode 100644 index 0000000..65ba7eb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S095_007_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S095_007_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S095_007_00000021.png new file mode 100644 index 0000000..0687089 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S095_007_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S096_004_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S096_004_00000009.png new file mode 100644 index 0000000..72a31de Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S096_004_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S096_004_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S096_004_00000010.png new file mode 100644 index 0000000..74893b4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S096_004_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S096_004_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S096_004_00000011.png new file mode 100644 index 0000000..1daee2e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S096_004_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S097_006_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S097_006_00000017.png new file mode 100644 index 0000000..2a40e77 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S097_006_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S097_006_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S097_006_00000018.png new file mode 100644 index 0000000..2f6d0d0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S097_006_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S097_006_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S097_006_00000019.png new file mode 100644 index 0000000..13b4f26 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S097_006_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S098_004_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S098_004_00000013.png new file mode 100644 index 0000000..e3abbb5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S098_004_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S098_004_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S098_004_00000014.png new file mode 100644 index 0000000..e5b1479 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S098_004_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S098_004_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S098_004_00000015.png new file mode 100644 index 0000000..ffe5dce Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S098_004_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S099_004_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S099_004_00000013.png new file mode 100644 index 0000000..f50914e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S099_004_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S099_004_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S099_004_00000014.png new file mode 100644 index 0000000..f963639 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S099_004_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S099_004_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S099_004_00000015.png new file mode 100644 index 0000000..de0a41a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S099_004_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S100_006_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S100_006_00000014.png new file mode 100644 index 0000000..c665fc0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S100_006_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S100_006_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S100_006_00000015.png new file mode 100644 index 0000000..3520e72 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S100_006_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S100_006_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S100_006_00000016.png new file mode 100644 index 0000000..5d4e25e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S100_006_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S106_006_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S106_006_00000009.png new file mode 100644 index 0000000..1f05fc6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S106_006_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S106_006_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S106_006_00000010.png new file mode 100644 index 0000000..440b124 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S106_006_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S106_006_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S106_006_00000011.png new file mode 100644 index 0000000..773d71b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S106_006_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S108_008_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S108_008_00000011.png new file mode 100644 index 0000000..f6f8a8e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S108_008_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S108_008_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S108_008_00000012.png new file mode 100644 index 0000000..06d245a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S108_008_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S108_008_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S108_008_00000013.png new file mode 100644 index 0000000..c78e88e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S108_008_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S109_006_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S109_006_00000013.png new file mode 100644 index 0000000..712a031 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S109_006_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S109_006_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S109_006_00000014.png new file mode 100644 index 0000000..2763a48 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S109_006_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S109_006_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S109_006_00000015.png new file mode 100644 index 0000000..b1d5b63 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S109_006_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S114_006_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S114_006_00000021.png new file mode 100644 index 0000000..4e8f874 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S114_006_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S114_006_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S114_006_00000022.png new file mode 100644 index 0000000..36976f0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S114_006_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S114_006_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S114_006_00000023.png new file mode 100644 index 0000000..e07eed4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S114_006_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S115_008_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S115_008_00000015.png new file mode 100644 index 0000000..47aede8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S115_008_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S115_008_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S115_008_00000016.png new file mode 100644 index 0000000..a4d0ef5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S115_008_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S115_008_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S115_008_00000017.png new file mode 100644 index 0000000..1e530e7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S115_008_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S116_007_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S116_007_00000015.png new file mode 100644 index 0000000..b85360e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S116_007_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S116_007_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S116_007_00000016.png new file mode 100644 index 0000000..b716a2c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S116_007_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S116_007_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S116_007_00000017.png new file mode 100644 index 0000000..719db61 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S116_007_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S124_007_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S124_007_00000022.png new file mode 100644 index 0000000..cacb75c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S124_007_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S124_007_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S124_007_00000023.png new file mode 100644 index 0000000..5325f61 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S124_007_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S124_007_00000024.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S124_007_00000024.png new file mode 100644 index 0000000..322880d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S124_007_00000024.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S125_005_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S125_005_00000011.png new file mode 100644 index 0000000..cda459d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S125_005_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S125_005_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S125_005_00000012.png new file mode 100644 index 0000000..8b1fb3a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S125_005_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S125_005_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S125_005_00000013.png new file mode 100644 index 0000000..6521b5f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S125_005_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S127_004_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S127_004_00000014.png new file mode 100644 index 0000000..65e6ca7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S127_004_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S127_004_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S127_004_00000015.png new file mode 100644 index 0000000..c787f2a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S127_004_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S127_004_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S127_004_00000016.png new file mode 100644 index 0000000..7ca65fd Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S127_004_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S128_011_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S128_011_00000014.png new file mode 100644 index 0000000..6455d5e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S128_011_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S128_011_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S128_011_00000015.png new file mode 100644 index 0000000..51390a8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S128_011_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S128_011_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S128_011_00000016.png new file mode 100644 index 0000000..caaca49 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S128_011_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S129_012_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S129_012_00000009.png new file mode 100644 index 0000000..386bf9e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S129_012_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S129_012_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S129_012_00000010.png new file mode 100644 index 0000000..25426ae Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S129_012_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S129_012_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S129_012_00000011.png new file mode 100644 index 0000000..d337f2c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S129_012_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S130_013_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S130_013_00000013.png new file mode 100644 index 0000000..808eff8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S130_013_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S130_013_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S130_013_00000014.png new file mode 100644 index 0000000..d3c348b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S130_013_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S130_013_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S130_013_00000015.png new file mode 100644 index 0000000..e004d5c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S130_013_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S131_006_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S131_006_00000020.png new file mode 100644 index 0000000..76b6623 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S131_006_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S131_006_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S131_006_00000021.png new file mode 100644 index 0000000..cc80ad1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S131_006_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S131_006_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S131_006_00000022.png new file mode 100644 index 0000000..940023c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S131_006_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S132_006_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S132_006_00000021.png new file mode 100644 index 0000000..7ec64a9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S132_006_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S132_006_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S132_006_00000022.png new file mode 100644 index 0000000..ea73cf6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S132_006_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S132_006_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S132_006_00000023.png new file mode 100644 index 0000000..1e92eac Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S132_006_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S133_010_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S133_010_00000012.png new file mode 100644 index 0000000..54445fc Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S133_010_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S133_010_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S133_010_00000013.png new file mode 100644 index 0000000..c7e2292 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S133_010_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S133_010_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S133_010_00000014.png new file mode 100644 index 0000000..8dad2ae Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S133_010_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S134_004_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S134_004_00000013.png new file mode 100644 index 0000000..bd94cbf Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S134_004_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S134_004_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S134_004_00000014.png new file mode 100644 index 0000000..cb6a519 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S134_004_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S134_004_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S134_004_00000015.png new file mode 100644 index 0000000..60b0a60 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S134_004_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S135_012_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S135_012_00000018.png new file mode 100644 index 0000000..c131960 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S135_012_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S135_012_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S135_012_00000019.png new file mode 100644 index 0000000..bb9133d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S135_012_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S135_012_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S135_012_00000020.png new file mode 100644 index 0000000..aa7704d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S135_012_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S136_006_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S136_006_00000018.png new file mode 100644 index 0000000..b6e269f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S136_006_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S136_006_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S136_006_00000019.png new file mode 100644 index 0000000..cd845b2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S136_006_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S136_006_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S136_006_00000020.png new file mode 100644 index 0000000..e810830 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S136_006_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S137_011_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S137_011_00000018.png new file mode 100644 index 0000000..e91bd28 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S137_011_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S137_011_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S137_011_00000019.png new file mode 100644 index 0000000..996060c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S137_011_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S137_011_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S137_011_00000020.png new file mode 100644 index 0000000..d75b058 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S137_011_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S138_005_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S138_005_00000014.png new file mode 100644 index 0000000..4641493 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S138_005_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S138_005_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S138_005_00000015.png new file mode 100644 index 0000000..3b179ff Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S138_005_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S138_005_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S138_005_00000016.png new file mode 100644 index 0000000..2a25bda Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/happy/S138_005_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S011_002_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S011_002_00000020.png new file mode 100644 index 0000000..219bb6c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S011_002_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S011_002_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S011_002_00000021.png new file mode 100644 index 0000000..bf881a3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S011_002_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S011_002_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S011_002_00000022.png new file mode 100644 index 0000000..5c1baea Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S011_002_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S014_002_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S014_002_00000014.png new file mode 100644 index 0000000..185ffda Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S014_002_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S014_002_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S014_002_00000015.png new file mode 100644 index 0000000..8acf6ef Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S014_002_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S014_002_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S014_002_00000016.png new file mode 100644 index 0000000..22c6a6c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S014_002_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S026_002_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S026_002_00000014.png new file mode 100644 index 0000000..46c29e7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S026_002_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S026_002_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S026_002_00000015.png new file mode 100644 index 0000000..93cd583 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S026_002_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S026_002_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S026_002_00000016.png new file mode 100644 index 0000000..4bce73e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S026_002_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S042_002_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S042_002_00000014.png new file mode 100644 index 0000000..2943f61 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S042_002_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S042_002_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S042_002_00000015.png new file mode 100644 index 0000000..92d3f46 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S042_002_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S042_002_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S042_002_00000016.png new file mode 100644 index 0000000..94385c6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S042_002_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S046_001_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S046_001_00000023.png new file mode 100644 index 0000000..60a7d31 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S046_001_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S046_001_00000024.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S046_001_00000024.png new file mode 100644 index 0000000..0acabec Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S046_001_00000024.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S046_001_00000025.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S046_001_00000025.png new file mode 100644 index 0000000..71a4a1c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S046_001_00000025.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S064_004_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S064_004_00000012.png new file mode 100644 index 0000000..bc8b411 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S064_004_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S064_004_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S064_004_00000013.png new file mode 100644 index 0000000..af9bfd7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S064_004_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S064_004_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S064_004_00000014.png new file mode 100644 index 0000000..b076c87 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S064_004_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S066_004_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S066_004_00000008.png new file mode 100644 index 0000000..c9a7dcb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S066_004_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S066_004_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S066_004_00000009.png new file mode 100644 index 0000000..915ea4a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S066_004_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S066_004_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S066_004_00000010.png new file mode 100644 index 0000000..a208994 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S066_004_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S071_002_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S071_002_00000018.png new file mode 100644 index 0000000..e55a118 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S071_002_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S071_002_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S071_002_00000019.png new file mode 100644 index 0000000..ddba67a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S071_002_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S071_002_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S071_002_00000020.png new file mode 100644 index 0000000..4a498c4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S071_002_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S080_005_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S080_005_00000011.png new file mode 100644 index 0000000..4a91e6d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S080_005_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S080_005_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S080_005_00000012.png new file mode 100644 index 0000000..65d9879 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S080_005_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S080_005_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S080_005_00000013.png new file mode 100644 index 0000000..1683dc0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S080_005_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S081_002_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S081_002_00000022.png new file mode 100644 index 0000000..be1b57c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S081_002_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S081_002_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S081_002_00000023.png new file mode 100644 index 0000000..23b44e8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S081_002_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S081_002_00000024.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S081_002_00000024.png new file mode 100644 index 0000000..5d23a25 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S081_002_00000024.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S093_001_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S093_001_00000018.png new file mode 100644 index 0000000..26c3559 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S093_001_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S093_001_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S093_001_00000019.png new file mode 100644 index 0000000..35f4a01 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S093_001_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S093_001_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S093_001_00000020.png new file mode 100644 index 0000000..1d0d907 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S093_001_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S095_010_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S095_010_00000012.png new file mode 100644 index 0000000..7d469b2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S095_010_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S095_010_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S095_010_00000013.png new file mode 100644 index 0000000..f921698 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S095_010_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S095_010_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S095_010_00000014.png new file mode 100644 index 0000000..e1255e1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S095_010_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S106_002_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S106_002_00000014.png new file mode 100644 index 0000000..575f303 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S106_002_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S106_002_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S106_002_00000015.png new file mode 100644 index 0000000..ee9e3b3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S106_002_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S106_002_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S106_002_00000016.png new file mode 100644 index 0000000..380d7c7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S106_002_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S108_005_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S108_005_00000020.png new file mode 100644 index 0000000..28ce2a0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S108_005_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S108_005_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S108_005_00000021.png new file mode 100644 index 0000000..c023877 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S108_005_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S108_005_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S108_005_00000022.png new file mode 100644 index 0000000..fda83e2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S108_005_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S113_003_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S113_003_00000013.png new file mode 100644 index 0000000..4921abe Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S113_003_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S113_003_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S113_003_00000014.png new file mode 100644 index 0000000..eb0f6d8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S113_003_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S113_003_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S113_003_00000015.png new file mode 100644 index 0000000..771b113 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S113_003_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S115_004_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S115_004_00000015.png new file mode 100644 index 0000000..40e58ae Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S115_004_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S115_004_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S115_004_00000016.png new file mode 100644 index 0000000..749b492 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S115_004_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S115_004_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S115_004_00000017.png new file mode 100644 index 0000000..d742ae2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S115_004_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S125_001_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S125_001_00000012.png new file mode 100644 index 0000000..d761092 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S125_001_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S125_001_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S125_001_00000013.png new file mode 100644 index 0000000..35e9c94 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S125_001_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S125_001_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S125_001_00000014.png new file mode 100644 index 0000000..fb49cc1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S125_001_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S130_009_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S130_009_00000017.png new file mode 100644 index 0000000..cff9d5a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S130_009_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S130_009_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S130_009_00000018.png new file mode 100644 index 0000000..e4ba64a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S130_009_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S130_009_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S130_009_00000019.png new file mode 100644 index 0000000..c016384 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S130_009_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S131_003_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S131_003_00000022.png new file mode 100644 index 0000000..e88b942 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S131_003_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S131_003_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S131_003_00000023.png new file mode 100644 index 0000000..846461d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S131_003_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S131_003_00000024.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S131_003_00000024.png new file mode 100644 index 0000000..53f9fe6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S131_003_00000024.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S132_002_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S132_002_00000016.png new file mode 100644 index 0000000..8956d4e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S132_002_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S132_002_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S132_002_00000017.png new file mode 100644 index 0000000..84600aa Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S132_002_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S132_002_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S132_002_00000018.png new file mode 100644 index 0000000..6afcaba Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S132_002_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S136_003_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S136_003_00000012.png new file mode 100644 index 0000000..ff1cedf Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S136_003_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S136_003_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S136_003_00000013.png new file mode 100644 index 0000000..f942240 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S136_003_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S136_003_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S136_003_00000014.png new file mode 100644 index 0000000..e906b38 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S136_003_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S137_005_00000025.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S137_005_00000025.png new file mode 100644 index 0000000..6d133bb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S137_005_00000025.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S137_005_00000026.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S137_005_00000026.png new file mode 100644 index 0000000..f1c537d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S137_005_00000026.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S137_005_00000027.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S137_005_00000027.png new file mode 100644 index 0000000..541be2d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S137_005_00000027.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S138_007_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S138_007_00000009.png new file mode 100644 index 0000000..285b82c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S138_007_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S138_007_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S138_007_00000010.png new file mode 100644 index 0000000..53c1721 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S138_007_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S138_007_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S138_007_00000011.png new file mode 100644 index 0000000..f9893fd Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S138_007_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S501_006_00000039.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S501_006_00000039.png new file mode 100644 index 0000000..0a90415 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S501_006_00000039.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S501_006_00000040.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S501_006_00000040.png new file mode 100644 index 0000000..a16af3e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S501_006_00000040.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S501_006_00000041.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S501_006_00000041.png new file mode 100644 index 0000000..78b04d0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S501_006_00000041.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S503_006_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S503_006_00000018.png new file mode 100644 index 0000000..a1b42d2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S503_006_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S503_006_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S503_006_00000019.png new file mode 100644 index 0000000..30cb211 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S503_006_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S503_006_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S503_006_00000020.png new file mode 100644 index 0000000..e71a09e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S503_006_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S504_006_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S504_006_00000016.png new file mode 100644 index 0000000..0aec42f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S504_006_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S504_006_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S504_006_00000017.png new file mode 100644 index 0000000..e0104e8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S504_006_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S504_006_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S504_006_00000018.png new file mode 100644 index 0000000..3efd5f0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S504_006_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S505_006_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S505_006_00000017.png new file mode 100644 index 0000000..a694a4b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S505_006_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S505_006_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S505_006_00000018.png new file mode 100644 index 0000000..2187af7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S505_006_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S505_006_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S505_006_00000019.png new file mode 100644 index 0000000..b361d14 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S505_006_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S506_006_00000040.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S506_006_00000040.png new file mode 100644 index 0000000..b53620b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S506_006_00000040.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S506_006_00000041.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S506_006_00000041.png new file mode 100644 index 0000000..2fdbfd3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S506_006_00000041.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S506_006_00000042.png b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S506_006_00000042.png new file mode 100644 index 0000000..23c13a1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/sadness/S506_006_00000042.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S010_002_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S010_002_00000012.png new file mode 100644 index 0000000..4e25554 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S010_002_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S010_002_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S010_002_00000013.png new file mode 100644 index 0000000..851dcc1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S010_002_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S010_002_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S010_002_00000014.png new file mode 100644 index 0000000..bd272e9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S010_002_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S011_001_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S011_001_00000014.png new file mode 100644 index 0000000..6d345c5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S011_001_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S011_001_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S011_001_00000015.png new file mode 100644 index 0000000..7bc16a9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S011_001_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S011_001_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S011_001_00000016.png new file mode 100644 index 0000000..09d18ce Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S011_001_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S014_001_00000027.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S014_001_00000027.png new file mode 100644 index 0000000..7c22535 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S014_001_00000027.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S014_001_00000028.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S014_001_00000028.png new file mode 100644 index 0000000..bf586dd Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S014_001_00000028.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S014_001_00000029.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S014_001_00000029.png new file mode 100644 index 0000000..57d4bb5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S014_001_00000029.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S022_001_00000028.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S022_001_00000028.png new file mode 100644 index 0000000..23739f1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S022_001_00000028.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S022_001_00000029.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S022_001_00000029.png new file mode 100644 index 0000000..752b247 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S022_001_00000029.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S022_001_00000030.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S022_001_00000030.png new file mode 100644 index 0000000..245adc6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S022_001_00000030.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S026_001_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S026_001_00000013.png new file mode 100644 index 0000000..427cd2b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S026_001_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S026_001_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S026_001_00000014.png new file mode 100644 index 0000000..8b74afc Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S026_001_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S026_001_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S026_001_00000015.png new file mode 100644 index 0000000..1ba298c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S026_001_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S032_001_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S032_001_00000020.png new file mode 100644 index 0000000..b349968 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S032_001_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S032_001_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S032_001_00000021.png new file mode 100644 index 0000000..0406959 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S032_001_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S032_001_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S032_001_00000022.png new file mode 100644 index 0000000..9342fda Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S032_001_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S034_001_00000027.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S034_001_00000027.png new file mode 100644 index 0000000..e8e101b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S034_001_00000027.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S034_001_00000028.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S034_001_00000028.png new file mode 100644 index 0000000..2a8cad6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S034_001_00000028.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S034_001_00000029.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S034_001_00000029.png new file mode 100644 index 0000000..eff7011 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S034_001_00000029.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S035_001_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S035_001_00000013.png new file mode 100644 index 0000000..3193d2c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S035_001_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S035_001_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S035_001_00000014.png new file mode 100644 index 0000000..d49be4e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S035_001_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S035_001_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S035_001_00000015.png new file mode 100644 index 0000000..49d100a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S035_001_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S037_001_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S037_001_00000018.png new file mode 100644 index 0000000..6629542 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S037_001_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S037_001_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S037_001_00000019.png new file mode 100644 index 0000000..3a0942a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S037_001_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S037_001_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S037_001_00000020.png new file mode 100644 index 0000000..845c8fb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S037_001_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S042_001_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S042_001_00000017.png new file mode 100644 index 0000000..6047b0c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S042_001_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S042_001_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S042_001_00000018.png new file mode 100644 index 0000000..1f36229 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S042_001_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S042_001_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S042_001_00000019.png new file mode 100644 index 0000000..6448af2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S042_001_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S044_001_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S044_001_00000022.png new file mode 100644 index 0000000..8815863 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S044_001_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S044_001_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S044_001_00000023.png new file mode 100644 index 0000000..d3fcea0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S044_001_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S044_001_00000024.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S044_001_00000024.png new file mode 100644 index 0000000..f23434b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S044_001_00000024.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S046_002_00000004.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S046_002_00000004.png new file mode 100644 index 0000000..fcfd4ea Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S046_002_00000004.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S046_002_00000005.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S046_002_00000005.png new file mode 100644 index 0000000..8868ce6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S046_002_00000005.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S046_002_00000006.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S046_002_00000006.png new file mode 100644 index 0000000..e9e34c6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S046_002_00000006.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S050_002_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S050_002_00000016.png new file mode 100644 index 0000000..7dcbe2f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S050_002_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S050_002_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S050_002_00000017.png new file mode 100644 index 0000000..ca002a9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S050_002_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S050_002_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S050_002_00000018.png new file mode 100644 index 0000000..53f70aa Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S050_002_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S051_002_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S051_002_00000017.png new file mode 100644 index 0000000..07bd765 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S051_002_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S051_002_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S051_002_00000018.png new file mode 100644 index 0000000..dae92af Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S051_002_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S051_002_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S051_002_00000019.png new file mode 100644 index 0000000..6ecbbec Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S051_002_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S052_001_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S052_001_00000013.png new file mode 100644 index 0000000..7babf25 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S052_001_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S052_001_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S052_001_00000014.png new file mode 100644 index 0000000..864c2a2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S052_001_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S052_001_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S052_001_00000015.png new file mode 100644 index 0000000..cfee4cf Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S052_001_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S053_001_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S053_001_00000021.png new file mode 100644 index 0000000..f8fbad4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S053_001_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S053_001_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S053_001_00000022.png new file mode 100644 index 0000000..bfd057b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S053_001_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S053_001_00000023.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S053_001_00000023.png new file mode 100644 index 0000000..ef34f2a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S053_001_00000023.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S054_003_00000005.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S054_003_00000005.png new file mode 100644 index 0000000..229adce Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S054_003_00000005.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S054_003_00000006.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S054_003_00000006.png new file mode 100644 index 0000000..67c8a42 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S054_003_00000006.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S054_003_00000007.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S054_003_00000007.png new file mode 100644 index 0000000..f3a4548 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S054_003_00000007.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S055_001_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S055_001_00000010.png new file mode 100644 index 0000000..eaa4013 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S055_001_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S055_001_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S055_001_00000011.png new file mode 100644 index 0000000..c6456b9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S055_001_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S055_001_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S055_001_00000012.png new file mode 100644 index 0000000..8298a60 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S055_001_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S056_003_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S056_003_00000008.png new file mode 100644 index 0000000..b158df1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S056_003_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S056_003_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S056_003_00000009.png new file mode 100644 index 0000000..0e625e5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S056_003_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S056_003_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S056_003_00000010.png new file mode 100644 index 0000000..1860664 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S056_003_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S057_001_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S057_001_00000017.png new file mode 100644 index 0000000..c5c2144 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S057_001_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S057_001_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S057_001_00000018.png new file mode 100644 index 0000000..29082b2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S057_001_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S057_001_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S057_001_00000019.png new file mode 100644 index 0000000..ba3baf3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S057_001_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S058_001_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S058_001_00000018.png new file mode 100644 index 0000000..a6f0085 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S058_001_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S058_001_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S058_001_00000019.png new file mode 100644 index 0000000..b80cd9e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S058_001_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S058_001_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S058_001_00000020.png new file mode 100644 index 0000000..fda5616 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S058_001_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S059_001_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S059_001_00000016.png new file mode 100644 index 0000000..5cd761a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S059_001_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S059_001_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S059_001_00000017.png new file mode 100644 index 0000000..97462c2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S059_001_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S059_001_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S059_001_00000018.png new file mode 100644 index 0000000..2ad04ee Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S059_001_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S060_003_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S060_003_00000016.png new file mode 100644 index 0000000..947ab48 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S060_003_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S060_003_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S060_003_00000017.png new file mode 100644 index 0000000..1223fcd Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S060_003_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S060_003_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S060_003_00000018.png new file mode 100644 index 0000000..a71f6fe Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S060_003_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S061_001_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S061_001_00000010.png new file mode 100644 index 0000000..1984b81 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S061_001_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S061_001_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S061_001_00000011.png new file mode 100644 index 0000000..f9daad6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S061_001_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S061_001_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S061_001_00000012.png new file mode 100644 index 0000000..78606a9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S061_001_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S062_002_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S062_002_00000014.png new file mode 100644 index 0000000..b18c043 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S062_002_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S062_002_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S062_002_00000015.png new file mode 100644 index 0000000..b3fc69b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S062_002_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S062_002_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S062_002_00000016.png new file mode 100644 index 0000000..cea5b58 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S062_002_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S063_001_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S063_001_00000011.png new file mode 100644 index 0000000..b986b80 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S063_001_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S063_001_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S063_001_00000012.png new file mode 100644 index 0000000..5dfd7e3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S063_001_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S063_001_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S063_001_00000013.png new file mode 100644 index 0000000..0395329 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S063_001_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S064_001_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S064_001_00000010.png new file mode 100644 index 0000000..b1f2e4f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S064_001_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S064_001_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S064_001_00000011.png new file mode 100644 index 0000000..bec3797 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S064_001_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S064_001_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S064_001_00000012.png new file mode 100644 index 0000000..f487782 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S064_001_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S065_003_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S065_003_00000020.png new file mode 100644 index 0000000..2ef03b3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S065_003_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S065_003_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S065_003_00000021.png new file mode 100644 index 0000000..b787a5a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S065_003_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S065_003_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S065_003_00000022.png new file mode 100644 index 0000000..aacead9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S065_003_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S066_002_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S066_002_00000020.png new file mode 100644 index 0000000..ebc59c6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S066_002_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S066_002_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S066_002_00000021.png new file mode 100644 index 0000000..3264b04 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S066_002_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S066_002_00000022.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S066_002_00000022.png new file mode 100644 index 0000000..519a5ba Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S066_002_00000022.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S067_002_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S067_002_00000012.png new file mode 100644 index 0000000..9a1fd3e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S067_002_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S067_002_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S067_002_00000013.png new file mode 100644 index 0000000..b13a4b1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S067_002_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S067_002_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S067_002_00000014.png new file mode 100644 index 0000000..6a113ff Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S067_002_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S068_003_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S068_003_00000012.png new file mode 100644 index 0000000..6121cb3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S068_003_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S068_003_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S068_003_00000013.png new file mode 100644 index 0000000..5af3336 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S068_003_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S068_003_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S068_003_00000014.png new file mode 100644 index 0000000..c8834f3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S068_003_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S069_002_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S069_002_00000012.png new file mode 100644 index 0000000..b29b97a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S069_002_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S069_002_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S069_002_00000013.png new file mode 100644 index 0000000..9350c60 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S069_002_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S069_002_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S069_002_00000014.png new file mode 100644 index 0000000..48eb0a7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S069_002_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S070_002_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S070_002_00000014.png new file mode 100644 index 0000000..228e0b3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S070_002_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S070_002_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S070_002_00000015.png new file mode 100644 index 0000000..93cd19a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S070_002_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S070_002_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S070_002_00000016.png new file mode 100644 index 0000000..9dbbe8d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S070_002_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S071_001_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S071_001_00000011.png new file mode 100644 index 0000000..16b740b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S071_001_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S071_001_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S071_001_00000012.png new file mode 100644 index 0000000..933779b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S071_001_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S071_001_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S071_001_00000013.png new file mode 100644 index 0000000..1aa3e95 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S071_001_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S073_001_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S073_001_00000011.png new file mode 100644 index 0000000..91052d8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S073_001_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S073_001_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S073_001_00000012.png new file mode 100644 index 0000000..0de06de Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S073_001_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S073_001_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S073_001_00000013.png new file mode 100644 index 0000000..20c009a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S073_001_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S074_002_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S074_002_00000014.png new file mode 100644 index 0000000..8ec8bf6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S074_002_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S074_002_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S074_002_00000015.png new file mode 100644 index 0000000..638b9ae Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S074_002_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S074_002_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S074_002_00000016.png new file mode 100644 index 0000000..3390bd9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S074_002_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S075_002_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S075_002_00000012.png new file mode 100644 index 0000000..08d0c3a Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S075_002_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S075_002_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S075_002_00000013.png new file mode 100644 index 0000000..e43ac44 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S075_002_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S075_002_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S075_002_00000014.png new file mode 100644 index 0000000..d62ec8f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S075_002_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S076_001_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S076_001_00000015.png new file mode 100644 index 0000000..197e4f5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S076_001_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S076_001_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S076_001_00000016.png new file mode 100644 index 0000000..eccef32 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S076_001_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S076_001_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S076_001_00000017.png new file mode 100644 index 0000000..e3a8cd1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S076_001_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S077_001_00000026.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S077_001_00000026.png new file mode 100644 index 0000000..4d168a5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S077_001_00000026.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S077_001_00000027.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S077_001_00000027.png new file mode 100644 index 0000000..4f8c752 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S077_001_00000027.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S077_001_00000028.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S077_001_00000028.png new file mode 100644 index 0000000..b1a5528 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S077_001_00000028.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S078_001_00000031.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S078_001_00000031.png new file mode 100644 index 0000000..5c6dd81 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S078_001_00000031.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S078_001_00000032.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S078_001_00000032.png new file mode 100644 index 0000000..904c26d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S078_001_00000032.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S078_001_00000033.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S078_001_00000033.png new file mode 100644 index 0000000..104d1e7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S078_001_00000033.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S079_001_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S079_001_00000010.png new file mode 100644 index 0000000..3d2e5b8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S079_001_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S079_001_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S079_001_00000011.png new file mode 100644 index 0000000..174aad1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S079_001_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S079_001_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S079_001_00000012.png new file mode 100644 index 0000000..c0b8b65 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S079_001_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S080_001_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S080_001_00000016.png new file mode 100644 index 0000000..38ddfe5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S080_001_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S080_001_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S080_001_00000017.png new file mode 100644 index 0000000..bd4e7e7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S080_001_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S080_001_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S080_001_00000018.png new file mode 100644 index 0000000..79c2b03 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S080_001_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S081_001_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S081_001_00000017.png new file mode 100644 index 0000000..648f0ed Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S081_001_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S081_001_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S081_001_00000018.png new file mode 100644 index 0000000..fda5c5b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S081_001_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S081_001_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S081_001_00000019.png new file mode 100644 index 0000000..ab7415d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S081_001_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S082_001_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S082_001_00000013.png new file mode 100644 index 0000000..108cf6e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S082_001_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S082_001_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S082_001_00000014.png new file mode 100644 index 0000000..a8ddc59 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S082_001_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S082_001_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S082_001_00000015.png new file mode 100644 index 0000000..cbcae65 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S082_001_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S084_001_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S084_001_00000008.png new file mode 100644 index 0000000..573f73d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S084_001_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S084_001_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S084_001_00000009.png new file mode 100644 index 0000000..1375652 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S084_001_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S084_001_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S084_001_00000010.png new file mode 100644 index 0000000..0e55534 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S084_001_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S085_003_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S085_003_00000011.png new file mode 100644 index 0000000..b01c7cd Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S085_003_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S085_003_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S085_003_00000012.png new file mode 100644 index 0000000..8fdcc43 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S085_003_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S085_003_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S085_003_00000013.png new file mode 100644 index 0000000..ee9970c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S085_003_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S086_001_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S086_001_00000017.png new file mode 100644 index 0000000..1d9d5a0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S086_001_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S086_001_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S086_001_00000018.png new file mode 100644 index 0000000..63ccbee Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S086_001_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S086_001_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S086_001_00000019.png new file mode 100644 index 0000000..b36e1d7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S086_001_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S087_001_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S087_001_00000009.png new file mode 100644 index 0000000..7e84745 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S087_001_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S087_001_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S087_001_00000010.png new file mode 100644 index 0000000..305c781 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S087_001_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S087_001_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S087_001_00000011.png new file mode 100644 index 0000000..23e3fc6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S087_001_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S088_001_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S088_001_00000015.png new file mode 100644 index 0000000..1dbfed4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S088_001_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S088_001_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S088_001_00000016.png new file mode 100644 index 0000000..7146572 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S088_001_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S088_001_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S088_001_00000017.png new file mode 100644 index 0000000..6c967fa Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S088_001_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S089_001_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S089_001_00000014.png new file mode 100644 index 0000000..4fea8df Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S089_001_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S089_001_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S089_001_00000015.png new file mode 100644 index 0000000..c3d5d3d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S089_001_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S089_001_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S089_001_00000016.png new file mode 100644 index 0000000..93a36fe Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S089_001_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S090_002_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S090_002_00000009.png new file mode 100644 index 0000000..b46f204 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S090_002_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S090_002_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S090_002_00000010.png new file mode 100644 index 0000000..0a304bb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S090_002_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S090_002_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S090_002_00000011.png new file mode 100644 index 0000000..4f5834e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S090_002_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S092_001_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S092_001_00000015.png new file mode 100644 index 0000000..397ccb0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S092_001_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S092_001_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S092_001_00000016.png new file mode 100644 index 0000000..cb1588f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S092_001_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S092_001_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S092_001_00000017.png new file mode 100644 index 0000000..a92117d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S092_001_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S094_001_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S094_001_00000008.png new file mode 100644 index 0000000..5e28bee Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S094_001_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S094_001_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S094_001_00000009.png new file mode 100644 index 0000000..2877457 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S094_001_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S094_001_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S094_001_00000010.png new file mode 100644 index 0000000..26a05fb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S094_001_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S095_001_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S095_001_00000014.png new file mode 100644 index 0000000..239afe4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S095_001_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S095_001_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S095_001_00000015.png new file mode 100644 index 0000000..10b3878 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S095_001_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S095_001_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S095_001_00000016.png new file mode 100644 index 0000000..db12767 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S095_001_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S096_001_00000005.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S096_001_00000005.png new file mode 100644 index 0000000..da8c1bb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S096_001_00000005.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S096_001_00000006.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S096_001_00000006.png new file mode 100644 index 0000000..bbedec2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S096_001_00000006.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S096_001_00000007.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S096_001_00000007.png new file mode 100644 index 0000000..ac9fcb0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S096_001_00000007.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S097_001_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S097_001_00000019.png new file mode 100644 index 0000000..874cb8c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S097_001_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S097_001_00000020.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S097_001_00000020.png new file mode 100644 index 0000000..936b163 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S097_001_00000020.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S097_001_00000021.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S097_001_00000021.png new file mode 100644 index 0000000..aaff1a9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S097_001_00000021.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S099_001_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S099_001_00000012.png new file mode 100644 index 0000000..04a2fb5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S099_001_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S099_001_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S099_001_00000013.png new file mode 100644 index 0000000..87564c3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S099_001_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S099_001_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S099_001_00000014.png new file mode 100644 index 0000000..d0195fc Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S099_001_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S100_002_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S100_002_00000013.png new file mode 100644 index 0000000..51f01a6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S100_002_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S100_002_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S100_002_00000014.png new file mode 100644 index 0000000..4bffbd1 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S100_002_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S100_002_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S100_002_00000015.png new file mode 100644 index 0000000..57a22b0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S100_002_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S101_002_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S101_002_00000017.png new file mode 100644 index 0000000..16c9ec4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S101_002_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S101_002_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S101_002_00000018.png new file mode 100644 index 0000000..23f9226 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S101_002_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S101_002_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S101_002_00000019.png new file mode 100644 index 0000000..838a456 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S101_002_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S102_002_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S102_002_00000016.png new file mode 100644 index 0000000..72af891 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S102_002_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S102_002_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S102_002_00000017.png new file mode 100644 index 0000000..229f6c6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S102_002_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S102_002_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S102_002_00000018.png new file mode 100644 index 0000000..b4819f6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S102_002_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S107_001_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S107_001_00000008.png new file mode 100644 index 0000000..b35beb7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S107_001_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S107_001_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S107_001_00000009.png new file mode 100644 index 0000000..5bb1da9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S107_001_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S107_001_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S107_001_00000010.png new file mode 100644 index 0000000..2df7bf8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S107_001_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S110_001_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S110_001_00000011.png new file mode 100644 index 0000000..e453c69 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S110_001_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S110_001_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S110_001_00000012.png new file mode 100644 index 0000000..80d8cbe Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S110_001_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S110_001_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S110_001_00000013.png new file mode 100644 index 0000000..50004f5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S110_001_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S111_001_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S111_001_00000012.png new file mode 100644 index 0000000..c7a22e2 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S111_001_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S111_001_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S111_001_00000013.png new file mode 100644 index 0000000..981b685 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S111_001_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S111_001_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S111_001_00000014.png new file mode 100644 index 0000000..7cc1eff Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S111_001_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S113_001_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S113_001_00000010.png new file mode 100644 index 0000000..26d785e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S113_001_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S113_001_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S113_001_00000011.png new file mode 100644 index 0000000..bb7f614 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S113_001_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S113_001_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S113_001_00000012.png new file mode 100644 index 0000000..cb2e559 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S113_001_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S114_001_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S114_001_00000016.png new file mode 100644 index 0000000..fb8d291 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S114_001_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S114_001_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S114_001_00000017.png new file mode 100644 index 0000000..2238d5c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S114_001_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S114_001_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S114_001_00000018.png new file mode 100644 index 0000000..445ea15 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S114_001_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S115_001_00000006.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S115_001_00000006.png new file mode 100644 index 0000000..ce13ee5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S115_001_00000006.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S115_001_00000007.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S115_001_00000007.png new file mode 100644 index 0000000..2c7fe74 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S115_001_00000007.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S115_001_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S115_001_00000008.png new file mode 100644 index 0000000..34b0404 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S115_001_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S116_001_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S116_001_00000012.png new file mode 100644 index 0000000..21f3947 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S116_001_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S116_001_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S116_001_00000013.png new file mode 100644 index 0000000..0aa8abb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S116_001_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S116_001_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S116_001_00000014.png new file mode 100644 index 0000000..606b2ba Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S116_001_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S117_001_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S117_001_00000012.png new file mode 100644 index 0000000..5afc7b9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S117_001_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S117_001_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S117_001_00000013.png new file mode 100644 index 0000000..fae5ccf Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S117_001_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S117_001_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S117_001_00000014.png new file mode 100644 index 0000000..50dabed Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S117_001_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S119_001_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S119_001_00000009.png new file mode 100644 index 0000000..b7cec87 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S119_001_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S119_001_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S119_001_00000010.png new file mode 100644 index 0000000..57d7197 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S119_001_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S119_001_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S119_001_00000011.png new file mode 100644 index 0000000..bbea8da Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S119_001_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S122_001_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S122_001_00000010.png new file mode 100644 index 0000000..5912839 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S122_001_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S122_001_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S122_001_00000011.png new file mode 100644 index 0000000..9d9528c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S122_001_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S122_001_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S122_001_00000012.png new file mode 100644 index 0000000..41a90ec Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S122_001_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S124_001_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S124_001_00000012.png new file mode 100644 index 0000000..7396ee5 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S124_001_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S124_001_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S124_001_00000013.png new file mode 100644 index 0000000..50e05ab Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S124_001_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S124_001_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S124_001_00000014.png new file mode 100644 index 0000000..ad28531 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S124_001_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S125_007_00000007.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S125_007_00000007.png new file mode 100644 index 0000000..e6b583b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S125_007_00000007.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S125_007_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S125_007_00000008.png new file mode 100644 index 0000000..f466581 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S125_007_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S125_007_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S125_007_00000009.png new file mode 100644 index 0000000..2365783 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S125_007_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S126_004_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S126_004_00000010.png new file mode 100644 index 0000000..36fa2e9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S126_004_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S126_004_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S126_004_00000011.png new file mode 100644 index 0000000..43ab907 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S126_004_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S126_004_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S126_004_00000012.png new file mode 100644 index 0000000..6b9cefb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S126_004_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S127_001_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S127_001_00000015.png new file mode 100644 index 0000000..54ea015 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S127_001_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S127_001_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S127_001_00000016.png new file mode 100644 index 0000000..24f2eab Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S127_001_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S127_001_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S127_001_00000017.png new file mode 100644 index 0000000..9dad3b3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S127_001_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S129_002_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S129_002_00000009.png new file mode 100644 index 0000000..122d230 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S129_002_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S129_002_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S129_002_00000010.png new file mode 100644 index 0000000..822c2e4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S129_002_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S129_002_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S129_002_00000011.png new file mode 100644 index 0000000..cba7c6d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S129_002_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S130_001_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S130_001_00000016.png new file mode 100644 index 0000000..f24c03e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S130_001_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S130_001_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S130_001_00000017.png new file mode 100644 index 0000000..7e3ef85 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S130_001_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S130_001_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S130_001_00000018.png new file mode 100644 index 0000000..f5e6bf4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S130_001_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S131_001_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S131_001_00000014.png new file mode 100644 index 0000000..55c93d0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S131_001_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S131_001_00000015.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S131_001_00000015.png new file mode 100644 index 0000000..e62aee4 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S131_001_00000015.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S131_001_00000016.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S131_001_00000016.png new file mode 100644 index 0000000..989f8ac Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S131_001_00000016.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S132_008_00000008.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S132_008_00000008.png new file mode 100644 index 0000000..fb67d67 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S132_008_00000008.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S132_008_00000009.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S132_008_00000009.png new file mode 100644 index 0000000..9996e9d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S132_008_00000009.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S132_008_00000010.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S132_008_00000010.png new file mode 100644 index 0000000..f09e8bb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S132_008_00000010.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S133_009_00000004.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S133_009_00000004.png new file mode 100644 index 0000000..c771361 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S133_009_00000004.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S133_009_00000005.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S133_009_00000005.png new file mode 100644 index 0000000..e48d534 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S133_009_00000005.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S133_009_00000006.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S133_009_00000006.png new file mode 100644 index 0000000..333ccac Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S133_009_00000006.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S135_001_00000037.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S135_001_00000037.png new file mode 100644 index 0000000..65ce89c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S135_001_00000037.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S135_001_00000038.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S135_001_00000038.png new file mode 100644 index 0000000..da54cd7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S135_001_00000038.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S135_001_00000039.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S135_001_00000039.png new file mode 100644 index 0000000..c9cee8b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S135_001_00000039.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S136_001_00000017.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S136_001_00000017.png new file mode 100644 index 0000000..4ecaa01 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S136_001_00000017.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S136_001_00000018.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S136_001_00000018.png new file mode 100644 index 0000000..db0c813 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S136_001_00000018.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S136_001_00000019.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S136_001_00000019.png new file mode 100644 index 0000000..5d5170d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S136_001_00000019.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S137_001_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S137_001_00000012.png new file mode 100644 index 0000000..8a47b8b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S137_001_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S137_001_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S137_001_00000013.png new file mode 100644 index 0000000..aced17c Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S137_001_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S137_001_00000014.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S137_001_00000014.png new file mode 100644 index 0000000..6a5e72f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S137_001_00000014.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S138_004_00000011.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S138_004_00000011.png new file mode 100644 index 0000000..b46abd9 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S138_004_00000011.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S138_004_00000012.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S138_004_00000012.png new file mode 100644 index 0000000..260c96e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S138_004_00000012.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S138_004_00000013.png b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S138_004_00000013.png new file mode 100644 index 0000000..f36ea9b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/CK+48/surprise/S138_004_00000013.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/CK.py b/src/jetmax_demos/scripts/FER/FER/CK.py new file mode 100644 index 0000000..a0c2a05 --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/CK.py @@ -0,0 +1,90 @@ +from __future__ import print_function +from PIL import Image +import numpy as np +import h5py +import torch.utils.data as data + + +class CK(data.Dataset): + """`CK+ Dataset. + + Args: + train (bool, optional): If True, creates dataset from training set, otherwise + creates from test set. + transform (callable, optional): A function/transform that takes in an PIL image + and returns a transformed version. E.g, ``transforms.RandomCrop`` + + there are 135,177,75,207,84,249,54 images in data + we choose 123,159,66,186,75,225,48 images for training + we choose 12,8,9,21,9,24,6 images for testing + the split are in order according to the fold number + """ + + def __init__(self, split='Training', fold = 1, transform=None): + self.transform = transform + self.split = split # training set or test set + self.fold = fold # the k-fold cross validation + self.data = h5py.File('./data/CK_data.h5', 'r', driver='core') + + number = len(self.data['data_label']) #981 + sum_number = [0,135,312,387,594,678,927,981] # the sum of class number + test_number = [12,18,9,21,9,24,6] # the number of each class + + test_index = [] + train_index = [] + + for j in xrange(len(test_number)): + for k in xrange(test_number[j]): + if self.fold != 10: #the last fold start from the last element + test_index.append(sum_number[j]+(self.fold-1)*test_number[j]+k) + else: + test_index.append(sum_number[j+1]-1-k) + + for i in xrange(number): + if i not in test_index: + train_index.append(i) + + print(len(train_index),len(test_index)) + + # now load the picked numpy arrays + if self.split == 'Training': + self.train_data = [] + self.train_labels = [] + for ind in xrange(len(train_index)): + self.train_data.append(self.data['data_pixel'][train_index[ind]]) + self.train_labels.append(self.data['data_label'][train_index[ind]]) + + elif self.split == 'Testing': + self.test_data = [] + self.test_labels = [] + for ind in xrange(len(test_index)): + self.test_data.append(self.data['data_pixel'][test_index[ind]]) + self.test_labels.append(self.data['data_label'][test_index[ind]]) + + def __getitem__(self, index): + """ + Args: + index (int): Index + + Returns: + tuple: (image, target) where target is index of the target class. + """ + if self.split == 'Training': + img, target = self.train_data[index], self.train_labels[index] + elif self.split == 'Testing': + img, target = self.test_data[index], self.test_labels[index] + # doing this so that it is consistent with all other datasets + # to return a PIL Image + img = img[:, :, np.newaxis] + img = np.concatenate((img, img, img), axis=2) + img = Image.fromarray(img) + if self.transform is not None: + img = self.transform(img) + return img, target + + def __len__(self): + if self.split == 'Training': + return len(self.train_data) + elif self.split == 'Testing': + return len(self.test_data) + diff --git a/src/jetmax_demos/scripts/FER/FER/LICENSE b/src/jetmax_demos/scripts/FER/FER/LICENSE new file mode 100644 index 0000000..8defeeb --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 WuJie + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/jetmax_demos/scripts/FER/FER/Readme.md b/src/jetmax_demos/scripts/FER/FER/Readme.md new file mode 100644 index 0000000..6d55852 --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/Readme.md @@ -0,0 +1,56 @@ +# Facial-Expression-Recognition.Pytorch +A CNN based pytorch implementation on facial expression recognition (FER2013 and CK+), achieving 73.112% (state-of-the-art) in FER2013 and 94.64% in CK+ dataset + +## Demos ## +![Image text](https://raw.githubusercontent.com/WuJie1010/Facial-Expression-Recognition.Pytorch/master/demo/1.png) +![Image text](https://raw.githubusercontent.com/WuJie1010/Facial-Expression-Recognition.Pytorch/master/demo/2.png) + +## Dependencies ## +- Python 2.7 +- Pytorch >=0.2.0 +- h5py (Preprocessing) +- sklearn (plot confusion matrix) + +## Visualize for a test image by a pre-trained model ## +- Firstly, download the pre-trained model from https://drive.google.com/open?id=1Oy_9YmpkSKX1Q8jkOhJbz3Mc7qjyISzU (or https://pan.baidu.com/s/1gCL0TlCwKctAy_5yhzHy5Q, key: g2d3) and then put it in the "FER2013_VGG19" folder; Next, Put the test image (rename as 1.jpg) into the "images" folder, then +- python visualize.py + +## FER2013 Dataset ## +- Dataset from https://www.kaggle.com/c/challenges-in-representation-learning-facial-expression-recognition-challenge/data +Image Properties: 48 x 48 pixels (2304 bytes) +labels: 0=Angry, 1=Disgust, 2=Fear, 3=Happy, 4=Sad, 5=Surprise, 6=Neutral +The training set consists of 28,709 examples. The public test set consists of 3,589 examples. The private test set consists of another 3,589 examples. + +### Preprocessing Fer2013 ### +- first download the dataset(fer2013.csv) then put it in the "data" folder, then +- python preprocess_fer2013.py + +### Train and Eval model ### +- python mainpro_FER.py --model VGG19 --bs 128 --lr 0.01 + +### plot confusion matrix ### +- python plot_fer2013_confusion_matrix.py --model VGG19 --split PrivateTest + +### fer2013 Accurary ### + +- Model: VGG19 ; PublicTest_acc: 71.496% ; PrivateTest_acc:73.112%
+- Model: Resnet18 ; PublicTest_acc: 71.190% ; PrivateTest_acc:72.973% + +## CK+ Dataset ## +- The CK+ dataset is an extension of the CK dataset. It contains 327 labeled facial videos, +We extracted the last three frames from each sequence in the CK+ dataset, which +contains a total of 981 facial expressions. we use 10-fold Cross validation in the experiment. + +### Train and Eval model for a fold ### +- python mainpro_CK+.py --model VGG19 --bs 128 --lr 0.01 --fold 1 + +### Train and Eval model for all 10 fold ### +- python k_fold_train.py + +### plot confusion matrix for all fold ### +- python plot_CK+_confusion_matrix.py --model VGG19 + +### CK+ Accurary ### +- Model: VGG19 ; Test_acc: 94.646%
+- Model: Resnet18 ; Test_acc: 94.040% + diff --git a/src/jetmax_demos/scripts/FER/FER/data/CK_data.h5 b/src/jetmax_demos/scripts/FER/FER/data/CK_data.h5 new file mode 100644 index 0000000..053c5a3 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/data/CK_data.h5 differ diff --git a/src/jetmax_demos/scripts/FER/FER/demo/1.png b/src/jetmax_demos/scripts/FER/FER/demo/1.png new file mode 100644 index 0000000..81e5b47 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/demo/1.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/demo/2.png b/src/jetmax_demos/scripts/FER/FER/demo/2.png new file mode 100644 index 0000000..8a595eb Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/demo/2.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/demo/3.png b/src/jetmax_demos/scripts/FER/FER/demo/3.png new file mode 100644 index 0000000..aeaabb8 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/demo/3.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/demo/4.png b/src/jetmax_demos/scripts/FER/FER/demo/4.png new file mode 100644 index 0000000..50c89c7 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/demo/4.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/demo/5.png b/src/jetmax_demos/scripts/FER/FER/demo/5.png new file mode 100644 index 0000000..82b5761 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/demo/5.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/demo/6.png b/src/jetmax_demos/scripts/FER/FER/demo/6.png new file mode 100644 index 0000000..34d40ae Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/demo/6.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/demo/7.jpg b/src/jetmax_demos/scripts/FER/FER/demo/7.jpg new file mode 100644 index 0000000..f30212d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/demo/7.jpg differ diff --git a/src/jetmax_demos/scripts/FER/FER/fer.py b/src/jetmax_demos/scripts/FER/FER/fer.py new file mode 100644 index 0000000..544251e --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/fer.py @@ -0,0 +1,72 @@ +''' Fer2013 Dataset class''' + +from __future__ import print_function +from PIL import Image +import numpy as np +import h5py +import torch.utils.data as data + +class FER2013(data.Dataset): + """`FER2013 Dataset. + + Args: + train (bool, optional): If True, creates dataset from training set, otherwise + creates from test set. + transform (callable, optional): A function/transform that takes in an PIL image + and returns a transformed version. E.g, ``transforms.RandomCrop`` + """ + + def __init__(self, split='Training', transform=None): + self.transform = transform + self.split = split # training set or test set + self.data = h5py.File('./data/data.h5', 'r', driver='core') + # now load the picked numpy arrays + if self.split == 'Training': + self.train_data = self.data['Training_pixel'] + self.train_labels = self.data['Training_label'] + self.train_data = np.asarray(self.train_data) + self.train_data = self.train_data.reshape((28709, 48, 48)) + + elif self.split == 'PublicTest': + self.PublicTest_data = self.data['PublicTest_pixel'] + self.PublicTest_labels = self.data['PublicTest_label'] + self.PublicTest_data = np.asarray(self.PublicTest_data) + self.PublicTest_data = self.PublicTest_data.reshape((3589, 48, 48)) + + else: + self.PrivateTest_data = self.data['PrivateTest_pixel'] + self.PrivateTest_labels = self.data['PrivateTest_label'] + self.PrivateTest_data = np.asarray(self.PrivateTest_data) + self.PrivateTest_data = self.PrivateTest_data.reshape((3589, 48, 48)) + + def __getitem__(self, index): + """ + Args: + index (int): Index + + Returns: + tuple: (image, target) where target is index of the target class. + """ + if self.split == 'Training': + img, target = self.train_data[index], self.train_labels[index] + elif self.split == 'PublicTest': + img, target = self.PublicTest_data[index], self.PublicTest_labels[index] + else: + img, target = self.PrivateTest_data[index], self.PrivateTest_labels[index] + + # doing this so that it is consistent with all other datasets + # to return a PIL Image + img = img[:, :, np.newaxis] + img = np.concatenate((img, img, img), axis=2) + img = Image.fromarray(img) + if self.transform is not None: + img = self.transform(img) + return img, target + + def __len__(self): + if self.split == 'Training': + return len(self.train_data) + elif self.split == 'PublicTest': + return len(self.PublicTest_data) + else: + return len(self.PrivateTest_data) diff --git a/src/jetmax_demos/scripts/FER/FER/images/1.jpg b/src/jetmax_demos/scripts/FER/FER/images/1.jpg new file mode 100644 index 0000000..fe8522b Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/images/1.jpg differ diff --git a/src/jetmax_demos/scripts/FER/FER/images/2.jpg b/src/jetmax_demos/scripts/FER/FER/images/2.jpg new file mode 100644 index 0000000..12be26e Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/images/2.jpg differ diff --git a/src/jetmax_demos/scripts/FER/FER/images/emojis/Angry.png b/src/jetmax_demos/scripts/FER/FER/images/emojis/Angry.png new file mode 100644 index 0000000..78d6c6f Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/images/emojis/Angry.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/images/emojis/Disgust.png b/src/jetmax_demos/scripts/FER/FER/images/emojis/Disgust.png new file mode 100644 index 0000000..bd73f27 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/images/emojis/Disgust.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/images/emojis/Fear.png b/src/jetmax_demos/scripts/FER/FER/images/emojis/Fear.png new file mode 100644 index 0000000..f884121 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/images/emojis/Fear.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/images/emojis/Happy.png b/src/jetmax_demos/scripts/FER/FER/images/emojis/Happy.png new file mode 100644 index 0000000..7a301a6 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/images/emojis/Happy.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/images/emojis/Neutral.png b/src/jetmax_demos/scripts/FER/FER/images/emojis/Neutral.png new file mode 100644 index 0000000..d0617f0 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/images/emojis/Neutral.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/images/emojis/Sad.png b/src/jetmax_demos/scripts/FER/FER/images/emojis/Sad.png new file mode 100644 index 0000000..c8bc69d Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/images/emojis/Sad.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/images/emojis/Surprise.png b/src/jetmax_demos/scripts/FER/FER/images/emojis/Surprise.png new file mode 100644 index 0000000..9effb43 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER/images/emojis/Surprise.png differ diff --git a/src/jetmax_demos/scripts/FER/FER/k_fold_train.py b/src/jetmax_demos/scripts/FER/FER/k_fold_train.py new file mode 100644 index 0000000..6f29d84 --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/k_fold_train.py @@ -0,0 +1,7 @@ +import os + +for i in xrange(10): + cmd = 'python mainpro_CK+.py --model VGG19 --bs 32 --lr 0.01 --fold %d' %(i+1) + os.system(cmd) +print("Train VGG19 ok!") + diff --git a/src/jetmax_demos/scripts/FER/FER/mainpro_CK+.py b/src/jetmax_demos/scripts/FER/FER/mainpro_CK+.py new file mode 100644 index 0000000..bc7cffa --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/mainpro_CK+.py @@ -0,0 +1,176 @@ +'''Train CK+ with PyTorch.''' +# 10 crop for data enhancement +from __future__ import print_function + +import torch +import torch.nn as nn +import torch.optim as optim +import torch.nn.functional as F +import torch.backends.cudnn as cudnn +import torchvision +import transforms as transforms +import numpy as np +import os +import argparse +import utils +from CK import CK +from torch.autograd import Variable +from models import * + +parser = argparse.ArgumentParser(description='PyTorch CK+ CNN Training') +parser.add_argument('--model', type=str, default='VGG19', help='CNN architecture') +parser.add_argument('--dataset', type=str, default='CK+', help='dataset') +parser.add_argument('--fold', default=1, type=int, help='k fold number') +parser.add_argument('--bs', default=128, type=int, help='batch_size') +parser.add_argument('--lr', default=0.01, type=float, help='learning rate') +parser.add_argument('--resume', '-r', action='store_true', help='resume from checkpoint') +opt = parser.parse_args() + +use_cuda = torch.cuda.is_available() + +best_Test_acc = 0 # best PrivateTest accuracy +best_Test_acc_epoch = 0 +start_epoch = 0 # start from epoch 0 or last checkpoint epoch + +learning_rate_decay_start = 20 # 50 +learning_rate_decay_every = 1 # 5 +learning_rate_decay_rate = 0.8 # 0.9 + +cut_size = 44 +total_epoch = 60 + +path = os.path.join(opt.dataset + '_' + opt.model, str(opt.fold)) + +# Data +print('==> Preparing data..') +transform_train = transforms.Compose([ + transforms.RandomCrop(cut_size), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), +]) + +transform_test = transforms.Compose([ + transforms.TenCrop(cut_size), + transforms.Lambda(lambda crops: torch.stack([transforms.ToTensor()(crop) for crop in crops])), +]) + +trainset = CK(split = 'Training', fold = opt.fold, transform=transform_train) +trainloader = torch.utils.data.DataLoader(trainset, batch_size=opt.bs, shuffle=True, num_workers=1) +testset = CK(split = 'Testing', fold = opt.fold, transform=transform_test) +testloader = torch.utils.data.DataLoader(testset, batch_size=5, shuffle=False, num_workers=1) + +# Model +if opt.model == 'VGG19': + net = VGG('VGG19') +elif opt.model == 'Resnet18': + net = ResNet18() + +if opt.resume: + # Load checkpoint. + print('==> Resuming from checkpoint..') + assert os.path.isdir(path), 'Error: no checkpoint directory found!' + checkpoint = torch.load(os.path.join(path,'Test_model.t7')) + + net.load_state_dict(checkpoint['net']) + best_Test_acc = checkpoint['best_Test_acc'] + best_Test_acc_epoch = checkpoint['best_Test_acc_epoch'] + start_epoch = best_Test_acc_epoch + 1 +else: + print('==> Building model..') + +if use_cuda: + net.cuda() + +criterion = nn.CrossEntropyLoss() +optimizer = optim.SGD(net.parameters(), lr=opt.lr, momentum=0.9, weight_decay=5e-4) + +# Training +def train(epoch): + print('\nEpoch: %d' % epoch) + global Train_acc + net.train() + train_loss = 0 + correct = 0 + total = 0 + + if epoch > learning_rate_decay_start and learning_rate_decay_start >= 0: + frac = (epoch - learning_rate_decay_start) // learning_rate_decay_every + decay_factor = learning_rate_decay_rate ** frac + current_lr = opt.lr * decay_factor + utils.set_lr(optimizer, current_lr) # set the decayed rate + else: + current_lr = opt.lr + print('learning_rate: %s' % str(current_lr)) + + + for batch_idx, (inputs, targets) in enumerate(trainloader): + if use_cuda: + inputs, targets = inputs.cuda(), targets.cuda() + optimizer.zero_grad() + inputs, targets = Variable(inputs), Variable(targets) + outputs = net(inputs) + loss = criterion(outputs, targets) + loss.backward() + utils.clip_gradient(optimizer, 0.1) + optimizer.step() + + train_loss += loss.data[0] + _, predicted = torch.max(outputs.data, 1) + total += targets.size(0) + correct += predicted.eq(targets.data).cpu().sum() + + utils.progress_bar(batch_idx, len(trainloader), 'Loss: %.3f | Acc: %.3f%% (%d/%d)' + % (train_loss/(batch_idx+1), 100.*correct/total, correct, total)) + + Train_acc = 100.*correct/total + +def test(epoch): + global Test_acc + global best_Test_acc + global best_Test_acc_epoch + net.eval() + PrivateTest_loss = 0 + correct = 0 + total = 0 + for batch_idx, (inputs, targets) in enumerate(testloader): + bs, ncrops, c, h, w = np.shape(inputs) + inputs = inputs.view(-1, c, h, w) + + if use_cuda: + inputs, targets = inputs.cuda(), targets.cuda() + inputs, targets = Variable(inputs, volatile=True), Variable(targets) + outputs = net(inputs) + outputs_avg = outputs.view(bs, ncrops, -1).mean(1) # avg over crops + + loss = criterion(outputs_avg, targets) + PrivateTest_loss += loss.data[0] + _, predicted = torch.max(outputs_avg.data, 1) + total += targets.size(0) + correct += predicted.eq(targets.data).cpu().sum() + + utils.progress_bar(batch_idx, len(testloader), 'Loss: %.3f | Acc: %.3f%% (%d/%d)' + % (PrivateTest_loss / (batch_idx + 1), 100. * correct / total, correct, total)) + # Save checkpoint. + Test_acc = 100.*correct/total + + if Test_acc > best_Test_acc: + print('Saving..') + print("best_Test_acc: %0.3f" % Test_acc) + state = {'net': net.state_dict() if use_cuda else net, + 'best_Test_acc': Test_acc, + 'best_Test_acc_epoch': epoch, + } + if not os.path.isdir(opt.dataset + '_' + opt.model): + os.mkdir(opt.dataset + '_' + opt.model) + if not os.path.isdir(path): + os.mkdir(path) + torch.save(state, os.path.join(path, 'Test_model.t7')) + best_Test_acc = Test_acc + best_Test_acc_epoch = epoch + +for epoch in range(start_epoch, total_epoch): + train(epoch) + test(epoch) + +print("best_Test_acc: %0.3f" % best_Test_acc) +print("best_Test_acc_epoch: %d" % best_Test_acc_epoch) diff --git a/src/jetmax_demos/scripts/FER/FER/mainpro_FER.py b/src/jetmax_demos/scripts/FER/FER/mainpro_FER.py new file mode 100644 index 0000000..baed3a2 --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/mainpro_FER.py @@ -0,0 +1,221 @@ +'''Train Fer2013 with PyTorch.''' +# 10 crop for data enhancement +from __future__ import print_function + +import torch +import torch.nn as nn +import torch.optim as optim +import torch.nn.functional as F +import torch.backends.cudnn as cudnn +import torchvision +import transforms as transforms +import numpy as np +import os +import argparse +import utils +from fer import FER2013 +from torch.autograd import Variable +from models import * + +parser = argparse.ArgumentParser(description='PyTorch Fer2013 CNN Training') +parser.add_argument('--model', type=str, default='VGG19', help='CNN architecture') +parser.add_argument('--dataset', type=str, default='FER2013', help='CNN architecture') +parser.add_argument('--bs', default=128, type=int, help='learning rate') +parser.add_argument('--lr', default=0.01, type=float, help='learning rate') +parser.add_argument('--resume', '-r', action='store_true', help='resume from checkpoint') +opt = parser.parse_args() + +use_cuda = torch.cuda.is_available() +best_PublicTest_acc = 0 # best PublicTest accuracy +best_PublicTest_acc_epoch = 0 +best_PrivateTest_acc = 0 # best PrivateTest accuracy +best_PrivateTest_acc_epoch = 0 +start_epoch = 0 # start from epoch 0 or last checkpoint epoch + +learning_rate_decay_start = 80 # 50 +learning_rate_decay_every = 5 # 5 +learning_rate_decay_rate = 0.9 # 0.9 + +cut_size = 44 +total_epoch = 250 + +path = os.path.join(opt.dataset + '_' + opt.model) + +# Data +print('==> Preparing data..') +transform_train = transforms.Compose([ + transforms.RandomCrop(44), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), +]) + +transform_test = transforms.Compose([ + transforms.TenCrop(cut_size), + transforms.Lambda(lambda crops: torch.stack([transforms.ToTensor()(crop) for crop in crops])), +]) + +trainset = FER2013(split = 'Training', transform=transform_train) +trainloader = torch.utils.data.DataLoader(trainset, batch_size=opt.bs, shuffle=True, num_workers=1) +PublicTestset = FER2013(split = 'PublicTest', transform=transform_test) +PublicTestloader = torch.utils.data.DataLoader(PublicTestset, batch_size=opt.bs, shuffle=False, num_workers=1) +PrivateTestset = FER2013(split = 'PrivateTest', transform=transform_test) +PrivateTestloader = torch.utils.data.DataLoader(PrivateTestset, batch_size=opt.bs, shuffle=False, num_workers=1) + +# Model +if opt.model == 'VGG19': + net = VGG('VGG19') +elif opt.model == 'Resnet18': + net = ResNet18() + +if opt.resume: + # Load checkpoint. + print('==> Resuming from checkpoint..') + assert os.path.isdir(path), 'Error: no checkpoint directory found!' + checkpoint = torch.load(os.path.join(path,'PrivateTest_model.t7')) + + net.load_state_dict(checkpoint['net']) + best_PublicTest_acc = checkpoint['best_PublicTest_acc'] + best_PrivateTest_acc = checkpoint['best_PrivateTest_acc'] + best_PrivateTest_acc_epoch = checkpoint['best_PublicTest_acc_epoch'] + best_PrivateTest_acc_epoch = checkpoint['best_PrivateTest_acc_epoch'] + start_epoch = checkpoint['best_PrivateTest_acc_epoch'] + 1 +else: + print('==> Building model..') + +if use_cuda: + net.cuda() + +criterion = nn.CrossEntropyLoss() +optimizer = optim.SGD(net.parameters(), lr=opt.lr, momentum=0.9, weight_decay=5e-4) + +# Training +def train(epoch): + print('\nEpoch: %d' % epoch) + global Train_acc + net.train() + train_loss = 0 + correct = 0 + total = 0 + + if epoch > learning_rate_decay_start and learning_rate_decay_start >= 0: + frac = (epoch - learning_rate_decay_start) // learning_rate_decay_every + decay_factor = learning_rate_decay_rate ** frac + current_lr = opt.lr * decay_factor + utils.set_lr(optimizer, current_lr) # set the decayed rate + else: + current_lr = opt.lr + print('learning_rate: %s' % str(current_lr)) + + for batch_idx, (inputs, targets) in enumerate(trainloader): + if use_cuda: + inputs, targets = inputs.cuda(), targets.cuda() + optimizer.zero_grad() + inputs, targets = Variable(inputs), Variable(targets) + outputs = net(inputs) + loss = criterion(outputs, targets) + loss.backward() + utils.clip_gradient(optimizer, 0.1) + optimizer.step() + train_loss += loss.data[0] + _, predicted = torch.max(outputs.data, 1) + total += targets.size(0) + correct += predicted.eq(targets.data).cpu().sum() + + utils.progress_bar(batch_idx, len(trainloader), 'Loss: %.3f | Acc: %.3f%% (%d/%d)' + % (train_loss/(batch_idx+1), 100.*correct/total, correct, total)) + + Train_acc = 100.*correct/total + +def PublicTest(epoch): + global PublicTest_acc + global best_PublicTest_acc + global best_PublicTest_acc_epoch + net.eval() + PublicTest_loss = 0 + correct = 0 + total = 0 + for batch_idx, (inputs, targets) in enumerate(PublicTestloader): + bs, ncrops, c, h, w = np.shape(inputs) + inputs = inputs.view(-1, c, h, w) + if use_cuda: + inputs, targets = inputs.cuda(), targets.cuda() + inputs, targets = Variable(inputs, volatile=True), Variable(targets) + outputs = net(inputs) + outputs_avg = outputs.view(bs, ncrops, -1).mean(1) # avg over crops + loss = criterion(outputs_avg, targets) + PublicTest_loss += loss.data[0] + _, predicted = torch.max(outputs_avg.data, 1) + total += targets.size(0) + correct += predicted.eq(targets.data).cpu().sum() + + utils.progress_bar(batch_idx, len(PublicTestloader), 'Loss: %.3f | Acc: %.3f%% (%d/%d)' + % (PublicTest_loss / (batch_idx + 1), 100. * correct / total, correct, total)) + + # Save checkpoint. + PublicTest_acc = 100.*correct/total + if PublicTest_acc > best_PublicTest_acc: + print('Saving..') + print("best_PublicTest_acc: %0.3f" % PublicTest_acc) + state = { + 'net': net.state_dict() if use_cuda else net, + 'acc': PublicTest_acc, + 'epoch': epoch, + } + if not os.path.isdir(path): + os.mkdir(path) + torch.save(state, os.path.join(path,'PublicTest_model.t7')) + best_PublicTest_acc = PublicTest_acc + best_PublicTest_acc_epoch = epoch + +def PrivateTest(epoch): + global PrivateTest_acc + global best_PrivateTest_acc + global best_PrivateTest_acc_epoch + net.eval() + PrivateTest_loss = 0 + correct = 0 + total = 0 + for batch_idx, (inputs, targets) in enumerate(PrivateTestloader): + bs, ncrops, c, h, w = np.shape(inputs) + inputs = inputs.view(-1, c, h, w) + if use_cuda: + inputs, targets = inputs.cuda(), targets.cuda() + inputs, targets = Variable(inputs, volatile=True), Variable(targets) + outputs = net(inputs) + outputs_avg = outputs.view(bs, ncrops, -1).mean(1) # avg over crops + loss = criterion(outputs_avg, targets) + PrivateTest_loss += loss.data[0] + _, predicted = torch.max(outputs_avg.data, 1) + total += targets.size(0) + correct += predicted.eq(targets.data).cpu().sum() + + utils.progress_bar(batch_idx, len(PublicTestloader), 'Loss: %.3f | Acc: %.3f%% (%d/%d)' + % (PrivateTest_loss / (batch_idx + 1), 100. * correct / total, correct, total)) + # Save checkpoint. + PrivateTest_acc = 100.*correct/total + + if PrivateTest_acc > best_PrivateTest_acc: + print('Saving..') + print("best_PrivateTest_acc: %0.3f" % PrivateTest_acc) + state = { + 'net': net.state_dict() if use_cuda else net, + 'best_PublicTest_acc': best_PublicTest_acc, + 'best_PrivateTest_acc': PrivateTest_acc, + 'best_PublicTest_acc_epoch': best_PublicTest_acc_epoch, + 'best_PrivateTest_acc_epoch': epoch, + } + if not os.path.isdir(path): + os.mkdir(path) + torch.save(state, os.path.join(path,'PrivateTest_model.t7')) + best_PrivateTest_acc = PrivateTest_acc + best_PrivateTest_acc_epoch = epoch + +for epoch in range(start_epoch, total_epoch): + train(epoch) + PublicTest(epoch) + PrivateTest(epoch) + +print("best_PublicTest_acc: %0.3f" % best_PublicTest_acc) +print("best_PublicTest_acc_epoch: %d" % best_PublicTest_acc_epoch) +print("best_PrivateTest_acc: %0.3f" % best_PrivateTest_acc) +print("best_PrivateTest_acc_epoch: %d" % best_PrivateTest_acc_epoch) diff --git a/src/jetmax_demos/scripts/FER/FER/models/__init__.py b/src/jetmax_demos/scripts/FER/FER/models/__init__.py new file mode 100644 index 0000000..44236ed --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/models/__init__.py @@ -0,0 +1,2 @@ +from .vgg import * +from .resnet import * \ No newline at end of file diff --git a/src/jetmax_demos/scripts/FER/FER/models/resnet.py b/src/jetmax_demos/scripts/FER/FER/models/resnet.py new file mode 100644 index 0000000..59ded98 --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/models/resnet.py @@ -0,0 +1,104 @@ +'''ResNet in PyTorch. + +For Pre-activation ResNet, see 'preact_resnet.py'. + +Reference: +[1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun + Deep Residual Learning for Image Recognition. arXiv:1512.03385 +''' +import torch +import torch.nn as nn +import torch.nn.functional as F + +from torch.autograd import Variable + + +class BasicBlock(nn.Module): + expansion = 1 + + def __init__(self, in_planes, planes, stride=1): + super(BasicBlock, self).__init__() + self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) + self.bn2 = nn.BatchNorm2d(planes) + + self.shortcut = nn.Sequential() + if stride != 1 or in_planes != self.expansion*planes: + self.shortcut = nn.Sequential( + nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(self.expansion*planes) + ) + + def forward(self, x): + out = F.relu(self.bn1(self.conv1(x))) + out = self.bn2(self.conv2(out)) + out += self.shortcut(x) + out = F.relu(out) + return out + + +class Bottleneck(nn.Module): + expansion = 4 + + def __init__(self, in_planes, planes, stride=1): + super(Bottleneck, self).__init__() + self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) + self.bn2 = nn.BatchNorm2d(planes) + self.conv3 = nn.Conv2d(planes, self.expansion*planes, kernel_size=1, bias=False) + self.bn3 = nn.BatchNorm2d(self.expansion*planes) + + self.shortcut = nn.Sequential() + if stride != 1 or in_planes != self.expansion*planes: + self.shortcut = nn.Sequential( + nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(self.expansion*planes) + ) + + def forward(self, x): + out = F.relu(self.bn1(self.conv1(x))) + out = F.relu(self.bn2(self.conv2(out))) + out = self.bn3(self.conv3(out)) + out += self.shortcut(x) + out = F.relu(out) + return out + + +class ResNet(nn.Module): + def __init__(self, block, num_blocks, num_classes=7): + super(ResNet, self).__init__() + self.in_planes = 64 + + self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False) + self.bn1 = nn.BatchNorm2d(64) + self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1) + self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2) + self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2) + self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2) + self.linear = nn.Linear(512, num_classes) + + def _make_layer(self, block, planes, num_blocks, stride): + strides = [stride] + [1]*(num_blocks-1) + layers = [] + for stride in strides: + layers.append(block(self.in_planes, planes, stride)) + self.in_planes = planes * block.expansion + return nn.Sequential(*layers) + + def forward(self, x): + out = F.relu(self.bn1(self.conv1(x))) + out = self.layer1(out) + out = self.layer2(out) + out = self.layer3(out) + out = self.layer4(out) + out = F.avg_pool2d(out, 4) + out = out.view(out.size(0), -1) + out = F.dropout(out, p=0.5, training=self.training) + out = self.linear(out) + return out + + +def ResNet18(): + return ResNet(BasicBlock, [2,2,2,2]) \ No newline at end of file diff --git a/src/jetmax_demos/scripts/FER/FER/models/vgg.py b/src/jetmax_demos/scripts/FER/FER/models/vgg.py new file mode 100644 index 0000000..de75bb3 --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/models/vgg.py @@ -0,0 +1,41 @@ +'''VGG11/13/16/19 in Pytorch.''' +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.autograd import Variable + + +cfg = { + 'VGG11': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'], + 'VGG13': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'], + 'VGG16': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'], + 'VGG19': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'], +} + + +class VGG(nn.Module): + def __init__(self, vgg_name): + super(VGG, self).__init__() + self.features = self._make_layers(cfg[vgg_name]) + self.classifier = nn.Linear(512, 7) + + def forward(self, x): + out = self.features(x) + out = out.view(out.size(0), -1) + out = F.dropout(out, p=0.5, training=self.training) + out = self.classifier(out) + return out + + def _make_layers(self, cfg): + layers = [] + in_channels = 3 + for x in cfg: + if x == 'M': + layers += [nn.MaxPool2d(kernel_size=2, stride=2)] + else: + layers += [nn.Conv2d(in_channels, x, kernel_size=3, padding=1), + nn.BatchNorm2d(x), + nn.ReLU(inplace=True)] + in_channels = x + layers += [nn.AvgPool2d(kernel_size=1, stride=1)] + return nn.Sequential(*layers) diff --git a/src/jetmax_demos/scripts/FER/FER/plot_CK+_confusion_matrix.py b/src/jetmax_demos/scripts/FER/FER/plot_CK+_confusion_matrix.py new file mode 100644 index 0000000..66348c7 --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/plot_CK+_confusion_matrix.py @@ -0,0 +1,120 @@ +""" +plot confusion_matrix of fold Test set of CK+ +""" +import transforms as transforms + +import argparse +import itertools +import os + +import matplotlib.pyplot as plt +import numpy as np +from sklearn.metrics import confusion_matrix + + +from CK import CK +from models import * + +parser = argparse.ArgumentParser(description='PyTorch CK+ CNN Training') +parser.add_argument('--dataset', type=str, default='CK+', help='CNN architecture') +parser.add_argument('--model', type=str, default='VGG19', help='CNN architecture') +opt = parser.parse_args() + +cut_size = 44 + +transform_test = transforms.Compose([ + transforms.TenCrop(cut_size), + transforms.Lambda(lambda crops: torch.stack([transforms.ToTensor()(crop) for crop in crops])), +]) + +def plot_confusion_matrix(cm, classes, + normalize=False, + title='Confusion matrix', + cmap=plt.cm.Blues): + """ + This function prints and plots the confusion matrix. + Normalization can be applied by setting `normalize=True`. + """ + + if normalize: + cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis] + print("Normalized confusion matrix") + else: + print('Confusion matrix, without normalization') + + print(cm) + + plt.imshow(cm, interpolation='nearest', cmap=cmap) + plt.title(title, fontsize=16) + plt.colorbar() + tick_marks = np.arange(len(classes)) + plt.xticks(tick_marks, classes, rotation=45) + plt.yticks(tick_marks, classes) + + fmt = '.2f' if normalize else 'd' + thresh = cm.max() / 2. + for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])): + plt.text(j, i, format(cm[i, j], fmt), + horizontalalignment="center", + color="white" if cm[i, j] > thresh else "black") + + + plt.ylabel('True label', fontsize=18) + plt.xlabel('Predicted label', fontsize=18) + plt.tight_layout() + +class_names = ['Angry', 'Disgust', 'Fear', 'Happy', 'Sad', 'Surprise', 'Contempt'] + +# Model +if opt.model == 'VGG19': + net = VGG('VGG19') +elif opt.model == 'Resnet18': + net = ResNet18() + +correct = 0 +total = 0 +all_target = [] + +for i in xrange(10): + print("%d fold" % (i+1)) + path = os.path.join(opt.dataset + '_' + opt.model, '%d' %(i+1)) + checkpoint = torch.load(os.path.join(path, 'Test_model.t7')) + + net.load_state_dict(checkpoint['net']) + net.cuda() + net.eval() + testset = CK(split = 'Testing', fold = i+1, transform=transform_test) + testloader = torch.utils.data.DataLoader(testset, batch_size=5, shuffle=False, num_workers=1) + + for batch_idx, (inputs, targets) in enumerate(testloader): + bs, ncrops, c, h, w = np.shape(inputs) + inputs = inputs.view(-1, c, h, w) + inputs, targets = inputs.cuda(), targets.cuda() + inputs, targets = Variable(inputs, volatile=True), Variable(targets) + outputs = net(inputs) + outputs_avg = outputs.view(bs, ncrops, -1).mean(1) # avg over crops + _, predicted = torch.max(outputs_avg.data, 1) + total += targets.size(0) + correct += predicted.eq(targets.data).cpu().sum() + + if batch_idx == 0 and i == 0: + all_predicted = predicted + all_targets = targets + else: + all_predicted = torch.cat((all_predicted, predicted), 0) + all_targets = torch.cat((all_targets, targets), 0) + + acc = 100. * correct / total + print("accuracy: %0.3f" % acc) + +# Compute confusion matrix +matrix = confusion_matrix(all_targets.data.cpu().numpy(), all_predicted.cpu().numpy()) +np.set_printoptions(precision=2) + +# Plot normalized confusion matrix +plt.figure(figsize=(10, 8)) +plot_confusion_matrix(matrix, classes=class_names, normalize=False, + title= 'Confusion Matrix (Accuracy: %0.3f%%)' %acc) +#plt.show() +plt.savefig(os.path.join(opt.dataset + '_' + opt.model, 'Confusion Matrix.png')) +plt.close() diff --git a/src/jetmax_demos/scripts/FER/FER/plot_fer2013_confusion_matrix.py b/src/jetmax_demos/scripts/FER/FER/plot_fer2013_confusion_matrix.py new file mode 100644 index 0000000..2e48d62 --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/plot_fer2013_confusion_matrix.py @@ -0,0 +1,124 @@ +""" +plot confusion_matrix of PublicTest and PrivateTest +""" + +import itertools +import numpy as np +import matplotlib.pyplot as plt + +import torch +import torch.nn as nn +import torch.nn.functional as F + +import os +import argparse +from fer import FER2013 + +from torch.autograd import Variable +import torchvision +import transforms as transforms +from sklearn.metrics import confusion_matrix +from models import * + + +parser = argparse.ArgumentParser(description='PyTorch Fer2013 CNN Training') +parser.add_argument('--model', type=str, default='VGG19', help='CNN architecture') +parser.add_argument('--dataset', type=str, default='FER2013', help='CNN architecture') +parser.add_argument('--split', type=str, default='PrivateTest', help='split') +opt = parser.parse_args() + +cut_size = 44 + +transform_test = transforms.Compose([ + transforms.TenCrop(cut_size), + transforms.Lambda(lambda crops: torch.stack([transforms.ToTensor()(crop) for crop in crops])), +]) + + +def plot_confusion_matrix(cm, classes, + normalize=False, + title='Confusion matrix', + cmap=plt.cm.Blues): + """ + This function prints and plots the confusion matrix. + Normalization can be applied by setting `normalize=True`. + """ + if normalize: + cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis] + print("Normalized confusion matrix") + else: + print('Confusion matrix, without normalization') + + print(cm) + + plt.imshow(cm, interpolation='nearest', cmap=cmap) + plt.title(title, fontsize=16) + plt.colorbar() + tick_marks = np.arange(len(classes)) + plt.xticks(tick_marks, classes, rotation=45) + plt.yticks(tick_marks, classes) + + fmt = '.2f' if normalize else 'd' + thresh = cm.max() / 2. + for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])): + plt.text(j, i, format(cm[i, j], fmt), + horizontalalignment="center", + color="white" if cm[i, j] > thresh else "black") + + + plt.ylabel('True label', fontsize=18) + plt.xlabel('Predicted label', fontsize=18) + plt.tight_layout() + +class_names = ['Angry', 'Disgust', 'Fear', 'Happy', 'Sad', 'Surprise', 'Neutral'] + +# Model +if opt.model == 'VGG19': + net = VGG('VGG19') +elif opt.model == 'Resnet18': + net = ResNet18() + +path = os.path.join(opt.dataset + '_' + opt.model) +checkpoint = torch.load(os.path.join(path, opt.split + '_model.t7')) + +net.load_state_dict(checkpoint['net']) +net.cuda() +net.eval() +Testset = FER2013(split = opt.split, transform=transform_test) +Testloader = torch.utils.data.DataLoader(Testset, batch_size=128, shuffle=False, num_workers=1) +correct = 0 +total = 0 +all_target = [] +for batch_idx, (inputs, targets) in enumerate(Testloader): + + bs, ncrops, c, h, w = np.shape(inputs) + inputs = inputs.view(-1, c, h, w) + inputs, targets = inputs.cuda(), targets.cuda() + inputs, targets = Variable(inputs, volatile=True), Variable(targets) + outputs = net(inputs) + + outputs_avg = outputs.view(bs, ncrops, -1).mean(1) # avg over crops + _, predicted = torch.max(outputs_avg.data, 1) + + total += targets.size(0) + correct += predicted.eq(targets.data).cpu().sum() + if batch_idx == 0: + all_predicted = predicted + all_targets = targets + else: + all_predicted = torch.cat((all_predicted, predicted),0) + all_targets = torch.cat((all_targets, targets),0) + +acc = 100. * correct / total +print("accuracy: %0.3f" % acc) + +# Compute confusion matrix +matrix = confusion_matrix(all_targets.data.cpu().numpy(), all_predicted.cpu().numpy()) +np.set_printoptions(precision=2) + +# Plot normalized confusion matrix +plt.figure(figsize=(10, 8)) +plot_confusion_matrix(matrix, classes=class_names, normalize=True, + title= opt.split+' Confusion Matrix (Accuracy: %0.3f%%)' %acc) +plt.savefig(os.path.join(path, opt.split + '_cm.png')) +plt.close() diff --git a/src/jetmax_demos/scripts/FER/FER/preprocess_CK+.py b/src/jetmax_demos/scripts/FER/FER/preprocess_CK+.py new file mode 100644 index 0000000..695d402 --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/preprocess_CK+.py @@ -0,0 +1,87 @@ +# create data and label for CK+ +# 0=anger 1=disgust, 2=fear, 3=happy, 4=sadness, 5=surprise, 6=contempt +# contain 135,177,75,207,84,249,54 images + +import csv +import os +import numpy as np +import h5py +import skimage.io + +ck_path = 'CK+48' + +anger_path = os.path.join(ck_path, 'anger') +disgust_path = os.path.join(ck_path, 'disgust') +fear_path = os.path.join(ck_path, 'fear') +happy_path = os.path.join(ck_path, 'happy') +sadness_path = os.path.join(ck_path, 'sadness') +surprise_path = os.path.join(ck_path, 'surprise') +contempt_path = os.path.join(ck_path, 'contempt') + +# # Creat the list to store the data and label information +data_x = [] +data_y = [] + +datapath = os.path.join('data','CK_data.h5') +if not os.path.exists(os.path.dirname(datapath)): + os.makedirs(os.path.dirname(datapath)) + +# order the file, so the training set will not contain the test set (don't random) +files = os.listdir(anger_path) +files.sort() +for filename in files: + I = skimage.io.imread(os.path.join(anger_path,filename)) + data_x.append(I.tolist()) + data_y.append(0) + +files = os.listdir(disgust_path) +files.sort() +for filename in files: + I = skimage.io.imread(os.path.join(disgust_path,filename)) + data_x.append(I.tolist()) + data_y.append(1) + +files = os.listdir(fear_path) +files.sort() +for filename in files: + I = skimage.io.imread(os.path.join(fear_path,filename)) + data_x.append(I.tolist()) + data_y.append(2) + +files = os.listdir(happy_path) +files.sort() +for filename in files: + I = skimage.io.imread(os.path.join(happy_path,filename)) + data_x.append(I.tolist()) + data_y.append(3) + +files = os.listdir(sadness_path) +files.sort() +for filename in files: + I = skimage.io.imread(os.path.join(sadness_path,filename)) + data_x.append(I.tolist()) + data_y.append(4) + +files = os.listdir(surprise_path) +files.sort() +for filename in files: + I = skimage.io.imread(os.path.join(surprise_path,filename)) + data_x.append(I.tolist()) + data_y.append(5) + +files = os.listdir(contempt_path) +files.sort() +for filename in files: + I = skimage.io.imread(os.path.join(contempt_path,filename)) + data_x.append(I.tolist()) + data_y.append(6) + +print(np.shape(data_x)) +print(np.shape(data_y)) + +datafile = h5py.File(datapath, 'w') +datafile.create_dataset("data_pixel", dtype = 'uint8', data=data_x) +datafile.create_dataset("data_label", dtype = 'int64', data=data_y) +datafile.close() + +print("Save data finish!!!") diff --git a/src/jetmax_demos/scripts/FER/FER/preprocess_fer2013.py b/src/jetmax_demos/scripts/FER/FER/preprocess_fer2013.py new file mode 100644 index 0000000..b2bcbf2 --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/preprocess_fer2013.py @@ -0,0 +1,63 @@ +# create data and label for FER2013 +# labels: 0=Angry, 1=Disgust, 2=Fear, 3=Happy, 4=Sad, 5=Surprise, 6=Neutral +import csv +import os +import numpy as np +import h5py + +file = 'data/fer2013.csv' + +# Creat the list to store the data and label information +Training_x = [] +Training_y = [] +PublicTest_x = [] +PublicTest_y = [] +PrivateTest_x = [] +PrivateTest_y = [] + +datapath = os.path.join('data','data.h5') +if not os.path.exists(os.path.dirname(datapath)): + os.makedirs(os.path.dirname(datapath)) + +with open(file,'r') as csvin: + data=csv.reader(csvin) + for row in data: + if row[-1] == 'Training': + temp_list = [] + for pixel in row[1].split( ): + temp_list.append(int(pixel)) + I = np.asarray(temp_list) + Training_y.append(int(row[0])) + Training_x.append(I.tolist()) + + if row[-1] == "PublicTest" : + temp_list = [] + for pixel in row[1].split( ): + temp_list.append(int(pixel)) + I = np.asarray(temp_list) + PublicTest_y.append(int(row[0])) + PublicTest_x.append(I.tolist()) + + if row[-1] == 'PrivateTest': + temp_list = [] + for pixel in row[1].split( ): + temp_list.append(int(pixel)) + I = np.asarray(temp_list) + + PrivateTest_y.append(int(row[0])) + PrivateTest_x.append(I.tolist()) + +print(np.shape(Training_x)) +print(np.shape(PublicTest_x)) +print(np.shape(PrivateTest_x)) + +datafile = h5py.File(datapath, 'w') +datafile.create_dataset("Training_pixel", dtype = 'uint8', data=Training_x) +datafile.create_dataset("Training_label", dtype = 'int64', data=Training_y) +datafile.create_dataset("PublicTest_pixel", dtype = 'uint8', data=PublicTest_x) +datafile.create_dataset("PublicTest_label", dtype = 'int64', data=PublicTest_y) +datafile.create_dataset("PrivateTest_pixel", dtype = 'uint8', data=PrivateTest_x) +datafile.create_dataset("PrivateTest_label", dtype = 'int64', data=PrivateTest_y) +datafile.close() + +print("Save data finish!!!") diff --git a/src/jetmax_demos/scripts/FER/FER/transforms/__init__.py b/src/jetmax_demos/scripts/FER/FER/transforms/__init__.py new file mode 100644 index 0000000..7986cdd --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/transforms/__init__.py @@ -0,0 +1 @@ +from .transforms import * diff --git a/src/jetmax_demos/scripts/FER/FER/transforms/functional.py b/src/jetmax_demos/scripts/FER/FER/transforms/functional.py new file mode 100644 index 0000000..85beb38 --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/transforms/functional.py @@ -0,0 +1,579 @@ +from __future__ import division +import torch +import math +import random +from PIL import Image, ImageOps, ImageEnhance +try: + import accimage +except ImportError: + accimage = None +import numpy as np +import numbers +import types +import collections +import warnings + + +def _is_pil_image(img): + if accimage is not None: + return isinstance(img, (Image.Image, accimage.Image)) + else: + return isinstance(img, Image.Image) + + +def _is_tensor_image(img): + return torch.is_tensor(img) and img.ndimension() == 3 + + +def _is_numpy_image(img): + return isinstance(img, np.ndarray) and (img.ndim in {2, 3}) + + +def to_tensor(pic): + """Convert a ``PIL Image`` or ``numpy.ndarray`` to tensor. + + See ``ToTensor`` for more details. + + Args: + pic (PIL Image or numpy.ndarray): Image to be converted to tensor. + + Returns: + Tensor: Converted image. + """ + if not(_is_pil_image(pic) or _is_numpy_image(pic)): + raise TypeError('pic should be PIL Image or ndarray. Got {}'.format(type(pic))) + + if isinstance(pic, np.ndarray): + # handle numpy array + img = torch.from_numpy(pic.transpose((2, 0, 1))) + # backward compatibility + return img.float().div(255) + + if accimage is not None and isinstance(pic, accimage.Image): + nppic = np.zeros([pic.channels, pic.height, pic.width], dtype=np.float32) + pic.copyto(nppic) + return torch.from_numpy(nppic) + + # handle PIL Image + if pic.mode == 'I': + img = torch.from_numpy(np.array(pic, np.int32, copy=False)) + elif pic.mode == 'I;16': + img = torch.from_numpy(np.array(pic, np.int16, copy=False)) + else: + img = torch.ByteTensor(torch.ByteStorage.from_buffer(pic.tobytes())) + # PIL image mode: 1, L, P, I, F, RGB, YCbCr, RGBA, CMYK + if pic.mode == 'YCbCr': + nchannel = 3 + elif pic.mode == 'I;16': + nchannel = 1 + else: + nchannel = len(pic.mode) + img = img.view(pic.size[1], pic.size[0], nchannel) + # put it from HWC to CHW format + # yikes, this transpose takes 80% of the loading time/CPU + img = img.transpose(0, 1).transpose(0, 2).contiguous() + if isinstance(img, torch.ByteTensor): + return img.float().div(255) + else: + return img + + +def to_pil_image(pic, mode=None): + """Convert a tensor or an ndarray to PIL Image. + + See :class:`~torchvision.transforms.ToPIlImage` for more details. + + Args: + pic (Tensor or numpy.ndarray): Image to be converted to PIL Image. + mode (`PIL.Image mode`_): color space and pixel depth of input data (optional). + + .. _PIL.Image mode: http://pillow.readthedocs.io/en/3.4.x/handbook/concepts.html#modes + + Returns: + PIL Image: Image converted to PIL Image. + """ + if not(_is_numpy_image(pic) or _is_tensor_image(pic)): + raise TypeError('pic should be Tensor or ndarray. Got {}.'.format(type(pic))) + + npimg = pic + if isinstance(pic, torch.FloatTensor): + pic = pic.mul(255).byte() + if torch.is_tensor(pic): + npimg = np.transpose(pic.numpy(), (1, 2, 0)) + + if not isinstance(npimg, np.ndarray): + raise TypeError('Input pic must be a torch.Tensor or NumPy ndarray, ' + + 'not {}'.format(type(npimg))) + + if npimg.shape[2] == 1: + expected_mode = None + npimg = npimg[:, :, 0] + if npimg.dtype == np.uint8: + expected_mode = 'L' + if npimg.dtype == np.int16: + expected_mode = 'I;16' + if npimg.dtype == np.int32: + expected_mode = 'I' + elif npimg.dtype == np.float32: + expected_mode = 'F' + if mode is not None and mode != expected_mode: + raise ValueError("Incorrect mode ({}) supplied for input type {}. Should be {}" + .format(mode, np.dtype, expected_mode)) + mode = expected_mode + + elif npimg.shape[2] == 4: + permitted_4_channel_modes = ['RGBA', 'CMYK'] + if mode is not None and mode not in permitted_4_channel_modes: + raise ValueError("Only modes {} are supported for 4D inputs".format(permitted_4_channel_modes)) + + if mode is None and npimg.dtype == np.uint8: + mode = 'RGBA' + else: + permitted_3_channel_modes = ['RGB', 'YCbCr', 'HSV'] + if mode is not None and mode not in permitted_3_channel_modes: + raise ValueError("Only modes {} are supported for 3D inputs".format(permitted_3_channel_modes)) + if mode is None and npimg.dtype == np.uint8: + mode = 'RGB' + + if mode is None: + raise TypeError('Input type {} is not supported'.format(npimg.dtype)) + + return Image.fromarray(npimg, mode=mode) + + +def normalize(tensor, mean, std): + """Normalize a tensor image with mean and standard deviation. + + See ``Normalize`` for more details. + + Args: + tensor (Tensor): Tensor image of size (C, H, W) to be normalized. + mean (sequence): Sequence of means for each channel. + std (sequence): Sequence of standard deviations for each channely. + + Returns: + Tensor: Normalized Tensor image. + """ + if not _is_tensor_image(tensor): + raise TypeError('tensor is not a torch image.') + # TODO: make efficient + for t, m, s in zip(tensor, mean, std): + t.sub_(m).div_(s) + return tensor + + +def resize(img, size, interpolation=Image.BILINEAR): + """Resize the input PIL Image to the given size. + + Args: + img (PIL Image): Image to be resized. + size (sequence or int): Desired output size. If size is a sequence like + (h, w), the output size will be matched to this. If size is an int, + the smaller edge of the image will be matched to this number maintaing + the aspect ratio. i.e, if height > width, then image will be rescaled to + (size * height / width, size) + interpolation (int, optional): Desired interpolation. Default is + ``PIL.Image.BILINEAR`` + + Returns: + PIL Image: Resized image. + """ + if not _is_pil_image(img): + raise TypeError('img should be PIL Image. Got {}'.format(type(img))) + if not (isinstance(size, int) or (isinstance(size, collections.Iterable) and len(size) == 2)): + raise TypeError('Got inappropriate size arg: {}'.format(size)) + + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def scale(*args, **kwargs): + warnings.warn("The use of the transforms.Scale transform is deprecated, " + + "please use transforms.Resize instead.") + return resize(*args, **kwargs) + + +def pad(img, padding, fill=0): + """Pad the given PIL Image on all sides with the given "pad" value. + + Args: + img (PIL Image): Image to be padded. + padding (int or tuple): Padding on each border. If a single int is provided this + is used to pad all borders. If tuple of length 2 is provided this is the padding + on left/right and top/bottom respectively. If a tuple of length 4 is provided + this is the padding for the left, top, right and bottom borders + respectively. + fill: Pixel fill value. Default is 0. If a tuple of + length 3, it is used to fill R, G, B channels respectively. + + Returns: + PIL Image: Padded image. + """ + if not _is_pil_image(img): + raise TypeError('img should be PIL Image. Got {}'.format(type(img))) + + if not isinstance(padding, (numbers.Number, tuple)): + raise TypeError('Got inappropriate padding arg') + if not isinstance(fill, (numbers.Number, str, tuple)): + raise TypeError('Got inappropriate fill arg') + + if isinstance(padding, collections.Sequence) and len(padding) not in [2, 4]: + raise ValueError("Padding must be an int or a 2, or 4 element tuple, not a " + + "{} element tuple".format(len(padding))) + + return ImageOps.expand(img, border=padding, fill=fill) + + +def crop(img, i, j, h, w): + """Crop the given PIL Image. + + Args: + img (PIL Image): Image to be cropped. + i: Upper pixel coordinate. + j: Left pixel coordinate. + h: Height of the cropped image. + w: Width of the cropped image. + + Returns: + PIL Image: Cropped image. + """ + if not _is_pil_image(img): + raise TypeError('img should be PIL Image. Got {}'.format(type(img))) + + return img.crop((j, i, j + w, i + h)) + + +def center_crop(img, output_size): + if isinstance(output_size, numbers.Number): + output_size = (int(output_size), int(output_size)) + w, h = img.size + th, tw = output_size + i = int(round((h - th) / 2.)) + j = int(round((w - tw) / 2.)) + return crop(img, i, j, th, tw) + + +def resized_crop(img, i, j, h, w, size, interpolation=Image.BILINEAR): + """Crop the given PIL Image and resize it to desired size. + + Notably used in RandomResizedCrop. + + Args: + img (PIL Image): Image to be cropped. + i: Upper pixel coordinate. + j: Left pixel coordinate. + h: Height of the cropped image. + w: Width of the cropped image. + size (sequence or int): Desired output size. Same semantics as ``scale``. + interpolation (int, optional): Desired interpolation. Default is + ``PIL.Image.BILINEAR``. + Returns: + PIL Image: Cropped image. + """ + assert _is_pil_image(img), 'img should be PIL Image' + img = crop(img, i, j, h, w) + img = resize(img, size, interpolation) + return img + + +def hflip(img): + """Horizontally flip the given PIL Image. + + Args: + img (PIL Image): Image to be flipped. + + Returns: + PIL Image: Horizontall flipped image. + """ + if not _is_pil_image(img): + raise TypeError('img should be PIL Image. Got {}'.format(type(img))) + + return img.transpose(Image.FLIP_LEFT_RIGHT) + + +def vflip(img): + """Vertically flip the given PIL Image. + + Args: + img (PIL Image): Image to be flipped. + + Returns: + PIL Image: Vertically flipped image. + """ + if not _is_pil_image(img): + raise TypeError('img should be PIL Image. Got {}'.format(type(img))) + + return img.transpose(Image.FLIP_TOP_BOTTOM) + + +def five_crop(img, size): + """Crop the given PIL Image into four corners and the central crop. + + .. Note:: + This transform returns a tuple of images and there may be a + mismatch in the number of inputs and targets your ``Dataset`` returns. + + Args: + size (sequence or int): Desired output size of the crop. If size is an + int instead of sequence like (h, w), a square crop (size, size) is + made. + Returns: + tuple: tuple (tl, tr, bl, br, center) corresponding top left, + top right, bottom left, bottom right and center crop. + """ + if isinstance(size, numbers.Number): + size = (int(size), int(size)) + else: + assert len(size) == 2, "Please provide only two dimensions (h, w) for size." + + w, h = img.size + crop_h, crop_w = size + if crop_w > w or crop_h > h: + raise ValueError("Requested crop size {} is bigger than input size {}".format(size, + (h, w))) + tl = img.crop((0, 0, crop_w, crop_h)) + tr = img.crop((w - crop_w, 0, w, crop_h)) + bl = img.crop((0, h - crop_h, crop_w, h)) + br = img.crop((w - crop_w, h - crop_h, w, h)) + center = center_crop(img, (crop_h, crop_w)) + return (tl, tr, bl, br, center) + + +def ten_crop(img, size, vertical_flip=False): + """Crop the given PIL Image into four corners and the central crop plus the + flipped version of these (horizontal flipping is used by default). + + .. Note:: + This transform returns a tuple of images and there may be a + mismatch in the number of inputs and targets your ``Dataset`` returns. + + Args: + size (sequence or int): Desired output size of the crop. If size is an + int instead of sequence like (h, w), a square crop (size, size) is + made. + vertical_flip (bool): Use vertical flipping instead of horizontal + + Returns: + tuple: tuple (tl, tr, bl, br, center, tl_flip, tr_flip, bl_flip, + br_flip, center_flip) corresponding top left, top right, + bottom left, bottom right and center crop and same for the + flipped image. + """ + if isinstance(size, numbers.Number): + size = (int(size), int(size)) + else: + assert len(size) == 2, "Please provide only two dimensions (h, w) for size." + + first_five = five_crop(img, size) + + if vertical_flip: + img = vflip(img) + else: + img = hflip(img) + + second_five = five_crop(img, size) + return first_five + second_five + + +def adjust_brightness(img, brightness_factor): + """Adjust brightness of an Image. + + Args: + img (PIL Image): PIL Image to be adjusted. + brightness_factor (float): How much to adjust the brightness. Can be + any non negative number. 0 gives a black image, 1 gives the + original image while 2 increases the brightness by a factor of 2. + + Returns: + PIL Image: Brightness adjusted image. + """ + if not _is_pil_image(img): + raise TypeError('img should be PIL Image. Got {}'.format(type(img))) + + enhancer = ImageEnhance.Brightness(img) + img = enhancer.enhance(brightness_factor) + return img + + +def adjust_contrast(img, contrast_factor): + """Adjust contrast of an Image. + + Args: + img (PIL Image): PIL Image to be adjusted. + contrast_factor (float): How much to adjust the contrast. Can be any + non negative number. 0 gives a solid gray image, 1 gives the + original image while 2 increases the contrast by a factor of 2. + + Returns: + PIL Image: Contrast adjusted image. + """ + if not _is_pil_image(img): + raise TypeError('img should be PIL Image. Got {}'.format(type(img))) + + enhancer = ImageEnhance.Contrast(img) + img = enhancer.enhance(contrast_factor) + return img + + +def adjust_saturation(img, saturation_factor): + """Adjust color saturation of an image. + + Args: + img (PIL Image): PIL Image to be adjusted. + saturation_factor (float): How much to adjust the saturation. 0 will + give a black and white image, 1 will give the original image while + 2 will enhance the saturation by a factor of 2. + + Returns: + PIL Image: Saturation adjusted image. + """ + if not _is_pil_image(img): + raise TypeError('img should be PIL Image. Got {}'.format(type(img))) + + enhancer = ImageEnhance.Color(img) + img = enhancer.enhance(saturation_factor) + return img + + +def adjust_hue(img, hue_factor): + """Adjust hue of an image. + + The image hue is adjusted by converting the image to HSV and + cyclically shifting the intensities in the hue channel (H). + The image is then converted back to original image mode. + + `hue_factor` is the amount of shift in H channel and must be in the + interval `[-0.5, 0.5]`. + + See https://en.wikipedia.org/wiki/Hue for more details on Hue. + + Args: + img (PIL Image): PIL Image to be adjusted. + hue_factor (float): How much to shift the hue channel. Should be in + [-0.5, 0.5]. 0.5 and -0.5 give complete reversal of hue channel in + HSV space in positive and negative direction respectively. + 0 means no shift. Therefore, both -0.5 and 0.5 will give an image + with complementary colors while 0 gives the original image. + + Returns: + PIL Image: Hue adjusted image. + """ + if not(-0.5 <= hue_factor <= 0.5): + raise ValueError('hue_factor is not in [-0.5, 0.5].'.format(hue_factor)) + + if not _is_pil_image(img): + raise TypeError('img should be PIL Image. Got {}'.format(type(img))) + + input_mode = img.mode + if input_mode in {'L', '1', 'I', 'F'}: + return img + + h, s, v = img.convert('HSV').split() + + np_h = np.array(h, dtype=np.uint8) + # uint8 addition take cares of rotation across boundaries + with np.errstate(over='ignore'): + np_h += np.uint8(hue_factor * 255) + h = Image.fromarray(np_h, 'L') + + img = Image.merge('HSV', (h, s, v)).convert(input_mode) + return img + + +def adjust_gamma(img, gamma, gain=1): + """Perform gamma correction on an image. + + Also known as Power Law Transform. Intensities in RGB mode are adjusted + based on the following equation: + + I_out = 255 * gain * ((I_in / 255) ** gamma) + + See https://en.wikipedia.org/wiki/Gamma_correction for more details. + + Args: + img (PIL Image): PIL Image to be adjusted. + gamma (float): Non negative real number. gamma larger than 1 make the + shadows darker, while gamma smaller than 1 make dark regions + lighter. + gain (float): The constant multiplier. + """ + if not _is_pil_image(img): + raise TypeError('img should be PIL Image. Got {}'.format(type(img))) + + if gamma < 0: + raise ValueError('Gamma should be a non-negative real number') + + input_mode = img.mode + img = img.convert('RGB') + + np_img = np.array(img, dtype=np.float32) + np_img = 255 * gain * ((np_img / 255) ** gamma) + np_img = np.uint8(np.clip(np_img, 0, 255)) + + img = Image.fromarray(np_img, 'RGB').convert(input_mode) + return img + + +def rotate(img, angle, resample=False, expand=False, center=None): + """Rotate the image by angle and then (optionally) translate it by (n_columns, n_rows) + + + Args: + img (PIL Image): PIL Image to be rotated. + angle ({float, int}): In degrees degrees counter clockwise order. + resample ({PIL.Image.NEAREST, PIL.Image.BILINEAR, PIL.Image.BICUBIC}, optional): + An optional resampling filter. + See http://pillow.readthedocs.io/en/3.4.x/handbook/concepts.html#filters + If omitted, or if the image has mode "1" or "P", it is set to PIL.Image.NEAREST. + expand (bool, optional): Optional expansion flag. + If true, expands the output image to make it large enough to hold the entire rotated image. + If false or omitted, make the output image the same size as the input image. + Note that the expand flag assumes rotation around the center and no translation. + center (2-tuple, optional): Optional center of rotation. + Origin is the upper left corner. + Default is the center of the image. + """ + + if not _is_pil_image(img): + raise TypeError('img should be PIL Image. Got {}'.format(type(img))) + + return img.rotate(angle, resample, expand, center) + + +def to_grayscale(img, num_output_channels=1): + """Convert image to grayscale version of image. + + Args: + img (PIL Image): Image to be converted to grayscale. + + Returns: + PIL Image: Grayscale version of the image. + if num_output_channels == 1 : returned image is single channel + if num_output_channels == 3 : returned image is 3 channel with r == g == b + """ + if not _is_pil_image(img): + raise TypeError('img should be PIL Image. Got {}'.format(type(img))) + + if num_output_channels == 1: + img = img.convert('L') + elif num_output_channels == 3: + img = img.convert('L') + np_img = np.array(img, dtype=np.uint8) + np_img = np.dstack([np_img, np_img, np_img]) + img = Image.fromarray(np_img, 'RGB') + else: + raise ValueError('num_output_channels should be either 1 or 3') + + return img diff --git a/src/jetmax_demos/scripts/FER/FER/transforms/transforms.py b/src/jetmax_demos/scripts/FER/FER/transforms/transforms.py new file mode 100644 index 0000000..fd2baa3 --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/transforms/transforms.py @@ -0,0 +1,695 @@ +from __future__ import division +import torch +import math +import random +from PIL import Image, ImageOps, ImageEnhance +try: + import accimage +except ImportError: + accimage = None +import numpy as np +import numbers +import types +import collections +import warnings + +from . import functional as F + +__all__ = ["Compose", "ToTensor", "ToPILImage", "Normalize", "Resize", "Scale", "CenterCrop", "Pad", + "Lambda", "RandomCrop", "RandomHorizontalFlip", "RandomVerticalFlip", "RandomResizedCrop", + "RandomSizedCrop", "FiveCrop", "TenCrop", "LinearTransformation", "ColorJitter", "RandomRotation", + "Grayscale", "RandomGrayscale"] + + +class Compose(object): + """Composes several transforms together. + + Args: + transforms (list of ``Transform`` objects): list of transforms to compose. + + Example: + >>> transforms.Compose([ + >>> transforms.CenterCrop(10), + >>> transforms.ToTensor(), + >>> ]) + """ + + def __init__(self, transforms): + self.transforms = transforms + + def __call__(self, img): + for t in self.transforms: + img = t(img) + return img + + +class ToTensor(object): + """Convert a ``PIL Image`` or ``numpy.ndarray`` to tensor. + + Converts a PIL Image or numpy.ndarray (H x W x C) in the range + [0, 255] to a torch.FloatTensor of shape (C x H x W) in the range [0.0, 1.0]. + """ + + def __call__(self, pic): + """ + Args: + pic (PIL Image or numpy.ndarray): Image to be converted to tensor. + + Returns: + Tensor: Converted image. + """ + return F.to_tensor(pic) + + +class ToPILImage(object): + """Convert a tensor or an ndarray to PIL Image. + + Converts a torch.*Tensor of shape C x H x W or a numpy ndarray of shape + H x W x C to a PIL Image while preserving the value range. + + Args: + mode (`PIL.Image mode`_): color space and pixel depth of input data (optional). + If ``mode`` is ``None`` (default) there are some assumptions made about the input data: + 1. If the input has 3 channels, the ``mode`` is assumed to be ``RGB``. + 2. If the input has 4 channels, the ``mode`` is assumed to be ``RGBA``. + 3. If the input has 1 channel, the ``mode`` is determined by the data type (i,e, + ``int``, ``float``, ``short``). + + .. _PIL.Image mode: http://pillow.readthedocs.io/en/3.4.x/handbook/concepts.html#modes + """ + def __init__(self, mode=None): + self.mode = mode + + def __call__(self, pic): + """ + Args: + pic (Tensor or numpy.ndarray): Image to be converted to PIL Image. + + Returns: + PIL Image: Image converted to PIL Image. + + """ + return F.to_pil_image(pic, self.mode) + + +class Normalize(object): + """Normalize an tensor image with mean and standard deviation. + Given mean: ``(M1,...,Mn)`` and std: ``(S1,..,Sn)`` for ``n`` channels, this transform + will normalize each channel of the input ``torch.*Tensor`` i.e. + ``input[channel] = (input[channel] - mean[channel]) / std[channel]`` + + Args: + mean (sequence): Sequence of means for each channel. + std (sequence): Sequence of standard deviations for each channel. + """ + + def __init__(self, mean, std): + self.mean = mean + self.std = std + + def __call__(self, tensor): + """ + Args: + tensor (Tensor): Tensor image of size (C, H, W) to be normalized. + + Returns: + Tensor: Normalized Tensor image. + """ + return F.normalize(tensor, self.mean, self.std) + + +class Resize(object): + """Resize the input PIL Image to the given size. + + Args: + size (sequence or int): Desired output size. If size is a sequence like + (h, w), output size will be matched to this. If size is an int, + smaller edge of the image will be matched to this number. + i.e, if height > width, then image will be rescaled to + (size * height / width, size) + interpolation (int, optional): Desired interpolation. Default is + ``PIL.Image.BILINEAR`` + """ + + def __init__(self, size, interpolation=Image.BILINEAR): + assert isinstance(size, int) or (isinstance(size, collections.Iterable) and len(size) == 2) + self.size = size + self.interpolation = interpolation + + def __call__(self, img): + """ + Args: + img (PIL Image): Image to be scaled. + + Returns: + PIL Image: Rescaled image. + """ + return F.resize(img, self.size, self.interpolation) + + +class Scale(Resize): + """ + Note: This transform is deprecated in favor of Resize. + """ + def __init__(self, *args, **kwargs): + warnings.warn("The use of the transforms.Scale transform is deprecated, " + + "please use transforms.Resize instead.") + super(Scale, self).__init__(*args, **kwargs) + + +class CenterCrop(object): + """Crops the given PIL Image at the center. + + Args: + size (sequence or int): Desired output size of the crop. If size is an + int instead of sequence like (h, w), a square crop (size, size) is + made. + """ + + def __init__(self, size): + if isinstance(size, numbers.Number): + self.size = (int(size), int(size)) + else: + self.size = size + + def __call__(self, img): + """ + Args: + img (PIL Image): Image to be cropped. + + Returns: + PIL Image: Cropped image. + """ + return F.center_crop(img, self.size) + + +class Pad(object): + """Pad the given PIL Image on all sides with the given "pad" value. + + Args: + padding (int or tuple): Padding on each border. If a single int is provided this + is used to pad all borders. If tuple of length 2 is provided this is the padding + on left/right and top/bottom respectively. If a tuple of length 4 is provided + this is the padding for the left, top, right and bottom borders + respectively. + fill: Pixel fill value. Default is 0. If a tuple of + length 3, it is used to fill R, G, B channels respectively. + """ + + def __init__(self, padding, fill=0): + assert isinstance(padding, (numbers.Number, tuple)) + assert isinstance(fill, (numbers.Number, str, tuple)) + if isinstance(padding, collections.Sequence) and len(padding) not in [2, 4]: + raise ValueError("Padding must be an int or a 2, or 4 element tuple, not a " + + "{} element tuple".format(len(padding))) + + self.padding = padding + self.fill = fill + + def __call__(self, img): + """ + Args: + img (PIL Image): Image to be padded. + + Returns: + PIL Image: Padded image. + """ + return F.pad(img, self.padding, self.fill) + + +class Lambda(object): + """Apply a user-defined lambda as a transform. + + Args: + lambd (function): Lambda/function to be used for transform. + """ + + def __init__(self, lambd): + assert isinstance(lambd, types.LambdaType) + self.lambd = lambd + + def __call__(self, img): + return self.lambd(img) + + +class RandomCrop(object): + """Crop the given PIL Image at a random location. + + Args: + size (sequence or int): Desired output size of the crop. If size is an + int instead of sequence like (h, w), a square crop (size, size) is + made. + padding (int or sequence, optional): Optional padding on each border + of the image. Default is 0, i.e no padding. If a sequence of length + 4 is provided, it is used to pad left, top, right, bottom borders + respectively. + """ + + def __init__(self, size, padding=0): + if isinstance(size, numbers.Number): + self.size = (int(size), int(size)) + else: + self.size = size + self.padding = padding + + @staticmethod + def get_params(img, output_size): + """Get parameters for ``crop`` for a random crop. + + Args: + img (PIL Image): Image to be cropped. + output_size (tuple): Expected output size of the crop. + + Returns: + tuple: params (i, j, h, w) to be passed to ``crop`` for random crop. + """ + w, h = img.size + th, tw = output_size + if w == tw and h == th: + return 0, 0, h, w + + i = random.randint(0, h - th) + j = random.randint(0, w - tw) + return i, j, th, tw + + def __call__(self, img): + """ + Args: + img (PIL Image): Image to be cropped. + + Returns: + PIL Image: Cropped image. + """ + if self.padding > 0: + img = F.pad(img, self.padding) + + i, j, h, w = self.get_params(img, self.size) + + return F.crop(img, i, j, h, w) + + +class RandomHorizontalFlip(object): + """Horizontally flip the given PIL Image randomly with a probability of 0.5.""" + + def __call__(self, img): + """ + Args: + img (PIL Image): Image to be flipped. + + Returns: + PIL Image: Randomly flipped image. + """ + if random.random() < 0.5: + return F.hflip(img) + return img + + +class RandomVerticalFlip(object): + """Vertically flip the given PIL Image randomly with a probability of 0.5.""" + + def __call__(self, img): + """ + Args: + img (PIL Image): Image to be flipped. + + Returns: + PIL Image: Randomly flipped image. + """ + if random.random() < 0.5: + return F.vflip(img) + return img + + +class RandomResizedCrop(object): + """Crop the given PIL Image to random size and aspect ratio. + + A crop of random size (default: of 0.08 to 1.0) of the original size and a random + aspect ratio (default: of 3/4 to 4/3) of the original aspect ratio is made. This crop + is finally resized to given size. + This is popularly used to train the Inception networks. + + Args: + size: expected output size of each edge + scale: range of size of the origin size cropped + ratio: range of aspect ratio of the origin aspect ratio cropped + interpolation: Default: PIL.Image.BILINEAR + """ + + def __init__(self, size, scale=(0.08, 1.0), ratio=(3. / 4., 4. / 3.), interpolation=Image.BILINEAR): + self.size = (size, size) + self.interpolation = interpolation + self.scale = scale + self.ratio = ratio + + @staticmethod + def get_params(img, scale, ratio): + """Get parameters for ``crop`` for a random sized crop. + + Args: + img (PIL Image): Image to be cropped. + scale (tuple): range of size of the origin size cropped + ratio (tuple): range of aspect ratio of the origin aspect ratio cropped + + Returns: + tuple: params (i, j, h, w) to be passed to ``crop`` for a random + sized crop. + """ + for attempt in range(10): + area = img.size[0] * img.size[1] + target_area = random.uniform(*scale) * area + aspect_ratio = random.uniform(*ratio) + + w = int(round(math.sqrt(target_area * aspect_ratio))) + h = int(round(math.sqrt(target_area / aspect_ratio))) + + if random.random() < 0.5: + w, h = h, w + + if w <= img.size[0] and h <= img.size[1]: + i = random.randint(0, img.size[1] - h) + j = random.randint(0, img.size[0] - w) + return i, j, h, w + + # Fallback + w = min(img.size[0], img.size[1]) + i = (img.size[1] - w) // 2 + j = (img.size[0] - w) // 2 + return i, j, w, w + + def __call__(self, img): + """ + Args: + img (PIL Image): Image to be flipped. + + Returns: + PIL Image: Randomly cropped and resize image. + """ + i, j, h, w = self.get_params(img, self.scale, self.ratio) + return F.resized_crop(img, i, j, h, w, self.size, self.interpolation) + + +class RandomSizedCrop(RandomResizedCrop): + """ + Note: This transform is deprecated in favor of RandomResizedCrop. + """ + def __init__(self, *args, **kwargs): + warnings.warn("The use of the transforms.RandomSizedCrop transform is deprecated, " + + "please use transforms.RandomResizedCrop instead.") + super(RandomSizedCrop, self).__init__(*args, **kwargs) + + +class FiveCrop(object): + """Crop the given PIL Image into four corners and the central crop + + .. Note:: + This transform returns a tuple of images and there may be a mismatch in the number of + inputs and targets your Dataset returns. See below for an example of how to deal with + this. + + Args: + size (sequence or int): Desired output size of the crop. If size is an ``int`` + instead of sequence like (h, w), a square crop of size (size, size) is made. + + Example: + >>> transform = Compose([ + >>> FiveCrop(size), # this is a list of PIL Images + >>> Lambda(lambda crops: torch.stack([ToTensor()(crop) for crop in crops])) # returns a 4D tensor + >>> ]) + >>> #In your test loop you can do the following: + >>> input, target = batch # input is a 5d tensor, target is 2d + >>> bs, ncrops, c, h, w = input.size() + >>> result = model(input.view(-1, c, h, w)) # fuse batch size and ncrops + >>> result_avg = result.view(bs, ncrops, -1).mean(1) # avg over crops + """ + + def __init__(self, size): + self.size = size + if isinstance(size, numbers.Number): + self.size = (int(size), int(size)) + else: + assert len(size) == 2, "Please provide only two dimensions (h, w) for size." + self.size = size + + def __call__(self, img): + return F.five_crop(img, self.size) + + +class TenCrop(object): + """Crop the given PIL Image into four corners and the central crop plus the flipped version of + these (horizontal flipping is used by default) + + .. Note:: + This transform returns a tuple of images and there may be a mismatch in the number of + inputs and targets your Dataset returns. See below for an example of how to deal with + this. + + Args: + size (sequence or int): Desired output size of the crop. If size is an + int instead of sequence like (h, w), a square crop (size, size) is + made. + vertical_flip(bool): Use vertical flipping instead of horizontal + + Example: + >>> transform = Compose([ + >>> TenCrop(size), # this is a list of PIL Images + >>> Lambda(lambda crops: torch.stack([ToTensor()(crop) for crop in crops])) # returns a 4D tensor + >>> ]) + >>> #In your test loop you can do the following: + >>> input, target = batch # input is a 5d tensor, target is 2d + >>> bs, ncrops, c, h, w = input.size() + >>> result = model(input.view(-1, c, h, w)) # fuse batch size and ncrops + >>> result_avg = result.view(bs, ncrops, -1).mean(1) # avg over crops + """ + + def __init__(self, size, vertical_flip=False): + self.size = size + if isinstance(size, numbers.Number): + self.size = (int(size), int(size)) + else: + assert len(size) == 2, "Please provide only two dimensions (h, w) for size." + self.size = size + self.vertical_flip = vertical_flip + + def __call__(self, img): + return F.ten_crop(img, self.size, self.vertical_flip) + + +class LinearTransformation(object): + """Transform a tensor image with a square transformation matrix computed + offline. + + Given transformation_matrix, will flatten the torch.*Tensor, compute the dot + product with the transformation matrix and reshape the tensor to its + original shape. + + Applications: + - whitening: zero-center the data, compute the data covariance matrix + [D x D] with np.dot(X.T, X), perform SVD on this matrix and + pass it as transformation_matrix. + + Args: + transformation_matrix (Tensor): tensor [D x D], D = C x H x W + """ + + def __init__(self, transformation_matrix): + if transformation_matrix.size(0) != transformation_matrix.size(1): + raise ValueError("transformation_matrix should be square. Got " + + "[{} x {}] rectangular matrix.".format(*transformation_matrix.size())) + self.transformation_matrix = transformation_matrix + + def __call__(self, tensor): + """ + Args: + tensor (Tensor): Tensor image of size (C, H, W) to be whitened. + + Returns: + Tensor: Transformed image. + """ + if tensor.size(0) * tensor.size(1) * tensor.size(2) != self.transformation_matrix.size(0): + raise ValueError("tensor and transformation matrix have incompatible shape." + + "[{} x {} x {}] != ".format(*tensor.size()) + + "{}".format(self.transformation_matrix.size(0))) + flat_tensor = tensor.view(1, -1) + transformed_tensor = torch.mm(flat_tensor, self.transformation_matrix) + tensor = transformed_tensor.view(tensor.size()) + return tensor + + +class ColorJitter(object): + """Randomly change the brightness, contrast and saturation of an image. + + Args: + brightness (float): How much to jitter brightness. brightness_factor + is chosen uniformly from [max(0, 1 - brightness), 1 + brightness]. + contrast (float): How much to jitter contrast. contrast_factor + is chosen uniformly from [max(0, 1 - contrast), 1 + contrast]. + saturation (float): How much to jitter saturation. saturation_factor + is chosen uniformly from [max(0, 1 - saturation), 1 + saturation]. + hue(float): How much to jitter hue. hue_factor is chosen uniformly from + [-hue, hue]. Should be >=0 and <= 0.5. + """ + def __init__(self, brightness=0, contrast=0, saturation=0, hue=0): + self.brightness = brightness + self.contrast = contrast + self.saturation = saturation + self.hue = hue + + @staticmethod + def get_params(brightness, contrast, saturation, hue): + """Get a randomized transform to be applied on image. + + Arguments are same as that of __init__. + + Returns: + Transform which randomly adjusts brightness, contrast and + saturation in a random order. + """ + transforms = [] + if brightness > 0: + brightness_factor = np.random.uniform(max(0, 1 - brightness), 1 + brightness) + transforms.append(Lambda(lambda img: F.adjust_brightness(img, brightness_factor))) + + if contrast > 0: + contrast_factor = np.random.uniform(max(0, 1 - contrast), 1 + contrast) + transforms.append(Lambda(lambda img: F.adjust_contrast(img, contrast_factor))) + + if saturation > 0: + saturation_factor = np.random.uniform(max(0, 1 - saturation), 1 + saturation) + transforms.append(Lambda(lambda img: F.adjust_saturation(img, saturation_factor))) + + if hue > 0: + hue_factor = np.random.uniform(-hue, hue) + transforms.append(Lambda(lambda img: F.adjust_hue(img, hue_factor))) + + np.random.shuffle(transforms) + transform = Compose(transforms) + + return transform + + def __call__(self, img): + """ + Args: + img (PIL Image): Input image. + + Returns: + PIL Image: Color jittered image. + """ + transform = self.get_params(self.brightness, self.contrast, + self.saturation, self.hue) + return transform(img) + + +class RandomRotation(object): + """Rotate the image by angle. + + Args: + degrees (sequence or float or int): Range of degrees to select from. + If degrees is a number instead of sequence like (min, max), the range of degrees + will be (-degrees, +degrees). + resample ({PIL.Image.NEAREST, PIL.Image.BILINEAR, PIL.Image.BICUBIC}, optional): + An optional resampling filter. + See http://pillow.readthedocs.io/en/3.4.x/handbook/concepts.html#filters + If omitted, or if the image has mode "1" or "P", it is set to PIL.Image.NEAREST. + expand (bool, optional): Optional expansion flag. + If true, expands the output to make it large enough to hold the entire rotated image. + If false or omitted, make the output image the same size as the input image. + Note that the expand flag assumes rotation around the center and no translation. + center (2-tuple, optional): Optional center of rotation. + Origin is the upper left corner. + Default is the center of the image. + """ + + def __init__(self, degrees, resample=False, expand=False, center=None): + if isinstance(degrees, numbers.Number): + if degrees < 0: + raise ValueError("If degrees is a single number, it must be positive.") + self.degrees = (-degrees, degrees) + else: + if len(degrees) != 2: + raise ValueError("If degrees is a sequence, it must be of len 2.") + self.degrees = degrees + + self.resample = resample + self.expand = expand + self.center = center + + @staticmethod + def get_params(degrees): + """Get parameters for ``rotate`` for a random rotation. + + Returns: + sequence: params to be passed to ``rotate`` for random rotation. + """ + angle = np.random.uniform(degrees[0], degrees[1]) + + return angle + + def __call__(self, img): + """ + img (PIL Image): Image to be rotated. + + Returns: + PIL Image: Rotated image. + """ + + angle = self.get_params(self.degrees) + + return F.rotate(img, angle, self.resample, self.expand, self.center) + + +class Grayscale(object): + """Convert image to grayscale. + + Args: + num_output_channels (int): (1 or 3) number of channels desired for output image + + Returns: + PIL Image: Grayscale version of the input. + - If num_output_channels == 1 : returned image is single channel + - If num_output_channels == 3 : returned image is 3 channel with r == g == b + + """ + + def __init__(self, num_output_channels=1): + self.num_output_channels = num_output_channels + + def __call__(self, img): + """ + Args: + img (PIL Image): Image to be converted to grayscale. + + Returns: + PIL Image: Randomly grayscaled image. + """ + return F.to_grayscale(img, num_output_channels=self.num_output_channels) + + +class RandomGrayscale(object): + """Randomly convert image to grayscale with a probability of p (default 0.1). + + Args: + p (float): probability that image should be converted to grayscale. + + Returns: + PIL Image: Grayscale version of the input image with probability p and unchanged + with probability (1-p). + - If input image is 1 channel: grayscale version is 1 channel + - If input image is 3 channel: grayscale version is 3 channel with r == g == b + + """ + + def __init__(self, p=0.1): + self.p = p + + def __call__(self, img): + """ + Args: + img (PIL Image): Image to be converted to grayscale. + + Returns: + PIL Image: Randomly grayscaled image. + """ + num_output_channels = 1 if img.mode == 'L' else 3 + if random.random() < self.p: + return F.to_grayscale(img, num_output_channels=num_output_channels) + return img diff --git a/src/jetmax_demos/scripts/FER/FER/utils.py b/src/jetmax_demos/scripts/FER/FER/utils.py new file mode 100644 index 0000000..14fec84 --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/utils.py @@ -0,0 +1,72 @@ +'''Some helper functions for PyTorch, including: + - progress_bar: progress bar mimic xlua.progress. + - set_lr : set the learning rate + - clip_gradient : clip gradient +''' + +import os +import sys +import time +import math +import torch +import torch.nn as nn +import torch.nn.init as init +from torch.autograd import Function + +_, term_width = os.popen('stty size', 'r').read().split() +term_width = int(term_width) + +TOTAL_BAR_LENGTH = 30. +last_time = time.time() +begin_time = last_time + +def progress_bar(current, total, msg=None): + global last_time, begin_time + if current == 0: + begin_time = time.time() # Reset for new bar. + + cur_len = int(TOTAL_BAR_LENGTH*current/total) + rest_len = int(TOTAL_BAR_LENGTH - cur_len) - 1 + + sys.stdout.write(' [') + for i in range(cur_len): + sys.stdout.write('=') + sys.stdout.write('>') + for i in range(rest_len): + sys.stdout.write('.') + sys.stdout.write(']') + + cur_time = time.time() + step_time = cur_time - last_time + last_time = cur_time + tot_time = cur_time - begin_time + + L = [] + if msg: + L.append(' | ' + msg) + + msg = ''.join(L) + sys.stdout.write(msg) + for i in range(term_width-int(TOTAL_BAR_LENGTH)-len(msg)-3): + sys.stdout.write(' ') + + # Go back to the center of the bar. + for i in range(term_width-int(TOTAL_BAR_LENGTH/2)+2): + sys.stdout.write('\b') + sys.stdout.write(' %d/%d ' % (current+1, total)) + + if current < total-1: + sys.stdout.write('\r') + else: + sys.stdout.write('\n') + sys.stdout.flush() + +def set_lr(optimizer, lr): + for group in optimizer.param_groups: + group['lr'] = lr + +def clip_gradient(optimizer, grad_clip): + for group in optimizer.param_groups: + #print(group['params']) + for param in group['params']: + param.grad.data.clamp_(-grad_clip, grad_clip) diff --git a/src/jetmax_demos/scripts/FER/FER/visualize.py b/src/jetmax_demos/scripts/FER/FER/visualize.py new file mode 100644 index 0000000..5133971 --- /dev/null +++ b/src/jetmax_demos/scripts/FER/FER/visualize.py @@ -0,0 +1,96 @@ +""" +visualize results for test image +""" + +import numpy as np +import matplotlib.pyplot as plt +from PIL import Image +import torch +import torch.nn as nn +import torch.nn.functional as F +import os +from torch.autograd import Variable + +import transforms as transforms +from skimage import io +from skimage.transform import resize +from models import * + +cut_size = 44 + +transform_test = transforms.Compose([ + transforms.TenCrop(cut_size), + transforms.Lambda(lambda crops: torch.stack([transforms.ToTensor()(crop) for crop in crops])), +]) + +def rgb2gray(rgb): + return np.dot(rgb[...,:3], [0.299, 0.587, 0.114]) + +raw_img = io.imread('images/1.jpg') +gray = rgb2gray(raw_img) +gray = resize(gray, (48,48), mode='symmetric').astype(np.uint8) + +img = gray[:, :, np.newaxis] + +img = np.concatenate((img, img, img), axis=2) +img = Image.fromarray(img) +inputs = transform_test(img) + +class_names = ['Angry', 'Disgust', 'Fear', 'Happy', 'Sad', 'Surprise', 'Neutral'] + +net = VGG('VGG19') +checkpoint = torch.load(os.path.join('FER2013_VGG19', 'PrivateTest_model.t7')) +net.load_state_dict(checkpoint['net']) +net.cuda() +net.eval() + +ncrops, c, h, w = np.shape(inputs) + +inputs = inputs.view(-1, c, h, w) +inputs = inputs.cuda() +inputs = Variable(inputs, volatile=True) +outputs = net(inputs) + +outputs_avg = outputs.view(ncrops, -1).mean(0) # avg over crops + +score = F.softmax(outputs_avg) +_, predicted = torch.max(outputs_avg.data, 0) + +plt.rcParams['figure.figsize'] = (13.5,5.5) +axes=plt.subplot(1, 3, 1) +plt.imshow(raw_img) +plt.xlabel('Input Image', fontsize=16) +axes.set_xticks([]) +axes.set_yticks([]) +plt.tight_layout() + + +plt.subplots_adjust(left=0.05, bottom=0.2, right=0.95, top=0.9, hspace=0.02, wspace=0.3) + +plt.subplot(1, 3, 2) +ind = 0.1+0.6*np.arange(len(class_names)) # the x locations for the groups +width = 0.4 # the width of the bars: can also be len(x) sequence +color_list = ['red','orangered','darkorange','limegreen','darkgreen','royalblue','navy'] +for i in range(len(class_names)): + plt.bar(ind[i], score.data.cpu().numpy()[i], width, color=color_list[i]) +plt.title("Classification results ",fontsize=20) +plt.xlabel(" Expression Category ",fontsize=16) +plt.ylabel(" Classification Score ",fontsize=16) +plt.xticks(ind, class_names, rotation=45, fontsize=14) + +axes=plt.subplot(1, 3, 3) +emojis_img = io.imread('images/emojis/%s.png' % str(class_names[int(predicted.cpu().numpy())])) +plt.imshow(emojis_img) +plt.xlabel('Emoji Expression', fontsize=16) +axes.set_xticks([]) +axes.set_yticks([]) +plt.tight_layout() +# show emojis + +#plt.show() +plt.savefig(os.path.join('images/results/l.png')) +plt.close() + +print("The Expression is %s" %str(class_names[int(predicted.cpu().numpy())])) + + diff --git a/src/jetmax_demos/scripts/FER/FER2013_VGG19/PrivateTest_model.t7 b/src/jetmax_demos/scripts/FER/FER2013_VGG19/PrivateTest_model.t7 new file mode 100644 index 0000000..b970b04 Binary files /dev/null and b/src/jetmax_demos/scripts/FER/FER2013_VGG19/PrivateTest_model.t7 differ diff --git a/src/jetmax_demos/scripts/FER/fer.py b/src/jetmax_demos/scripts/FER/fer.py new file mode 100644 index 0000000..2043e6f --- /dev/null +++ b/src/jetmax_demos/scripts/FER/fer.py @@ -0,0 +1,47 @@ +import os +import sys +import cv2 +import numpy as np +import matplotlib.pyplot as plt +from PIL import Image +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.autograd import Variable +import FER.FER.transforms as transforms +from FER.FER.models import * + +cut_size = 44 + +transform_test = transforms.Compose([ + transforms.TenCrop(cut_size), + transforms.Lambda(lambda crops: torch.stack([transforms.ToTensor()(crop) for crop in crops])), +]) + +class_names = ['Angry', 'Disgust', 'Fear', 'Happy', 'Sad', 'Surprise', 'Neutral'] +checkpoint = torch.load( + os.path.join(os.path.split(os.path.realpath(__file__))[0], 'FER2013_VGG19/PrivateTest_model.t7')) +net = VGG('VGG19') +net.load_state_dict(checkpoint['net']) +net.cuda() +net.eval() + + +def fer(raw_img): + img = cv2.resize(raw_img, (48, 48)) + gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) + + img = gray[:, :, np.newaxis] + img = np.concatenate((img, img, img), axis=2) + img = Image.fromarray(img) + inputs = transform_test(img) + + ncrops, c, h, w = np.shape(inputs) + inputs = inputs.view(-1, c, h, w) + inputs = inputs.cuda() + with torch.no_grad(): + outputs = net(inputs) + outputs_avg = outputs.view(ncrops, -1).mean(0) # avg over crops + score = F.softmax(outputs_avg, dim=0) + _, predicted = torch.max(outputs_avg.data, 0) + return str(class_names[int(predicted.cpu().numpy())]) diff --git a/src/jetmax_demos/scripts/FER/fer_test.py b/src/jetmax_demos/scripts/FER/fer_test.py new file mode 100644 index 0000000..328f8d7 --- /dev/null +++ b/src/jetmax_demos/scripts/FER/fer_test.py @@ -0,0 +1,9 @@ +import cv2 +import fer + +raw_img = cv2.imread('FER/images/2.jpg') +ep = fer(raw_img) + +print("The Expression is %s" %ep) + + diff --git a/src/jetmax_demos/scripts/FER/test.py.bak b/src/jetmax_demos/scripts/FER/test.py.bak new file mode 100644 index 0000000..0b5cbc2 --- /dev/null +++ b/src/jetmax_demos/scripts/FER/test.py.bak @@ -0,0 +1,52 @@ +import numpy as np +import matplotlib.pyplot as plt +from PIL import Image +import torch +import torch.nn as nn +import torch.nn.functional as F +import os +from torch.autograd import Variable +import FER.transforms as transforms +import cv2 +from FER.models import * + +cut_size = 44 + +transform_test = transforms.Compose([ + transforms.TenCrop(cut_size), + transforms.Lambda(lambda crops: torch.stack([transforms.ToTensor()(crop) for crop in crops])), +]) + +raw_img = cv2.imread('FER/images/2.jpg') +gray = cv2.cvtColor(raw_img, cv2.COLOR_RGB2GRAY) +gray = cv2.resize(gray, (48, 48)) + +img = gray[:, :, np.newaxis] + +img = np.concatenate((img, img, img), axis=2) +img = Image.fromarray(img) +inputs = transform_test(img) + +class_names = ['Angry', 'Disgust', 'Fear', 'Happy', 'Sad', 'Surprise', 'Neutral'] + +net = VGG('VGG19') +checkpoint = torch.load(os.path.join(os.path.split(os.path.realpath(__file__))[0], 'FER2013_VGG19/PrivateTest_model.t7')) +net.load_state_dict(checkpoint['net']) +net.cuda() +net.eval() + +ncrops, c, h, w = np.shape(inputs) + +inputs = inputs.view(-1, c, h, w) +inputs = inputs.cuda() +inputs = Variable(inputs, volatile=True) +outputs = net(inputs) + +outputs_avg = outputs.view(ncrops, -1).mean(0) # avg over crops + +score = F.softmax(outputs_avg) +_, predicted = torch.max(outputs_avg.data, 0) + +print("The Expression is %s" %str(class_names[int(predicted.cpu().numpy())])) + + diff --git a/src/jetmax_demos/scripts/alphabetically_main.py b/src/jetmax_demos/scripts/alphabetically_main.py new file mode 100755 index 0000000..32a36e8 --- /dev/null +++ b/src/jetmax_demos/scripts/alphabetically_main.py @@ -0,0 +1,271 @@ +#!/usr/bin/env python3 +import os +import sys +import cv2 +import math +import time +import queue +import random +import threading +import numpy as np +import rospy +from sensor_msgs.msg import Image +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +import hiwonder +from hiwonder import serial_servo as ss +from yolov5_tensorrt import Yolov5TensorRT + +WORD_WANT = tuple([i for i in "DBRH"]) + +ROS_NODE_NAME = "hiwonder_jetmax_aph" +IMAGE_SIZE = 640, 480 +CHARACTERS_ENGINE_PATH = os.path.join(sys.path[0], 'models/characters_v5_160.trt') +CHARACTER_LABELS = tuple([i for i in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ']) +CHARACTER_NUM = 26 +TRT_INPUT_SIZE = 160 +COLORS = tuple([tuple([random.randint(10, 255) for j in range(3)]) for i in range(CHARACTER_NUM)]) +TARGET_POSITION = (-200, -180, 65) +yolov5_chars = Yolov5TensorRT(CHARACTERS_ENGINE_PATH, TRT_INPUT_SIZE, CHARACTER_NUM) + + +class Alphabetically: + def __init__(self): + self.lock = threading.RLock() + self.moving_box = None + self.index = 0 + self.pos_add = 0 + self.last_target = TARGET_POSITION + + self.runner = None + self.moving_count = 0 + self.count = 0 + self.fps_t0 = time.time() + self.fps = 0 + self.camera_params = None + self.K = None + self.R = None + self.T = None + + def load_camera_params(self): + self.camera_params = rospy.get_param('/camera_cal/block_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + + +def camera_to_world(cam_mtx, r, t, img_points): + inv_k = np.asmatrix(cam_mtx).I + r_mat = np.zeros((3, 3), dtype=np.float64) + cv2.Rodrigues(r, r_mat) + # invR * T + inv_r = np.asmatrix(r_mat).I # 3*3 + transPlaneToCam = np.dot(inv_r, np.asmatrix(t)) # 3*3 dot 3*1 = 3*1 + world_pt = [] + coords = np.zeros((3, 1), dtype=np.float64) + for img_pt in img_points: + coords[0][0] = img_pt[0][0] + coords[1][0] = img_pt[0][1] + coords[2][0] = 1.0 + worldPtCam = np.dot(inv_k, coords) # 3*3 dot 3*1 = 3*1 + # [x,y,1] * invR + worldPtPlane = np.dot(inv_r, worldPtCam) # 3*3 dot 3*1 = 3*1 + # zc + scale = transPlaneToCam[2][0] / worldPtPlane[2][0] + # zc * [x,y,1] * invR + scale_worldPtPlane = np.multiply(scale, worldPtPlane) + # [X,Y,Z]=zc*[x,y,1]*invR - invR*T + worldPtPlaneReproject = np.asmatrix(scale_worldPtPlane) - np.asmatrix(transPlaneToCam) # 3*1 dot 1*3 = 3*3 + pt = np.zeros((3, 1), dtype=np.float64) + pt[0][0] = worldPtPlaneReproject[0][0] + pt[1][0] = worldPtPlaneReproject[1][0] + pt[2][0] = 0 + world_pt.append(pt.T.tolist()) + return world_pt + + +def moving(): + # 计算机械臂当前位置与目标位置的x, y 轴距离 + c_x, c_y, cls_id, cls_conf = state.moving_box + cur_x, cur_y, cur_z = jetmax.position + + x, y, _ = camera_to_world(state.K, state.R, state.T, np.array([c_x, c_y]).reshape((1, 1, 2)))[0][0] + + # 计算当前位置与目标位置的欧氏距离,以控制运动速度 + t = math.sqrt(x * x + y * y + 120 * 120) / 120 + + # 计算气泵旋转舵机要旋转的角度 + # 机械臂吸取物品时的相对相对于初始位置时机械比正前方夹角加物品的旋转角度 + new_x, new_y = cur_x + x, cur_y + y + arm_angle = math.atan(new_x / new_y) * 180 / math.pi + + hiwonder.pwm_servo1.set_position(90 - arm_angle, 0.1) + jetmax.set_position((new_x, new_y, 70), t) + rospy.sleep(t + 0.4) + + sucker.set_state(True) + jetmax.set_position((new_x, new_y, 60), 1) # 下移机械臂,吸取物品 + rospy.sleep(1) + hiwonder.pwm_servo1.set_position(90, 0.1) + + # 获取码垛的位置 + x, y, z = state.last_target + y += 45 + state.last_target = x, y, z + + cur_x, cur_y, cur_z = jetmax.position # 当前的机械臂位置 + jetmax.set_position((cur_x, cur_y, 100), 0.8) + rospy.sleep(0.8) + + angle = math.atan(x / y) * 180 / math.pi + angle = 90 + (90 - angle) if angle > 0 else -angle + hiwonder.pwm_servo1.set_position(angle, t) + cur_x, cur_y, cur_z = jetmax.position + t = math.sqrt((cur_x - x) ** 2 + (cur_y - y) ** 2) / 150 + rospy.loginfo((x, y, z)) + jetmax.set_position((x, y, z + 30), t) + rospy.sleep(t) + + # 机械臂下移到目标码垛位置 + jetmax.set_position((x, y, z), 0.8) + rospy.sleep(0.8) + + sucker.release(3) + jetmax.set_position((x, y, z + 30), 0.8) # 上提机械臂 + rospy.sleep(0.1) + hiwonder.pwm_servo1.set_position(90, 0.5) # 恢复吸盘角度 + rospy.sleep(0.5) + + # 回到初始位置 + jetmax.go_home(t) + rospy.sleep(t + 0.5) + with state.lock: + state.moving_box = None + state.moving_count += 1 + state.index += 1 + if state.moving_count >= len(WORD_WANT): + state.moving_count = 0 + state.runner = None + print("FINISHED") + + +def image_proc(img_in): + result_image = cv2.cvtColor(img_in, cv2.COLOR_RGB2BGR) + + if state.runner is not None: + return result_image + + outputs = yolov5_chars.detect(np.copy(img_in)) + boxes, confs, classes = yolov5_chars.post_process(img_in, outputs, 0.65) + + cards = [] + width, height = IMAGE_SIZE + if state.index >= len(WORD_WANT): + state.index = 0 + state.last_target = TARGET_POSITION + + if WORD_WANT[state.index] == '\n': + state.index += 1 + x, y, z = state.last_target + y -= 50 + x = TARGET_POSITION[0] - 5 - 40 + state.last_target = x, y, z + + for box, cls_id, cls_conf in zip(boxes, classes, confs): + x1 = box[0] / TRT_INPUT_SIZE * width + y1 = box[1] / TRT_INPUT_SIZE * height + x2 = box[2] / TRT_INPUT_SIZE * width + y2 = box[3] / TRT_INPUT_SIZE * height + char = CHARACTER_LABELS[cls_id] + if char == WORD_WANT[state.index]: + cards.append((x1, y1, x2, y2, cls_id, cls_conf)) + cv2.putText(result_image, char + " " + str(float(cls_conf))[:4], (int(x1), int(y1) - 5), + cv2.FONT_HERSHEY_SIMPLEX, 0.7, COLORS[cls_id], 2) + cv2.rectangle(result_image, (int(x1), int(y1)), (int(x2), int(y2)), COLORS[cls_id], 3) + + if len(cards) == 0: + state.count = 0 + state.moving_box = None + rospy.logwarn("can not find card '{}'".format(WORD_WANT[state.index])) + else: + if state.moving_box is None: + moving_box = max(cards, key=lambda x: x[-1]) # 识别到的所有卡牌中概率最大的一个 + x1, y1, x2, y2, cls_id, cls_conf = moving_box + c_x, c_y = (x1 + x2) / 2, (y1 + y2) / 2 + state.moving_box = c_x, c_y, cls_id, cls_conf # 存起来 + result_image = cv2.circle(result_image, (int(c_x), int(c_y)), 1, (255, 0, 0), 30) + state.count = 0 + else: + l_c_x, l_c_y, l_cls_id, _ = state.moving_box + cards = [((x1 + x2) / 2, (y1 + y2) / 2, cls_id, cls_conf) for x1, y1, x2, y2, cls_id, cls_conf in + cards] # 计算中心坐标 + distances = [math.sqrt((l_c_x - c_x) ** 2 + (l_c_y - c_y) ** 2) for c_x, c_y, _, _ in cards] # 计算两次的中心坐标距离 + new_moving_box = min(zip(distances, cards), key=lambda x: x[0]) # 找到距离最小的 + _, (c_x, c_y, cls_id, cls_conf) = new_moving_box + result_image = cv2.circle(result_image, (int(l_c_x), int(l_c_y)), 1, (0, 255, 0), 30) + result_image = cv2.circle(result_image, (int(c_x), int(c_y)), 1, (255, 0, 0), 30) + if cls_id == l_cls_id: # 前后两次识别到的id相同,则进行搬运分类。若不同则重新识别 + state.moving_box = c_x, c_y, cls_id, cls_conf + state.count += 1 + if state.count > 5: + print("MOVE") + state.count = 0 + state.runner = threading.Thread(target=moving, daemon=True) + state.runner.start() + else: + state.moving_box = None + return result_image + + +def show_fps(img, fps): + """Draw fps number at top-left corner of the image.""" + font = cv2.FONT_HERSHEY_PLAIN + line = cv2.LINE_AA + fps_text = 'FPS: {:.2f}'.format(fps) + cv2.putText(img, fps_text, (11, 20), font, 1.0, (32, 32, 32), 4, line) + cv2.putText(img, fps_text, (10, 20), font, 1.0, (240, 240, 240), 1, line) + return img + + +def image_proc_b(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + result_img = image_proc(image) + # fps cal + fps_t1 = time.time() + fps_cur = (1.0 / (fps_t1 - state.fps_t0)) + state.fps = fps_cur if state.fps == 0.0 else (state.fps * 0.8 + fps_cur * 0.2) + state.fps_t0 = fps_t1 + # show_fps(result_img, state.fps) + cv2.cvtColor(result_img, cv2.COLOR_RGB2BGR) + cv2.imshow(ROS_NODE_NAME, result_img) + cv2.waitKey(1) + + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + state = Alphabetically() + image_queue = queue.Queue(maxsize=1) + state.load_camera_params() + if state.camera_params is None: + rospy.logerr("Can not load camera parameters!") + + jetmax = hiwonder.JetMax() + jetmax.go_home() + sucker = hiwonder.Sucker() + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) # 订阅摄像头画面 + while True: + try: + image_proc_b() + if rospy.is_shutdown(): + sys.exit(0) + except KeyboardInterrupt: + break diff --git a/src/jetmax_demos/scripts/apriltag_detect.py b/src/jetmax_demos/scripts/apriltag_detect.py new file mode 100755 index 0000000..c0411fb --- /dev/null +++ b/src/jetmax_demos/scripts/apriltag_detect.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import time +import rospy +import numpy as np +import threading +from sensor_msgs.msg import Image +from std_msgs.msg import Bool +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from std_srvs.srv import Empty +from jetmax_control.msg import SetServo +import hiwonder +import queue +import pupil_apriltags as apriltag +import yaml + + +""" +探测Apriltag +""" + +ROS_NODE_NAME = "apriltag_detector" +TAG_SIZE = 33.30 + + +class AprilTagDetect: + def __init__(self): + self.camera_params = None + self.K = None + self.R = None + self.T = None + + + def load_camera_params(self): + self.camera_params = rospy.get_param('/camera_cal/block_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + + +def image_proc_a(img): + frame_gray = cv2.cvtColor(np.copy(img), cv2.COLOR_RGB2GRAY) # 将画面转为灰度图 + params = [state.K[0][0], state.K[1][1], state.K[0][2], state.K[1][2]] # 相机内参 + tags = at_detector.detect(frame_gray, estimate_tag_pose=True, camera_params=params, tag_size=TAG_SIZE) # 进行AprilTag的检测 + if not tags: + hiwonder.buzzer.off() + for tag in tags: + corners = tag.corners.reshape(1, -1, 2).astype(int) # 检测到的AprilTag的四个角的点 + center = tag.center.astype(int) # AprilTag中心点 + + cv2.drawContours(img, corners, -1, (255, 0, 0), 3) # 画出外框 + cv2.circle(img, tuple(center), 5, (255, 255, 0), 10) # 画出中心点 + print("tag id: {}, center: x:{} y:{}".format(tag.tag_id, center[0], center[1])) + + + img_h, img_w = img.shape[:2] + cv2.line(img, (int(img_w / 2 - 10), int(img_h / 2)), (int(img_w / 2 + 10), int(img_h / 2)), (0, 255, 255), 2) + cv2.line(img, (int(img_w / 2), int(img_h / 2 - 10)), (int(img_w / 2), int(img_h / 2 + 10)), (0, 255, 255), 2) + return img + + +def image_proc_b(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = image.copy() + frame_result = image_proc_a(frame_result) + bgr_image = cv2.cvtColor(frame_result, cv2.COLOR_RGB2BGR) + cv2.imshow('result', bgr_image) + cv2.waitKey(1) + + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +if __name__ == '__main__': + state = AprilTagDetect() + jetmax = hiwonder.JetMax() + sucker = hiwonder.Sucker() + at_detector = apriltag.Detector() + image_queue = queue.Queue(maxsize=1) + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + jetmax.go_home() + state.load_camera_params() + if state.camera_params is None: + rospy.logerr('Can not load camera parameters') + sys.exit(-1) + rospy.ServiceProxy('/jetmax/go_home', Empty)() + rospy.Publisher('/jetmax/end_effector/sucker/command', Bool, queue_size=1).publish(data=False) + rospy.Publisher('/jetmax/end_effector/servo1/command', SetServo, queue_size=1).publish(data=90, duration=0.5) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) + while not rospy.is_shutdown(): + image_proc_b() diff --git a/src/jetmax_demos/scripts/apriltag_pose.py b/src/jetmax_demos/scripts/apriltag_pose.py new file mode 100755 index 0000000..e26816f --- /dev/null +++ b/src/jetmax_demos/scripts/apriltag_pose.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import time +import rospy +import numpy as np +import threading +from sensor_msgs.msg import Image +from std_msgs.msg import Bool +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from std_srvs.srv import Empty +from jetmax_control.msg import SetServo +import hiwonder +import queue +import pupil_apriltags as apriltag +import yaml + + +""" +Apriltag识别实验 +""" + +ROS_NODE_NAME = "apriltag_detector" +TAG_SIZE = 33.30 + + +class AprilTagDetect: + def __init__(self): + self.camera_params = None + self.K = None + self.R = None + self.T = None + + def load_camera_params(self): + self.camera_params = rospy.get_param('/camera_cal/block_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + + +def RotateByZ(Cx, Cy, thetaZ): + rz = thetaZ*math.pi/180.0 + outX = math.cos(rz)*Cx - math.sin(rz)*Cy + outY = math.sin(rz)*Cx + math.cos(rz)*Cy + return outX, outY + +def RotateByY(Cx, Cz, thetaY): + ry = thetaY*math.pi/180.0 + outZ = math.cos(ry)*Cz - math.sin(ry)*Cx + outX = math.sin(ry)*Cz + math.cos(ry)*Cx + return outX, outZ + +def RotateByX(Cy, Cz, thetaX): + rx = thetaX*math.pi/180.0 + outY = math.cos(rx)*Cy - math.sin(rx)*Cz + outZ = math.sin(rx)*Cy + math.cos(rx)*Cz + return outY, outZ + + +def image_proc_a(img): + frame_gray = cv2.cvtColor(np.copy(img), cv2.COLOR_RGB2GRAY) # 将画面转为灰度图 + params = [state.K[0][0], state.K[1][1], state.K[0][2], state.K[1][2]] # 相机内参 + tags = at_detector.detect(frame_gray, estimate_tag_pose=True, camera_params=params, tag_size=TAG_SIZE) # 进行AprilTag的检测 + for tag in tags: + corners = tag.corners.reshape(1, -1, 2).astype(int) # 检测到的AprilTag的四个角的点 + center = tag.center.astype(int) # AprilTag中心点 + + cv2.drawContours(img, corners, -1, (255, 0, 0), 3) # 画出外框 + cv2.circle(img, tuple(center), 5, (255, 255, 0), 10) # 画出中心点 + + rotM = tag.pose_R #旋转矩阵 + tvec = tag.pose_t #平移矩阵 + + # 旋转矩阵转欧拉角 + thetaZ = math.atan2(rotM[1, 0], rotM[0, 0])*180.0/math.pi + thetaY = math.atan2(-1.0*rotM[2, 0], math.sqrt(rotM[2, 1]**2 + rotM[2, 2]**2))*180.0/math.pi + thetaX = math.atan2(rotM[2, 1], rotM[2, 2])*180.0/math.pi + # camera coordinates + x = tvec[0] + y = tvec[1] + z = tvec[2] + (x, y) = RotateByZ(x, y, -1.0*thetaZ) + (x, z) = RotateByY(x, z, -1.0*thetaY) + (y, z) = RotateByX(y, z, -1.0*thetaX) + Cx = x*-1 + Cy = y*-1 + Cz = z*-1 + print("camera position:",Cx, Cy, Cz) + print("camera rotation:", thetaX, thetaY, thetaZ) + + + img_h, img_w = img.shape[:2] + cv2.line(img, (int(img_w / 2 - 10), int(img_h / 2)), (int(img_w / 2 + 10), int(img_h / 2)), (0, 255, 255), 2) + cv2.line(img, (int(img_w / 2), int(img_h / 2 - 10)), (int(img_w / 2), int(img_h / 2 + 10)), (0, 255, 255), 2) + return img + + +def image_proc_b(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = image.copy() + frame_result = image_proc_a(frame_result) + bgr_image = cv2.cvtColor(frame_result, cv2.COLOR_RGB2BGR) + cv2.imshow('result', bgr_image) + cv2.waitKey(1) + + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +if __name__ == '__main__': + state = AprilTagDetect() + jetmax = hiwonder.JetMax() + sucker = hiwonder.Sucker() + at_detector = apriltag.Detector() + image_queue = queue.Queue(maxsize=1) + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + jetmax.go_home() + state.load_camera_params() + if state.camera_params is None: + rospy.logerr('Can not load camera parameters') + sys.exit(-1) + rospy.ServiceProxy('/jetmax/go_home', Empty)() + rospy.Publisher('/jetmax/end_effector/sucker/command', Bool, queue_size=1).publish(data=False) + rospy.Publisher('/jetmax/end_effector/servo1/command', SetServo, queue_size=1).publish(data=90, duration=0.5) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) + while not rospy.is_shutdown(): + image_proc_b() diff --git a/src/jetmax_demos/scripts/face_expression.py b/src/jetmax_demos/scripts/face_expression.py new file mode 100755 index 0000000..60b0fb6 --- /dev/null +++ b/src/jetmax_demos/scripts/face_expression.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 +import sys +import math +import rospy +import time +import queue +import threading +import cv2 +import numpy as np +import hiwonder +from sensor_msgs.msg import Image as RosImage + +import simple_draw +from PIL import Image +import torch +from facenet_pytorch import MTCNN + +device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') +print(device) + +from FER import fer + +mtcnn = MTCNN(keep_all=True, min_face_size=50, factor=0.709, post_process=False, device=device) + +ROS_NODE_NAME = 'face_expression' +jetmax = hiwonder.JetMax() +image_queue = queue.Queue(maxsize=1) + + +class FaceExpression: + def __init__(self): + self.lock = threading.RLock() + self.servo_x = 500 + self.face_tracking = None + self.no_face_count = 0 + self.lost_target_count = 0 + self.is_running_face = False + self.fps = 0.0 + self.tic = time.time() + self.exp = '' + self.count = 0 + + +def show_faces(img, boxes, landmarks, color): + new_boxes = [] + new_landmarks = [] + for bb, ll in zip(boxes, landmarks): + x1 = int(hiwonder.misc.val_map(bb[0], 0, 160, 0, 640)) + y1 = int(hiwonder.misc.val_map(bb[1], 0, 160, 0, 480)) + x2 = int(hiwonder.misc.val_map(bb[2], 0, 160, 0, 640)) + y2 = int(hiwonder.misc.val_map(bb[3], 0, 160, 0, 480)) + cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) + new_boxes.append([x1, y1, x2, y2]) + landmarks_curr_face = [] + if len(landmarks): + for j in range(5): + lx = int(hiwonder.misc.val_map(ll[j][0], 0, 160, 0, 640)) + ly = int(hiwonder.misc.val_map(ll[j][1], 0, 160, 0, 480)) + cv2.circle(img, (lx, ly), 2, color, 2) + landmarks_curr_face.append([lx, ly]) + new_landmarks.append(landmarks_curr_face) + return img, new_boxes, new_landmarks + + + +def image_proc_a(image): + img_ret = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) + org_img1 = np.copy(image) + image = cv2.resize(image, (160, 160)) + boxes, _, landmarks = mtcnn.detect(Image.fromarray(image), landmarks=True) + if boxes is None: + return img_ret + boxes = list(boxes) + landmarks = list(landmarks) + + img_ret, boxes, landmarks = show_faces(img_ret, boxes, landmarks, (0, 255, 0)) + box = None + if state.face_tracking is None: + if len(boxes) > 0: + box = min(boxes, key=lambda b: math.sqrt(((b[2] + b[0]) / 2 - 320) ** 2 + ((b[3] + b[1]) / 2 - 240) ** 2)) + x1, y1, x2, y2 = box + center_x, center_y = int((x1 + x2) / 2), int((y1 + y2) / 2) + cv2.rectangle(img_ret, (x1, y1), (x2, y2), (255, 0, 0), 3) + cv2.circle(img_ret, (center_x, center_y), 2, (0, 255, 0), 4) + state.face_tracking = center_x, center_y + state.no_face_count = time.time() + 2 + else: + centers = [(int((box[2] + box[0]) / 2), int((box[3] + box[1]) / 2), box) for box in boxes] + get_face = False + if len(centers) > 0: + center_x, center_y = state.face_tracking + cv2.circle(img_ret, (center_x, center_y), 2, (255, 0, 0), 4) + min_dist_center = min(centers, key=lambda c: math.sqrt((c[0] - center_x) ** 2 + (c[1] - center_y) ** 2)) + new_center_x, new_center_y, box = min_dist_center + x1, y1, x2, y2 = box + dist = math.sqrt((new_center_x - center_x) ** 2 + (new_center_y - center_y) ** 2) + if dist < 250: + cv2.rectangle(img_ret, (x1, y1), (x2, y2), (0, 0, 255), 3) + cv2.circle(img_ret, (new_center_x, new_center_y), 2, (0, 0, 255), 4) + get_face = True + state.face_tracking = int(new_center_x), int(new_center_y) + state.no_face_count = time.time() + 0.2 + + if state.no_face_count < time.time(): + state.face_tracking = None + get_face = False + if get_face: + x1, y1, x2, y2 = box + x1 = 0 if x1 < 0 else 639 if x1 > 639 else x1 + x2 = 0 if x2 < 0 else 639 if x2 > 639 else x2 + y1 = 0 if y1 < 0 else 479 if y1 > 479 else y1 + y2 = 0 if y2 < 0 else 479 if y2 > 479 else y2 + + print(x1, y1, x2, y2, end= ' ') + face = org_img1[y1: y2, x1: x2] + cv2.imshow("face", cv2.cvtColor(face, cv2.COLOR_RGB2BGR)) + a = fer.fer(face) + print(a) + cv2.putText(img_ret, a, (0, 200), 0, 1.6, (255, 50, 50), 5) + return img_ret + +def image_proc_b(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + image = image_proc_a(image) + toc = time.time() + curr_fps = 1.0 / (state.tic - toc) + state.fps = curr_fps if state.fps == 0.0 else (state.fps * 0.95 + curr_fps * 0.05) + state.tic = toc + cv2.imshow(ROS_NODE_NAME, image) + cv2.waitKey(1) + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + state = FaceExpression() + jetmax.go_home(1) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', RosImage, image_callback) + try: + while not rospy.is_shutdown(): + image_proc_b() + except Exception as e: + rospy.logerr(e) + print(e.__traceback__.tb_lineno) + sys.exit() diff --git a/src/jetmax_demos/scripts/face_expression_draw.py b/src/jetmax_demos/scripts/face_expression_draw.py new file mode 100755 index 0000000..3fc322d --- /dev/null +++ b/src/jetmax_demos/scripts/face_expression_draw.py @@ -0,0 +1,180 @@ +#!/usr/bin/env python3 +import sys +import math +import rospy +import time +import queue +import threading +import cv2 +import numpy as np +import hiwonder +from sensor_msgs.msg import Image as RosImage + +import simple_draw +from PIL import Image +import torch +from facenet_pytorch import MTCNN + +device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') +print(device) + +from FER import fer + +mtcnn = MTCNN(keep_all=True, min_face_size=50, factor=0.709, post_process=False, device=device) + +ROS_NODE_NAME = 'face_expression' +jetmax = hiwonder.JetMax() +image_queue = queue.Queue(maxsize=1) + + +class FaceExpression: + def __init__(self): + self.lock = threading.RLock() + self.servo_x = 500 + self.face_tracking = None + self.no_face_count = 0 + self.lost_target_count = 0 + self.is_running_face = False + self.fps = 0.0 + self.tic = time.time() + self.runner = None + self.exp = '' + self.count = 0 + + +def show_faces(img, boxes, landmarks, color): + new_boxes = [] + new_landmarks = [] + for bb, ll in zip(boxes, landmarks): + x1 = int(hiwonder.misc.val_map(bb[0], 0, 160, 0, 640)) + y1 = int(hiwonder.misc.val_map(bb[1], 0, 160, 0, 480)) + x2 = int(hiwonder.misc.val_map(bb[2], 0, 160, 0, 640)) + y2 = int(hiwonder.misc.val_map(bb[3], 0, 160, 0, 480)) + cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) + new_boxes.append([x1, y1, x2, y2]) + landmarks_curr_face = [] + if len(landmarks): + for j in range(5): + lx = int(hiwonder.misc.val_map(ll[j][0], 0, 160, 0, 640)) + ly = int(hiwonder.misc.val_map(ll[j][1], 0, 160, 0, 480)) + cv2.circle(img, (lx, ly), 2, color, 2) + landmarks_curr_face.append([lx, ly]) + new_landmarks.append(landmarks_curr_face) + return img, new_boxes, new_landmarks + + +def draw_exp(name): + ngcs = { + 'Angry': 'gcode/angry.ngc', + 'Happy': 'gcode/happy.ngc', + 'Neutral': 'gcode/neutral.ngc', + 'Surprise': 'gcode/surprise.ngc', + } + try: + if name in ngcs: + simple_draw.draw_ngc(ngcs[name]) + jetmax.go_home(1) + rospy.sleep(1.2) + finally: + state.runner = None + + +def image_proc_a(image): + img_ret = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) + if state.runner is not None: + return img_ret + org_img1 = np.copy(image) + image = cv2.resize(image, (160, 160)) + boxes, _, landmarks = mtcnn.detect(Image.fromarray(image), landmarks=True) + if boxes is None: + return img_ret + boxes = list(boxes) + landmarks = list(landmarks) + + img_ret, boxes, landmarks = show_faces(img_ret, boxes, landmarks, (0, 255, 0)) + box = None + if state.face_tracking is None: + if len(boxes) > 0: + box = min(boxes, key=lambda b: math.sqrt(((b[2] + b[0]) / 2 - 320) ** 2 + ((b[3] + b[1]) / 2 - 240) ** 2)) + x1, y1, x2, y2 = box + center_x, center_y = int((x1 + x2) / 2), int((y1 + y2) / 2) + cv2.rectangle(img_ret, (x1, y1), (x2, y2), (255, 0, 0), 3) + cv2.circle(img_ret, (center_x, center_y), 2, (0, 255, 0), 4) + state.face_tracking = center_x, center_y + state.no_face_count = time.time() + 2 + else: + centers = [(int((box[2] + box[0]) / 2), int((box[3] + box[1]) / 2), box) for box in boxes] + get_face = False + if len(centers) > 0: + center_x, center_y = state.face_tracking + cv2.circle(img_ret, (center_x, center_y), 2, (255, 0, 0), 4) + min_dist_center = min(centers, key=lambda c: math.sqrt((c[0] - center_x) ** 2 + (c[1] - center_y) ** 2)) + new_center_x, new_center_y, box = min_dist_center + x1, y1, x2, y2 = box + dist = math.sqrt((new_center_x - center_x) ** 2 + (new_center_y - center_y) ** 2) + if dist < 250: + cv2.rectangle(img_ret, (x1, y1), (x2, y2), (0, 0, 255), 3) + cv2.circle(img_ret, (new_center_x, new_center_y), 2, (0, 0, 255), 4) + get_face = True + state.face_tracking = int(new_center_x), int(new_center_y) + state.no_face_count = time.time() + 0.2 + + if state.no_face_count < time.time(): + state.face_tracking = None + get_face = False + if get_face: + x1, y1, x2, y2 = box + x1 = 0 if x1 < 0 else 639 if x1 > 639 else x1 + x2 = 0 if x2 < 0 else 639 if x2 > 639 else x2 + y1 = 0 if y1 < 0 else 479 if y1 > 479 else y1 + y2 = 0 if y2 < 0 else 479 if y2 > 479 else y2 + + face = org_img1[y1: y2, x1: x2] + cv2.imshow('face', cv2.cvtColor(face, cv2.COLOR_RGB2BGR)) + a = fer.fer(face) + cv2.putText(img_ret, a, (0, 200), 0, 1.6, (255, 50, 50), 5) + if state.exp == a: + state.count += 1 + else: + state.count = 0 + state.exp = a + + if state.count > 7: + state.count = 0 + state.runner = threading.Thread(target=draw_exp, args=(a,)) + state.runner.start() + else: + state.count = 0 + return img_ret + +def image_proc_b(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + image = image_proc_a(image) + toc = time.time() + curr_fps = 1.0 / (state.tic - toc) + state.fps = curr_fps if state.fps == 0.0 else (state.fps * 0.95 + curr_fps * 0.05) + state.tic = toc + cv2.imshow(ROS_NODE_NAME, image) + cv2.waitKey(1) + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + state = FaceExpression() + jetmax.go_home(1) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', RosImage, image_callback) + try: + while not rospy.is_shutdown(): + image_proc_b() + except Exception as e: + rospy.logerr(e) + print(e.__traceback__.tb_lineno) + sys.exit() diff --git a/src/jetmax_demos/scripts/face_mask_main.py b/src/jetmax_demos/scripts/face_mask_main.py new file mode 100755 index 0000000..9726416 --- /dev/null +++ b/src/jetmax_demos/scripts/face_mask_main.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 +import os +import sys +import cv2 +import math +import time +import queue +import random +import threading +import numpy as np +import rospy +from sensor_msgs.msg import Image +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +import hiwonder +from hiwonder import serial_servo as ss +from yolov5_tensorrt import Yolov5TensorRT +import tm1640 + +ROS_NODE_NAME = "face_mask" + +DEFAULT_X, DEFAULT_Y, DEFAULT_Z = hiwonder.JetMax.ORIGIN +FACEMASK_ENGINE_PATH = os.path.join(sys.path[0], 'models/facemask_v5_160.trt') +CLASSNUM = 2 +TRT_INPUT_SIZE = 160 +FACEMASK_LABELS = ("nomask", "mask") +COLORS = ((255, 0, 0), (0, 0, 255)) +IMAGE_SIZE = 640, 480 + + +def draw_cross(): + tm1640.display_buf = [0] * 16 + for i in range(0, 8): + tm1640.set_bit(i, i, 1) + tm1640.set_bit(i, 7 - i, 1) + + for i in range(8, 16): + tm1640.set_bit(i, i - 8, 1) + tm1640.set_bit(i, 7 - (i - 8), 1) + tm1640.update_display() + + +def draw_smail(): + tm1640.display_buf = [0] * 16 + tm1640.set_bit(5, 1, 1) + tm1640.set_bit(5, 2, 1) + tm1640.set_bit(6, 1, 1) + tm1640.set_bit(6, 2, 1) + tm1640.set_bit(10, 1, 1) + tm1640.set_bit(10, 2, 1) + tm1640.set_bit(9, 1, 1) + tm1640.set_bit(9, 2, 1) + + for i in range(5, 11): + tm1640.set_bit(i, 7, 1) + + tm1640.set_bit(11, 6, 1) + tm1640.set_bit(12, 5, 1) + + tm1640.set_bit(3, 5, 1) + tm1640.set_bit(4, 6, 1) + tm1640.update_display() + + +def clear_disp(): + tm1640.display_buf = [0] * 16 + tm1640.update_display() + + +def moving(): + hiwonder.motor2.set_speed(0) + jetmax.set_position((-DEFAULT_Y, DEFAULT_X, DEFAULT_Z), 1.5) + rospy.sleep(1.5) + hiwonder.motor1.set_speed(100) + jetmax.set_position((-DEFAULT_Y, DEFAULT_X, 60), 0.8) + rospy.sleep(1.2) + jetmax.set_position((-DEFAULT_Y, DEFAULT_X, DEFAULT_Z), 1) + rospy.sleep(1) + jetmax.set_position((DEFAULT_X, DEFAULT_Y, DEFAULT_Z), 1.5) + rospy.sleep(1.5) + rospy.sleep(4) + + clear_disp() + draw_smail() + jetmax.set_position((DEFAULT_X, DEFAULT_Y, DEFAULT_Z - 50), 300) + rospy.sleep(0.3) + jetmax.set_position((DEFAULT_X, DEFAULT_Y, DEFAULT_Z), 300) + rospy.sleep(0.3) + jetmax.set_position((DEFAULT_X, DEFAULT_Y, DEFAULT_Z - 50), 300) + rospy.sleep(0.3) + jetmax.set_position((DEFAULT_X, DEFAULT_Y, DEFAULT_Z), 300) + + +def image_proc_a(img_in): + global runner, count + outputs = yolov5_chars.detect(img_in) + boxes, confs, classes = yolov5_chars.post_process(img_in, outputs, 0.6, 0.2) + facex = [] + width, height = IMAGE_SIZE + result_image = img_in + no_mask = False + mask = False + for box, cls_id, cls_conf in zip(boxes, classes, confs): + x1 = box[0] / TRT_INPUT_SIZE * width + y1 = box[1] / TRT_INPUT_SIZE * height + x2 = box[2] / TRT_INPUT_SIZE * width + y2 = box[3] / TRT_INPUT_SIZE * height + + ''' + if x2 - x1 > y2 - y1: + x1 = int(((x1 + x2) / 2) - ((y2 - y1) / 2)) + x2 = x1 + (y2 - y1) + ''' + + facex.append((x1, y1, x2, y2, cls_id, cls_conf)) + result_image = cv2.putText(img_in, FACEMASK_LABELS[cls_id] + " " + str(float(cls_conf))[:4], + (int(x1), int(y1) - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, COLORS[cls_id], 2) + result_image = cv2.rectangle(result_image, (int(x1), int(y1)), (int(x2), int(y2)), COLORS[cls_id], 3) + rospy.loginfo((cls_id, float(cls_conf), x1, x2, y1, y2)) + if x2 - x1 > 100 and abs(((x2 + x1) / 2) - 320) < 100: + if cls_id == 0: + no_mask = True + elif cls_id == 1: + mask = True + + if runner is None or not runner.isAlive(): + if no_mask: + count += 1 + # if count > 10: + draw_cross() + # r#unner = threading.Thread(target=moving, daemon=True) + # runner.start() + else: + count = 0 + if mask: + draw_smail() + else: + clear_disp() + + return result_image + + +def show_fps(img, fps): + return img + """Draw fps number at top-left corner of the image.""" + font = cv2.FONT_HERSHEY_PLAIN + line = cv2.LINE_AA + fps_text = 'FPS: {:.2f}'.format(fps) + cv2.putText(img, fps_text, (11, 20), font, 1.0, (32, 32, 32), 4, line) + cv2.putText(img, fps_text, (10, 20), font, 1.0, (240, 240, 240), 1, line) + return img + + +def image_proc(): + global fps, fps_t0 + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + + result_img = image_proc_a(image) + # fps cal + fps_t1 = time.time() + fps_cur = (1.0 / (fps_t1 - fps_t0)) + fps = fps_cur if fps == 0.0 else (fps * 0.8 + fps_cur * 0.2) + fps_t0 = fps_t1 + show_fps(result_img, fps) + # + # rgb_image = result_img.tostring() + result_img = cv2.cvtColor(result_img, cv2.COLOR_RGB2BGR) + result_img = cv2.resize(result_img, (1024, 768)) + cv2.imshow(ROS_NODE_NAME, result_img) + cv2.waitKey(1) + # ros_image.data = rgb_image + # image_pub.publish(ros_image) + + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + yolov5_chars = Yolov5TensorRT(FACEMASK_ENGINE_PATH, TRT_INPUT_SIZE, CLASSNUM) + image_queue = queue.Queue(maxsize=2) + jetmax = hiwonder.JetMax() + jetmax.set_position((DEFAULT_X, DEFAULT_Y, DEFAULT_Z), 1) + runner = None + count = 0 + fps = 0 + fps_t0 = 0 + rospy.sleep(1) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) # 订阅摄像头画面 + # image_pub = rospy.Publisher('/%s/image_result' % ROS_NODE_NAME, Image, queue_size=1) # register result image pub + + while True: + try: + image_proc() + if rospy.is_shutdown(): + break + except KeyboardInterrupt: + break diff --git a/src/jetmax_demos/scripts/gcode/1.ngc b/src/jetmax_demos/scripts/gcode/1.ngc new file mode 100644 index 0000000..80137d6 --- /dev/null +++ b/src/jetmax_demos/scripts/gcode/1.ngc @@ -0,0 +1,38 @@ +(Generated with: DXF2GCODE, Version: Py3.7.10 PyQt5.10.1, Date: $Date: Fri Oct 25 20:45:56 2019 +0200 $) +(Created from file: /home/lucas/1.dxf) +(Output format description: G-CODE for LinuxCNC) +(Time: Wed Jul 14 19:51:40 2021) +G21 (Units in millimeters) +G90 (Absolute programming) +G64 (Default cutting) G17 (XY plane) G40 (Cancel radius comp.) G49 (Cancel length comp.) +G0 Z 100.000 + +(*** LAYER: 0 ***) +T1 M6 +S6000 + +(* SHAPE Nr: 0 *) +G0 X 0.387 Y 99.938 +M3 M8 +G0 Z 30.000 +F150 +G1 Z 30.000 +F400 +G1 X 0.387 Y 99.938 +G1 X 0.470 Y 99.912 +G1 X 0.551 Y 99.878 +G1 X 0.629 Y 99.838 +G1 X 0.703 Y 99.792 +G1 X 0.773 Y 99.738 +G1 X 0.838 Y 99.680 +G1 X 0.897 Y 99.615 +G1 X 0.950 Y 99.546 +G1 X 0.997 Y 99.472 +G1 X 1.038 Y 99.394 +G1 X 1.000 Y -1.029 +F100 +G1 Z 50.000 +G0 Z 100.000 +M9 M5 +G0 X 0.000 Y 0.000 +M2 (Program end) diff --git a/src/jetmax_demos/scripts/gcode/2.ngc b/src/jetmax_demos/scripts/gcode/2.ngc new file mode 100644 index 0000000..8589585 --- /dev/null +++ b/src/jetmax_demos/scripts/gcode/2.ngc @@ -0,0 +1,90 @@ +(Generated with: DXF2GCODE, Version: Py3.7.10 PyQt5.10.1, Date: $Date: Fri Oct 25 20:45:56 2019 +0200 $) +(Created from file: /home/lucas/2.dxf) +(Output format description: G-CODE for LinuxCNC) +(Time: Wed Jul 14 17:42:28 2021) +G21 (Units in millimeters) +G90 (Absolute programming) +G64 (Default cutting) G17 (XY plane) G40 (Cancel radius comp.) G49 (Cancel length comp.) +G0 Z 100.000 + +(*** LAYER: 0 ***) +T1 M6 +S6000 + +(* SHAPE Nr: 0 *) +G0 X -28.221 Y 81.245 +M3 M8 +G0 Z 30.000 +F150 +G1 Z 30.000 +F400 +G1 X -28.221 Y 86.007 +G1 X -28.218 Y 86.084 +G1 X -28.209 Y 86.161 +G1 X -28.195 Y 86.236 +G1 X -28.174 Y 86.311 +G1 X -28.148 Y 86.383 +G1 X -28.116 Y 86.454 +G1 X -23.354 Y 95.978 +G1 X -23.315 Y 96.048 +G1 X -23.271 Y 96.115 +G1 X -23.221 Y 96.178 +G1 X -23.166 Y 96.238 +G1 X -18.405 Y 100.999 +G1 X -18.346 Y 101.054 +G1 X -18.282 Y 101.104 +G1 X -18.215 Y 101.148 +G1 X -18.145 Y 101.187 +G1 X -8.621 Y 105.949 +G1 X -8.550 Y 105.981 +G1 X -8.478 Y 106.007 +G1 X -8.403 Y 106.027 +G1 X -8.328 Y 106.042 +G1 X -8.251 Y 106.051 +G1 X -8.174 Y 106.054 +G1 X 10.874 Y 106.054 +G1 X 10.951 Y 106.051 +G1 X 11.028 Y 106.042 +G1 X 11.104 Y 106.027 +G1 X 11.178 Y 106.007 +G1 X 11.251 Y 105.981 +G1 X 11.321 Y 105.949 +G1 X 20.845 Y 101.187 +G1 X 20.915 Y 101.148 +G1 X 20.983 Y 101.104 +G1 X 21.046 Y 101.054 +G1 X 21.105 Y 100.999 +G1 X 25.867 Y 96.238 +G1 X 25.921 Y 96.178 +G1 X 25.971 Y 96.115 +G1 X 26.015 Y 96.048 +G1 X 26.054 Y 95.978 +G1 X 30.816 Y 86.454 +G1 X 30.848 Y 86.383 +G1 X 30.874 Y 86.311 +G1 X 30.895 Y 86.236 +G1 X 30.910 Y 86.161 +G1 X 30.919 Y 86.084 +G1 X 30.922 Y 86.007 +G1 X 30.922 Y 76.483 +G1 X 30.919 Y 76.406 +G1 X 30.910 Y 76.329 +G1 X 30.895 Y 76.253 +G1 X 30.874 Y 76.179 +G1 X 30.848 Y 76.106 +G1 X 30.816 Y 76.036 +G1 X 26.054 Y 66.512 +G1 X 26.025 Y 66.457 +G1 X 25.992 Y 66.404 +G1 X 16.468 Y 52.119 +G1 X 16.430 Y 52.065 +G1 X 16.388 Y 52.014 +G1 X 16.343 Y 51.966 +G1 X -29.569 Y 6.054 +G1 X 34.683 Y 6.054 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 +G0 X 0.000 Y 0.000 +M2 (Program end) \ No newline at end of file diff --git a/src/jetmax_demos/scripts/gcode/3.ngc b/src/jetmax_demos/scripts/gcode/3.ngc new file mode 100644 index 0000000..cf04294 --- /dev/null +++ b/src/jetmax_demos/scripts/gcode/3.ngc @@ -0,0 +1,371 @@ +(Generated with: DXF2GCODE, Version: Py3.7.10 PyQt5.10.1, Date: $Date: Fri Oct 25 20:45:56 2019 +0200 $) +(Created from file: /home/lucas/3.dxf) +(Output format description: G-CODE for LinuxCNC) +(Time: Thu Jul 15 10:50:26 2021) +G21 (Units in millimeters) +G90 (Absolute programming) +G64 (Default cutting) G17 (XY plane) G40 (Cancel radius comp.) G49 (Cancel length comp.) +G0 Z 100.000 + +(*** LAYER: 0 ***) +T1 M6 +S6000 + +(* SHAPE Nr: 0 *) +G0 X -19.610 Y 104.420 +M3 M8 +G0 Z 30.000 +F150 +G1 Z 30.000 +F600 +G1 X 2.612 Y 104.420 +G1 X 3.041 Y 104.416 +G1 X 3.470 Y 104.404 +G1 X 3.899 Y 104.384 +G1 X 4.327 Y 104.357 +G1 X 4.755 Y 104.321 +G1 X 5.182 Y 104.277 +G1 X 5.608 Y 104.226 +G1 X 6.033 Y 104.167 +G1 X 6.457 Y 104.100 +G1 X 6.879 Y 104.025 +G1 X 7.300 Y 103.942 +G1 X 7.720 Y 103.851 +G1 X 8.137 Y 103.753 +G1 X 8.553 Y 103.647 +G1 X 8.967 Y 103.534 +G1 X 9.379 Y 103.412 +G1 X 9.788 Y 103.283 +G1 X 10.195 Y 103.147 +G1 X 10.599 Y 103.003 +G1 X 11.001 Y 102.852 +G1 X 11.400 Y 102.693 +G1 X 11.795 Y 102.527 +G1 X 12.188 Y 102.354 +G1 X 12.577 Y 102.173 +G1 X 12.963 Y 101.986 +G1 X 13.345 Y 101.791 +G1 X 13.724 Y 101.589 +G1 X 14.099 Y 101.380 +G1 X 14.470 Y 101.164 +G1 X 14.837 Y 100.942 +G1 X 15.200 Y 100.713 +G1 X 15.558 Y 100.477 +G1 X 15.912 Y 100.234 +G1 X 16.262 Y 99.985 +G1 X 16.607 Y 99.730 +G1 X 16.947 Y 99.468 +G1 X 17.282 Y 99.200 +G1 X 17.612 Y 98.926 +G1 X 17.937 Y 98.645 +G1 X 18.257 Y 98.359 +G1 X 18.571 Y 98.067 +G1 X 18.880 Y 97.769 +G1 X 19.184 Y 97.466 +G1 X 19.481 Y 97.157 +G1 X 19.774 Y 96.843 +G1 X 20.060 Y 96.523 +G1 X 20.340 Y 96.198 +G1 X 20.614 Y 95.868 +G1 X 20.882 Y 95.532 +G1 X 21.144 Y 95.192 +G1 X 21.399 Y 94.848 +G1 X 21.648 Y 94.498 +G1 X 21.891 Y 94.144 +G1 X 22.127 Y 93.786 +G1 X 22.356 Y 93.423 +G1 X 22.579 Y 93.056 +G1 X 22.794 Y 92.685 +G1 X 23.003 Y 92.310 +G1 X 23.205 Y 91.931 +G1 X 23.400 Y 91.549 +G1 X 23.588 Y 91.163 +G1 X 23.768 Y 90.774 +G1 X 23.941 Y 90.381 +G1 X 24.107 Y 89.985 +G1 X 24.266 Y 89.587 +G1 X 24.417 Y 89.185 +G1 X 24.561 Y 88.781 +G1 X 24.698 Y 88.374 +G1 X 24.827 Y 87.965 +G1 X 24.948 Y 87.553 +G1 X 25.061 Y 87.139 +G1 X 25.167 Y 86.723 +G1 X 25.266 Y 86.305 +G1 X 25.356 Y 85.886 +G1 X 25.439 Y 85.465 +G1 X 25.514 Y 85.042 +G1 X 25.581 Y 84.619 +G1 X 25.640 Y 84.193 +G1 X 25.692 Y 83.767 +G1 X 25.735 Y 83.341 +G1 X 25.771 Y 82.913 +G1 X 25.799 Y 82.485 +G1 X 25.818 Y 82.056 +G1 X 25.830 Y 81.627 +G1 X 25.834 Y 81.198 +G1 X 25.830 Y 80.769 +G1 X 25.818 Y 80.340 +G1 X 25.799 Y 79.911 +G1 X 25.771 Y 79.483 +G1 X 25.735 Y 79.055 +G1 X 25.692 Y 78.628 +G1 X 25.640 Y 78.202 +G1 X 25.581 Y 77.777 +G1 X 25.514 Y 77.353 +G1 X 25.439 Y 76.931 +G1 X 25.356 Y 76.510 +G1 X 25.266 Y 76.090 +G1 X 25.167 Y 75.672 +G1 X 25.061 Y 75.257 +G1 X 24.948 Y 74.843 +G1 X 24.827 Y 74.431 +G1 X 24.698 Y 74.022 +G1 X 24.561 Y 73.615 +G1 X 24.417 Y 73.211 +G1 X 24.266 Y 72.809 +G1 X 24.107 Y 72.410 +G1 X 23.941 Y 72.015 +G1 X 23.768 Y 71.622 +G1 X 23.588 Y 71.233 +G1 X 23.400 Y 70.847 +G1 X 23.205 Y 70.464 +G1 X 23.003 Y 70.086 +G1 X 22.794 Y 69.711 +G1 X 22.579 Y 69.340 +G1 X 22.356 Y 68.973 +G1 X 22.127 Y 68.610 +G1 X 21.891 Y 68.252 +G1 X 21.648 Y 67.898 +G1 X 21.399 Y 67.548 +G1 X 21.144 Y 67.203 +G1 X 20.882 Y 66.863 +G1 X 20.614 Y 66.528 +G1 X 20.340 Y 66.198 +G1 X 20.060 Y 65.873 +G1 X 19.774 Y 65.553 +G1 X 19.481 Y 65.239 +G1 X 19.184 Y 64.930 +G1 X 18.880 Y 64.626 +G1 X 18.571 Y 64.328 +G1 X 18.257 Y 64.036 +G1 X 17.937 Y 63.750 +G1 X 17.612 Y 63.470 +G1 X 17.282 Y 63.196 +G1 X 16.947 Y 62.928 +G1 X 16.607 Y 62.666 +G1 X 16.262 Y 62.411 +G1 X 15.912 Y 62.162 +G1 X 15.558 Y 61.919 +G1 X 15.200 Y 61.683 +G1 X 14.837 Y 61.454 +G1 X 14.470 Y 61.231 +G1 X 14.099 Y 61.016 +G1 X 13.724 Y 60.807 +G1 X 13.345 Y 60.605 +G1 X 12.963 Y 60.410 +G1 X 12.577 Y 60.222 +G1 X 12.188 Y 60.042 +G1 X 11.795 Y 59.869 +G1 X 11.400 Y 59.702 +G1 X 11.001 Y 59.544 +G1 X 10.599 Y 59.392 +G1 X 10.195 Y 59.249 +G1 X 9.788 Y 59.112 +G1 X 9.379 Y 58.983 +G1 X 8.967 Y 58.862 +G1 X 8.553 Y 58.748 +G1 X 8.137 Y 58.643 +G1 X 7.720 Y 58.544 +G1 X 7.300 Y 58.454 +G1 X 6.879 Y 58.371 +G1 X 6.457 Y 58.296 +G1 X 6.033 Y 58.229 +G1 X 5.608 Y 58.170 +G1 X 5.182 Y 58.118 +G1 X 4.755 Y 58.075 +G1 X 4.327 Y 58.039 +G1 X 3.899 Y 58.011 +G1 X 3.470 Y 57.991 +G1 X 3.041 Y 57.980 +G1 X 2.612 Y 57.976 +G1 X -8.499 Y 57.976 +G1 X 2.612 Y 59.420 +G1 X 3.041 Y 59.416 +G1 X 3.470 Y 59.404 +G1 X 3.899 Y 59.384 +G1 X 4.327 Y 59.357 +G1 X 4.755 Y 59.321 +G1 X 5.182 Y 59.277 +G1 X 5.608 Y 59.226 +G1 X 6.033 Y 59.167 +G1 X 6.457 Y 59.100 +G1 X 6.879 Y 59.025 +G1 X 7.300 Y 58.942 +G1 X 7.720 Y 58.851 +G1 X 8.137 Y 58.753 +G1 X 8.553 Y 58.647 +G1 X 8.967 Y 58.534 +G1 X 9.379 Y 58.412 +G1 X 9.788 Y 58.283 +G1 X 10.195 Y 58.147 +G1 X 10.599 Y 58.003 +G1 X 11.001 Y 57.852 +G1 X 11.400 Y 57.693 +G1 X 11.795 Y 57.527 +G1 X 12.188 Y 57.354 +G1 X 12.577 Y 57.173 +G1 X 12.963 Y 56.986 +G1 X 13.346 Y 56.791 +G1 X 13.724 Y 56.589 +G1 X 14.099 Y 56.380 +G1 X 14.470 Y 56.164 +G1 X 14.837 Y 55.942 +G1 X 15.200 Y 55.713 +G1 X 15.558 Y 55.477 +G1 X 15.912 Y 55.234 +G1 X 16.262 Y 54.985 +G1 X 16.607 Y 54.730 +G1 X 16.947 Y 54.468 +G1 X 17.282 Y 54.200 +G1 X 17.612 Y 53.926 +G1 X 17.937 Y 53.645 +G1 X 18.257 Y 53.359 +G1 X 18.571 Y 53.067 +G1 X 18.880 Y 52.769 +G1 X 19.184 Y 52.466 +G1 X 19.482 Y 52.157 +G1 X 19.774 Y 51.843 +G1 X 20.060 Y 51.523 +G1 X 20.340 Y 51.198 +G1 X 20.614 Y 50.868 +G1 X 20.882 Y 50.532 +G1 X 21.144 Y 50.192 +G1 X 21.399 Y 49.848 +G1 X 21.648 Y 49.498 +G1 X 21.891 Y 49.144 +G1 X 22.127 Y 48.786 +G1 X 22.356 Y 48.423 +G1 X 22.579 Y 48.056 +G1 X 22.794 Y 47.685 +G1 X 23.003 Y 47.310 +G1 X 23.205 Y 46.931 +G1 X 23.400 Y 46.549 +G1 X 23.588 Y 46.163 +G1 X 23.768 Y 45.774 +G1 X 23.941 Y 45.381 +G1 X 24.107 Y 44.985 +G1 X 24.266 Y 44.587 +G1 X 24.417 Y 44.185 +G1 X 24.561 Y 43.781 +G1 X 24.698 Y 43.374 +G1 X 24.827 Y 42.965 +G1 X 24.948 Y 42.553 +G1 X 25.061 Y 42.139 +G1 X 25.167 Y 41.723 +G1 X 25.266 Y 41.305 +G1 X 25.356 Y 40.886 +G1 X 25.439 Y 40.465 +G1 X 25.514 Y 40.042 +G1 X 25.581 Y 39.619 +G1 X 25.640 Y 39.193 +G1 X 25.692 Y 38.767 +G1 X 25.735 Y 38.341 +G1 X 25.771 Y 37.913 +G1 X 25.799 Y 37.485 +G1 X 25.818 Y 37.056 +G1 X 25.830 Y 36.627 +G1 X 25.834 Y 36.198 +G1 X 25.834 Y 25.642 +G1 X 25.830 Y 25.213 +G1 X 25.818 Y 24.784 +G1 X 25.799 Y 24.355 +G1 X 25.771 Y 23.927 +G1 X 25.735 Y 23.500 +G1 X 25.692 Y 23.073 +G1 X 25.640 Y 22.647 +G1 X 25.581 Y 22.222 +G1 X 25.514 Y 21.798 +G1 X 25.439 Y 21.375 +G1 X 25.356 Y 20.954 +G1 X 25.266 Y 20.535 +G1 X 25.167 Y 20.117 +G1 X 25.061 Y 19.701 +G1 X 24.948 Y 19.287 +G1 X 24.827 Y 18.876 +G1 X 24.698 Y 18.466 +G1 X 24.561 Y 18.059 +G1 X 24.417 Y 17.655 +G1 X 24.266 Y 17.253 +G1 X 24.107 Y 16.855 +G1 X 23.941 Y 16.459 +G1 X 23.768 Y 16.066 +G1 X 23.587 Y 15.677 +G1 X 23.400 Y 15.291 +G1 X 23.205 Y 14.909 +G1 X 23.003 Y 14.530 +G1 X 22.794 Y 14.155 +G1 X 22.579 Y 13.784 +G1 X 22.356 Y 13.417 +G1 X 22.127 Y 13.055 +G1 X 21.891 Y 12.696 +G1 X 21.648 Y 12.342 +G1 X 21.399 Y 11.993 +G1 X 21.144 Y 11.648 +G1 X 20.882 Y 11.308 +G1 X 20.614 Y 10.973 +G1 X 20.340 Y 10.642 +G1 X 20.060 Y 10.317 +G1 X 19.774 Y 9.998 +G1 X 19.481 Y 9.683 +G1 X 19.184 Y 9.374 +G1 X 18.880 Y 9.071 +G1 X 18.571 Y 8.773 +G1 X 18.257 Y 8.481 +G1 X 17.937 Y 8.195 +G1 X 17.612 Y 7.914 +G1 X 17.282 Y 7.640 +G1 X 16.947 Y 7.372 +G1 X 16.607 Y 7.111 +G1 X 16.262 Y 6.855 +G1 X 15.912 Y 6.606 +G1 X 15.558 Y 6.364 +G1 X 15.200 Y 6.128 +G1 X 14.837 Y 5.898 +G1 X 14.470 Y 5.676 +G1 X 14.099 Y 5.460 +G1 X 13.724 Y 5.251 +G1 X 13.345 Y 5.049 +G1 X 12.963 Y 4.855 +G1 X 12.577 Y 4.667 +G1 X 12.188 Y 4.486 +G1 X 11.795 Y 4.313 +G1 X 11.400 Y 4.147 +G1 X 11.001 Y 3.988 +G1 X 10.599 Y 3.837 +G1 X 10.195 Y 3.693 +G1 X 9.788 Y 3.557 +G1 X 9.379 Y 3.428 +G1 X 8.967 Y 3.307 +G1 X 8.553 Y 3.193 +G1 X 8.137 Y 3.087 +G1 X 7.720 Y 2.989 +G1 X 7.300 Y 2.898 +G1 X 6.879 Y 2.815 +G1 X 6.457 Y 2.741 +G1 X 6.033 Y 2.673 +G1 X 5.608 Y 2.614 +G1 X 5.182 Y 2.563 +G1 X 4.755 Y 2.519 +G1 X 4.327 Y 2.483 +G1 X 3.899 Y 2.456 +G1 X 3.470 Y 2.436 +G1 X 3.041 Y 2.424 +G1 X 2.612 Y 2.420 +G1 X -19.610 Y 10.420 +F150 +G1 Z 60.000 +G0 Z 100.000 +M9 M5 +G0 X 0.000 Y 0.000 +M2 (Program end) diff --git a/src/jetmax_demos/scripts/gcode/4.ngc b/src/jetmax_demos/scripts/gcode/4.ngc new file mode 100644 index 0000000..0ac6a63 --- /dev/null +++ b/src/jetmax_demos/scripts/gcode/4.ngc @@ -0,0 +1,40 @@ +(Generated with: DXF2GCODE, Version: Py3.7.10 PyQt5.10.1, Date: $Date: Fri Oct 25 20:45:56 2019 +0200 $) +(Created from file: /home/lucas/4.dxf) +(Output format description: G-CODE for LinuxCNC) +(Time: Wed Jul 14 19:47:30 2021) +G21 (Units in millimeters) +G90 (Absolute programming) +G64 (Default cutting) G17 (XY plane) G40 (Cancel radius comp.) G49 (Cancel length comp.) +G0 Z 100.000 + +(*** LAYER: 0 ***) +T1 M6 +S6000 + +(* SHAPE Nr: 0 *) +G0 X -13.076 Y 100.811 +M3 M8 +G0 Z 30.000 +F150 +G1 Z 30.000 +F400 +G1 X -34.934 Y 24.308 +G1 X 30.296 Y 24.308 +F150 +G1 Z 50.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 1 *) +G0 X 3.629 Y 90.099 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F400 +G1 X 3.629 Y -4.889 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 +G0 X 0.000 Y 0.000 +M2 (Program end) diff --git a/src/jetmax_demos/scripts/gcode/5.ngc b/src/jetmax_demos/scripts/gcode/5.ngc new file mode 100644 index 0000000..64f4122 --- /dev/null +++ b/src/jetmax_demos/scripts/gcode/5.ngc @@ -0,0 +1,117 @@ +(Generated with: DXF2GCODE, Version: Py3.7.10 PyQt5.10.1, Date: $Date: Fri Oct 25 20:45:56 2019 +0200 $) +(Created from file: /home/lucas/5.dxf) +(Output format description: G-CODE for LinuxCNC) +(Time: Thu Jul 15 10:47:51 2021) +G21 (Units in millimeters) +G90 (Absolute programming) +G64 (Default cutting) G17 (XY plane) G40 (Cancel radius comp.) G49 (Cancel length comp.) +G0 Z 100.000 + +(*** LAYER: 0 ***) +T1 M6 +S6000 + +(* SHAPE Nr: 0 *) +G0 X -21.295 Y 101.825 +M3 M8 +G0 Z 30.000 +F150 +G1 Z 30.000 +F400 +G1 X -26.963 Y 49.582 +G1 X -24.209 Y 52.336 +G1 X -24.152 Y 52.389 +G1 X -24.091 Y 52.437 +G1 X -24.027 Y 52.480 +G1 X -23.960 Y 52.518 +G1 X -23.890 Y 52.551 +G1 X -23.818 Y 52.578 +G1 X -9.532 Y 57.340 +G1 X -9.455 Y 57.362 +G1 X -9.376 Y 57.378 +G1 X -9.296 Y 57.388 +G1 X -9.216 Y 57.391 +G1 X 5.070 Y 57.391 +G1 X 5.150 Y 57.388 +G1 X 5.230 Y 57.378 +G1 X 5.309 Y 57.362 +G1 X 5.386 Y 57.340 +G1 X 19.672 Y 52.578 +G1 X 19.744 Y 52.551 +G1 X 19.814 Y 52.518 +G1 X 19.881 Y 52.480 +G1 X 19.946 Y 52.437 +G1 X 20.006 Y 52.389 +G1 X 20.063 Y 52.336 +G1 X 29.587 Y 42.813 +G1 X 29.639 Y 42.756 +G1 X 29.687 Y 42.695 +G1 X 29.730 Y 42.631 +G1 X 29.768 Y 42.564 +G1 X 29.801 Y 42.494 +G1 X 29.828 Y 42.422 +G1 X 34.590 Y 28.136 +G1 X 34.612 Y 28.059 +G1 X 34.628 Y 27.980 +G1 X 34.638 Y 27.900 +G1 X 34.641 Y 27.820 +G1 X 34.641 Y 18.296 +G1 X 34.638 Y 18.216 +G1 X 34.628 Y 18.136 +G1 X 34.612 Y 18.057 +G1 X 34.590 Y 17.980 +G1 X 29.828 Y 3.694 +G1 X 29.801 Y 3.622 +G1 X 29.768 Y 3.552 +G1 X 29.730 Y 3.484 +G1 X 29.687 Y 3.420 +G1 X 29.639 Y 3.360 +G1 X 29.587 Y 3.303 +G1 X 20.063 Y -6.221 +G1 X 20.006 Y -6.273 +G1 X 19.946 Y -6.321 +G1 X 19.881 Y -6.364 +G1 X 19.814 Y -6.402 +G1 X 19.744 Y -6.435 +G1 X 19.672 Y -6.462 +G1 X 5.386 Y -11.224 +G1 X 5.309 Y -11.247 +G1 X 5.230 Y -11.263 +G1 X 5.150 Y -11.272 +G1 X 5.070 Y -11.275 +G1 X -9.216 Y -11.275 +G1 X -9.296 Y -11.272 +G1 X -9.376 Y -11.263 +G1 X -9.455 Y -11.247 +G1 X -9.532 Y -11.224 +G1 X -23.818 Y -6.462 +G1 X -23.890 Y -6.435 +G1 X -23.960 Y -6.402 +G1 X -24.027 Y -6.364 +G1 X -24.091 Y -6.321 +G1 X -24.152 Y -6.273 +G1 X -24.209 Y -6.221 +G1 X -28.970 Y -1.459 +G1 X -29.025 Y -1.400 +G1 X -29.075 Y -1.336 +G1 X -29.119 Y -1.269 +G1 X -29.158 Y -1.199 +G1 X -33.920 Y 8.325 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 1 *) +G0 X -18.501 Y 88.725 +M3 M8 +G0 Z 30.000 +G1 Z 25.000 +F400 +G1 X 19.561 Y 88.725 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 +G0 X 0.000 Y 0.000 +M2 (Program end) diff --git a/src/jetmax_demos/scripts/gcode/6.ngc b/src/jetmax_demos/scripts/gcode/6.ngc new file mode 100644 index 0000000..d0cc18c --- /dev/null +++ b/src/jetmax_demos/scripts/gcode/6.ngc @@ -0,0 +1,47 @@ +(Generated with: DXF2GCODE, Version: Py3.7.10 PyQt5.10.1, Date: $Date: Fri Oct 25 20:45:56 2019 +0200 $) +(Created from file: /home/lucas/6.dxf) +(Output format description: G-CODE for LinuxCNC) +(Time: Wed Jul 14 19:44:16 2021) +G21 (Units in millimeters) +G90 (Absolute programming) +G64 (Default cutting) G17 (XY plane) G40 (Cancel radius comp.) G49 (Cancel length comp.) +G0 Z 100.000 + +(*** LAYER: 0 ***) +T1 M6 +S6000 + +(* SHAPE Nr: 0 *) +G0 X 25.708 Y 93.016 +M3 M8 +G0 Z 30.000 +F150 +G1 Z 30.000 +F400 +G1 X 21.132 Y 102.169 +G1 X 7.393 Y 106.749 +G1 X -1.807 Y 106.749 +G1 X -15.613 Y 102.147 +G1 X -24.837 Y 88.311 +G1 X -29.540 Y 64.793 +G1 X -29.540 Y 41.205 +G1 X -24.875 Y 22.546 +G1 X -15.714 Y 13.385 +G1 X -1.807 Y 8.749 +G1 X 2.631 Y 8.749 +G1 X 16.539 Y 13.385 +G1 X 25.729 Y 22.575 +G1 X 30.365 Y 36.482 +G1 X 30.365 Y 40.920 +G1 X 25.729 Y 54.828 +G1 X 16.539 Y 64.018 +G1 X 2.631 Y 68.654 +G1 X -1.807 Y 68.654 +G1 X -15.714 Y 64.018 +G1 X -25.071 Y 54.661 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 +G0 X 0.000 Y 0.000 +M2 (Program end) \ No newline at end of file diff --git a/src/jetmax_demos/scripts/gcode/angry.ngc b/src/jetmax_demos/scripts/gcode/angry.ngc new file mode 100644 index 0000000..2847203 --- /dev/null +++ b/src/jetmax_demos/scripts/gcode/angry.ngc @@ -0,0 +1,823 @@ +(Generated with: DXF2GCODE, Version: Py3.7.10 PyQt5.10.1, Date: $Date: Fri Oct 25 20:45:56 2019 +0200 $) +(Created from file: /home/lucas/ang.dxf) +(Output format description: G-CODE for LinuxCNC) +(Time: Sat Jul 17 18:22:49 2021) +G21 (Units in millimeters) +G90 (Absolute programming) +G64 (Default cutting) G17 (XY plane) G40 (Cancel radius comp.) G49 (Cancel length comp.) +G0 Z 100.000 + +(*** LAYER: 0 ***) +T1 M6 +S6000 + +(* SHAPE Nr: 0 *) +G0 X 54.703 Y 136.723 +M3 M8 +G0 Z 30.000 +F150 +G1 Z 30.000 +F400 +G1 X 55.256 Y 136.164 +G1 X 55.804 Y 135.599 +G1 X 56.345 Y 135.029 +G1 X 56.881 Y 134.454 +G1 X 57.412 Y 133.873 +G1 X 57.936 Y 133.286 +G1 X 58.454 Y 132.694 +G1 X 58.966 Y 132.098 +G1 X 59.472 Y 131.495 +G1 X 59.972 Y 130.888 +G1 X 60.466 Y 130.276 +G1 X 60.953 Y 129.659 +G1 X 61.435 Y 129.037 +G1 X 61.909 Y 128.410 +G1 X 62.378 Y 127.778 +G1 X 62.840 Y 127.141 +G1 X 63.295 Y 126.500 +G1 X 63.744 Y 125.854 +G1 X 64.187 Y 125.204 +G1 X 64.622 Y 124.549 +G1 X 65.051 Y 123.890 +G1 X 65.474 Y 123.226 +G1 X 65.889 Y 122.559 +G1 X 66.298 Y 121.887 +G1 X 66.700 Y 121.210 +G1 X 67.095 Y 120.530 +G1 X 67.483 Y 119.846 +G1 X 67.864 Y 119.158 +G1 X 68.238 Y 118.466 +G1 X 68.605 Y 117.771 +G1 X 68.965 Y 117.071 +G1 X 69.318 Y 116.368 +G1 X 69.663 Y 115.662 +G1 X 70.002 Y 114.952 +G1 X 70.333 Y 114.238 +G1 X 70.657 Y 113.522 +G1 X 70.974 Y 112.802 +G1 X 71.283 Y 112.079 +G1 X 71.585 Y 111.352 +G1 X 71.879 Y 110.623 +G1 X 72.166 Y 109.891 +G1 X 72.446 Y 109.156 +G1 X 72.718 Y 108.418 +G1 X 72.983 Y 107.677 +G1 X 73.240 Y 106.934 +G1 X 73.489 Y 106.188 +G1 X 73.731 Y 105.439 +G1 X 73.966 Y 104.688 +G1 X 74.192 Y 103.935 +G1 X 74.411 Y 103.180 +G1 X 74.622 Y 102.422 +G1 X 74.826 Y 101.663 +G1 X 75.022 Y 100.901 +G1 X 75.210 Y 100.137 +G1 X 75.390 Y 99.372 +G1 X 75.563 Y 98.604 +G1 X 75.727 Y 97.835 +G1 X 75.884 Y 97.064 +G1 X 76.033 Y 96.292 +G1 X 76.175 Y 95.518 +G1 X 76.308 Y 94.743 +G1 X 76.433 Y 93.967 +G1 X 76.551 Y 93.189 +G1 X 76.660 Y 92.410 +G1 X 76.762 Y 91.630 +G1 X 76.856 Y 90.849 +G1 X 76.942 Y 90.067 +G1 X 77.019 Y 89.285 +G1 X 77.089 Y 88.501 +G1 X 77.151 Y 87.717 +G1 X 77.205 Y 86.933 +G1 X 77.251 Y 86.147 +G1 X 77.289 Y 85.362 +G1 X 77.319 Y 84.576 +G1 X 77.341 Y 83.790 +G1 X 77.355 Y 83.003 +G1 X 77.361 Y 82.217 +G1 X 77.359 Y 81.430 +G1 X 77.349 Y 80.644 +G1 X 77.331 Y 79.857 +G1 X 77.305 Y 79.071 +G1 X 77.271 Y 78.286 +G1 X 77.229 Y 77.500 +G1 X 77.179 Y 76.715 +G1 X 77.121 Y 75.931 +G1 X 77.055 Y 75.147 +G1 X 76.981 Y 74.364 +G1 X 76.900 Y 73.582 +G1 X 76.810 Y 72.800 +G1 X 76.712 Y 72.020 +G1 X 76.607 Y 71.241 +G1 X 76.493 Y 70.462 +G1 X 76.372 Y 69.685 +G1 X 76.242 Y 68.909 +G1 X 76.105 Y 68.135 +G1 X 75.960 Y 67.362 +G1 X 75.807 Y 66.590 +G1 X 75.646 Y 65.820 +G1 X 75.477 Y 65.052 +G1 X 75.301 Y 64.286 +G1 X 75.117 Y 63.521 +G1 X 74.925 Y 62.758 +G1 X 74.725 Y 61.998 +G1 X 74.518 Y 61.239 +G1 X 74.303 Y 60.482 +G1 X 74.080 Y 59.728 +G1 X 73.849 Y 58.976 +G1 X 73.611 Y 58.226 +G1 X 73.366 Y 57.479 +G1 X 73.112 Y 56.735 +G1 X 72.851 Y 55.993 +G1 X 72.583 Y 55.253 +G1 X 72.307 Y 54.517 +G1 X 72.024 Y 53.783 +G1 X 71.733 Y 53.052 +G1 X 71.435 Y 52.324 +G1 X 71.129 Y 51.600 +G1 X 70.816 Y 50.878 +G1 X 70.496 Y 50.160 +G1 X 70.168 Y 49.445 +G1 X 69.834 Y 48.733 +G1 X 69.492 Y 48.025 +G1 X 69.142 Y 47.320 +G1 X 68.786 Y 46.619 +G1 X 68.423 Y 45.921 +G1 X 68.052 Y 45.228 +G1 X 67.674 Y 44.538 +G1 X 67.290 Y 43.851 +G1 X 66.898 Y 43.169 +G1 X 66.500 Y 42.491 +G1 X 66.095 Y 41.817 +G1 X 65.682 Y 41.147 +G1 X 65.263 Y 40.482 +G1 X 64.838 Y 39.820 +G1 X 64.405 Y 39.163 +G1 X 63.966 Y 38.511 +G1 X 63.521 Y 37.863 +G1 X 63.068 Y 37.219 +G1 X 62.610 Y 36.580 +G1 X 62.144 Y 35.946 +G1 X 61.673 Y 35.317 +G1 X 61.195 Y 34.692 +G1 X 60.710 Y 34.072 +G1 X 60.220 Y 33.457 +G1 X 59.723 Y 32.848 +G1 X 59.220 Y 32.243 +G1 X 58.711 Y 31.644 +G1 X 58.196 Y 31.049 +G1 X 57.674 Y 30.460 +G1 X 57.147 Y 29.877 +G1 X 56.614 Y 29.298 +G1 X 56.075 Y 28.725 +G1 X 55.531 Y 28.158 +G1 X 54.980 Y 27.596 +G1 X 54.424 Y 27.040 +G1 X 53.862 Y 26.490 +G1 X 53.295 Y 25.945 +G1 X 52.722 Y 25.406 +G1 X 52.144 Y 24.873 +G1 X 51.560 Y 24.346 +G1 X 50.971 Y 23.824 +G1 X 50.377 Y 23.309 +G1 X 49.777 Y 22.800 +G1 X 49.172 Y 22.297 +G1 X 48.563 Y 21.800 +G1 X 47.948 Y 21.310 +G1 X 47.328 Y 20.825 +G1 X 46.704 Y 20.347 +G1 X 46.074 Y 19.876 +G1 X 45.440 Y 19.410 +G1 X 44.801 Y 18.952 +G1 X 44.158 Y 18.499 +G1 X 43.509 Y 18.054 +G1 X 42.857 Y 17.615 +G1 X 42.200 Y 17.182 +G1 X 41.539 Y 16.757 +G1 X 40.873 Y 16.338 +G1 X 40.203 Y 15.926 +G1 X 39.529 Y 15.520 +G1 X 38.851 Y 15.122 +G1 X 38.169 Y 14.730 +G1 X 37.483 Y 14.346 +G1 X 36.793 Y 13.968 +G1 X 36.099 Y 13.598 +G1 X 35.401 Y 13.234 +G1 X 34.700 Y 12.878 +G1 X 33.995 Y 12.529 +G1 X 33.287 Y 12.187 +G1 X 32.575 Y 11.852 +G1 X 31.860 Y 11.524 +G1 X 31.142 Y 11.204 +G1 X 30.420 Y 10.891 +G1 X 29.696 Y 10.585 +G1 X 28.968 Y 10.287 +G1 X 28.237 Y 9.996 +G1 X 27.503 Y 9.713 +G1 X 26.767 Y 9.437 +G1 X 26.028 Y 9.169 +G1 X 25.285 Y 8.908 +G1 X 24.541 Y 8.655 +G1 X 23.794 Y 8.409 +G1 X 23.044 Y 8.171 +G1 X 22.292 Y 7.940 +G1 X 21.538 Y 7.717 +G1 X 20.781 Y 7.502 +G1 X 20.023 Y 7.295 +G1 X 19.262 Y 7.095 +G1 X 18.499 Y 6.903 +G1 X 17.734 Y 6.719 +G1 X 16.968 Y 6.543 +G1 X 16.200 Y 6.374 +G1 X 15.430 Y 6.213 +G1 X 14.658 Y 6.060 +G1 X 13.885 Y 5.915 +G1 X 13.111 Y 5.778 +G1 X 12.335 Y 5.649 +G1 X 11.558 Y 5.527 +G1 X 10.780 Y 5.414 +G1 X 10.000 Y 5.308 +G1 X 9.220 Y 5.210 +G1 X 8.438 Y 5.120 +G1 X 7.656 Y 5.039 +G1 X 6.873 Y 4.965 +G1 X 6.089 Y 4.899 +G1 X 5.305 Y 4.841 +G1 X 4.520 Y 4.791 +G1 X 3.735 Y 4.749 +G1 X 2.949 Y 4.715 +G1 X 2.163 Y 4.689 +G1 X 1.376 Y 4.671 +G1 X 0.590 Y 4.661 +G1 X -0.197 Y 4.659 +G1 X -0.983 Y 4.665 +G1 X -1.770 Y 4.679 +G1 X -2.556 Y 4.701 +G1 X -3.342 Y 4.731 +G1 X -4.127 Y 4.769 +G1 X -4.913 Y 4.815 +G1 X -5.697 Y 4.869 +G1 X -6.481 Y 4.931 +G1 X -7.265 Y 5.001 +G1 X -8.047 Y 5.079 +G1 X -8.829 Y 5.164 +G1 X -9.610 Y 5.258 +G1 X -10.390 Y 5.360 +G1 X -11.169 Y 5.469 +G1 X -11.947 Y 5.587 +G1 X -12.723 Y 5.712 +G1 X -13.498 Y 5.846 +G1 X -14.272 Y 5.987 +G1 X -15.044 Y 6.136 +G1 X -15.815 Y 6.293 +G1 X -16.584 Y 6.457 +G1 X -17.351 Y 6.630 +G1 X -18.117 Y 6.810 +G1 X -18.881 Y 6.998 +G1 X -19.642 Y 7.194 +G1 X -20.402 Y 7.398 +G1 X -21.160 Y 7.609 +G1 X -21.915 Y 7.828 +G1 X -22.668 Y 8.055 +G1 X -23.419 Y 8.289 +G1 X -24.168 Y 8.531 +G1 X -24.914 Y 8.780 +G1 X -25.657 Y 9.037 +G1 X -26.398 Y 9.302 +G1 X -27.135 Y 9.574 +G1 X -27.871 Y 9.854 +G1 X -28.603 Y 10.141 +G1 X -29.332 Y 10.435 +G1 X -30.058 Y 10.737 +G1 X -30.782 Y 11.046 +G1 X -31.502 Y 11.363 +G1 X -32.218 Y 11.687 +G1 X -32.932 Y 12.018 +G1 X -33.642 Y 12.357 +G1 X -34.348 Y 12.702 +G1 X -35.051 Y 13.055 +G1 X -35.751 Y 13.415 +G1 X -36.446 Y 13.782 +G1 X -37.138 Y 14.156 +G1 X -37.826 Y 14.537 +G1 X -38.510 Y 14.925 +G1 X -39.190 Y 15.320 +G1 X -39.866 Y 15.722 +G1 X -40.538 Y 16.131 +G1 X -41.206 Y 16.546 +G1 X -41.870 Y 16.969 +G1 X -42.529 Y 17.398 +G1 X -43.184 Y 17.833 +G1 X -43.834 Y 18.276 +G1 X -44.480 Y 18.725 +G1 X -45.121 Y 19.180 +G1 X -45.758 Y 19.642 +G1 X -46.389 Y 20.111 +G1 X -47.017 Y 20.586 +G1 X -47.639 Y 21.067 +G1 X -48.256 Y 21.554 +G1 X -48.868 Y 22.048 +G1 X -49.475 Y 22.548 +G1 X -50.077 Y 23.054 +G1 X -50.674 Y 23.566 +G1 X -51.266 Y 24.084 +G1 X -51.852 Y 24.609 +G1 X -52.433 Y 25.139 +G1 X -53.009 Y 25.675 +G1 X -53.579 Y 26.217 +G1 X -54.144 Y 26.764 +G1 X -54.703 Y 27.317 +G1 X -55.256 Y 27.876 +G1 X -55.804 Y 28.441 +G1 X -56.345 Y 29.011 +G1 X -56.881 Y 29.587 +G1 X -57.412 Y 30.168 +G1 X -57.936 Y 30.754 +G1 X -58.454 Y 31.346 +G1 X -58.966 Y 31.943 +G1 X -59.472 Y 32.545 +G1 X -59.972 Y 33.152 +G1 X -60.466 Y 33.764 +G1 X -60.953 Y 34.381 +G1 X -61.435 Y 35.004 +G1 X -61.909 Y 35.631 +G1 X -62.378 Y 36.262 +G1 X -62.840 Y 36.899 +G1 X -63.295 Y 37.540 +G1 X -63.744 Y 38.186 +G1 X -64.187 Y 38.836 +G1 X -64.622 Y 39.491 +G1 X -65.051 Y 40.150 +G1 X -65.474 Y 40.814 +G1 X -65.889 Y 41.482 +G1 X -66.298 Y 42.154 +G1 X -66.700 Y 42.830 +G1 X -67.095 Y 43.510 +G1 X -67.483 Y 44.194 +G1 X -67.864 Y 44.882 +G1 X -68.238 Y 45.574 +G1 X -68.605 Y 46.270 +G1 X -68.965 Y 46.969 +G1 X -69.318 Y 47.672 +G1 X -69.663 Y 48.378 +G1 X -70.002 Y 49.088 +G1 X -70.333 Y 49.802 +G1 X -70.657 Y 50.519 +G1 X -70.974 Y 51.239 +G1 X -71.283 Y 51.962 +G1 X -71.585 Y 52.688 +G1 X -71.879 Y 53.417 +G1 X -72.166 Y 54.150 +G1 X -72.446 Y 54.885 +G1 X -72.718 Y 55.623 +G1 X -72.983 Y 56.363 +G1 X -73.240 Y 57.107 +G1 X -73.489 Y 57.853 +G1 X -73.731 Y 58.601 +G1 X -73.966 Y 59.352 +G1 X -74.192 Y 60.105 +G1 X -74.411 Y 60.860 +G1 X -74.622 Y 61.618 +G1 X -74.826 Y 62.378 +G1 X -75.022 Y 63.139 +G1 X -75.210 Y 63.903 +G1 X -75.390 Y 64.669 +G1 X -75.563 Y 65.436 +G1 X -75.727 Y 66.205 +G1 X -75.884 Y 66.976 +G1 X -76.033 Y 67.748 +G1 X -76.175 Y 68.522 +G1 X -76.308 Y 69.297 +G1 X -76.433 Y 70.074 +G1 X -76.551 Y 70.851 +G1 X -76.660 Y 71.630 +G1 X -76.762 Y 72.410 +G1 X -76.856 Y 73.191 +G1 X -76.942 Y 73.973 +G1 X -77.019 Y 74.755 +G1 X -77.089 Y 75.539 +G1 X -77.151 Y 76.323 +G1 X -77.205 Y 77.108 +G1 X -77.251 Y 77.893 +G1 X -77.289 Y 78.678 +G1 X -77.319 Y 79.464 +G1 X -77.341 Y 80.251 +G1 X -77.355 Y 81.037 +G1 X -77.361 Y 81.823 +G1 X -77.359 Y 82.610 +G1 X -77.349 Y 83.396 +G1 X -77.331 Y 84.183 +G1 X -77.305 Y 84.969 +G1 X -77.271 Y 85.755 +G1 X -77.229 Y 86.540 +G1 X -77.179 Y 87.325 +G1 X -77.121 Y 88.109 +G1 X -77.055 Y 88.893 +G1 X -76.981 Y 89.676 +G1 X -76.900 Y 90.458 +G1 X -76.810 Y 91.240 +G1 X -76.712 Y 92.020 +G1 X -76.607 Y 92.800 +G1 X -76.493 Y 93.578 +G1 X -76.372 Y 94.355 +G1 X -76.242 Y 95.131 +G1 X -76.105 Y 95.905 +G1 X -75.960 Y 96.678 +G1 X -75.807 Y 97.450 +G1 X -75.646 Y 98.220 +G1 X -75.477 Y 98.988 +G1 X -75.301 Y 99.755 +G1 X -75.117 Y 100.519 +G1 X -74.925 Y 101.282 +G1 X -74.725 Y 102.043 +G1 X -74.518 Y 102.801 +G1 X -74.303 Y 103.558 +G1 X -74.080 Y 104.312 +G1 X -73.849 Y 105.064 +G1 X -73.611 Y 105.814 +G1 X -73.366 Y 106.561 +G1 X -73.112 Y 107.306 +G1 X -72.851 Y 108.048 +G1 X -72.583 Y 108.787 +G1 X -72.307 Y 109.523 +G1 X -72.024 Y 110.257 +G1 X -71.733 Y 110.988 +G1 X -71.435 Y 111.716 +G1 X -71.129 Y 112.441 +G1 X -70.816 Y 113.162 +G1 X -70.496 Y 113.880 +G1 X -70.168 Y 114.596 +G1 X -69.834 Y 115.307 +G1 X -69.492 Y 116.016 +G1 X -69.142 Y 116.720 +G1 X -68.786 Y 117.421 +G1 X -68.423 Y 118.119 +G1 X -68.052 Y 118.813 +G1 X -67.674 Y 119.503 +G1 X -67.290 Y 120.189 +G1 X -66.898 Y 120.871 +G1 X -66.500 Y 121.549 +G1 X -66.095 Y 122.223 +G1 X -65.682 Y 122.893 +G1 X -65.263 Y 123.559 +G1 X -64.838 Y 124.220 +G1 X -64.405 Y 124.877 +G1 X -63.966 Y 125.530 +G1 X -63.521 Y 126.178 +G1 X -63.068 Y 126.821 +G1 X -62.610 Y 127.460 +G1 X -62.144 Y 128.094 +G1 X -61.673 Y 128.724 +G1 X -61.195 Y 129.348 +G1 X -60.710 Y 129.968 +G1 X -60.220 Y 130.583 +G1 X -59.723 Y 131.193 +G1 X -59.220 Y 131.797 +G1 X -58.711 Y 132.397 +G1 X -58.196 Y 132.991 +G1 X -57.674 Y 133.580 +G1 X -57.147 Y 134.164 +G1 X -56.614 Y 134.742 +G1 X -56.075 Y 135.315 +G1 X -55.531 Y 135.882 +G1 X -54.980 Y 136.444 +G1 X -54.424 Y 137.000 +G1 X -53.862 Y 137.551 +G1 X -53.295 Y 138.095 +G1 X -52.722 Y 138.634 +G1 X -52.144 Y 139.167 +G1 X -51.560 Y 139.695 +G1 X -50.971 Y 140.216 +G1 X -50.377 Y 140.731 +G1 X -49.777 Y 141.240 +G1 X -49.172 Y 141.743 +G1 X -48.563 Y 142.240 +G1 X -47.948 Y 142.731 +G1 X -47.328 Y 143.215 +G1 X -46.704 Y 143.693 +G1 X -46.074 Y 144.165 +G1 X -45.440 Y 144.630 +G1 X -44.801 Y 145.089 +G1 X -44.158 Y 145.541 +G1 X -43.509 Y 145.986 +G1 X -42.857 Y 146.425 +G1 X -42.200 Y 146.858 +G1 X -41.539 Y 147.284 +G1 X -40.873 Y 147.702 +G1 X -40.203 Y 148.115 +G1 X -39.529 Y 148.520 +G1 X -38.851 Y 148.918 +G1 X -38.169 Y 149.310 +G1 X -37.483 Y 149.694 +G1 X -36.793 Y 150.072 +G1 X -36.099 Y 150.443 +G1 X -35.401 Y 150.806 +G1 X -34.700 Y 151.162 +G1 X -33.995 Y 151.512 +G1 X -33.287 Y 151.854 +G1 X -32.575 Y 152.189 +G1 X -31.860 Y 152.516 +G1 X -31.142 Y 152.836 +G1 X -30.420 Y 153.149 +G1 X -29.696 Y 153.455 +G1 X -28.968 Y 153.753 +G1 X -28.237 Y 154.044 +G1 X -27.503 Y 154.327 +G1 X -26.767 Y 154.603 +G1 X -26.028 Y 154.872 +G1 X -25.285 Y 155.132 +G1 X -24.541 Y 155.386 +G1 X -23.794 Y 155.631 +G1 X -23.044 Y 155.870 +G1 X -22.292 Y 156.100 +G1 X -21.538 Y 156.323 +G1 X -20.781 Y 156.538 +G1 X -20.023 Y 156.745 +G1 X -19.262 Y 156.945 +G1 X -18.499 Y 157.137 +G1 X -17.734 Y 157.321 +G1 X -16.968 Y 157.498 +G1 X -16.200 Y 157.666 +G1 X -15.430 Y 157.827 +G1 X -14.658 Y 157.980 +G1 X -13.885 Y 158.125 +G1 X -13.111 Y 158.262 +G1 X -12.335 Y 158.392 +G1 X -11.558 Y 158.513 +G1 X -10.780 Y 158.627 +G1 X -10.000 Y 158.732 +G1 X -9.220 Y 158.830 +G1 X -8.438 Y 158.920 +G1 X -7.656 Y 159.002 +G1 X -6.873 Y 159.075 +G1 X -6.089 Y 159.141 +G1 X -5.305 Y 159.199 +G1 X -4.520 Y 159.249 +G1 X -3.735 Y 159.291 +G1 X -2.949 Y 159.325 +G1 X -2.163 Y 159.351 +G1 X -1.376 Y 159.369 +G1 X -0.590 Y 159.379 +G1 X 0.197 Y 159.381 +G1 X 0.983 Y 159.375 +G1 X 1.770 Y 159.361 +G1 X 2.556 Y 159.339 +G1 X 3.342 Y 159.309 +G1 X 4.127 Y 159.271 +G1 X 4.913 Y 159.225 +G1 X 5.697 Y 159.171 +G1 X 6.481 Y 159.109 +G1 X 7.265 Y 159.040 +G1 X 8.047 Y 158.962 +G1 X 8.829 Y 158.876 +G1 X 9.610 Y 158.782 +G1 X 10.390 Y 158.680 +G1 X 11.169 Y 158.571 +G1 X 11.947 Y 158.453 +G1 X 12.723 Y 158.328 +G1 X 13.498 Y 158.195 +G1 X 14.272 Y 158.053 +G1 X 15.044 Y 157.904 +G1 X 15.815 Y 157.748 +G1 X 16.584 Y 157.583 +G1 X 17.351 Y 157.410 +G1 X 18.117 Y 157.230 +G1 X 18.881 Y 157.042 +G1 X 19.642 Y 156.846 +G1 X 20.402 Y 156.643 +G1 X 21.160 Y 156.431 +G1 X 21.915 Y 156.212 +G1 X 22.668 Y 155.986 +G1 X 23.419 Y 155.751 +G1 X 24.168 Y 155.510 +G1 X 24.914 Y 155.260 +G1 X 25.657 Y 155.003 +G1 X 26.398 Y 154.738 +G1 X 27.135 Y 154.466 +G1 X 27.871 Y 154.187 +G1 X 28.603 Y 153.899 +G1 X 29.332 Y 153.605 +G1 X 30.058 Y 153.303 +G1 X 30.782 Y 152.994 +G1 X 31.502 Y 152.677 +G1 X 32.218 Y 152.353 +G1 X 32.932 Y 152.022 +G1 X 33.642 Y 151.684 +G1 X 34.348 Y 151.338 +G1 X 35.051 Y 150.985 +G1 X 35.751 Y 150.625 +G1 X 36.446 Y 150.258 +G1 X 37.138 Y 149.884 +G1 X 37.826 Y 149.503 +G1 X 38.510 Y 149.115 +G1 X 39.190 Y 148.720 +G1 X 39.866 Y 148.318 +G1 X 40.538 Y 147.909 +G1 X 41.206 Y 147.494 +G1 X 41.870 Y 147.072 +G1 X 42.529 Y 146.642 +G1 X 43.184 Y 146.207 +G1 X 43.834 Y 145.764 +G1 X 44.480 Y 145.315 +G1 X 45.121 Y 144.860 +G1 X 45.758 Y 144.398 +G1 X 46.389 Y 143.930 +G1 X 47.017 Y 143.455 +G1 X 47.639 Y 142.974 +G1 X 48.256 Y 142.486 +G1 X 48.868 Y 141.992 +G1 X 49.475 Y 141.492 +G1 X 50.077 Y 140.986 +G1 X 50.674 Y 140.474 +G1 X 51.266 Y 139.956 +G1 X 51.852 Y 139.432 +G1 X 52.433 Y 138.902 +G1 X 53.009 Y 138.366 +G1 X 53.579 Y 137.824 +G1 X 54.144 Y 137.276 +G1 X 54.703 Y 136.723 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 2 *) +G0 X -44.639 Y 121.008 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F100 +G1 X -14.095 Y 93.045 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 3 *) +G0 X 43.115 Y 122.483 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F100 +G1 X 12.571 Y 94.521 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 1 *) +G0 X -28.616 Y 38.604 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F400 +G1 X -28.313 Y 39.108 +G1 X -28.003 Y 39.608 +G1 X -27.688 Y 40.105 +G1 X -27.367 Y 40.597 +G1 X -27.040 Y 41.086 +G1 X -26.711 Y 41.566 +G1 X -26.375 Y 42.041 +G1 X -26.033 Y 42.512 +G1 X -25.685 Y 42.978 +G1 X -25.331 Y 43.439 +G1 X -24.970 Y 43.896 +G1 X -24.649 Y 44.292 +G1 X -24.322 Y 44.685 +G1 X -23.990 Y 45.073 +G1 X -23.654 Y 45.457 +G1 X -23.312 Y 45.836 +G1 X -22.965 Y 46.211 +G1 X -22.635 Y 46.559 +G1 X -22.301 Y 46.902 +G1 X -21.962 Y 47.241 +G1 X -21.618 Y 47.575 +G1 X -21.270 Y 47.905 +G1 X -20.918 Y 48.230 +G1 X -20.561 Y 48.550 +G1 X -20.193 Y 48.871 +G1 X -19.820 Y 49.187 +G1 X -19.442 Y 49.498 +G1 X -19.060 Y 49.802 +G1 X -18.673 Y 50.101 +G1 X -18.282 Y 50.395 +G1 X -17.887 Y 50.682 +G1 X -17.487 Y 50.964 +G1 X -17.079 Y 51.242 +G1 X -16.667 Y 51.513 +G1 X -16.251 Y 51.778 +G1 X -15.831 Y 52.037 +G1 X -15.407 Y 52.289 +G1 X -14.978 Y 52.534 +G1 X -14.551 Y 52.770 +G1 X -14.119 Y 52.999 +G1 X -13.684 Y 53.222 +G1 X -13.245 Y 53.437 +G1 X -12.803 Y 53.646 +G1 X -12.358 Y 53.848 +G1 X -11.910 Y 54.043 +G1 X -11.459 Y 54.230 +G1 X -11.005 Y 54.411 +G1 X -10.535 Y 54.589 +G1 X -10.063 Y 54.761 +G1 X -9.588 Y 54.924 +G1 X -9.110 Y 55.081 +G1 X -8.630 Y 55.230 +G1 X -8.148 Y 55.371 +G1 X -7.664 Y 55.505 +G1 X -7.178 Y 55.632 +G1 X -6.691 Y 55.751 +G1 X -6.203 Y 55.863 +G1 X -5.713 Y 55.968 +G1 X -5.222 Y 56.066 +G1 X -4.730 Y 56.157 +G1 X -4.236 Y 56.241 +G1 X -3.741 Y 56.318 +G1 X -3.278 Y 56.383 +G1 X -2.815 Y 56.443 +G1 X -2.351 Y 56.498 +G1 X -1.886 Y 56.547 +G1 X -1.420 Y 56.590 +G1 X -0.955 Y 56.627 +G1 X -0.407 Y 56.664 +G1 X 0.141 Y 56.693 +G1 X 0.599 Y 56.712 +G1 X 1.058 Y 56.723 +G1 X 1.517 Y 56.729 +G1 X 1.976 Y 56.727 +G1 X 2.435 Y 56.720 +G1 X 2.894 Y 56.706 +G1 X 3.353 Y 56.686 +G1 X 3.811 Y 56.659 +G1 X 4.261 Y 56.626 +G1 X 4.711 Y 56.587 +G1 X 5.160 Y 56.541 +G1 X 5.608 Y 56.489 +G1 X 6.056 Y 56.430 +G1 X 6.502 Y 56.365 +G1 X 6.948 Y 56.293 +G1 X 7.410 Y 56.211 +G1 X 7.871 Y 56.122 +G1 X 8.330 Y 56.026 +G1 X 8.788 Y 55.923 +G1 X 9.244 Y 55.813 +G1 X 9.699 Y 55.696 +G1 X 10.151 Y 55.572 +G1 X 10.602 Y 55.441 +G1 X 11.050 Y 55.303 +G1 X 11.497 Y 55.158 +G1 X 11.941 Y 55.006 +G1 X 12.412 Y 54.837 +G1 X 12.880 Y 54.660 +G1 X 13.345 Y 54.476 +G1 X 13.807 Y 54.285 +G1 X 14.266 Y 54.087 +G1 X 14.722 Y 53.881 +G1 X 15.175 Y 53.668 +G1 X 15.624 Y 53.448 +G1 X 16.052 Y 53.231 +G1 X 16.477 Y 53.007 +G1 X 16.899 Y 52.778 +G1 X 17.317 Y 52.543 +G1 X 17.732 Y 52.302 +G1 X 18.144 Y 52.055 +G1 X 18.553 Y 51.803 +G1 X 18.978 Y 51.532 +G1 X 19.400 Y 51.255 +G1 X 19.819 Y 50.972 +G1 X 20.233 Y 50.684 +G1 X 20.644 Y 50.390 +G1 X 21.051 Y 50.091 +G1 X 21.465 Y 49.778 +G1 X 21.875 Y 49.460 +G1 X 22.281 Y 49.136 +G1 X 22.683 Y 48.808 +G1 X 23.081 Y 48.475 +G1 X 23.475 Y 48.137 +G1 X 23.881 Y 47.780 +G1 X 24.282 Y 47.418 +G1 X 24.680 Y 47.052 +G1 X 25.073 Y 46.681 +G1 X 25.462 Y 46.305 +G1 X 25.847 Y 45.926 +G1 X 26.245 Y 45.524 +G1 X 26.638 Y 45.118 +G1 X 27.027 Y 44.709 +G1 X 27.412 Y 44.295 +G1 X 27.792 Y 43.877 +G1 X 28.168 Y 43.455 +G1 X 28.606 Y 42.951 +G1 X 29.039 Y 42.443 +G1 X 29.467 Y 41.929 +G1 X 29.889 Y 41.412 +G1 X 30.305 Y 40.889 +G1 X 30.666 Y 40.427 +G1 X 31.023 Y 39.961 +G1 X 31.376 Y 39.492 +G1 X 31.725 Y 39.021 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 +G0 X 0.000 Y 0.000 +M2 (Program end) diff --git a/src/jetmax_demos/scripts/gcode/hand_heart.ngc b/src/jetmax_demos/scripts/gcode/hand_heart.ngc new file mode 100644 index 0000000..30c5a48 --- /dev/null +++ b/src/jetmax_demos/scripts/gcode/hand_heart.ngc @@ -0,0 +1,698 @@ +(Generated with: DXF2GCODE, Version: Py3.7.10 PyQt5.10.1, Date: $Date: Fri Oct 25 20:45:56 2019 +0200 $) +(Created from file: /home/lucas/爱心.dxf) +(Output format description: G-CODE for LinuxCNC) +(Time: Fri Jul 16 10:30:20 2021) +G21 (Units in millimeters) +G90 (Absolute programming) +G64 (Default cutting) G17 (XY plane) G40 (Cancel radius comp.) G49 (Cancel length comp.) +G0 Z 100.000 + +(*** LAYER: 0 ***) +T1 M6 +S6000 + +(* SHAPE Nr: 0 *) +G0 X -8.144 Y 6.296 +M3 M8 +G0 Z 30.000 +F150 +G1 Z 30.000 +F100 +G1 X -8.144 Y 6.296 +G1 X -8.401 Y 6.467 +G1 X -8.653 Y 6.644 +G1 X -8.902 Y 6.827 +G1 X -9.147 Y 7.018 +G1 X -9.389 Y 7.215 +G1 X -9.625 Y 7.417 +G1 X -9.857 Y 7.624 +G1 X -10.084 Y 7.838 +G1 X -10.306 Y 8.056 +G1 X -32.663 Y 30.413 +G1 X -55.014 Y 52.764 +G1 X -55.027 Y 52.777 +G1 X -55.029 Y 52.778 +G1 X -55.050 Y 52.798 +G1 X -55.051 Y 52.800 +G1 X -55.072 Y 52.820 +G1 X -55.073 Y 52.821 +G1 X -55.094 Y 52.841 +G1 X -55.095 Y 52.842 +G1 X -55.116 Y 52.862 +G1 X -55.117 Y 52.864 +G1 X -55.138 Y 52.884 +G1 X -55.139 Y 52.885 +G1 X -55.159 Y 52.905 +G1 X -55.160 Y 52.906 +G1 X -55.181 Y 52.927 +G1 X -55.182 Y 52.928 +G1 X -55.203 Y 52.948 +G1 X -55.204 Y 52.949 +G1 X -55.224 Y 52.969 +G1 X -55.225 Y 52.970 +G1 X -55.245 Y 52.990 +G1 X -55.246 Y 52.991 +G1 X -55.267 Y 53.012 +G1 X -55.268 Y 53.013 +G1 X -55.288 Y 53.033 +G1 X -55.289 Y 53.034 +G1 X -55.309 Y 53.054 +G1 X -55.310 Y 53.055 +G1 X -55.330 Y 53.075 +G1 X -55.331 Y 53.076 +G1 X -55.351 Y 53.096 +G1 X -55.352 Y 53.097 +G1 X -55.372 Y 53.117 +G1 X -55.373 Y 53.118 +G1 X -55.393 Y 53.138 +G1 X -55.394 Y 53.139 +G1 X -55.414 Y 53.159 +G1 X -55.414 Y 53.160 +G1 X -55.435 Y 53.180 +G1 X -55.435 Y 53.181 +G1 X -55.455 Y 53.201 +G1 X -55.456 Y 53.202 +G1 X -55.476 Y 53.222 +G1 X -55.476 Y 53.223 +G1 X -55.496 Y 53.243 +G1 X -55.497 Y 53.244 +G1 X -55.517 Y 53.264 +G1 X -55.537 Y 53.285 +G1 X -55.558 Y 53.306 +G1 X -55.578 Y 53.326 +G1 X -55.598 Y 53.347 +G1 X -55.618 Y 53.367 +G1 X -55.618 Y 53.368 +G1 X -55.638 Y 53.388 +G1 X -55.658 Y 53.409 +G1 X -55.659 Y 53.409 +G1 X -55.883 Y 53.640 +G1 X -56.104 Y 53.872 +G1 X -56.467 Y 54.260 +G1 X -56.823 Y 54.653 +G1 X -57.175 Y 55.051 +G1 X -57.521 Y 55.453 +G1 X -57.862 Y 55.860 +G1 X -58.197 Y 56.272 +G1 X -58.526 Y 56.688 +G1 X -58.850 Y 57.108 +G1 X -59.168 Y 57.533 +G1 X -59.480 Y 57.962 +G1 X -59.782 Y 58.389 +G1 X -60.079 Y 58.820 +G1 X -60.369 Y 59.255 +G1 X -60.653 Y 59.694 +G1 X -60.932 Y 60.136 +G1 X -61.204 Y 60.583 +G1 X -61.471 Y 61.033 +G1 X -61.731 Y 61.486 +G1 X -61.985 Y 61.943 +G1 X -62.233 Y 62.404 +G1 X -62.474 Y 62.868 +G1 X -62.710 Y 63.335 +G1 X -62.938 Y 63.805 +G1 X -63.161 Y 64.278 +G1 X -63.377 Y 64.754 +G1 X -63.587 Y 65.233 +G1 X -63.793 Y 65.722 +G1 X -63.992 Y 66.214 +G1 X -64.185 Y 66.708 +G1 X -64.370 Y 67.205 +G1 X -64.549 Y 67.705 +G1 X -64.721 Y 68.206 +G1 X -64.886 Y 68.711 +G1 X -65.045 Y 69.217 +G1 X -65.196 Y 69.725 +G1 X -65.340 Y 70.236 +G1 X -65.477 Y 70.748 +G1 X -65.610 Y 71.274 +G1 X -65.736 Y 71.802 +G1 X -65.855 Y 72.331 +G1 X -65.966 Y 72.862 +G1 X -66.069 Y 73.394 +G1 X -66.165 Y 73.928 +G1 X -66.254 Y 74.462 +G1 X -66.336 Y 74.999 +G1 X -66.410 Y 75.536 +G1 X -66.476 Y 76.074 +G1 X -66.535 Y 76.613 +G1 X -66.587 Y 77.153 +G1 X -66.631 Y 77.693 +G1 X -66.667 Y 78.234 +G1 X -66.696 Y 78.776 +G1 X -66.718 Y 79.318 +G1 X -66.732 Y 79.860 +G1 X -66.738 Y 80.369 +G1 X -66.737 Y 80.878 +G1 X -66.730 Y 81.386 +G1 X -66.717 Y 81.895 +G1 X -66.697 Y 82.404 +G1 X -66.670 Y 82.912 +G1 X -66.636 Y 83.420 +G1 X -66.596 Y 83.927 +G1 X -66.550 Y 84.434 +G1 X -66.496 Y 84.940 +G1 X -66.432 Y 85.484 +G1 X -66.360 Y 86.026 +G1 X -66.280 Y 86.568 +G1 X -66.192 Y 87.108 +G1 X -66.097 Y 87.647 +G1 X -65.995 Y 88.185 +G1 X -65.885 Y 88.721 +G1 X -65.767 Y 89.255 +G1 X -65.642 Y 89.788 +G1 X -65.509 Y 90.319 +G1 X -65.369 Y 90.848 +G1 X -65.222 Y 91.375 +G1 X -65.067 Y 91.900 +G1 X -64.905 Y 92.423 +G1 X -64.735 Y 92.944 +G1 X -64.558 Y 93.461 +G1 X -64.380 Y 93.960 +G1 X -64.196 Y 94.456 +G1 X -64.004 Y 94.949 +G1 X -63.806 Y 95.439 +G1 X -63.601 Y 95.927 +G1 X -63.390 Y 96.412 +G1 X -63.171 Y 96.894 +G1 X -62.947 Y 97.373 +G1 X -62.715 Y 97.849 +G1 X -62.478 Y 98.321 +G1 X -62.233 Y 98.791 +G1 X -61.983 Y 99.257 +G1 X -61.726 Y 99.719 +G1 X -61.462 Y 100.178 +G1 X -61.193 Y 100.633 +G1 X -60.907 Y 101.101 +G1 X -60.614 Y 101.564 +G1 X -60.315 Y 102.024 +G1 X -60.009 Y 102.479 +G1 X -59.697 Y 102.930 +G1 X -59.379 Y 103.376 +G1 X -59.054 Y 103.818 +G1 X -58.723 Y 104.255 +G1 X -58.386 Y 104.687 +G1 X -58.035 Y 105.124 +G1 X -57.678 Y 105.556 +G1 X -57.315 Y 105.983 +G1 X -56.946 Y 106.405 +G1 X -56.571 Y 106.821 +G1 X -56.190 Y 107.232 +G1 X -55.803 Y 107.638 +G1 X -55.411 Y 108.038 +G1 X -55.012 Y 108.432 +G1 X -55.010 Y 108.434 +G1 X -54.599 Y 108.830 +G1 X -54.183 Y 109.219 +G1 X -53.763 Y 109.604 +G1 X -53.338 Y 109.984 +G1 X -52.909 Y 110.359 +G1 X -52.539 Y 110.674 +G1 X -52.166 Y 110.984 +G1 X -51.789 Y 111.289 +G1 X -51.409 Y 111.590 +G1 X -51.025 Y 111.887 +G1 X -50.637 Y 112.178 +G1 X -50.240 Y 112.469 +G1 X -49.839 Y 112.754 +G1 X -49.434 Y 113.033 +G1 X -49.025 Y 113.307 +G1 X -48.612 Y 113.575 +G1 X -48.196 Y 113.837 +G1 X -47.787 Y 114.085 +G1 X -47.375 Y 114.327 +G1 X -46.959 Y 114.563 +G1 X -46.540 Y 114.792 +G1 X -46.117 Y 115.015 +G1 X -45.691 Y 115.232 +G1 X -45.262 Y 115.442 +G1 X -44.827 Y 115.646 +G1 X -44.389 Y 115.843 +G1 X -43.948 Y 116.033 +G1 X -43.504 Y 116.216 +G1 X -43.057 Y 116.391 +G1 X -42.607 Y 116.559 +G1 X -42.155 Y 116.720 +G1 X -41.700 Y 116.874 +G1 X -41.242 Y 117.020 +G1 X -40.783 Y 117.159 +G1 X -40.372 Y 117.276 +G1 X -39.959 Y 117.387 +G1 X -39.546 Y 117.493 +G1 X -39.130 Y 117.593 +G1 X -38.713 Y 117.687 +G1 X -38.295 Y 117.775 +G1 X -37.876 Y 117.858 +G1 X -37.369 Y 117.950 +G1 X -36.859 Y 118.034 +G1 X -36.349 Y 118.111 +G1 X -35.838 Y 118.180 +G1 X -35.325 Y 118.240 +G1 X -34.812 Y 118.293 +G1 X -34.333 Y 118.335 +G1 X -33.854 Y 118.372 +G1 X -33.374 Y 118.402 +G1 X -32.894 Y 118.426 +G1 X -32.414 Y 118.444 +G1 X -31.934 Y 118.456 +G1 X -31.372 Y 118.462 +G1 X -30.811 Y 118.462 +G1 X -30.250 Y 118.453 +G1 X -29.689 Y 118.438 +G1 X -29.128 Y 118.415 +G1 X -28.507 Y 118.382 +G1 X -27.886 Y 118.341 +G1 X -27.266 Y 118.292 +G1 X -26.646 Y 118.236 +G1 X -26.641 Y 118.235 +G1 X -26.613 Y 118.232 +G1 X -26.473 Y 118.214 +G1 X -26.333 Y 118.194 +G1 X -26.020 Y 118.141 +G1 X -25.707 Y 118.082 +G1 X -25.395 Y 118.016 +G1 X -25.003 Y 117.925 +G1 X -24.613 Y 117.827 +G1 X -24.224 Y 117.722 +G1 X -23.838 Y 117.610 +G1 X -23.413 Y 117.478 +G1 X -22.990 Y 117.339 +G1 X -22.570 Y 117.193 +G1 X -22.152 Y 117.040 +G1 X -21.737 Y 116.879 +G1 X -21.338 Y 116.718 +G1 X -20.941 Y 116.550 +G1 X -20.547 Y 116.377 +G1 X -20.156 Y 116.198 +G1 X -19.767 Y 116.013 +G1 X -19.381 Y 115.822 +G1 X -18.998 Y 115.625 +G1 X -18.601 Y 115.414 +G1 X -18.206 Y 115.197 +G1 X -17.815 Y 114.974 +G1 X -17.427 Y 114.746 +G1 X -17.043 Y 114.512 +G1 X -16.662 Y 114.272 +G1 X -16.284 Y 114.027 +G1 X -15.910 Y 113.777 +G1 X -15.535 Y 113.518 +G1 X -15.164 Y 113.255 +G1 X -14.797 Y 112.986 +G1 X -14.433 Y 112.712 +G1 X -14.073 Y 112.433 +G1 X -13.717 Y 112.149 +G1 X -13.365 Y 111.860 +G1 X -13.017 Y 111.567 +G1 X -12.623 Y 111.224 +G1 X -12.234 Y 110.876 +G1 X -11.850 Y 110.522 +G1 X -11.471 Y 110.163 +G1 X -11.098 Y 109.797 +G1 X -10.730 Y 109.427 +G1 X -10.368 Y 109.051 +G1 X -10.043 Y 108.704 +G1 X -9.723 Y 108.354 +G1 X -9.408 Y 108.000 +G1 X -9.096 Y 107.641 +G1 X -8.790 Y 107.279 +G1 X -8.488 Y 106.913 +G1 X -8.190 Y 106.543 +G1 X -7.875 Y 106.141 +G1 X -7.566 Y 105.736 +G1 X -7.261 Y 105.326 +G1 X -6.962 Y 104.913 +G1 X -6.668 Y 104.496 +G1 X -6.379 Y 104.076 +G1 X -6.095 Y 103.651 +G1 X -5.770 Y 103.151 +G1 X -5.451 Y 102.645 +G1 X -5.139 Y 102.136 +G1 X -4.833 Y 101.622 +G1 X -4.535 Y 101.105 +G1 X -4.244 Y 100.583 +G1 X -3.971 Y 100.081 +G1 X -3.705 Y 99.576 +G1 X -3.444 Y 99.068 +G1 X -3.190 Y 98.556 +G1 X -2.941 Y 98.042 +G1 X -2.698 Y 97.525 +G1 X -2.435 Y 96.946 +G1 X -2.178 Y 96.363 +G1 X -1.928 Y 95.778 +G1 X -1.685 Y 95.190 +G1 X -1.449 Y 94.599 +G1 X -1.220 Y 94.005 +G1 X -1.001 Y 93.418 +G1 X -0.788 Y 92.830 +G1 X -0.581 Y 92.239 +G1 X -0.380 Y 91.646 +G1 X -0.185 Y 91.051 +G1 X 0.003 Y 90.454 +G1 X 0.131 Y 90.037 +G1 X 0.191 Y 90.164 +G1 X 0.486 Y 90.785 +G1 X 0.787 Y 91.402 +G1 X 1.094 Y 92.016 +G1 X 1.407 Y 92.628 +G1 X 1.725 Y 93.236 +G1 X 2.049 Y 93.842 +G1 X 2.381 Y 94.445 +G1 X 2.718 Y 95.045 +G1 X 3.063 Y 95.641 +G1 X 3.413 Y 96.234 +G1 X 3.770 Y 96.822 +G1 X 4.134 Y 97.407 +G1 X 4.482 Y 97.955 +G1 X 4.837 Y 98.498 +G1 X 5.198 Y 99.037 +G1 X 5.565 Y 99.572 +G1 X 5.939 Y 100.103 +G1 X 6.318 Y 100.630 +G1 X 6.682 Y 101.123 +G1 X 7.052 Y 101.612 +G1 X 7.428 Y 102.096 +G1 X 7.810 Y 102.576 +G1 X 8.198 Y 103.051 +G1 X 8.591 Y 103.522 +G1 X 8.969 Y 103.963 +G1 X 9.352 Y 104.399 +G1 X 9.741 Y 104.830 +G1 X 10.136 Y 105.256 +G1 X 10.535 Y 105.677 +G1 X 10.940 Y 106.093 +G1 X 11.330 Y 106.484 +G1 X 11.726 Y 106.869 +G1 X 12.126 Y 107.249 +G1 X 12.531 Y 107.623 +G1 X 12.941 Y 107.993 +G1 X 13.355 Y 108.356 +G1 X 13.760 Y 108.701 +G1 X 14.168 Y 109.041 +G1 X 14.582 Y 109.374 +G1 X 15.000 Y 109.702 +G1 X 15.422 Y 110.024 +G1 X 15.849 Y 110.341 +G1 X 16.255 Y 110.633 +G1 X 16.666 Y 110.920 +G1 X 17.080 Y 111.201 +G1 X 17.498 Y 111.476 +G1 X 17.920 Y 111.745 +G1 X 18.346 Y 112.008 +G1 X 18.775 Y 112.266 +G1 X 19.213 Y 112.519 +G1 X 19.654 Y 112.766 +G1 X 20.100 Y 113.006 +G1 X 20.548 Y 113.240 +G1 X 21.000 Y 113.466 +G1 X 21.456 Y 113.686 +G1 X 21.915 Y 113.899 +G1 X 22.377 Y 114.105 +G1 X 22.797 Y 114.284 +G1 X 23.219 Y 114.457 +G1 X 23.644 Y 114.625 +G1 X 24.071 Y 114.786 +G1 X 24.500 Y 114.940 +G1 X 24.932 Y 115.089 +G1 X 25.366 Y 115.231 +G1 X 25.802 Y 115.366 +G1 X 26.239 Y 115.496 +G1 X 26.679 Y 115.618 +G1 X 27.115 Y 115.733 +G1 X 27.553 Y 115.842 +G1 X 27.993 Y 115.944 +G1 X 28.434 Y 116.039 +G1 X 28.876 Y 116.127 +G1 X 29.320 Y 116.209 +G1 X 29.765 Y 116.284 +G1 X 30.211 Y 116.352 +G1 X 30.658 Y 116.414 +G1 X 31.105 Y 116.468 +G1 X 31.554 Y 116.516 +G1 X 32.003 Y 116.558 +G1 X 32.483 Y 116.594 +G1 X 32.963 Y 116.622 +G1 X 33.444 Y 116.642 +G1 X 33.924 Y 116.655 +G1 X 34.405 Y 116.659 +G1 X 34.886 Y 116.655 +G1 X 35.367 Y 116.644 +G1 X 35.848 Y 116.624 +G1 X 36.328 Y 116.597 +G1 X 36.807 Y 116.561 +G1 X 37.286 Y 116.517 +G1 X 37.765 Y 116.466 +G1 X 38.242 Y 116.406 +G1 X 38.680 Y 116.345 +G1 X 39.118 Y 116.276 +G1 X 39.554 Y 116.200 +G1 X 39.990 Y 116.118 +G1 X 40.423 Y 116.028 +G1 X 40.856 Y 115.932 +G1 X 41.286 Y 115.829 +G1 X 41.715 Y 115.719 +G1 X 42.143 Y 115.602 +G1 X 42.568 Y 115.479 +G1 X 42.991 Y 115.349 +G1 X 43.405 Y 115.215 +G1 X 43.817 Y 115.073 +G1 X 44.226 Y 114.926 +G1 X 44.633 Y 114.771 +G1 X 45.038 Y 114.610 +G1 X 45.439 Y 114.442 +G1 X 45.838 Y 114.268 +G1 X 46.234 Y 114.088 +G1 X 46.627 Y 113.900 +G1 X 46.990 Y 113.720 +G1 X 47.350 Y 113.534 +G1 X 47.707 Y 113.342 +G1 X 48.061 Y 113.145 +G1 X 48.412 Y 112.941 +G1 X 48.759 Y 112.732 +G1 X 49.103 Y 112.517 +G1 X 49.443 Y 112.297 +G1 X 49.754 Y 112.088 +G1 X 50.063 Y 111.874 +G1 X 50.367 Y 111.654 +G1 X 50.668 Y 111.430 +G1 X 50.965 Y 111.201 +G1 X 51.258 Y 110.967 +G1 X 51.548 Y 110.728 +G1 X 51.845 Y 110.473 +G1 X 52.138 Y 110.213 +G1 X 52.425 Y 109.947 +G1 X 52.708 Y 109.676 +G1 X 52.985 Y 109.400 +G1 X 53.257 Y 109.118 +G1 X 53.484 Y 108.875 +G1 X 53.706 Y 108.628 +G1 X 53.924 Y 108.377 +G1 X 53.944 Y 108.358 +G1 X 53.946 Y 108.356 +G1 X 54.004 Y 108.300 +G1 X 54.006 Y 108.298 +G1 X 54.065 Y 108.242 +G1 X 54.066 Y 108.240 +G1 X 54.125 Y 108.184 +G1 X 54.126 Y 108.182 +G1 X 54.184 Y 108.126 +G1 X 54.186 Y 108.124 +G1 X 54.244 Y 108.068 +G1 X 54.246 Y 108.066 +G1 X 54.304 Y 108.009 +G1 X 54.305 Y 108.007 +G1 X 54.363 Y 107.950 +G1 X 54.365 Y 107.949 +G1 X 54.422 Y 107.892 +G1 X 54.424 Y 107.890 +G1 X 54.481 Y 107.833 +G1 X 54.483 Y 107.831 +G1 X 54.540 Y 107.774 +G1 X 54.542 Y 107.772 +G1 X 54.599 Y 107.714 +G1 X 54.601 Y 107.712 +G1 X 54.658 Y 107.655 +G1 X 54.660 Y 107.653 +G1 X 54.716 Y 107.595 +G1 X 54.718 Y 107.593 +G1 X 54.775 Y 107.536 +G1 X 54.776 Y 107.534 +G1 X 54.833 Y 107.476 +G1 X 54.835 Y 107.474 +G1 X 54.891 Y 107.416 +G1 X 54.893 Y 107.414 +G1 X 54.949 Y 107.355 +G1 X 54.951 Y 107.354 +G1 X 55.007 Y 107.295 +G1 X 55.009 Y 107.293 +G1 X 55.064 Y 107.235 +G1 X 55.066 Y 107.233 +G1 X 55.122 Y 107.174 +G1 X 55.124 Y 107.172 +G1 X 55.179 Y 107.113 +G1 X 55.181 Y 107.111 +G1 X 55.237 Y 107.052 +G1 X 55.238 Y 107.050 +G1 X 55.294 Y 106.991 +G1 X 55.295 Y 106.989 +G1 X 55.351 Y 106.930 +G1 X 55.352 Y 106.928 +G1 X 55.407 Y 106.868 +G1 X 55.409 Y 106.867 +G1 X 55.464 Y 106.807 +G1 X 55.466 Y 106.805 +G1 X 55.520 Y 106.745 +G1 X 55.522 Y 106.743 +G1 X 55.577 Y 106.683 +G1 X 55.578 Y 106.681 +G1 X 55.633 Y 106.621 +G1 X 55.635 Y 106.619 +G1 X 55.689 Y 106.559 +G1 X 55.899 Y 106.325 +G1 X 56.107 Y 106.089 +G1 X 56.446 Y 105.695 +G1 X 56.780 Y 105.296 +G1 X 57.108 Y 104.894 +G1 X 57.431 Y 104.486 +G1 X 57.748 Y 104.075 +G1 X 58.060 Y 103.659 +G1 X 58.366 Y 103.239 +G1 X 58.667 Y 102.815 +G1 X 58.961 Y 102.387 +G1 X 59.250 Y 101.955 +G1 X 59.539 Y 101.509 +G1 X 59.822 Y 101.060 +G1 X 60.099 Y 100.606 +G1 X 60.369 Y 100.149 +G1 X 60.632 Y 99.688 +G1 X 60.889 Y 99.224 +G1 X 61.140 Y 98.755 +G1 X 61.384 Y 98.284 +G1 X 61.621 Y 97.808 +G1 X 61.852 Y 97.330 +G1 X 62.076 Y 96.849 +G1 X 62.293 Y 96.364 +G1 X 62.503 Y 95.876 +G1 X 62.706 Y 95.386 +G1 X 62.903 Y 94.892 +G1 X 63.092 Y 94.396 +G1 X 63.275 Y 93.897 +G1 X 63.450 Y 93.398 +G1 X 63.617 Y 92.897 +G1 X 63.778 Y 92.393 +G1 X 63.932 Y 91.886 +G1 X 64.079 Y 91.378 +G1 X 64.218 Y 90.868 +G1 X 64.351 Y 90.356 +G1 X 64.476 Y 89.842 +G1 X 64.595 Y 89.326 +G1 X 64.706 Y 88.809 +G1 X 64.809 Y 88.290 +G1 X 64.906 Y 87.770 +G1 X 64.998 Y 87.232 +G1 X 65.082 Y 86.693 +G1 X 65.159 Y 86.153 +G1 X 65.228 Y 85.612 +G1 X 65.289 Y 85.070 +G1 X 65.342 Y 84.527 +G1 X 65.388 Y 83.984 +G1 X 65.426 Y 83.439 +G1 X 65.456 Y 82.895 +G1 X 65.479 Y 82.350 +G1 X 65.494 Y 81.804 +G1 X 65.501 Y 81.259 +G1 X 65.500 Y 80.713 +G1 X 65.491 Y 80.168 +G1 X 65.475 Y 79.623 +G1 X 65.451 Y 79.078 +G1 X 65.419 Y 78.533 +G1 X 65.379 Y 77.989 +G1 X 65.332 Y 77.445 +G1 X 65.277 Y 76.903 +G1 X 65.214 Y 76.361 +G1 X 65.144 Y 75.820 +G1 X 65.066 Y 75.280 +G1 X 64.981 Y 74.751 +G1 X 64.889 Y 74.223 +G1 X 64.790 Y 73.696 +G1 X 64.684 Y 73.170 +G1 X 64.570 Y 72.647 +G1 X 64.449 Y 72.125 +G1 X 64.320 Y 71.604 +G1 X 64.184 Y 71.086 +G1 X 64.041 Y 70.569 +G1 X 63.891 Y 70.055 +G1 X 63.733 Y 69.542 +G1 X 63.568 Y 69.032 +G1 X 63.396 Y 68.525 +G1 X 63.217 Y 68.019 +G1 X 63.031 Y 67.517 +G1 X 62.838 Y 67.017 +G1 X 62.644 Y 66.534 +G1 X 62.444 Y 66.055 +G1 X 62.236 Y 65.578 +G1 X 62.023 Y 65.105 +G1 X 61.802 Y 64.634 +G1 X 61.576 Y 64.166 +G1 X 61.343 Y 63.701 +G1 X 61.103 Y 63.240 +G1 X 60.858 Y 62.782 +G1 X 60.606 Y 62.328 +G1 X 60.347 Y 61.877 +G1 X 60.083 Y 61.429 +G1 X 59.813 Y 60.985 +G1 X 59.536 Y 60.545 +G1 X 59.260 Y 60.120 +G1 X 58.979 Y 59.698 +G1 X 58.692 Y 59.279 +G1 X 58.399 Y 58.865 +G1 X 58.101 Y 58.455 +G1 X 57.797 Y 58.048 +G1 X 57.488 Y 57.646 +G1 X 57.174 Y 57.248 +G1 X 56.854 Y 56.854 +G1 X 56.529 Y 56.465 +G1 X 56.192 Y 56.072 +G1 X 55.850 Y 55.684 +G1 X 55.503 Y 55.301 +G1 X 55.151 Y 54.922 +G1 X 54.794 Y 54.548 +G1 X 54.432 Y 54.179 +G1 X 54.065 Y 53.815 +G1 X 53.693 Y 53.456 +G1 X 53.317 Y 53.102 +G1 X 52.935 Y 52.753 +G1 X 30.595 Y 30.413 +G1 X 8.160 Y 7.978 +G1 X 8.157 Y 7.975 +G1 X 7.934 Y 7.759 +G1 X 7.706 Y 7.548 +G1 X 7.473 Y 7.343 +G1 X 7.235 Y 7.143 +G1 X 6.992 Y 6.949 +G1 X 6.745 Y 6.761 +G1 X 6.496 Y 6.580 +G1 X 6.242 Y 6.405 +G1 X 5.984 Y 6.236 +G1 X 5.723 Y 6.073 +G1 X 5.457 Y 5.917 +G1 X 5.188 Y 5.767 +G1 X 4.915 Y 5.623 +G1 X 4.639 Y 5.486 +G1 X 4.360 Y 5.356 +G1 X 4.078 Y 5.232 +G1 X 3.793 Y 5.115 +G1 X 3.505 Y 5.004 +G1 X 3.215 Y 4.901 +G1 X 2.922 Y 4.804 +G1 X 2.627 Y 4.715 +G1 X -0.627 Y 0.715 +G1 X -2.627 Y -2.715 +G1 X -4.627 Y -4.715 +G1 X -6.627 Y -6.715 +G1 X -8.627 Y -8.715 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 +G0 X 0.000 Y 0.000 +M2 (Program end) diff --git a/src/jetmax_demos/scripts/gcode/happy.ngc b/src/jetmax_demos/scripts/gcode/happy.ngc new file mode 100644 index 0000000..d6e03e8 --- /dev/null +++ b/src/jetmax_demos/scripts/gcode/happy.ngc @@ -0,0 +1,1256 @@ +(Generated with: DXF2GCODE, Version: Py3.7.10 PyQt5.10.1, Date: $Date: Fri Oct 25 20:45:56 2019 +0200 $) +(Created from file: /home/lucas/大笑.dxf) +(Output format description: G-CODE for LinuxCNC) +(Time: Sat Jul 17 11:14:06 2021) +G21 (Units in millimeters) +G90 (Absolute programming) +G64 (Default cutting) G17 (XY plane) G40 (Cancel radius comp.) G49 (Cancel length comp.) +G0 Z 100.000 + +(*** LAYER: 0 ***) +T1 M6 +S6000 + +(* SHAPE Nr: 0 *) +G0 X 54.703 Y 136.723 +M3 M8 +G0 Z 30.000 +F150 +G1 Z 30.000 +F400 +G1 X 55.256 Y 136.164 +G1 X 55.804 Y 135.599 +G1 X 56.345 Y 135.029 +G1 X 56.881 Y 134.454 +G1 X 57.412 Y 133.873 +G1 X 57.936 Y 133.286 +G1 X 58.454 Y 132.694 +G1 X 58.966 Y 132.098 +G1 X 59.472 Y 131.495 +G1 X 59.972 Y 130.888 +G1 X 60.466 Y 130.276 +G1 X 60.953 Y 129.659 +G1 X 61.435 Y 129.037 +G1 X 61.909 Y 128.410 +G1 X 62.378 Y 127.778 +G1 X 62.840 Y 127.141 +G1 X 63.295 Y 126.500 +G1 X 63.744 Y 125.854 +G1 X 64.187 Y 125.204 +G1 X 64.622 Y 124.549 +G1 X 65.051 Y 123.890 +G1 X 65.474 Y 123.226 +G1 X 65.889 Y 122.559 +G1 X 66.298 Y 121.887 +G1 X 66.700 Y 121.210 +G1 X 67.095 Y 120.530 +G1 X 67.483 Y 119.846 +G1 X 67.864 Y 119.158 +G1 X 68.238 Y 118.466 +G1 X 68.605 Y 117.771 +G1 X 68.965 Y 117.071 +G1 X 69.318 Y 116.368 +G1 X 69.663 Y 115.662 +G1 X 70.002 Y 114.952 +G1 X 70.333 Y 114.238 +G1 X 70.657 Y 113.522 +G1 X 70.974 Y 112.802 +G1 X 71.283 Y 112.079 +G1 X 71.585 Y 111.352 +G1 X 71.879 Y 110.623 +G1 X 72.166 Y 109.891 +G1 X 72.446 Y 109.156 +G1 X 72.718 Y 108.418 +G1 X 72.983 Y 107.677 +G1 X 73.240 Y 106.934 +G1 X 73.489 Y 106.188 +G1 X 73.731 Y 105.439 +G1 X 73.966 Y 104.688 +G1 X 74.192 Y 103.935 +G1 X 74.411 Y 103.180 +G1 X 74.622 Y 102.422 +G1 X 74.826 Y 101.663 +G1 X 75.022 Y 100.901 +G1 X 75.210 Y 100.137 +G1 X 75.390 Y 99.372 +G1 X 75.563 Y 98.604 +G1 X 75.727 Y 97.835 +G1 X 75.884 Y 97.064 +G1 X 76.033 Y 96.292 +G1 X 76.175 Y 95.518 +G1 X 76.308 Y 94.743 +G1 X 76.433 Y 93.967 +G1 X 76.551 Y 93.189 +G1 X 76.660 Y 92.410 +G1 X 76.762 Y 91.630 +G1 X 76.856 Y 90.849 +G1 X 76.942 Y 90.067 +G1 X 77.019 Y 89.285 +G1 X 77.089 Y 88.501 +G1 X 77.151 Y 87.717 +G1 X 77.205 Y 86.933 +G1 X 77.251 Y 86.147 +G1 X 77.289 Y 85.362 +G1 X 77.319 Y 84.576 +G1 X 77.341 Y 83.790 +G1 X 77.355 Y 83.003 +G1 X 77.361 Y 82.217 +G1 X 77.359 Y 81.430 +G1 X 77.349 Y 80.644 +G1 X 77.331 Y 79.857 +G1 X 77.305 Y 79.071 +G1 X 77.271 Y 78.286 +G1 X 77.229 Y 77.500 +G1 X 77.179 Y 76.715 +G1 X 77.121 Y 75.931 +G1 X 77.055 Y 75.147 +G1 X 76.981 Y 74.364 +G1 X 76.900 Y 73.582 +G1 X 76.810 Y 72.800 +G1 X 76.712 Y 72.020 +G1 X 76.607 Y 71.241 +G1 X 76.493 Y 70.462 +G1 X 76.372 Y 69.685 +G1 X 76.242 Y 68.909 +G1 X 76.105 Y 68.135 +G1 X 75.960 Y 67.362 +G1 X 75.807 Y 66.590 +G1 X 75.646 Y 65.820 +G1 X 75.477 Y 65.052 +G1 X 75.301 Y 64.286 +G1 X 75.117 Y 63.521 +G1 X 74.925 Y 62.758 +G1 X 74.725 Y 61.998 +G1 X 74.518 Y 61.239 +G1 X 74.303 Y 60.482 +G1 X 74.080 Y 59.728 +G1 X 73.849 Y 58.976 +G1 X 73.611 Y 58.226 +G1 X 73.366 Y 57.479 +G1 X 73.112 Y 56.735 +G1 X 72.851 Y 55.993 +G1 X 72.583 Y 55.253 +G1 X 72.307 Y 54.517 +G1 X 72.024 Y 53.783 +G1 X 71.733 Y 53.052 +G1 X 71.435 Y 52.324 +G1 X 71.129 Y 51.600 +G1 X 70.816 Y 50.878 +G1 X 70.496 Y 50.160 +G1 X 70.168 Y 49.445 +G1 X 69.834 Y 48.733 +G1 X 69.492 Y 48.025 +G1 X 69.142 Y 47.320 +G1 X 68.786 Y 46.619 +G1 X 68.423 Y 45.921 +G1 X 68.052 Y 45.228 +G1 X 67.674 Y 44.538 +G1 X 67.290 Y 43.851 +G1 X 66.898 Y 43.169 +G1 X 66.500 Y 42.491 +G1 X 66.095 Y 41.817 +G1 X 65.682 Y 41.147 +G1 X 65.263 Y 40.482 +G1 X 64.838 Y 39.820 +G1 X 64.405 Y 39.163 +G1 X 63.966 Y 38.511 +G1 X 63.521 Y 37.863 +G1 X 63.068 Y 37.219 +G1 X 62.610 Y 36.580 +G1 X 62.144 Y 35.946 +G1 X 61.673 Y 35.317 +G1 X 61.195 Y 34.692 +G1 X 60.710 Y 34.072 +G1 X 60.220 Y 33.457 +G1 X 59.723 Y 32.848 +G1 X 59.220 Y 32.243 +G1 X 58.711 Y 31.644 +G1 X 58.196 Y 31.049 +G1 X 57.674 Y 30.460 +G1 X 57.147 Y 29.877 +G1 X 56.614 Y 29.298 +G1 X 56.075 Y 28.725 +G1 X 55.531 Y 28.158 +G1 X 54.980 Y 27.596 +G1 X 54.424 Y 27.040 +G1 X 53.862 Y 26.490 +G1 X 53.295 Y 25.945 +G1 X 52.722 Y 25.406 +G1 X 52.144 Y 24.873 +G1 X 51.560 Y 24.346 +G1 X 50.971 Y 23.824 +G1 X 50.377 Y 23.309 +G1 X 49.777 Y 22.800 +G1 X 49.172 Y 22.297 +G1 X 48.563 Y 21.800 +G1 X 47.948 Y 21.310 +G1 X 47.328 Y 20.825 +G1 X 46.704 Y 20.347 +G1 X 46.074 Y 19.876 +G1 X 45.440 Y 19.410 +G1 X 44.801 Y 18.952 +G1 X 44.158 Y 18.499 +G1 X 43.509 Y 18.054 +G1 X 42.857 Y 17.615 +G1 X 42.200 Y 17.182 +G1 X 41.539 Y 16.757 +G1 X 40.873 Y 16.338 +G1 X 40.203 Y 15.926 +G1 X 39.529 Y 15.520 +G1 X 38.851 Y 15.122 +G1 X 38.169 Y 14.730 +G1 X 37.483 Y 14.346 +G1 X 36.793 Y 13.968 +G1 X 36.099 Y 13.598 +G1 X 35.401 Y 13.234 +G1 X 34.700 Y 12.878 +G1 X 33.995 Y 12.529 +G1 X 33.287 Y 12.187 +G1 X 32.575 Y 11.852 +G1 X 31.860 Y 11.524 +G1 X 31.142 Y 11.204 +G1 X 30.420 Y 10.891 +G1 X 29.696 Y 10.585 +G1 X 28.968 Y 10.287 +G1 X 28.237 Y 9.996 +G1 X 27.503 Y 9.713 +G1 X 26.767 Y 9.437 +G1 X 26.028 Y 9.169 +G1 X 25.285 Y 8.908 +G1 X 24.541 Y 8.655 +G1 X 23.794 Y 8.409 +G1 X 23.044 Y 8.171 +G1 X 22.292 Y 7.940 +G1 X 21.538 Y 7.717 +G1 X 20.781 Y 7.502 +G1 X 20.023 Y 7.295 +G1 X 19.262 Y 7.095 +G1 X 18.499 Y 6.903 +G1 X 17.734 Y 6.719 +G1 X 16.968 Y 6.543 +G1 X 16.200 Y 6.374 +G1 X 15.430 Y 6.213 +G1 X 14.658 Y 6.060 +G1 X 13.885 Y 5.915 +G1 X 13.111 Y 5.778 +G1 X 12.335 Y 5.649 +G1 X 11.558 Y 5.527 +G1 X 10.780 Y 5.414 +G1 X 10.000 Y 5.308 +G1 X 9.220 Y 5.210 +G1 X 8.438 Y 5.120 +G1 X 7.656 Y 5.039 +G1 X 6.873 Y 4.965 +G1 X 6.089 Y 4.899 +G1 X 5.305 Y 4.841 +G1 X 4.520 Y 4.791 +G1 X 3.735 Y 4.749 +G1 X 2.949 Y 4.715 +G1 X 2.163 Y 4.689 +G1 X 1.376 Y 4.671 +G1 X 0.590 Y 4.661 +G1 X -0.197 Y 4.659 +G1 X -0.983 Y 4.665 +G1 X -1.770 Y 4.679 +G1 X -2.556 Y 4.701 +G1 X -3.342 Y 4.731 +G1 X -4.127 Y 4.769 +G1 X -4.913 Y 4.815 +G1 X -5.697 Y 4.869 +G1 X -6.481 Y 4.931 +G1 X -7.265 Y 5.001 +G1 X -8.047 Y 5.079 +G1 X -8.829 Y 5.164 +G1 X -9.610 Y 5.258 +G1 X -10.390 Y 5.360 +G1 X -11.169 Y 5.469 +G1 X -11.947 Y 5.587 +G1 X -12.723 Y 5.712 +G1 X -13.498 Y 5.846 +G1 X -14.272 Y 5.987 +G1 X -15.044 Y 6.136 +G1 X -15.815 Y 6.293 +G1 X -16.584 Y 6.457 +G1 X -17.351 Y 6.630 +G1 X -18.117 Y 6.810 +G1 X -18.881 Y 6.998 +G1 X -19.642 Y 7.194 +G1 X -20.402 Y 7.398 +G1 X -21.160 Y 7.609 +G1 X -21.915 Y 7.828 +G1 X -22.668 Y 8.055 +G1 X -23.419 Y 8.289 +G1 X -24.168 Y 8.531 +G1 X -24.914 Y 8.780 +G1 X -25.657 Y 9.037 +G1 X -26.398 Y 9.302 +G1 X -27.135 Y 9.574 +G1 X -27.871 Y 9.854 +G1 X -28.603 Y 10.141 +G1 X -29.332 Y 10.435 +G1 X -30.058 Y 10.737 +G1 X -30.782 Y 11.046 +G1 X -31.502 Y 11.363 +G1 X -32.218 Y 11.687 +G1 X -32.932 Y 12.018 +G1 X -33.642 Y 12.357 +G1 X -34.348 Y 12.702 +G1 X -35.051 Y 13.055 +G1 X -35.751 Y 13.415 +G1 X -36.446 Y 13.782 +G1 X -37.138 Y 14.156 +G1 X -37.826 Y 14.537 +G1 X -38.510 Y 14.925 +G1 X -39.190 Y 15.320 +G1 X -39.866 Y 15.722 +G1 X -40.538 Y 16.131 +G1 X -41.206 Y 16.546 +G1 X -41.870 Y 16.969 +G1 X -42.529 Y 17.398 +G1 X -43.184 Y 17.833 +G1 X -43.834 Y 18.276 +G1 X -44.480 Y 18.725 +G1 X -45.121 Y 19.180 +G1 X -45.758 Y 19.642 +G1 X -46.389 Y 20.111 +G1 X -47.017 Y 20.586 +G1 X -47.639 Y 21.067 +G1 X -48.256 Y 21.554 +G1 X -48.868 Y 22.048 +G1 X -49.475 Y 22.548 +G1 X -50.077 Y 23.054 +G1 X -50.674 Y 23.566 +G1 X -51.266 Y 24.084 +G1 X -51.852 Y 24.609 +G1 X -52.433 Y 25.139 +G1 X -53.009 Y 25.675 +G1 X -53.579 Y 26.217 +G1 X -54.144 Y 26.764 +G1 X -54.703 Y 27.317 +G1 X -55.256 Y 27.876 +G1 X -55.804 Y 28.441 +G1 X -56.345 Y 29.011 +G1 X -56.881 Y 29.587 +G1 X -57.412 Y 30.168 +G1 X -57.936 Y 30.754 +G1 X -58.454 Y 31.346 +G1 X -58.966 Y 31.943 +G1 X -59.472 Y 32.545 +G1 X -59.972 Y 33.152 +G1 X -60.466 Y 33.764 +G1 X -60.953 Y 34.381 +G1 X -61.435 Y 35.004 +G1 X -61.909 Y 35.631 +G1 X -62.378 Y 36.262 +G1 X -62.840 Y 36.899 +G1 X -63.295 Y 37.540 +G1 X -63.744 Y 38.186 +G1 X -64.187 Y 38.836 +G1 X -64.622 Y 39.491 +G1 X -65.051 Y 40.150 +G1 X -65.474 Y 40.814 +G1 X -65.889 Y 41.482 +G1 X -66.298 Y 42.154 +G1 X -66.700 Y 42.830 +G1 X -67.095 Y 43.510 +G1 X -67.483 Y 44.194 +G1 X -67.864 Y 44.882 +G1 X -68.238 Y 45.574 +G1 X -68.605 Y 46.270 +G1 X -68.965 Y 46.969 +G1 X -69.318 Y 47.672 +G1 X -69.663 Y 48.378 +G1 X -70.002 Y 49.088 +G1 X -70.333 Y 49.802 +G1 X -70.657 Y 50.519 +G1 X -70.974 Y 51.239 +G1 X -71.283 Y 51.962 +G1 X -71.585 Y 52.688 +G1 X -71.879 Y 53.417 +G1 X -72.166 Y 54.150 +G1 X -72.446 Y 54.885 +G1 X -72.718 Y 55.623 +G1 X -72.983 Y 56.363 +G1 X -73.240 Y 57.107 +G1 X -73.489 Y 57.853 +G1 X -73.731 Y 58.601 +G1 X -73.966 Y 59.352 +G1 X -74.192 Y 60.105 +G1 X -74.411 Y 60.860 +G1 X -74.622 Y 61.618 +G1 X -74.826 Y 62.378 +G1 X -75.022 Y 63.139 +G1 X -75.210 Y 63.903 +G1 X -75.390 Y 64.669 +G1 X -75.563 Y 65.436 +G1 X -75.727 Y 66.205 +G1 X -75.884 Y 66.976 +G1 X -76.033 Y 67.748 +G1 X -76.175 Y 68.522 +G1 X -76.308 Y 69.297 +G1 X -76.433 Y 70.074 +G1 X -76.551 Y 70.851 +G1 X -76.660 Y 71.630 +G1 X -76.762 Y 72.410 +G1 X -76.856 Y 73.191 +G1 X -76.942 Y 73.973 +G1 X -77.019 Y 74.755 +G1 X -77.089 Y 75.539 +G1 X -77.151 Y 76.323 +G1 X -77.205 Y 77.108 +G1 X -77.251 Y 77.893 +G1 X -77.289 Y 78.678 +G1 X -77.319 Y 79.464 +G1 X -77.341 Y 80.251 +G1 X -77.355 Y 81.037 +G1 X -77.361 Y 81.823 +G1 X -77.359 Y 82.610 +G1 X -77.349 Y 83.396 +G1 X -77.331 Y 84.183 +G1 X -77.305 Y 84.969 +G1 X -77.271 Y 85.755 +G1 X -77.229 Y 86.540 +G1 X -77.179 Y 87.325 +G1 X -77.121 Y 88.109 +G1 X -77.055 Y 88.893 +G1 X -76.981 Y 89.676 +G1 X -76.900 Y 90.458 +G1 X -76.810 Y 91.240 +G1 X -76.712 Y 92.020 +G1 X -76.607 Y 92.800 +G1 X -76.493 Y 93.578 +G1 X -76.372 Y 94.355 +G1 X -76.242 Y 95.131 +G1 X -76.105 Y 95.905 +G1 X -75.960 Y 96.678 +G1 X -75.807 Y 97.450 +G1 X -75.646 Y 98.220 +G1 X -75.477 Y 98.988 +G1 X -75.301 Y 99.755 +G1 X -75.117 Y 100.519 +G1 X -74.925 Y 101.282 +G1 X -74.725 Y 102.043 +G1 X -74.518 Y 102.801 +G1 X -74.303 Y 103.558 +G1 X -74.080 Y 104.312 +G1 X -73.849 Y 105.064 +G1 X -73.611 Y 105.814 +G1 X -73.366 Y 106.561 +G1 X -73.112 Y 107.306 +G1 X -72.851 Y 108.048 +G1 X -72.583 Y 108.787 +G1 X -72.307 Y 109.523 +G1 X -72.024 Y 110.257 +G1 X -71.733 Y 110.988 +G1 X -71.435 Y 111.716 +G1 X -71.129 Y 112.441 +G1 X -70.816 Y 113.162 +G1 X -70.496 Y 113.880 +G1 X -70.168 Y 114.596 +G1 X -69.834 Y 115.307 +G1 X -69.492 Y 116.016 +G1 X -69.142 Y 116.720 +G1 X -68.786 Y 117.421 +G1 X -68.423 Y 118.119 +G1 X -68.052 Y 118.813 +G1 X -67.674 Y 119.503 +G1 X -67.290 Y 120.189 +G1 X -66.898 Y 120.871 +G1 X -66.500 Y 121.549 +G1 X -66.095 Y 122.223 +G1 X -65.682 Y 122.893 +G1 X -65.263 Y 123.559 +G1 X -64.838 Y 124.220 +G1 X -64.405 Y 124.877 +G1 X -63.966 Y 125.530 +G1 X -63.521 Y 126.178 +G1 X -63.068 Y 126.821 +G1 X -62.610 Y 127.460 +G1 X -62.144 Y 128.094 +G1 X -61.673 Y 128.724 +G1 X -61.195 Y 129.348 +G1 X -60.710 Y 129.968 +G1 X -60.220 Y 130.583 +G1 X -59.723 Y 131.193 +G1 X -59.220 Y 131.797 +G1 X -58.711 Y 132.397 +G1 X -58.196 Y 132.991 +G1 X -57.674 Y 133.580 +G1 X -57.147 Y 134.164 +G1 X -56.614 Y 134.742 +G1 X -56.075 Y 135.315 +G1 X -55.531 Y 135.882 +G1 X -54.980 Y 136.444 +G1 X -54.424 Y 137.000 +G1 X -53.862 Y 137.551 +G1 X -53.295 Y 138.095 +G1 X -52.722 Y 138.634 +G1 X -52.144 Y 139.167 +G1 X -51.560 Y 139.695 +G1 X -50.971 Y 140.216 +G1 X -50.377 Y 140.731 +G1 X -49.777 Y 141.240 +G1 X -49.172 Y 141.743 +G1 X -48.563 Y 142.240 +G1 X -47.948 Y 142.731 +G1 X -47.328 Y 143.215 +G1 X -46.704 Y 143.693 +G1 X -46.074 Y 144.165 +G1 X -45.440 Y 144.630 +G1 X -44.801 Y 145.089 +G1 X -44.158 Y 145.541 +G1 X -43.509 Y 145.986 +G1 X -42.857 Y 146.425 +G1 X -42.200 Y 146.858 +G1 X -41.539 Y 147.284 +G1 X -40.873 Y 147.702 +G1 X -40.203 Y 148.115 +G1 X -39.529 Y 148.520 +G1 X -38.851 Y 148.918 +G1 X -38.169 Y 149.310 +G1 X -37.483 Y 149.694 +G1 X -36.793 Y 150.072 +G1 X -36.099 Y 150.443 +G1 X -35.401 Y 150.806 +G1 X -34.700 Y 151.162 +G1 X -33.995 Y 151.512 +G1 X -33.287 Y 151.854 +G1 X -32.575 Y 152.189 +G1 X -31.860 Y 152.516 +G1 X -31.142 Y 152.836 +G1 X -30.420 Y 153.149 +G1 X -29.696 Y 153.455 +G1 X -28.968 Y 153.753 +G1 X -28.237 Y 154.044 +G1 X -27.503 Y 154.327 +G1 X -26.767 Y 154.603 +G1 X -26.028 Y 154.872 +G1 X -25.285 Y 155.132 +G1 X -24.541 Y 155.386 +G1 X -23.794 Y 155.631 +G1 X -23.044 Y 155.870 +G1 X -22.292 Y 156.100 +G1 X -21.538 Y 156.323 +G1 X -20.781 Y 156.538 +G1 X -20.023 Y 156.745 +G1 X -19.262 Y 156.945 +G1 X -18.499 Y 157.137 +G1 X -17.734 Y 157.321 +G1 X -16.968 Y 157.498 +G1 X -16.200 Y 157.666 +G1 X -15.430 Y 157.827 +G1 X -14.658 Y 157.980 +G1 X -13.885 Y 158.125 +G1 X -13.111 Y 158.262 +G1 X -12.335 Y 158.392 +G1 X -11.558 Y 158.513 +G1 X -10.780 Y 158.627 +G1 X -10.000 Y 158.732 +G1 X -9.220 Y 158.830 +G1 X -8.438 Y 158.920 +G1 X -7.656 Y 159.002 +G1 X -6.873 Y 159.075 +G1 X -6.089 Y 159.141 +G1 X -5.305 Y 159.199 +G1 X -4.520 Y 159.249 +G1 X -3.735 Y 159.291 +G1 X -2.949 Y 159.325 +G1 X -2.163 Y 159.351 +G1 X -1.376 Y 159.369 +G1 X -0.590 Y 159.379 +G1 X 0.197 Y 159.381 +G1 X 0.983 Y 159.375 +G1 X 1.770 Y 159.361 +G1 X 2.556 Y 159.339 +G1 X 3.342 Y 159.309 +G1 X 4.127 Y 159.271 +G1 X 4.913 Y 159.225 +G1 X 5.697 Y 159.171 +G1 X 6.481 Y 159.109 +G1 X 7.265 Y 159.040 +G1 X 8.047 Y 158.962 +G1 X 8.829 Y 158.876 +G1 X 9.610 Y 158.782 +G1 X 10.390 Y 158.680 +G1 X 11.169 Y 158.571 +G1 X 11.947 Y 158.453 +G1 X 12.723 Y 158.328 +G1 X 13.498 Y 158.195 +G1 X 14.272 Y 158.053 +G1 X 15.044 Y 157.904 +G1 X 15.815 Y 157.748 +G1 X 16.584 Y 157.583 +G1 X 17.351 Y 157.410 +G1 X 18.117 Y 157.230 +G1 X 18.881 Y 157.042 +G1 X 19.642 Y 156.846 +G1 X 20.402 Y 156.643 +G1 X 21.160 Y 156.431 +G1 X 21.915 Y 156.212 +G1 X 22.668 Y 155.986 +G1 X 23.419 Y 155.751 +G1 X 24.168 Y 155.510 +G1 X 24.914 Y 155.260 +G1 X 25.657 Y 155.003 +G1 X 26.398 Y 154.738 +G1 X 27.135 Y 154.466 +G1 X 27.871 Y 154.187 +G1 X 28.603 Y 153.899 +G1 X 29.332 Y 153.605 +G1 X 30.058 Y 153.303 +G1 X 30.782 Y 152.994 +G1 X 31.502 Y 152.677 +G1 X 32.218 Y 152.353 +G1 X 32.932 Y 152.022 +G1 X 33.642 Y 151.684 +G1 X 34.348 Y 151.338 +G1 X 35.051 Y 150.985 +G1 X 35.751 Y 150.625 +G1 X 36.446 Y 150.258 +G1 X 37.138 Y 149.884 +G1 X 37.826 Y 149.503 +G1 X 38.510 Y 149.115 +G1 X 39.190 Y 148.720 +G1 X 39.866 Y 148.318 +G1 X 40.538 Y 147.909 +G1 X 41.206 Y 147.494 +G1 X 41.870 Y 147.072 +G1 X 42.529 Y 146.642 +G1 X 43.184 Y 146.207 +G1 X 43.834 Y 145.764 +G1 X 44.480 Y 145.315 +G1 X 45.121 Y 144.860 +G1 X 45.758 Y 144.398 +G1 X 46.389 Y 143.930 +G1 X 47.017 Y 143.455 +G1 X 47.639 Y 142.974 +G1 X 48.256 Y 142.486 +G1 X 48.868 Y 141.992 +G1 X 49.475 Y 141.492 +G1 X 50.077 Y 140.986 +G1 X 50.674 Y 140.474 +G1 X 51.266 Y 139.956 +G1 X 51.852 Y 139.432 +G1 X 52.433 Y 138.902 +G1 X 53.009 Y 138.366 +G1 X 53.579 Y 137.824 +G1 X 54.144 Y 137.276 +G1 X 54.703 Y 136.723 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 3 *) +G0 X 11.190 Y 98.679 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F400 +G1 X 11.193 Y 98.871 +G1 X 11.200 Y 99.063 +G1 X 11.215 Y 99.294 +G1 X 11.237 Y 99.525 +G1 X 11.265 Y 99.754 +G1 X 11.301 Y 99.983 +G1 X 11.344 Y 100.211 +G1 X 11.393 Y 100.437 +G1 X 11.449 Y 100.662 +G1 X 11.514 Y 100.891 +G1 X 11.585 Y 101.118 +G1 X 11.663 Y 101.344 +G1 X 11.748 Y 101.566 +G1 X 11.839 Y 101.787 +G1 X 11.936 Y 102.004 +G1 X 12.039 Y 102.219 +G1 X 12.164 Y 102.459 +G1 X 12.295 Y 102.695 +G1 X 12.433 Y 102.927 +G1 X 12.578 Y 103.155 +G1 X 12.729 Y 103.379 +G1 X 12.887 Y 103.598 +G1 X 13.052 Y 103.815 +G1 X 13.223 Y 104.027 +G1 X 13.399 Y 104.235 +G1 X 13.581 Y 104.439 +G1 X 13.767 Y 104.638 +G1 X 13.959 Y 104.832 +G1 X 14.181 Y 105.044 +G1 X 14.407 Y 105.252 +G1 X 14.639 Y 105.453 +G1 X 14.875 Y 105.648 +G1 X 15.117 Y 105.838 +G1 X 15.363 Y 106.022 +G1 X 15.637 Y 106.215 +G1 X 15.915 Y 106.402 +G1 X 16.197 Y 106.583 +G1 X 16.484 Y 106.757 +G1 X 16.775 Y 106.923 +G1 X 17.069 Y 107.083 +G1 X 17.363 Y 107.235 +G1 X 17.661 Y 107.380 +G1 X 17.961 Y 107.519 +G1 X 18.264 Y 107.651 +G1 X 18.570 Y 107.777 +G1 X 18.879 Y 107.897 +G1 X 19.189 Y 108.011 +G1 X 19.510 Y 108.120 +G1 X 19.833 Y 108.224 +G1 X 20.157 Y 108.321 +G1 X 20.484 Y 108.412 +G1 X 20.812 Y 108.497 +G1 X 21.142 Y 108.576 +G1 X 21.473 Y 108.648 +G1 X 21.805 Y 108.713 +G1 X 22.185 Y 108.781 +G1 X 22.567 Y 108.840 +G1 X 22.949 Y 108.892 +G1 X 23.333 Y 108.936 +G1 X 23.717 Y 108.972 +G1 X 24.102 Y 109.001 +G1 X 24.487 Y 109.021 +G1 X 24.772 Y 109.032 +G1 X 25.057 Y 109.038 +G1 X 25.342 Y 109.040 +G1 X 25.719 Y 109.036 +G1 X 26.095 Y 109.025 +G1 X 26.472 Y 109.007 +G1 X 26.848 Y 108.981 +G1 X 27.223 Y 108.948 +G1 X 27.598 Y 108.908 +G1 X 27.972 Y 108.860 +G1 X 28.314 Y 108.810 +G1 X 28.656 Y 108.752 +G1 X 28.997 Y 108.689 +G1 X 29.336 Y 108.619 +G1 X 29.674 Y 108.542 +G1 X 30.011 Y 108.459 +G1 X 30.345 Y 108.369 +G1 X 30.678 Y 108.273 +G1 X 30.986 Y 108.178 +G1 X 31.292 Y 108.077 +G1 X 31.596 Y 107.969 +G1 X 31.898 Y 107.856 +G1 X 32.198 Y 107.737 +G1 X 32.495 Y 107.612 +G1 X 32.790 Y 107.482 +G1 X 33.095 Y 107.339 +G1 X 33.396 Y 107.189 +G1 X 33.694 Y 107.032 +G1 X 33.989 Y 106.869 +G1 X 34.280 Y 106.699 +G1 X 34.567 Y 106.522 +G1 X 34.822 Y 106.357 +G1 X 35.074 Y 106.186 +G1 X 35.321 Y 106.009 +G1 X 35.564 Y 105.827 +G1 X 35.803 Y 105.639 +G1 X 36.038 Y 105.445 +G1 X 36.242 Y 105.269 +G1 X 36.442 Y 105.088 +G1 X 36.638 Y 104.902 +G1 X 36.829 Y 104.712 +G1 X 37.016 Y 104.517 +G1 X 37.198 Y 104.318 +G1 X 37.370 Y 104.120 +G1 X 37.537 Y 103.918 +G1 X 37.699 Y 103.711 +G1 X 37.855 Y 103.501 +G1 X 38.005 Y 103.286 +G1 X 38.150 Y 103.068 +G1 X 38.290 Y 102.844 +G1 X 38.424 Y 102.616 +G1 X 38.550 Y 102.384 +G1 X 38.669 Y 102.148 +G1 X 38.781 Y 101.909 +G1 X 38.886 Y 101.667 +G1 X 38.973 Y 101.449 +G1 X 39.053 Y 101.230 +G1 X 39.127 Y 101.007 +G1 X 39.194 Y 100.783 +G1 X 39.254 Y 100.557 +G1 X 39.308 Y 100.330 +G1 X 39.352 Y 100.115 +G1 X 39.390 Y 99.899 +G1 X 39.422 Y 99.683 +G1 X 39.448 Y 99.465 +G1 X 39.467 Y 99.247 +G1 X 39.480 Y 99.028 +G1 X 39.486 Y 98.854 +G1 X 39.488 Y 98.679 +G1 X 42.488 Y 90.679 +F150 +G1 Z 60.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 2 *) +G0 X -41.551 Y 98.679 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F400 +G1 X -41.549 Y 98.871 +G1 X -41.542 Y 99.062 +G1 X -41.527 Y 99.293 +G1 X -41.505 Y 99.524 +G1 X -41.476 Y 99.754 +G1 X -41.440 Y 99.982 +G1 X -41.398 Y 100.210 +G1 X -41.348 Y 100.436 +G1 X -41.292 Y 100.661 +G1 X -41.228 Y 100.890 +G1 X -41.156 Y 101.118 +G1 X -41.078 Y 101.343 +G1 X -40.994 Y 101.566 +G1 X -40.903 Y 101.786 +G1 X -40.806 Y 102.004 +G1 X -40.702 Y 102.219 +G1 X -40.578 Y 102.459 +G1 X -40.447 Y 102.695 +G1 X -40.309 Y 102.927 +G1 X -40.164 Y 103.155 +G1 X -40.013 Y 103.379 +G1 X -39.855 Y 103.598 +G1 X -39.690 Y 103.815 +G1 X -39.519 Y 104.027 +G1 X -39.343 Y 104.235 +G1 X -39.161 Y 104.439 +G1 X -38.974 Y 104.638 +G1 X -38.783 Y 104.832 +G1 X -38.561 Y 105.044 +G1 X -38.335 Y 105.252 +G1 X -38.103 Y 105.453 +G1 X -37.867 Y 105.649 +G1 X -37.625 Y 105.838 +G1 X -37.379 Y 106.022 +G1 X -37.106 Y 106.215 +G1 X -36.828 Y 106.402 +G1 X -36.545 Y 106.583 +G1 X -36.259 Y 106.757 +G1 X -35.968 Y 106.923 +G1 X -35.674 Y 107.083 +G1 X -35.379 Y 107.235 +G1 X -35.082 Y 107.380 +G1 X -34.782 Y 107.519 +G1 X -34.479 Y 107.651 +G1 X -34.173 Y 107.777 +G1 X -33.865 Y 107.897 +G1 X -33.554 Y 108.011 +G1 X -33.234 Y 108.120 +G1 X -32.911 Y 108.224 +G1 X -32.587 Y 108.321 +G1 X -32.261 Y 108.412 +G1 X -31.933 Y 108.497 +G1 X -31.603 Y 108.575 +G1 X -31.272 Y 108.648 +G1 X -30.940 Y 108.713 +G1 X -30.560 Y 108.780 +G1 X -30.179 Y 108.840 +G1 X -29.797 Y 108.892 +G1 X -29.413 Y 108.936 +G1 X -29.029 Y 108.972 +G1 X -28.644 Y 109.001 +G1 X -28.259 Y 109.021 +G1 X -27.975 Y 109.032 +G1 X -27.690 Y 109.038 +G1 X -27.405 Y 109.040 +G1 X -27.028 Y 109.036 +G1 X -26.651 Y 109.025 +G1 X -26.274 Y 109.007 +G1 X -25.898 Y 108.981 +G1 X -25.523 Y 108.948 +G1 X -25.148 Y 108.907 +G1 X -24.774 Y 108.860 +G1 X -24.431 Y 108.809 +G1 X -24.089 Y 108.752 +G1 X -23.749 Y 108.688 +G1 X -23.410 Y 108.618 +G1 X -23.072 Y 108.542 +G1 X -22.736 Y 108.458 +G1 X -22.401 Y 108.369 +G1 X -22.068 Y 108.273 +G1 X -21.760 Y 108.177 +G1 X -21.454 Y 108.076 +G1 X -21.151 Y 107.969 +G1 X -20.849 Y 107.856 +G1 X -20.549 Y 107.737 +G1 X -20.252 Y 107.612 +G1 X -19.957 Y 107.481 +G1 X -19.652 Y 107.338 +G1 X -19.350 Y 107.188 +G1 X -19.052 Y 107.032 +G1 X -18.757 Y 106.868 +G1 X -18.466 Y 106.698 +G1 X -18.179 Y 106.522 +G1 X -17.924 Y 106.357 +G1 X -17.672 Y 106.186 +G1 X -17.424 Y 106.009 +G1 X -17.181 Y 105.826 +G1 X -16.942 Y 105.638 +G1 X -16.707 Y 105.445 +G1 X -16.503 Y 105.268 +G1 X -16.303 Y 105.087 +G1 X -16.107 Y 104.901 +G1 X -15.915 Y 104.711 +G1 X -15.729 Y 104.516 +G1 X -15.546 Y 104.317 +G1 X -15.374 Y 104.119 +G1 X -15.207 Y 103.917 +G1 X -15.045 Y 103.711 +G1 X -14.889 Y 103.500 +G1 X -14.738 Y 103.286 +G1 X -14.592 Y 103.067 +G1 X -14.452 Y 102.843 +G1 X -14.319 Y 102.615 +G1 X -14.193 Y 102.383 +G1 X -14.073 Y 102.147 +G1 X -13.961 Y 101.908 +G1 X -13.856 Y 101.666 +G1 X -13.769 Y 101.448 +G1 X -13.689 Y 101.228 +G1 X -13.615 Y 101.005 +G1 X -13.547 Y 100.780 +G1 X -13.487 Y 100.554 +G1 X -13.433 Y 100.325 +G1 X -13.389 Y 100.111 +G1 X -13.351 Y 99.895 +G1 X -13.319 Y 99.678 +G1 X -13.293 Y 99.461 +G1 X -13.274 Y 99.243 +G1 X -13.261 Y 99.024 +G1 X -13.255 Y 98.851 +G1 X -13.253 Y 98.679 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 1 *) +G0 X -33.758 Y 58.680 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F400 +G1 X -33.758 Y 58.680 +G1 X -36.758 Y 61.680 +G1 X -36.874 Y 62.184 +G1 X -36.982 Y 62.690 +G1 X -37.084 Y 63.198 +G1 X -37.178 Y 63.706 +G1 X -37.266 Y 64.216 +G1 X -37.346 Y 64.727 +G1 X -37.420 Y 65.239 +G1 X -37.486 Y 65.752 +G1 X -37.546 Y 66.266 +G1 X -37.598 Y 66.781 +G1 X -37.643 Y 67.296 +G1 X -37.682 Y 67.812 +G1 X -37.712 Y 68.316 +G1 X -37.736 Y 68.820 +G1 X -37.752 Y 69.325 +G1 X -37.763 Y 69.830 +G1 X -37.766 Y 70.334 +G1 X -37.764 Y 70.487 +G1 X -37.757 Y 70.640 +G1 X -37.741 Y 70.836 +G1 X -37.718 Y 71.030 +G1 X -37.687 Y 71.224 +G1 X -37.648 Y 71.416 +G1 X -37.602 Y 71.606 +G1 X -37.549 Y 71.797 +G1 X -37.487 Y 71.985 +G1 X -37.419 Y 72.170 +G1 X -37.343 Y 72.353 +G1 X -37.260 Y 72.532 +G1 X -37.170 Y 72.708 +G1 X -37.074 Y 72.880 +G1 X -36.972 Y 73.046 +G1 X -36.864 Y 73.207 +G1 X -36.750 Y 73.364 +G1 X -36.630 Y 73.517 +G1 X -36.505 Y 73.664 +G1 X -36.401 Y 73.778 +G1 X -36.294 Y 73.889 +G1 X -36.184 Y 73.996 +G1 X -36.071 Y 74.099 +G1 X -35.921 Y 74.226 +G1 X -35.767 Y 74.347 +G1 X -35.609 Y 74.462 +G1 X -35.445 Y 74.571 +G1 X -35.278 Y 74.673 +G1 X -35.106 Y 74.769 +G1 X -34.930 Y 74.859 +G1 X -34.750 Y 74.941 +G1 X -34.567 Y 75.017 +G1 X -34.382 Y 75.085 +G1 X -34.194 Y 75.146 +G1 X -34.004 Y 75.200 +G1 X -33.815 Y 75.245 +G1 X -33.625 Y 75.283 +G1 X -33.433 Y 75.313 +G1 X -33.240 Y 75.336 +G1 X -33.047 Y 75.352 +G1 X -32.893 Y 75.359 +G1 X -32.739 Y 75.361 +G1 X 32.660 Y 75.361 +G1 X 32.813 Y 75.359 +G1 X 32.966 Y 75.352 +G1 X 33.162 Y 75.336 +G1 X 33.356 Y 75.313 +G1 X 33.550 Y 75.282 +G1 X 33.742 Y 75.244 +G1 X 33.932 Y 75.198 +G1 X 34.123 Y 75.144 +G1 X 34.311 Y 75.083 +G1 X 34.496 Y 75.014 +G1 X 34.679 Y 74.938 +G1 X 34.858 Y 74.855 +G1 X 35.034 Y 74.766 +G1 X 35.206 Y 74.669 +G1 X 35.372 Y 74.567 +G1 X 35.533 Y 74.460 +G1 X 35.690 Y 74.346 +G1 X 35.843 Y 74.226 +G1 X 35.990 Y 74.100 +G1 X 36.104 Y 73.996 +G1 X 36.215 Y 73.889 +G1 X 36.322 Y 73.779 +G1 X 36.425 Y 73.666 +G1 X 36.552 Y 73.517 +G1 X 36.673 Y 73.362 +G1 X 36.788 Y 73.204 +G1 X 36.897 Y 73.041 +G1 X 36.999 Y 72.874 +G1 X 37.095 Y 72.701 +G1 X 37.185 Y 72.525 +G1 X 37.267 Y 72.345 +G1 X 37.343 Y 72.163 +G1 X 37.411 Y 71.977 +G1 X 37.472 Y 71.789 +G1 X 37.526 Y 71.599 +G1 X 37.571 Y 71.410 +G1 X 37.609 Y 71.220 +G1 X 37.639 Y 71.028 +G1 X 37.662 Y 70.836 +G1 X 37.678 Y 70.642 +G1 X 37.685 Y 70.488 +G1 X 37.687 Y 70.334 +G1 X 37.684 Y 69.830 +G1 X 37.674 Y 69.325 +G1 X 37.657 Y 68.821 +G1 X 37.633 Y 68.316 +G1 X 37.603 Y 67.813 +G1 X 37.565 Y 67.296 +G1 X 37.519 Y 66.779 +G1 X 37.467 Y 66.263 +G1 X 37.407 Y 65.748 +G1 X 37.340 Y 65.234 +G1 X 37.267 Y 64.721 +G1 X 37.186 Y 64.208 +G1 X 37.098 Y 63.697 +G1 X 37.003 Y 63.188 +G1 X 36.901 Y 62.679 +G1 X 36.792 Y 62.172 +G1 X 36.676 Y 61.667 +G1 X 36.553 Y 61.163 +G1 X 36.421 Y 60.653 +G1 X 36.283 Y 60.146 +G1 X 36.136 Y 59.640 +G1 X 35.983 Y 59.136 +G1 X 35.823 Y 58.634 +G1 X 35.656 Y 58.135 +G1 X 35.482 Y 57.638 +G1 X 35.301 Y 57.144 +G1 X 35.113 Y 56.652 +G1 X 34.918 Y 56.163 +G1 X 34.717 Y 55.676 +G1 X 34.508 Y 55.193 +G1 X 34.293 Y 54.712 +G1 X 34.072 Y 54.235 +G1 X 33.843 Y 53.760 +G1 X 33.608 Y 53.289 +G1 X 33.366 Y 52.822 +G1 X 33.118 Y 52.357 +G1 X 32.864 Y 51.896 +G1 X 32.603 Y 51.439 +G1 X 32.335 Y 50.985 +G1 X 32.066 Y 50.543 +G1 X 31.791 Y 50.105 +G1 X 31.510 Y 49.671 +G1 X 31.224 Y 49.240 +G1 X 30.931 Y 48.814 +G1 X 30.632 Y 48.391 +G1 X 30.328 Y 47.973 +G1 X 30.018 Y 47.559 +G1 X 29.702 Y 47.149 +G1 X 29.380 Y 46.744 +G1 X 29.053 Y 46.343 +G1 X 28.721 Y 45.946 +G1 X 28.383 Y 45.554 +G1 X 28.048 Y 45.177 +G1 X 27.709 Y 44.803 +G1 X 27.364 Y 44.435 +G1 X 27.014 Y 44.071 +G1 X 26.660 Y 43.711 +G1 X 26.300 Y 43.357 +G1 X 25.936 Y 43.007 +G1 X 25.568 Y 42.663 +G1 X 25.195 Y 42.323 +G1 X 24.817 Y 41.988 +G1 X 24.424 Y 41.649 +G1 X 24.027 Y 41.316 +G1 X 23.625 Y 40.989 +G1 X 23.219 Y 40.667 +G1 X 22.808 Y 40.350 +G1 X 22.393 Y 40.039 +G1 X 21.973 Y 39.734 +G1 X 21.550 Y 39.435 +G1 X 21.122 Y 39.142 +G1 X 20.691 Y 38.854 +G1 X 20.255 Y 38.573 +G1 X 19.816 Y 38.298 +G1 X 19.373 Y 38.028 +G1 X 18.919 Y 37.761 +G1 X 18.462 Y 37.500 +G1 X 18.001 Y 37.246 +G1 X 17.536 Y 36.998 +G1 X 17.069 Y 36.756 +G1 X 16.597 Y 36.521 +G1 X 16.123 Y 36.293 +G1 X 15.645 Y 36.072 +G1 X 15.165 Y 35.857 +G1 X 14.681 Y 35.648 +G1 X 14.195 Y 35.447 +G1 X 13.705 Y 35.252 +G1 X 13.213 Y 35.065 +G1 X 12.719 Y 34.884 +G1 X 12.222 Y 34.710 +G1 X 11.723 Y 34.543 +G1 X 11.221 Y 34.383 +G1 X 10.717 Y 34.230 +G1 X 10.211 Y 34.085 +G1 X 9.703 Y 33.946 +G1 X 9.194 Y 33.814 +G1 X 8.691 Y 33.692 +G1 X 8.187 Y 33.576 +G1 X 7.681 Y 33.468 +G1 X 7.173 Y 33.366 +G1 X 6.665 Y 33.272 +G1 X 6.155 Y 33.184 +G1 X 5.644 Y 33.103 +G1 X 5.132 Y 33.030 +G1 X 4.619 Y 32.963 +G1 X 4.105 Y 32.904 +G1 X 3.590 Y 32.852 +G1 X 3.075 Y 32.806 +G1 X 2.559 Y 32.768 +G1 X 2.055 Y 32.738 +G1 X 1.551 Y 32.714 +G1 X 1.046 Y 32.697 +G1 X 0.541 Y 32.687 +G1 X 0.037 Y 32.684 +G1 X -0.115 Y 32.684 +G1 X -0.620 Y 32.687 +G1 X -1.125 Y 32.697 +G1 X -1.629 Y 32.714 +G1 X -2.133 Y 32.738 +G1 X -2.637 Y 32.768 +G1 X -3.154 Y 32.806 +G1 X -3.671 Y 32.852 +G1 X -4.187 Y 32.904 +G1 X -4.702 Y 32.964 +G1 X -5.216 Y 33.031 +G1 X -5.729 Y 33.104 +G1 X -6.241 Y 33.185 +G1 X -6.752 Y 33.273 +G1 X -7.262 Y 33.368 +G1 X -7.771 Y 33.470 +G1 X -8.277 Y 33.579 +G1 X -8.783 Y 33.695 +G1 X -9.287 Y 33.818 +G1 X -9.796 Y 33.950 +G1 X -10.304 Y 34.088 +G1 X -10.810 Y 34.235 +G1 X -11.314 Y 34.388 +G1 X -11.815 Y 34.548 +G1 X -12.315 Y 34.715 +G1 X -12.812 Y 34.889 +G1 X -13.306 Y 35.070 +G1 X -13.798 Y 35.258 +G1 X -14.287 Y 35.453 +G1 X -14.773 Y 35.654 +G1 X -15.257 Y 35.863 +G1 X -15.737 Y 36.078 +G1 X -16.215 Y 36.299 +G1 X -16.689 Y 36.528 +G1 X -17.160 Y 36.763 +G1 X -17.628 Y 37.005 +G1 X -18.093 Y 37.253 +G1 X -18.553 Y 37.507 +G1 X -19.011 Y 37.768 +G1 X -19.464 Y 38.036 +G1 X -19.906 Y 38.305 +G1 X -20.345 Y 38.580 +G1 X -20.779 Y 38.861 +G1 X -21.209 Y 39.147 +G1 X -21.636 Y 39.440 +G1 X -22.059 Y 39.739 +G1 X -22.477 Y 40.043 +G1 X -22.891 Y 40.353 +G1 X -23.301 Y 40.669 +G1 X -23.706 Y 40.991 +G1 X -24.107 Y 41.318 +G1 X -24.504 Y 41.650 +G1 X -24.895 Y 41.988 +G1 X -25.273 Y 42.323 +G1 X -25.646 Y 42.662 +G1 X -26.015 Y 43.007 +G1 X -26.379 Y 43.357 +G1 X -26.738 Y 43.711 +G1 X -27.093 Y 44.071 +G1 X -27.443 Y 44.435 +G1 X -27.787 Y 44.803 +G1 X -28.127 Y 45.176 +G1 X -28.462 Y 45.554 +G1 X -28.800 Y 45.947 +G1 X -29.133 Y 46.344 +G1 X -29.461 Y 46.746 +G1 X -29.783 Y 47.152 +G1 X -30.100 Y 47.563 +G1 X -30.410 Y 47.978 +G1 X -30.715 Y 48.398 +G1 X -31.015 Y 48.821 +G1 X -31.308 Y 49.249 +G1 X -31.595 Y 49.680 +G1 X -31.877 Y 50.116 +G1 X -32.152 Y 50.555 +G1 X -32.422 Y 50.998 +G1 X -32.689 Y 51.452 +G1 X -32.950 Y 51.909 +G1 X -33.204 Y 52.370 +G1 X -33.452 Y 52.835 +G1 X -33.693 Y 53.302 +G1 X -33.928 Y 53.774 +G1 X -34.157 Y 54.248 +G1 X -34.378 Y 54.726 +G1 X -34.593 Y 55.206 +G1 X -34.801 Y 55.690 +G1 X -35.003 Y 56.176 +G1 X -35.197 Y 56.666 +G1 X -35.385 Y 57.158 +G1 X -35.566 Y 57.652 +G1 X -35.740 Y 58.149 +G1 X -35.907 Y 58.648 +G1 X -36.067 Y 59.150 +G1 X -36.219 Y 59.654 +G1 X -36.365 Y 60.160 +G1 X -36.504 Y 60.668 +G1 X -36.636 Y 61.177 +G1 X -33.758 Y 58.680 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 +G0 X 0.000 Y 0.000 +M2 (Program end) diff --git a/src/jetmax_demos/scripts/gcode/jy.ngc b/src/jetmax_demos/scripts/gcode/jy.ngc new file mode 100644 index 0000000..aa020a2 --- /dev/null +++ b/src/jetmax_demos/scripts/gcode/jy.ngc @@ -0,0 +1,1570 @@ +(Generated with: DXF2GCODE, Version: Py3.7.10 PyQt5.10.1, Date: $Date: Fri Oct 25 20:45:56 2019 +0200 $) +(Created from file: /home/lucas/jy.dxf) +(Output format description: G-CODE for LinuxCNC) +(Time: Sat Jul 17 10:53:55 2021) +G21 (Units in millimeters) +G90 (Absolute programming) +G64 (Default cutting) G17 (XY plane) G40 (Cancel radius comp.) G49 (Cancel length comp.) +G0 Z 100.000 + +(*** LAYER: 0 ***) +T1 M6 +S6000 + +(* SHAPE Nr: 0 *) +G0 X 77.104 Y 81.591 +M3 M8 +G0 Z 30.000 +F150 +G1 Z 30.000 +F400 +G1 X 77.151 Y 80.845 +G1 X 77.191 Y 80.098 +G1 X 77.223 Y 79.351 +G1 X 77.249 Y 78.604 +G1 X 77.267 Y 77.856 +G1 X 77.277 Y 77.109 +G1 X 77.281 Y 76.361 +G1 X 77.278 Y 75.627 +G1 X 77.267 Y 74.893 +G1 X 77.250 Y 74.160 +G1 X 77.226 Y 73.426 +G1 X 77.194 Y 72.693 +G1 X 77.156 Y 71.960 +G1 X 77.111 Y 71.227 +G1 X 77.059 Y 70.495 +G1 X 77.000 Y 69.763 +G1 X 76.934 Y 69.032 +G1 X 76.862 Y 68.302 +G1 X 76.779 Y 67.549 +G1 X 76.690 Y 66.796 +G1 X 76.592 Y 66.045 +G1 X 76.488 Y 65.294 +G1 X 76.376 Y 64.544 +G1 X 76.257 Y 63.796 +G1 X 76.130 Y 63.049 +G1 X 75.996 Y 62.303 +G1 X 75.855 Y 61.558 +G1 X 75.706 Y 60.815 +G1 X 75.551 Y 60.073 +G1 X 75.387 Y 59.333 +G1 X 75.217 Y 58.595 +G1 X 75.039 Y 57.858 +G1 X 74.855 Y 57.123 +G1 X 74.663 Y 56.390 +G1 X 74.463 Y 55.659 +G1 X 74.257 Y 54.930 +G1 X 74.043 Y 54.203 +G1 X 73.823 Y 53.478 +G1 X 73.595 Y 52.755 +G1 X 73.360 Y 52.034 +G1 X 73.118 Y 51.316 +G1 X 72.869 Y 50.600 +G1 X 72.613 Y 49.887 +G1 X 72.350 Y 49.176 +G1 X 72.080 Y 48.468 +G1 X 71.797 Y 47.748 +G1 X 71.507 Y 47.030 +G1 X 71.210 Y 46.315 +G1 X 70.906 Y 45.604 +G1 X 70.594 Y 44.895 +G1 X 70.276 Y 44.190 +G1 X 69.950 Y 43.488 +G1 X 69.618 Y 42.789 +G1 X 69.278 Y 42.093 +G1 X 68.932 Y 41.401 +G1 X 68.578 Y 40.713 +G1 X 68.218 Y 40.028 +G1 X 67.851 Y 39.346 +G1 X 67.477 Y 38.668 +G1 X 67.097 Y 37.994 +G1 X 66.710 Y 37.324 +G1 X 66.316 Y 36.658 +G1 X 65.915 Y 35.996 +G1 X 65.508 Y 35.338 +G1 X 65.094 Y 34.684 +G1 X 64.674 Y 34.034 +G1 X 64.247 Y 33.388 +G1 X 63.814 Y 32.747 +G1 X 63.375 Y 32.109 +G1 X 62.929 Y 31.477 +G1 X 62.477 Y 30.849 +G1 X 62.018 Y 30.225 +G1 X 61.553 Y 29.606 +G1 X 61.083 Y 28.992 +G1 X 60.606 Y 28.382 +G1 X 60.123 Y 27.777 +G1 X 59.634 Y 27.178 +G1 X 59.139 Y 26.582 +G1 X 58.638 Y 25.992 +G1 X 58.131 Y 25.407 +G1 X 57.619 Y 24.828 +G1 X 57.100 Y 24.253 +G1 X 56.576 Y 23.683 +G1 X 56.047 Y 23.119 +G1 X 55.511 Y 22.560 +G1 X 54.970 Y 22.006 +G1 X 54.424 Y 21.458 +G1 X 53.872 Y 20.916 +G1 X 53.315 Y 20.378 +G1 X 52.764 Y 19.858 +G1 X 52.208 Y 19.342 +G1 X 51.647 Y 18.833 +G1 X 51.081 Y 18.328 +G1 X 50.510 Y 17.830 +G1 X 49.934 Y 17.337 +G1 X 49.353 Y 16.849 +G1 X 48.768 Y 16.368 +G1 X 48.177 Y 15.892 +G1 X 47.583 Y 15.422 +G1 X 46.983 Y 14.958 +G1 X 46.379 Y 14.500 +G1 X 45.771 Y 14.047 +G1 X 45.158 Y 13.601 +G1 X 44.541 Y 13.161 +G1 X 43.919 Y 12.727 +G1 X 43.294 Y 12.299 +G1 X 42.664 Y 11.877 +G1 X 42.030 Y 11.461 +G1 X 41.392 Y 11.052 +G1 X 40.750 Y 10.649 +G1 X 40.104 Y 10.252 +G1 X 39.454 Y 9.862 +G1 X 38.800 Y 9.478 +G1 X 38.143 Y 9.100 +G1 X 37.482 Y 8.729 +G1 X 36.817 Y 8.364 +G1 X 36.170 Y 8.017 +G1 X 35.519 Y 7.676 +G1 X 34.865 Y 7.341 +G1 X 34.208 Y 7.013 +G1 X 33.547 Y 6.690 +G1 X 32.884 Y 6.374 +G1 X 32.218 Y 6.065 +G1 X 31.549 Y 5.761 +G1 X 30.877 Y 5.464 +G1 X 30.202 Y 5.173 +G1 X 29.525 Y 4.889 +G1 X 28.845 Y 4.611 +G1 X 28.163 Y 4.340 +G1 X 27.479 Y 4.075 +G1 X 26.792 Y 3.817 +G1 X 26.102 Y 3.565 +G1 X 25.410 Y 3.320 +G1 X 24.716 Y 3.081 +G1 X 24.020 Y 2.849 +G1 X 23.322 Y 2.623 +G1 X 22.621 Y 2.404 +G1 X 21.918 Y 2.192 +G1 X 21.191 Y 1.980 +G1 X 20.461 Y 1.775 +G1 X 19.730 Y 1.577 +G1 X 18.996 Y 1.386 +G1 X 18.261 Y 1.203 +G1 X 17.524 Y 1.027 +G1 X 16.785 Y 0.858 +G1 X 16.045 Y 0.696 +G1 X 15.303 Y 0.541 +G1 X 14.559 Y 0.394 +G1 X 13.814 Y 0.254 +G1 X 13.068 Y 0.122 +G1 X 12.321 Y -0.003 +G1 X 11.572 Y -0.121 +G1 X 10.822 Y -0.232 +G1 X 10.072 Y -0.335 +G1 X 9.320 Y -0.430 +G1 X 8.567 Y -0.519 +G1 X 7.814 Y -0.600 +G1 X 7.059 Y -0.673 +G1 X 6.304 Y -0.739 +G1 X 5.549 Y -0.798 +G1 X 4.793 Y -0.849 +G1 X 4.036 Y -0.893 +G1 X 3.279 Y -0.930 +G1 X 2.522 Y -0.959 +G1 X 1.764 Y -0.980 +G1 X 0.991 Y -0.995 +G1 X 0.217 Y -1.001 +G1 X -0.557 Y -1.000 +G1 X -1.331 Y -0.991 +G1 X -2.105 Y -0.975 +G1 X -2.879 Y -0.950 +G1 X -3.652 Y -0.918 +G1 X -4.425 Y -0.879 +G1 X -5.197 Y -0.831 +G1 X -5.969 Y -0.776 +G1 X -6.741 Y -0.713 +G1 X -7.512 Y -0.643 +G1 X -8.282 Y -0.564 +G1 X -9.051 Y -0.478 +G1 X -9.819 Y -0.385 +G1 X -10.586 Y -0.283 +G1 X -11.353 Y -0.174 +G1 X -12.118 Y -0.058 +G1 X -12.882 Y 0.067 +G1 X -13.644 Y 0.199 +G1 X -14.405 Y 0.338 +G1 X -15.165 Y 0.485 +G1 X -15.924 Y 0.640 +G1 X -16.680 Y 0.802 +G1 X -17.436 Y 0.972 +G1 X -18.189 Y 1.149 +G1 X -18.940 Y 1.334 +G1 X -19.690 Y 1.527 +G1 X -20.438 Y 1.727 +G1 X -21.184 Y 1.934 +G1 X -21.927 Y 2.149 +G1 X -22.669 Y 2.371 +G1 X -23.408 Y 2.600 +G1 X -24.144 Y 2.837 +G1 X -24.879 Y 3.082 +G1 X -25.611 Y 3.333 +G1 X -26.340 Y 3.592 +G1 X -27.067 Y 3.858 +G1 X -27.791 Y 4.132 +G1 X -28.512 Y 4.413 +G1 X -29.231 Y 4.700 +G1 X -29.946 Y 4.995 +G1 X -30.659 Y 5.298 +G1 X -31.368 Y 5.607 +G1 X -32.060 Y 5.917 +G1 X -32.749 Y 6.233 +G1 X -33.435 Y 6.557 +G1 X -34.117 Y 6.887 +G1 X -34.796 Y 7.223 +G1 X -35.472 Y 7.567 +G1 X -36.145 Y 7.917 +G1 X -36.814 Y 8.273 +G1 X -37.479 Y 8.636 +G1 X -38.141 Y 9.006 +G1 X -38.799 Y 9.382 +G1 X -39.454 Y 9.765 +G1 X -40.104 Y 10.154 +G1 X -40.751 Y 10.549 +G1 X -41.394 Y 10.951 +G1 X -42.033 Y 11.359 +G1 X -42.668 Y 11.773 +G1 X -43.299 Y 12.194 +G1 X -43.925 Y 12.621 +G1 X -44.548 Y 13.053 +G1 X -45.166 Y 13.492 +G1 X -45.780 Y 13.937 +G1 X -46.389 Y 14.388 +G1 X -46.994 Y 14.845 +G1 X -47.594 Y 15.308 +G1 X -48.190 Y 15.777 +G1 X -48.781 Y 16.251 +G1 X -49.350 Y 16.717 +G1 X -49.914 Y 17.187 +G1 X -50.473 Y 17.664 +G1 X -51.028 Y 18.145 +G1 X -51.579 Y 18.632 +G1 X -52.125 Y 19.123 +G1 X -52.666 Y 19.620 +G1 X -53.202 Y 20.122 +G1 X -53.734 Y 20.629 +G1 X -54.261 Y 21.142 +G1 X -54.783 Y 21.659 +G1 X -55.300 Y 22.180 +G1 X -55.811 Y 22.707 +G1 X -56.318 Y 23.238 +G1 X -56.820 Y 23.774 +G1 X -57.317 Y 24.315 +G1 X -57.808 Y 24.861 +G1 X -58.294 Y 25.411 +G1 X -58.776 Y 25.965 +G1 X -59.251 Y 26.525 +G1 X -59.722 Y 27.088 +G1 X -60.187 Y 27.656 +G1 X -60.666 Y 28.253 +G1 X -61.139 Y 28.855 +G1 X -61.606 Y 29.461 +G1 X -62.068 Y 30.072 +G1 X -62.523 Y 30.687 +G1 X -62.972 Y 31.307 +G1 X -63.414 Y 31.931 +G1 X -63.851 Y 32.560 +G1 X -64.281 Y 33.193 +G1 X -64.705 Y 33.830 +G1 X -65.123 Y 34.471 +G1 X -65.534 Y 35.116 +G1 X -65.939 Y 35.766 +G1 X -66.337 Y 36.419 +G1 X -66.729 Y 37.077 +G1 X -67.114 Y 37.738 +G1 X -67.493 Y 38.403 +G1 X -67.865 Y 39.072 +G1 X -68.231 Y 39.744 +G1 X -68.589 Y 40.420 +G1 X -68.942 Y 41.099 +G1 X -69.287 Y 41.782 +G1 X -69.625 Y 42.469 +G1 X -69.957 Y 43.158 +G1 X -70.278 Y 43.842 +G1 X -70.591 Y 44.528 +G1 X -70.898 Y 45.218 +G1 X -71.199 Y 45.910 +G1 X -71.492 Y 46.605 +G1 X -71.779 Y 47.304 +G1 X -72.059 Y 48.005 +G1 X -72.332 Y 48.708 +G1 X -72.598 Y 49.414 +G1 X -72.858 Y 50.123 +G1 X -73.110 Y 50.835 +G1 X -73.355 Y 51.548 +G1 X -73.594 Y 52.264 +G1 X -73.825 Y 52.983 +G1 X -74.050 Y 53.703 +G1 X -74.267 Y 54.426 +G1 X -74.478 Y 55.151 +G1 X -74.687 Y 55.899 +G1 X -74.888 Y 56.650 +G1 X -75.083 Y 57.403 +G1 X -75.269 Y 58.157 +G1 X -75.448 Y 58.913 +G1 X -75.620 Y 59.671 +G1 X -75.783 Y 60.431 +G1 X -75.940 Y 61.192 +G1 X -76.088 Y 61.955 +G1 X -76.229 Y 62.719 +G1 X -76.362 Y 63.485 +G1 X -76.488 Y 64.252 +G1 X -76.606 Y 65.020 +G1 X -76.716 Y 65.790 +G1 X -76.818 Y 66.560 +G1 X -76.913 Y 67.331 +G1 X -77.000 Y 68.104 +G1 X -77.079 Y 68.877 +G1 X -77.150 Y 69.651 +G1 X -77.214 Y 70.425 +G1 X -77.270 Y 71.200 +G1 X -77.318 Y 71.976 +G1 X -77.358 Y 72.752 +G1 X -77.391 Y 73.529 +G1 X -77.415 Y 74.306 +G1 X -77.432 Y 75.083 +G1 X -77.442 Y 75.860 +G1 X -77.443 Y 76.637 +G1 X -77.436 Y 77.414 +G1 X -77.422 Y 78.191 +G1 X -77.401 Y 78.949 +G1 X -77.372 Y 79.706 +G1 X -77.336 Y 80.464 +G1 X -77.292 Y 81.220 +G1 X -77.241 Y 81.977 +G1 X -77.182 Y 82.733 +G1 X -77.116 Y 83.488 +G1 X -77.043 Y 84.242 +G1 X -76.962 Y 84.996 +G1 X -76.873 Y 85.749 +G1 X -76.778 Y 86.501 +G1 X -76.675 Y 87.252 +G1 X -76.564 Y 88.002 +G1 X -76.447 Y 88.751 +G1 X -76.321 Y 89.499 +G1 X -76.189 Y 90.245 +G1 X -76.049 Y 90.990 +G1 X -75.902 Y 91.734 +G1 X -75.748 Y 92.476 +G1 X -75.586 Y 93.217 +G1 X -75.417 Y 93.956 +G1 X -75.241 Y 94.693 +G1 X -75.057 Y 95.429 +G1 X -74.867 Y 96.163 +G1 X -74.669 Y 96.894 +G1 X -74.464 Y 97.624 +G1 X -74.252 Y 98.352 +G1 X -74.039 Y 99.055 +G1 X -73.820 Y 99.757 +G1 X -73.594 Y 100.456 +G1 X -73.362 Y 101.153 +G1 X -73.123 Y 101.848 +G1 X -72.878 Y 102.540 +G1 X -72.626 Y 103.230 +G1 X -72.367 Y 103.918 +G1 X -72.102 Y 104.603 +G1 X -71.831 Y 105.286 +G1 X -71.553 Y 105.966 +G1 X -71.269 Y 106.643 +G1 X -70.978 Y 107.317 +G1 X -70.681 Y 107.988 +G1 X -70.378 Y 108.657 +G1 X -70.069 Y 109.322 +G1 X -69.753 Y 109.985 +G1 X -69.431 Y 110.644 +G1 X -69.103 Y 111.301 +G1 X -68.768 Y 111.954 +G1 X -68.428 Y 112.604 +G1 X -68.081 Y 113.251 +G1 X -67.717 Y 113.916 +G1 X -67.346 Y 114.577 +G1 X -66.968 Y 115.234 +G1 X -66.585 Y 115.887 +G1 X -66.194 Y 116.537 +G1 X -65.798 Y 117.183 +G1 X -65.395 Y 117.825 +G1 X -64.986 Y 118.463 +G1 X -64.570 Y 119.097 +G1 X -64.149 Y 119.726 +G1 X -63.721 Y 120.352 +G1 X -63.287 Y 120.973 +G1 X -62.847 Y 121.590 +G1 X -62.401 Y 122.203 +G1 X -61.949 Y 122.811 +G1 X -61.491 Y 123.415 +G1 X -61.027 Y 124.014 +G1 X -60.557 Y 124.609 +G1 X -60.082 Y 125.199 +G1 X -59.600 Y 125.784 +G1 X -59.113 Y 126.365 +G1 X -58.621 Y 126.941 +G1 X -58.122 Y 127.512 +G1 X -57.618 Y 128.078 +G1 X -57.109 Y 128.639 +G1 X -56.594 Y 129.195 +G1 X -56.073 Y 129.746 +G1 X -55.536 Y 130.303 +G1 X -54.994 Y 130.855 +G1 X -54.446 Y 131.401 +G1 X -53.892 Y 131.942 +G1 X -53.333 Y 132.478 +G1 X -52.769 Y 133.008 +G1 X -52.200 Y 133.532 +G1 X -51.625 Y 134.050 +G1 X -51.045 Y 134.563 +G1 X -50.460 Y 135.070 +G1 X -49.870 Y 135.571 +G1 X -49.275 Y 136.066 +G1 X -48.676 Y 136.555 +G1 X -48.071 Y 137.038 +G1 X -47.461 Y 137.515 +G1 X -46.847 Y 137.986 +G1 X -46.228 Y 138.451 +G1 X -45.605 Y 138.909 +G1 X -44.977 Y 139.362 +G1 X -44.344 Y 139.808 +G1 X -43.707 Y 140.247 +G1 X -43.066 Y 140.680 +G1 X -42.420 Y 141.107 +G1 X -41.770 Y 141.528 +G1 X -41.116 Y 141.942 +G1 X -40.458 Y 142.349 +G1 X -39.796 Y 142.749 +G1 X -39.130 Y 143.144 +G1 X -38.460 Y 143.531 +G1 X -37.786 Y 143.912 +G1 X -37.108 Y 144.286 +G1 X -36.427 Y 144.653 +G1 X -35.742 Y 145.013 +G1 X -35.053 Y 145.366 +G1 X -34.361 Y 145.713 +G1 X -33.666 Y 146.053 +G1 X -32.967 Y 146.385 +G1 X -32.265 Y 146.711 +G1 X -31.560 Y 147.030 +G1 X -30.851 Y 147.341 +G1 X -30.140 Y 147.646 +G1 X -29.425 Y 147.943 +G1 X -28.708 Y 148.233 +G1 X -27.987 Y 148.516 +G1 X -27.279 Y 148.786 +G1 X -26.568 Y 149.050 +G1 X -25.854 Y 149.306 +G1 X -25.139 Y 149.555 +G1 X -24.420 Y 149.797 +G1 X -23.699 Y 150.032 +G1 X -22.976 Y 150.260 +G1 X -22.251 Y 150.481 +G1 X -21.524 Y 150.695 +G1 X -20.794 Y 150.902 +G1 X -20.063 Y 151.101 +G1 X -19.330 Y 151.293 +G1 X -18.595 Y 151.478 +G1 X -17.858 Y 151.656 +G1 X -17.119 Y 151.826 +G1 X -16.379 Y 151.990 +G1 X -15.637 Y 152.146 +G1 X -14.893 Y 152.294 +G1 X -14.149 Y 152.436 +G1 X -13.402 Y 152.570 +G1 X -12.655 Y 152.697 +G1 X -11.906 Y 152.816 +G1 X -11.157 Y 152.928 +G1 X -10.406 Y 153.033 +G1 X -9.654 Y 153.130 +G1 X -8.901 Y 153.220 +G1 X -8.148 Y 153.302 +G1 X -7.416 Y 153.375 +G1 X -6.685 Y 153.441 +G1 X -5.952 Y 153.500 +G1 X -5.220 Y 153.552 +G1 X -4.486 Y 153.597 +G1 X -3.752 Y 153.636 +G1 X -3.018 Y 153.667 +G1 X -2.284 Y 153.691 +G1 X -1.550 Y 153.709 +G1 X -0.815 Y 153.719 +G1 X -0.080 Y 153.722 +G1 X 0.667 Y 153.719 +G1 X 1.415 Y 153.708 +G1 X 2.162 Y 153.690 +G1 X 2.909 Y 153.665 +G1 X 3.655 Y 153.632 +G1 X 4.402 Y 153.593 +G1 X 5.148 Y 153.546 +G1 X 5.907 Y 153.491 +G1 X 6.666 Y 153.428 +G1 X 7.425 Y 153.358 +G1 X 8.182 Y 153.280 +G1 X 8.939 Y 153.195 +G1 X 9.695 Y 153.103 +G1 X 10.450 Y 153.003 +G1 X 11.204 Y 152.895 +G1 X 11.957 Y 152.781 +G1 X 12.709 Y 152.658 +G1 X 13.459 Y 152.529 +G1 X 14.208 Y 152.392 +G1 X 14.956 Y 152.247 +G1 X 15.702 Y 152.096 +G1 X 16.447 Y 151.937 +G1 X 17.190 Y 151.770 +G1 X 17.932 Y 151.597 +G1 X 18.672 Y 151.416 +G1 X 19.410 Y 151.227 +G1 X 20.146 Y 151.032 +G1 X 20.881 Y 150.829 +G1 X 21.613 Y 150.619 +G1 X 22.343 Y 150.401 +G1 X 23.072 Y 150.177 +G1 X 23.797 Y 149.945 +G1 X 24.521 Y 149.707 +G1 X 25.242 Y 149.461 +G1 X 25.961 Y 149.208 +G1 X 26.677 Y 148.948 +G1 X 27.391 Y 148.681 +G1 X 28.102 Y 148.407 +G1 X 28.810 Y 148.126 +G1 X 29.515 Y 147.838 +G1 X 30.218 Y 147.543 +G1 X 30.917 Y 147.241 +G1 X 31.614 Y 146.932 +G1 X 32.307 Y 146.617 +G1 X 32.998 Y 146.294 +G1 X 33.685 Y 145.965 +G1 X 34.369 Y 145.629 +G1 X 35.049 Y 145.286 +G1 X 35.727 Y 144.937 +G1 X 36.400 Y 144.581 +G1 X 37.070 Y 144.219 +G1 X 37.737 Y 143.849 +G1 X 38.400 Y 143.474 +G1 X 39.059 Y 143.091 +G1 X 39.714 Y 142.703 +G1 X 40.366 Y 142.307 +G1 X 41.014 Y 141.905 +G1 X 41.658 Y 141.497 +G1 X 42.299 Y 141.083 +G1 X 42.935 Y 140.662 +G1 X 43.566 Y 140.235 +G1 X 44.194 Y 139.801 +G1 X 44.817 Y 139.362 +G1 X 45.436 Y 138.916 +G1 X 46.050 Y 138.464 +G1 X 46.660 Y 138.006 +G1 X 47.266 Y 137.543 +G1 X 47.867 Y 137.073 +G1 X 48.463 Y 136.597 +G1 X 49.054 Y 136.116 +G1 X 49.641 Y 135.629 +G1 X 50.223 Y 135.136 +G1 X 50.799 Y 134.637 +G1 X 51.360 Y 134.142 +G1 X 51.916 Y 133.642 +G1 X 52.467 Y 133.137 +G1 X 53.014 Y 132.627 +G1 X 53.555 Y 132.111 +G1 X 54.091 Y 131.590 +G1 X 54.622 Y 131.064 +G1 X 55.148 Y 130.533 +G1 X 55.669 Y 129.997 +G1 X 56.185 Y 129.456 +G1 X 56.695 Y 128.910 +G1 X 57.200 Y 128.359 +G1 X 57.700 Y 127.803 +G1 X 58.194 Y 127.242 +G1 X 58.692 Y 126.666 +G1 X 59.185 Y 126.085 +G1 X 59.671 Y 125.499 +G1 X 60.152 Y 124.909 +G1 X 60.627 Y 124.313 +G1 X 61.096 Y 123.714 +G1 X 61.560 Y 123.109 +G1 X 62.017 Y 122.500 +G1 X 62.468 Y 121.886 +G1 X 62.913 Y 121.268 +G1 X 63.352 Y 120.646 +G1 X 63.785 Y 120.019 +G1 X 64.212 Y 119.389 +G1 X 64.632 Y 118.754 +G1 X 65.046 Y 118.115 +G1 X 65.454 Y 117.471 +G1 X 65.856 Y 116.824 +G1 X 66.251 Y 116.173 +G1 X 66.640 Y 115.518 +G1 X 67.022 Y 114.859 +G1 X 67.398 Y 114.196 +G1 X 67.767 Y 113.530 +G1 X 68.130 Y 112.860 +G1 X 68.486 Y 112.186 +G1 X 68.836 Y 111.509 +G1 X 69.179 Y 110.829 +G1 X 69.515 Y 110.145 +G1 X 69.844 Y 109.458 +G1 X 70.167 Y 108.767 +G1 X 70.482 Y 108.074 +G1 X 70.791 Y 107.377 +G1 X 71.093 Y 106.678 +G1 X 71.388 Y 105.976 +G1 X 71.677 Y 105.270 +G1 X 71.958 Y 104.562 +G1 X 72.232 Y 103.851 +G1 X 72.499 Y 103.138 +G1 X 72.759 Y 102.422 +G1 X 73.013 Y 101.703 +G1 X 73.259 Y 100.982 +G1 X 73.498 Y 100.258 +G1 X 73.729 Y 99.533 +G1 X 73.954 Y 98.804 +G1 X 74.172 Y 98.074 +G1 X 74.382 Y 97.342 +G1 X 74.585 Y 96.608 +G1 X 74.781 Y 95.871 +G1 X 74.969 Y 95.133 +G1 X 75.151 Y 94.392 +G1 X 75.325 Y 93.650 +G1 X 75.492 Y 92.906 +G1 X 75.651 Y 92.160 +G1 X 75.803 Y 91.412 +G1 X 75.948 Y 90.664 +G1 X 76.085 Y 89.914 +G1 X 76.215 Y 89.162 +G1 X 76.337 Y 88.409 +G1 X 76.452 Y 87.655 +G1 X 76.560 Y 86.900 +G1 X 76.660 Y 86.144 +G1 X 76.753 Y 85.387 +G1 X 76.838 Y 84.630 +G1 X 76.916 Y 83.871 +G1 X 76.986 Y 83.112 +G1 X 77.049 Y 82.352 +G1 X 77.104 Y 81.591 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 3 *) +G0 X 39.159 Y 89.110 +M3 M8 +G0 Z 34.000 +G1 Z 34.000 +F100 +G1 X 39.159 Y 89.110 +G1 X 38.951 Y 88.921 +G1 X 38.738 Y 88.738 +G1 X 38.521 Y 88.560 +G1 X 38.300 Y 88.387 +G1 X 38.074 Y 88.219 +G1 X 37.845 Y 88.057 +G1 X 37.614 Y 87.903 +G1 X 37.380 Y 87.756 +G1 X 37.141 Y 87.615 +G1 X 36.898 Y 87.480 +G1 X 36.652 Y 87.352 +G1 X 36.402 Y 87.231 +G1 X 36.173 Y 87.128 +G1 X 35.941 Y 87.031 +G1 X 35.706 Y 86.941 +G1 X 35.468 Y 86.857 +G1 X 35.229 Y 86.781 +G1 X 34.987 Y 86.711 +G1 X 34.743 Y 86.647 +G1 X 34.514 Y 86.595 +G1 X 34.284 Y 86.549 +G1 X 34.052 Y 86.509 +G1 X 33.819 Y 86.477 +G1 X 33.585 Y 86.450 +G1 X 33.351 Y 86.430 +G1 X 33.116 Y 86.417 +G1 X 32.937 Y 86.412 +G1 X 32.758 Y 86.410 +G1 X 32.582 Y 86.412 +G1 X 32.406 Y 86.418 +G1 X 32.187 Y 86.430 +G1 X 31.968 Y 86.448 +G1 X 31.750 Y 86.472 +G1 X 31.533 Y 86.502 +G1 X 31.317 Y 86.537 +G1 X 31.101 Y 86.577 +G1 X 30.870 Y 86.628 +G1 X 30.640 Y 86.684 +G1 X 30.411 Y 86.747 +G1 X 30.185 Y 86.816 +G1 X 29.960 Y 86.891 +G1 X 29.738 Y 86.973 +G1 X 29.484 Y 87.074 +G1 X 29.233 Y 87.182 +G1 X 28.985 Y 87.297 +G1 X 28.741 Y 87.420 +G1 X 28.500 Y 87.549 +G1 X 28.263 Y 87.685 +G1 X 28.039 Y 87.822 +G1 X 27.818 Y 87.964 +G1 X 27.600 Y 88.111 +G1 X 27.387 Y 88.264 +G1 X 27.177 Y 88.422 +G1 X 26.970 Y 88.585 +G1 X 26.757 Y 88.761 +G1 X 26.548 Y 88.942 +G1 X 26.343 Y 89.128 +G1 X 26.142 Y 89.319 +G1 X 25.945 Y 89.514 +G1 X 25.752 Y 89.713 +G1 X 25.549 Y 89.932 +G1 X 25.350 Y 90.157 +G1 X 25.156 Y 90.385 +G1 X 24.967 Y 90.617 +G1 X 24.782 Y 90.853 +G1 X 24.603 Y 91.093 +G1 X 24.404 Y 91.370 +G1 X 24.212 Y 91.651 +G1 X 24.025 Y 91.936 +G1 X 23.844 Y 92.225 +G1 X 23.669 Y 92.518 +G1 X 23.501 Y 92.814 +G1 X 23.317 Y 93.153 +G1 X 23.140 Y 93.496 +G1 X 22.970 Y 93.842 +G1 X 22.807 Y 94.192 +G1 X 22.652 Y 94.546 +G1 X 22.504 Y 94.902 +G1 X 22.367 Y 95.250 +G1 X 22.236 Y 95.600 +G1 X 22.112 Y 95.953 +G1 X 21.994 Y 96.308 +G1 X 21.883 Y 96.664 +G1 X 21.778 Y 97.023 +G1 X 21.679 Y 97.384 +G1 X 21.585 Y 97.752 +G1 X 21.497 Y 98.123 +G1 X 21.415 Y 98.494 +G1 X 21.340 Y 98.867 +G1 X 21.271 Y 99.242 +G1 X 21.208 Y 99.617 +G1 X 21.151 Y 99.993 +G1 X 21.101 Y 100.370 +G1 X 21.050 Y 100.804 +G1 X 21.008 Y 101.238 +G1 X 20.973 Y 101.673 +G1 X 20.946 Y 102.109 +G1 X 20.926 Y 102.545 +G1 X 20.915 Y 102.981 +G1 X 20.911 Y 103.418 +G1 X 20.913 Y 103.703 +G1 X 20.921 Y 104.102 +G1 X 20.936 Y 104.501 +G1 X 20.957 Y 104.899 +G1 X 20.985 Y 105.297 +G1 X 21.020 Y 105.695 +G1 X 21.061 Y 106.092 +G1 X 21.109 Y 106.488 +G1 X 21.163 Y 106.884 +G1 X 21.225 Y 107.286 +G1 X 21.295 Y 107.688 +G1 X 21.372 Y 108.088 +G1 X 21.456 Y 108.486 +G1 X 21.547 Y 108.884 +G1 X 21.646 Y 109.279 +G1 X 21.752 Y 109.672 +G1 X 21.865 Y 110.064 +G1 X 21.975 Y 110.423 +G1 X 22.093 Y 110.780 +G1 X 22.217 Y 111.135 +G1 X 22.347 Y 111.487 +G1 X 22.484 Y 111.837 +G1 X 22.628 Y 112.185 +G1 X 22.778 Y 112.529 +G1 X 22.918 Y 112.836 +G1 X 23.064 Y 113.140 +G1 X 23.215 Y 113.441 +G1 X 23.372 Y 113.739 +G1 X 23.535 Y 114.035 +G1 X 23.703 Y 114.327 +G1 X 23.877 Y 114.616 +G1 X 24.061 Y 114.909 +G1 X 24.251 Y 115.198 +G1 X 24.448 Y 115.482 +G1 X 24.651 Y 115.762 +G1 X 24.860 Y 116.038 +G1 X 25.075 Y 116.309 +G1 X 25.278 Y 116.553 +G1 X 25.487 Y 116.792 +G1 X 25.701 Y 117.027 +G1 X 25.921 Y 117.256 +G1 X 26.146 Y 117.480 +G1 X 26.377 Y 117.699 +G1 X 26.585 Y 117.888 +G1 X 26.798 Y 118.071 +G1 X 27.015 Y 118.249 +G1 X 27.236 Y 118.422 +G1 X 27.461 Y 118.590 +G1 X 27.691 Y 118.752 +G1 X 27.922 Y 118.906 +G1 X 28.157 Y 119.054 +G1 X 28.396 Y 119.195 +G1 X 28.639 Y 119.330 +G1 X 28.885 Y 119.458 +G1 X 29.135 Y 119.579 +G1 X 29.366 Y 119.683 +G1 X 29.600 Y 119.780 +G1 X 29.836 Y 119.871 +G1 X 30.075 Y 119.955 +G1 X 30.316 Y 120.032 +G1 X 30.560 Y 120.102 +G1 X 30.805 Y 120.165 +G1 X 31.034 Y 120.217 +G1 X 31.264 Y 120.263 +G1 X 31.495 Y 120.302 +G1 X 31.727 Y 120.334 +G1 X 31.960 Y 120.360 +G1 X 32.194 Y 120.379 +G1 X 32.428 Y 120.392 +G1 X 32.601 Y 120.397 +G1 X 32.774 Y 120.399 +G1 X 32.947 Y 120.397 +G1 X 33.121 Y 120.391 +G1 X 33.339 Y 120.379 +G1 X 33.557 Y 120.361 +G1 X 33.774 Y 120.338 +G1 X 33.991 Y 120.308 +G1 X 34.206 Y 120.273 +G1 X 34.421 Y 120.233 +G1 X 34.653 Y 120.183 +G1 X 34.884 Y 120.126 +G1 X 35.113 Y 120.063 +G1 X 35.341 Y 119.994 +G1 X 35.566 Y 119.918 +G1 X 35.789 Y 119.837 +G1 X 36.043 Y 119.736 +G1 X 36.294 Y 119.627 +G1 X 36.541 Y 119.512 +G1 X 36.786 Y 119.390 +G1 X 37.026 Y 119.260 +G1 X 37.263 Y 119.124 +G1 X 37.487 Y 118.988 +G1 X 37.708 Y 118.845 +G1 X 37.925 Y 118.698 +G1 X 38.139 Y 118.545 +G1 X 38.349 Y 118.387 +G1 X 38.555 Y 118.225 +G1 X 38.768 Y 118.048 +G1 X 38.977 Y 117.867 +G1 X 39.182 Y 117.681 +G1 X 39.383 Y 117.491 +G1 X 39.580 Y 117.296 +G1 X 39.772 Y 117.097 +G1 X 39.975 Y 116.877 +G1 X 40.174 Y 116.653 +G1 X 40.368 Y 116.425 +G1 X 40.557 Y 116.192 +G1 X 40.741 Y 115.956 +G1 X 40.921 Y 115.716 +G1 X 41.119 Y 115.439 +G1 X 41.312 Y 115.158 +G1 X 41.498 Y 114.873 +G1 X 41.679 Y 114.584 +G1 X 41.854 Y 114.292 +G1 X 42.023 Y 113.995 +G1 X 42.207 Y 113.656 +G1 X 42.384 Y 113.313 +G1 X 42.553 Y 112.967 +G1 X 42.716 Y 112.617 +G1 X 42.871 Y 112.264 +G1 X 43.019 Y 111.907 +G1 X 43.156 Y 111.559 +G1 X 43.287 Y 111.209 +G1 X 43.411 Y 110.856 +G1 X 43.529 Y 110.502 +G1 X 43.640 Y 110.145 +G1 X 43.745 Y 109.786 +G1 X 43.844 Y 109.425 +G1 X 43.938 Y 109.057 +G1 X 44.026 Y 108.686 +G1 X 44.107 Y 108.315 +G1 X 44.183 Y 107.942 +G1 X 44.252 Y 107.568 +G1 X 44.315 Y 107.192 +G1 X 44.371 Y 106.816 +G1 X 44.422 Y 106.439 +G1 X 44.472 Y 106.005 +G1 X 44.515 Y 105.571 +G1 X 44.550 Y 105.136 +G1 X 44.577 Y 104.700 +G1 X 44.596 Y 104.264 +G1 X 44.608 Y 103.827 +G1 X 44.612 Y 103.391 +G1 X 44.610 Y 103.123 +G1 X 44.606 Y 102.855 +G1 X 44.593 Y 102.427 +G1 X 44.572 Y 101.998 +G1 X 44.544 Y 101.570 +G1 X 44.508 Y 101.143 +G1 X 44.464 Y 100.716 +G1 X 44.413 Y 100.290 +G1 X 44.354 Y 99.865 +G1 X 44.293 Y 99.470 +G1 X 44.224 Y 99.076 +G1 X 44.148 Y 98.684 +G1 X 44.065 Y 98.293 +G1 X 43.975 Y 97.903 +G1 X 43.879 Y 97.515 +G1 X 43.775 Y 97.129 +G1 X 43.665 Y 96.745 +G1 X 43.554 Y 96.386 +G1 X 43.437 Y 96.029 +G1 X 43.313 Y 95.674 +G1 X 43.183 Y 95.321 +G1 X 43.046 Y 94.971 +G1 X 42.903 Y 94.624 +G1 X 42.754 Y 94.279 +G1 X 39.159 Y 89.110 +F150 +G1 Z 34.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 2 *) +G1 X -25.486 Y 93.378 +M3 M8 +G0 Z 32.000 +G1 Z 32.000 +F100 +G1 X -25.486 Y 93.378 +G1 X -30.486 Y 87.378 +G1 X -30.735 Y 87.257 +G1 X -30.963 Y 87.153 +G1 X -31.194 Y 87.056 +G1 X -31.428 Y 86.965 +G1 X -31.664 Y 86.881 +G1 X -31.903 Y 86.804 +G1 X -32.143 Y 86.734 +G1 X -32.386 Y 86.670 +G1 X -32.615 Y 86.617 +G1 X -32.845 Y 86.570 +G1 X -33.077 Y 86.530 +G1 X -33.310 Y 86.497 +G1 X -33.543 Y 86.470 +G1 X -33.778 Y 86.450 +G1 X -34.012 Y 86.436 +G1 X -34.194 Y 86.430 +G1 X -34.375 Y 86.428 +G1 X -34.552 Y 86.430 +G1 X -34.729 Y 86.436 +G1 X -34.961 Y 86.449 +G1 X -35.193 Y 86.468 +G1 X -35.424 Y 86.494 +G1 X -35.654 Y 86.526 +G1 X -35.883 Y 86.565 +G1 X -36.111 Y 86.610 +G1 X -36.337 Y 86.661 +G1 X -36.561 Y 86.718 +G1 X -36.783 Y 86.781 +G1 X -37.003 Y 86.849 +G1 X -37.222 Y 86.923 +G1 X -37.438 Y 87.003 +G1 X -37.653 Y 87.088 +G1 X -37.865 Y 87.179 +G1 X -38.095 Y 87.285 +G1 X -38.322 Y 87.396 +G1 X -38.547 Y 87.514 +G1 X -38.768 Y 87.637 +G1 X -38.986 Y 87.765 +G1 X -39.201 Y 87.900 +G1 X -39.422 Y 88.046 +G1 X -39.641 Y 88.198 +G1 X -39.855 Y 88.355 +G1 X -40.066 Y 88.516 +G1 X -40.273 Y 88.683 +G1 X -40.476 Y 88.855 +G1 X -40.686 Y 89.040 +G1 X -40.891 Y 89.230 +G1 X -41.092 Y 89.424 +G1 X -41.289 Y 89.622 +G1 X -41.481 Y 89.825 +G1 X -41.669 Y 90.032 +G1 X -41.863 Y 90.254 +G1 X -42.052 Y 90.480 +G1 X -42.237 Y 90.709 +G1 X -42.417 Y 90.943 +G1 X -42.593 Y 91.179 +G1 X -42.763 Y 91.420 +G1 X -42.943 Y 91.683 +G1 X -43.117 Y 91.950 +G1 X -43.287 Y 92.220 +G1 X -43.451 Y 92.493 +G1 X -43.610 Y 92.770 +G1 X -43.764 Y 93.049 +G1 X -43.936 Y 93.377 +G1 X -44.102 Y 93.708 +G1 X -44.261 Y 94.042 +G1 X -44.413 Y 94.379 +G1 X -44.559 Y 94.720 +G1 X -44.698 Y 95.063 +G1 X -44.835 Y 95.419 +G1 X -44.965 Y 95.777 +G1 X -45.089 Y 96.137 +G1 X -45.205 Y 96.500 +G1 X -45.316 Y 96.865 +G1 X -45.419 Y 97.231 +G1 X -45.516 Y 97.600 +G1 X -45.608 Y 97.975 +G1 X -45.693 Y 98.351 +G1 X -45.772 Y 98.729 +G1 X -45.845 Y 99.108 +G1 X -45.911 Y 99.488 +G1 X -45.971 Y 99.870 +G1 X -46.025 Y 100.252 +G1 X -46.072 Y 100.635 +G1 X -46.114 Y 101.031 +G1 X -46.149 Y 101.428 +G1 X -46.178 Y 101.825 +G1 X -46.201 Y 102.223 +G1 X -46.217 Y 102.621 +G1 X -46.227 Y 103.020 +G1 X -46.230 Y 103.418 +G1 X -46.226 Y 103.840 +G1 X -46.216 Y 104.261 +G1 X -46.198 Y 104.682 +G1 X -46.175 Y 105.064 +G1 X -46.146 Y 105.445 +G1 X -46.111 Y 105.826 +G1 X -46.070 Y 106.206 +G1 X -46.023 Y 106.586 +G1 X -45.970 Y 106.965 +G1 X -45.911 Y 107.343 +G1 X -45.846 Y 107.719 +G1 X -45.776 Y 108.086 +G1 X -45.700 Y 108.452 +G1 X -45.618 Y 108.816 +G1 X -45.530 Y 109.179 +G1 X -45.435 Y 109.541 +G1 X -45.335 Y 109.900 +G1 X -45.228 Y 110.258 +G1 X -45.115 Y 110.614 +G1 X -45.001 Y 110.956 +G1 X -44.879 Y 111.297 +G1 X -44.752 Y 111.635 +G1 X -44.619 Y 111.970 +G1 X -44.479 Y 112.303 +G1 X -44.334 Y 112.634 +G1 X -44.182 Y 112.961 +G1 X -44.024 Y 113.287 +G1 X -43.859 Y 113.610 +G1 X -43.687 Y 113.929 +G1 X -43.509 Y 114.244 +G1 X -43.325 Y 114.556 +G1 X -43.134 Y 114.864 +G1 X -42.953 Y 115.143 +G1 X -42.765 Y 115.419 +G1 X -42.572 Y 115.691 +G1 X -42.372 Y 115.958 +G1 X -42.167 Y 116.221 +G1 X -41.956 Y 116.480 +G1 X -41.766 Y 116.703 +G1 X -41.572 Y 116.922 +G1 X -41.372 Y 117.136 +G1 X -41.168 Y 117.346 +G1 X -40.959 Y 117.552 +G1 X -40.746 Y 117.753 +G1 X -40.545 Y 117.933 +G1 X -40.340 Y 118.110 +G1 X -40.131 Y 118.281 +G1 X -39.917 Y 118.447 +G1 X -39.700 Y 118.608 +G1 X -39.480 Y 118.765 +G1 X -39.250 Y 118.919 +G1 X -39.015 Y 119.067 +G1 X -38.777 Y 119.208 +G1 X -38.535 Y 119.343 +G1 X -38.289 Y 119.471 +G1 X -38.040 Y 119.592 +G1 X -37.812 Y 119.695 +G1 X -37.580 Y 119.792 +G1 X -37.346 Y 119.883 +G1 X -37.109 Y 119.966 +G1 X -36.870 Y 120.043 +G1 X -36.629 Y 120.114 +G1 X -36.386 Y 120.177 +G1 X -36.157 Y 120.230 +G1 X -35.927 Y 120.276 +G1 X -35.695 Y 120.316 +G1 X -35.463 Y 120.349 +G1 X -35.229 Y 120.376 +G1 X -34.995 Y 120.396 +G1 X -34.761 Y 120.409 +G1 X -34.582 Y 120.415 +G1 X -34.402 Y 120.417 +G1 X -34.242 Y 120.415 +G1 X -34.082 Y 120.411 +G1 X -33.845 Y 120.398 +G1 X -33.608 Y 120.379 +G1 X -33.372 Y 120.353 +G1 X -33.137 Y 120.320 +G1 X -32.902 Y 120.280 +G1 X -32.669 Y 120.233 +G1 X -32.430 Y 120.179 +G1 X -32.192 Y 120.117 +G1 X -31.957 Y 120.049 +G1 X -31.723 Y 119.974 +G1 X -31.491 Y 119.892 +G1 X -31.262 Y 119.804 +G1 X -31.031 Y 119.708 +G1 X -30.802 Y 119.606 +G1 X -30.576 Y 119.498 +G1 X -30.353 Y 119.384 +G1 X -30.133 Y 119.264 +G1 X -29.916 Y 119.138 +G1 X -29.692 Y 119.001 +G1 X -29.471 Y 118.858 +G1 X -29.254 Y 118.710 +G1 X -29.040 Y 118.556 +G1 X -28.830 Y 118.398 +G1 X -28.624 Y 118.234 +G1 X -28.411 Y 118.057 +G1 X -28.202 Y 117.875 +G1 X -27.997 Y 117.689 +G1 X -27.796 Y 117.498 +G1 X -27.600 Y 117.303 +G1 X -27.408 Y 117.104 +G1 X -27.210 Y 116.889 +G1 X -27.016 Y 116.671 +G1 X -26.827 Y 116.449 +G1 X -26.642 Y 116.222 +G1 X -26.462 Y 115.993 +G1 X -26.286 Y 115.759 +G1 X -26.101 Y 115.503 +G1 X -25.922 Y 115.244 +G1 X -25.747 Y 114.981 +G1 X -25.577 Y 114.714 +G1 X -25.413 Y 114.445 +G1 X -25.253 Y 114.172 +G1 X -25.074 Y 113.852 +G1 X -24.902 Y 113.529 +G1 X -24.736 Y 113.202 +G1 X -24.577 Y 112.872 +G1 X -24.424 Y 112.539 +G1 X -24.277 Y 112.203 +G1 X -24.133 Y 111.853 +G1 X -23.995 Y 111.502 +G1 X -23.864 Y 111.147 +G1 X -23.739 Y 110.791 +G1 X -23.621 Y 110.432 +G1 X -23.509 Y 110.071 +G1 X -23.404 Y 109.708 +G1 X -23.301 Y 109.325 +G1 X -23.204 Y 108.940 +G1 X -23.114 Y 108.554 +G1 X -23.031 Y 108.166 +G1 X -22.955 Y 107.777 +G1 X -22.885 Y 107.387 +G1 X -22.823 Y 106.995 +G1 X -22.767 Y 106.602 +G1 X -22.718 Y 106.206 +G1 X -22.675 Y 105.809 +G1 X -22.639 Y 105.412 +G1 X -22.609 Y 105.014 +G1 X -22.586 Y 104.615 +G1 X -22.569 Y 104.216 +G1 X -22.559 Y 103.817 +G1 X -22.556 Y 103.418 +G1 X -22.559 Y 103.078 +G1 X -22.566 Y 102.737 +G1 X -22.577 Y 102.397 +G1 X -25.094 Y 92.928 +F150 +G1 Z 34.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 1 *) +G0 X -30.080 Y 43.004 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F400 +G1 X -30.080 Y 43.617 +G1 X -30.076 Y 44.100 +G1 X -30.065 Y 44.582 +G1 X -30.046 Y 45.065 +G1 X -30.019 Y 45.547 +G1 X -29.985 Y 46.028 +G1 X -29.943 Y 46.509 +G1 X -29.894 Y 46.989 +G1 X -29.837 Y 47.468 +G1 X -29.772 Y 47.946 +G1 X -29.700 Y 48.421 +G1 X -29.621 Y 48.895 +G1 X -29.534 Y 49.367 +G1 X -29.440 Y 49.838 +G1 X -29.338 Y 50.307 +G1 X -29.228 Y 50.775 +G1 X -29.111 Y 51.240 +G1 X -28.987 Y 51.704 +G1 X -28.855 Y 52.166 +G1 X -28.716 Y 52.626 +G1 X -28.569 Y 53.083 +G1 X -28.415 Y 53.538 +G1 X -28.254 Y 53.990 +G1 X -28.086 Y 54.440 +G1 X -27.910 Y 54.887 +G1 X -27.728 Y 55.331 +G1 X -27.538 Y 55.772 +G1 X -27.341 Y 56.210 +G1 X -27.138 Y 56.645 +G1 X -26.927 Y 57.077 +G1 X -26.709 Y 57.505 +G1 X -26.491 Y 57.919 +G1 X -26.265 Y 58.330 +G1 X -26.034 Y 58.737 +G1 X -25.796 Y 59.141 +G1 X -25.552 Y 59.541 +G1 X -25.302 Y 59.937 +G1 X -25.046 Y 60.329 +G1 X -24.784 Y 60.717 +G1 X -24.516 Y 61.102 +G1 X -24.242 Y 61.482 +G1 X -23.962 Y 61.857 +G1 X -23.676 Y 62.229 +G1 X -23.385 Y 62.595 +G1 X -23.088 Y 62.958 +G1 X -22.785 Y 63.315 +G1 X -22.477 Y 63.668 +G1 X -22.164 Y 64.017 +G1 X -21.837 Y 64.368 +G1 X -21.505 Y 64.714 +G1 X -21.168 Y 65.055 +G1 X -20.825 Y 65.391 +G1 X -20.477 Y 65.721 +G1 X -20.124 Y 66.046 +G1 X -19.766 Y 66.365 +G1 X -19.402 Y 66.678 +G1 X -19.034 Y 66.986 +G1 X -18.661 Y 67.287 +G1 X -18.284 Y 67.583 +G1 X -17.901 Y 67.873 +G1 X -17.515 Y 68.157 +G1 X -17.123 Y 68.434 +G1 X -16.728 Y 68.706 +G1 X -16.328 Y 68.971 +G1 X -15.924 Y 69.229 +G1 X -15.516 Y 69.482 +G1 X -15.104 Y 69.728 +G1 X -14.683 Y 69.970 +G1 X -14.258 Y 70.206 +G1 X -13.829 Y 70.434 +G1 X -13.397 Y 70.656 +G1 X -12.961 Y 70.871 +G1 X -12.522 Y 71.078 +G1 X -12.079 Y 71.279 +G1 X -11.633 Y 71.472 +G1 X -11.184 Y 71.658 +G1 X -10.732 Y 71.837 +G1 X -10.278 Y 72.008 +G1 X -9.821 Y 72.172 +G1 X -9.361 Y 72.329 +G1 X -8.899 Y 72.478 +G1 X -8.434 Y 72.619 +G1 X -7.967 Y 72.753 +G1 X -7.498 Y 72.880 +G1 X -7.027 Y 72.998 +G1 X -6.554 Y 73.110 +G1 X -6.080 Y 73.213 +G1 X -5.604 Y 73.309 +G1 X -5.126 Y 73.397 +G1 X -4.647 Y 73.477 +G1 X -4.167 Y 73.550 +G1 X -3.689 Y 73.614 +G1 X -3.210 Y 73.671 +G1 X -2.730 Y 73.721 +G1 X -2.249 Y 73.763 +G1 X -1.768 Y 73.797 +G1 X -1.286 Y 73.823 +G1 X -0.804 Y 73.842 +G1 X -0.322 Y 73.854 +G1 X 0.160 Y 73.858 +G1 X 0.643 Y 73.854 +G1 X 1.125 Y 73.842 +G1 X 1.607 Y 73.823 +G1 X 2.089 Y 73.797 +G1 X 2.571 Y 73.762 +G1 X 3.051 Y 73.721 +G1 X 3.532 Y 73.671 +G1 X 4.011 Y 73.614 +G1 X 4.489 Y 73.550 +G1 X 4.964 Y 73.478 +G1 X 5.437 Y 73.399 +G1 X 5.910 Y 73.312 +G1 X 6.381 Y 73.217 +G1 X 6.850 Y 73.115 +G1 X 7.317 Y 73.006 +G1 X 7.783 Y 72.889 +G1 X 8.247 Y 72.764 +G1 X 8.709 Y 72.633 +G1 X 9.168 Y 72.493 +G1 X 9.626 Y 72.347 +G1 X 10.081 Y 72.193 +G1 X 10.533 Y 72.032 +G1 X 10.983 Y 71.864 +G1 X 11.430 Y 71.688 +G1 X 11.874 Y 71.505 +G1 X 12.315 Y 71.316 +G1 X 12.753 Y 71.119 +G1 X 13.188 Y 70.915 +G1 X 13.619 Y 70.705 +G1 X 14.048 Y 70.487 +G1 X 14.462 Y 70.268 +G1 X 14.873 Y 70.043 +G1 X 15.280 Y 69.812 +G1 X 15.684 Y 69.574 +G1 X 16.084 Y 69.330 +G1 X 16.480 Y 69.080 +G1 X 16.872 Y 68.824 +G1 X 17.260 Y 68.561 +G1 X 17.644 Y 68.293 +G1 X 18.024 Y 68.019 +G1 X 18.400 Y 67.739 +G1 X 18.771 Y 67.454 +G1 X 19.138 Y 67.162 +G1 X 19.501 Y 66.865 +G1 X 19.858 Y 66.563 +G1 X 20.211 Y 66.255 +G1 X 20.559 Y 65.941 +G1 X 20.911 Y 65.615 +G1 X 21.257 Y 65.283 +G1 X 21.598 Y 64.945 +G1 X 21.934 Y 64.603 +G1 X 22.264 Y 64.255 +G1 X 22.588 Y 63.901 +G1 X 22.908 Y 63.543 +G1 X 23.221 Y 63.180 +G1 X 23.528 Y 62.812 +G1 X 23.830 Y 62.439 +G1 X 24.126 Y 62.061 +G1 X 24.416 Y 61.679 +G1 X 24.699 Y 61.292 +G1 X 24.977 Y 60.901 +G1 X 25.248 Y 60.505 +G1 X 25.513 Y 60.106 +G1 X 25.772 Y 59.702 +G1 X 26.025 Y 59.294 +G1 X 26.270 Y 58.882 +G1 X 26.513 Y 58.461 +G1 X 26.748 Y 58.036 +G1 X 26.977 Y 57.607 +G1 X 27.199 Y 57.174 +G1 X 27.413 Y 56.739 +G1 X 27.621 Y 56.299 +G1 X 27.821 Y 55.857 +G1 X 28.015 Y 55.411 +G1 X 28.201 Y 54.962 +G1 X 28.379 Y 54.510 +G1 X 28.551 Y 54.056 +G1 X 28.715 Y 53.598 +G1 X 28.871 Y 53.139 +G1 X 29.020 Y 52.676 +G1 X 29.162 Y 52.212 +G1 X 29.296 Y 51.745 +G1 X 29.422 Y 51.276 +G1 X 29.541 Y 50.805 +G1 X 29.652 Y 50.332 +G1 X 29.756 Y 49.858 +G1 X 29.852 Y 49.381 +G1 X 29.940 Y 48.904 +G1 X 30.020 Y 48.425 +G1 X 30.093 Y 47.945 +G1 X 30.157 Y 47.466 +G1 X 30.214 Y 46.987 +G1 X 30.264 Y 46.508 +G1 X 30.305 Y 46.027 +G1 X 30.339 Y 45.546 +G1 X 30.366 Y 45.064 +G1 X 30.385 Y 44.582 +G1 X 30.397 Y 44.100 +G1 X 30.400 Y 43.617 +G1 X 30.400 Y 42.965 +G1 X 30.395 Y 42.573 +G1 X 30.383 Y 42.180 +G1 X 30.362 Y 41.788 +G1 X 30.333 Y 41.397 +G1 X 30.297 Y 41.006 +G1 X 30.252 Y 40.616 +G1 X 30.200 Y 40.227 +G1 X 30.142 Y 39.856 +G1 X 30.077 Y 39.485 +G1 X 30.005 Y 39.116 +G1 X 29.925 Y 38.749 +G1 X 29.839 Y 38.383 +G1 X 29.745 Y 38.019 +G1 X 29.643 Y 37.657 +G1 X 29.535 Y 37.296 +G1 X 29.420 Y 36.939 +G1 X 29.297 Y 36.583 +G1 X 29.168 Y 36.230 +G1 X 29.031 Y 35.879 +G1 X 28.888 Y 35.532 +G1 X 28.738 Y 35.187 +G1 X 28.581 Y 34.845 +G1 X 28.417 Y 34.507 +G1 X 28.247 Y 34.171 +G1 X 28.070 Y 33.840 +G1 X 27.883 Y 33.506 +G1 X 27.690 Y 33.176 +G1 X 27.490 Y 32.849 +G1 X 27.284 Y 32.527 +G1 X 27.072 Y 32.209 +G1 X 26.853 Y 31.896 +G1 X 26.628 Y 31.586 +G1 X 26.397 Y 31.282 +G1 X 26.160 Y 30.981 +G1 X 25.917 Y 30.686 +G1 X 25.669 Y 30.395 +G1 X 25.414 Y 30.110 +G1 X 25.154 Y 29.830 +G1 X 24.888 Y 29.554 +G1 X 24.618 Y 29.284 +G1 X 24.341 Y 29.020 +G1 X 24.060 Y 28.761 +G1 X 23.773 Y 28.508 +G1 X 23.482 Y 28.260 +G1 X 23.185 Y 28.019 +G1 X 22.884 Y 27.783 +G1 X 22.579 Y 27.553 +G1 X 22.268 Y 27.329 +G1 X 21.954 Y 27.112 +G1 X 21.635 Y 26.901 +G1 X 21.312 Y 26.696 +G1 X 20.985 Y 26.498 +G1 X 20.654 Y 26.306 +G1 X 20.350 Y 26.137 +G1 X 20.043 Y 25.974 +G1 X 19.733 Y 25.817 +G1 X 19.421 Y 25.665 +G1 X 19.105 Y 25.519 +G1 X 18.787 Y 25.379 +G1 X 18.467 Y 25.244 +G1 X 18.144 Y 25.116 +G1 X 17.818 Y 24.993 +G1 X 17.477 Y 24.872 +G1 X 17.134 Y 24.757 +G1 X 16.788 Y 24.649 +G1 X 16.441 Y 24.547 +G1 X 16.091 Y 24.452 +G1 X 15.740 Y 24.364 +G1 X 15.387 Y 24.282 +G1 X 15.033 Y 24.207 +G1 X 14.677 Y 24.139 +G1 X 14.320 Y 24.077 +G1 X 13.962 Y 24.023 +G1 X 13.573 Y 23.971 +G1 X 13.183 Y 23.927 +G1 X 12.792 Y 23.892 +G1 X 12.401 Y 23.864 +G1 X 12.009 Y 23.844 +G1 X 11.617 Y 23.832 +G1 X 11.224 Y 23.827 +G1 X -10.904 Y 23.827 +G1 X -11.297 Y 23.832 +G1 X -11.690 Y 23.844 +G1 X -12.082 Y 23.864 +G1 X -12.474 Y 23.892 +G1 X -12.866 Y 23.928 +G1 X -13.256 Y 23.972 +G1 X -13.646 Y 24.024 +G1 X -14.018 Y 24.081 +G1 X -14.389 Y 24.146 +G1 X -14.759 Y 24.218 +G1 X -15.127 Y 24.297 +G1 X -15.493 Y 24.383 +G1 X -15.858 Y 24.477 +G1 X -16.220 Y 24.578 +G1 X -16.581 Y 24.686 +G1 X -16.940 Y 24.801 +G1 X -17.296 Y 24.923 +G1 X -17.649 Y 25.052 +G1 X -18.000 Y 25.188 +G1 X -18.349 Y 25.331 +G1 X -18.694 Y 25.481 +G1 X -19.036 Y 25.638 +G1 X -19.376 Y 25.801 +G1 X -19.711 Y 25.971 +G1 X -20.044 Y 26.148 +G1 X -20.382 Y 26.337 +G1 X -20.716 Y 26.532 +G1 X -21.047 Y 26.734 +G1 X -21.373 Y 26.942 +G1 X -21.695 Y 27.158 +G1 X -22.012 Y 27.379 +G1 X -22.325 Y 27.607 +G1 X -22.634 Y 27.841 +G1 X -22.938 Y 28.081 +G1 X -23.236 Y 28.327 +G1 X -23.530 Y 28.579 +G1 X -23.819 Y 28.837 +G1 X -24.102 Y 29.101 +G1 X -24.380 Y 29.371 +G1 X -24.653 Y 29.646 +G1 X -24.920 Y 29.926 +G1 X -25.181 Y 30.212 +G1 X -25.437 Y 30.502 +G1 X -25.686 Y 30.798 +G1 X -25.930 Y 31.099 +G1 X -26.168 Y 31.405 +G1 X -26.399 Y 31.715 +G1 X -26.624 Y 32.030 +G1 X -26.843 Y 32.350 +G1 X -27.055 Y 32.674 +G1 X -27.261 Y 33.002 +G1 X -27.460 Y 33.334 +G1 X -27.651 Y 33.666 +G1 X -27.834 Y 34.002 +G1 X -28.011 Y 34.342 +G1 X -28.181 Y 34.686 +G1 X -28.345 Y 35.033 +G1 X -28.501 Y 35.383 +G1 X -28.650 Y 35.736 +G1 X -28.792 Y 36.092 +G1 X -28.919 Y 36.429 +G1 X -29.039 Y 36.768 +G1 X -29.153 Y 37.109 +G1 X -29.261 Y 37.453 +G1 X -29.362 Y 37.799 +G1 X -29.456 Y 38.146 +G1 X -29.544 Y 38.495 +G1 X -29.625 Y 38.846 +G1 X -29.700 Y 39.198 +G1 X -29.768 Y 39.552 +G1 X -29.829 Y 39.907 +G1 X -29.883 Y 40.263 +G1 X -29.935 Y 40.652 +G1 X -29.979 Y 41.043 +G1 X -30.015 Y 41.434 +G1 X -30.043 Y 41.826 +G1 X -30.063 Y 42.218 +G1 X -30.076 Y 42.611 +G1 X -30.080 Y 43.004 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 +G0 X 0.000 Y 0.000 +M2 (Program end) diff --git a/src/jetmax_demos/scripts/gcode/neutral.ngc b/src/jetmax_demos/scripts/gcode/neutral.ngc new file mode 100644 index 0000000..e8ad845 --- /dev/null +++ b/src/jetmax_demos/scripts/gcode/neutral.ngc @@ -0,0 +1,1324 @@ +(Generated with: DXF2GCODE, Version: Py3.7.10 PyQt5.10.1, Date: $Date: Fri Oct 25 20:45:56 2019 +0200 $) +(Created from file: /home/lucas/smail.dxf) +(Output format description: G-CODE for LinuxCNC) +(Time: Sat Jul 17 11:48:13 2021) +G21 (Units in millimeters) +G90 (Absolute programming) +G64 (Default cutting) G17 (XY plane) G40 (Cancel radius comp.) G49 (Cancel length comp.) +G0 Z 100.000 + +(*** LAYER: 0 ***) +T1 M6 +S6000 + +(* SHAPE Nr: 0 *) +G0 X -54.703 Y 27.317 +M3 M8 +G0 Z 30.000 +F150 +G1 Z 30.000 +F400 +G1 X -55.256 Y 27.876 +G1 X -55.804 Y 28.441 +G1 X -56.345 Y 29.011 +G1 X -56.881 Y 29.587 +G1 X -57.412 Y 30.168 +G1 X -57.936 Y 30.754 +G1 X -58.454 Y 31.346 +G1 X -58.966 Y 31.943 +G1 X -59.472 Y 32.545 +G1 X -59.972 Y 33.152 +G1 X -60.466 Y 33.764 +G1 X -60.953 Y 34.381 +G1 X -61.435 Y 35.004 +G1 X -61.909 Y 35.631 +G1 X -62.378 Y 36.262 +G1 X -62.840 Y 36.899 +G1 X -63.295 Y 37.540 +G1 X -63.744 Y 38.186 +G1 X -64.187 Y 38.836 +G1 X -64.622 Y 39.491 +G1 X -65.051 Y 40.150 +G1 X -65.474 Y 40.814 +G1 X -65.889 Y 41.482 +G1 X -66.298 Y 42.154 +G1 X -66.700 Y 42.830 +G1 X -67.095 Y 43.510 +G1 X -67.483 Y 44.194 +G1 X -67.864 Y 44.882 +G1 X -68.238 Y 45.574 +G1 X -68.605 Y 46.270 +G1 X -68.965 Y 46.969 +G1 X -69.318 Y 47.672 +G1 X -69.663 Y 48.378 +G1 X -70.002 Y 49.088 +G1 X -70.333 Y 49.802 +G1 X -70.657 Y 50.519 +G1 X -70.974 Y 51.239 +G1 X -71.283 Y 51.962 +G1 X -71.585 Y 52.688 +G1 X -71.879 Y 53.417 +G1 X -72.166 Y 54.150 +G1 X -72.446 Y 54.885 +G1 X -72.718 Y 55.623 +G1 X -72.983 Y 56.363 +G1 X -73.240 Y 57.107 +G1 X -73.489 Y 57.853 +G1 X -73.731 Y 58.601 +G1 X -73.966 Y 59.352 +G1 X -74.192 Y 60.105 +G1 X -74.411 Y 60.860 +G1 X -74.622 Y 61.618 +G1 X -74.826 Y 62.378 +G1 X -75.022 Y 63.139 +G1 X -75.210 Y 63.903 +G1 X -75.390 Y 64.669 +G1 X -75.563 Y 65.436 +G1 X -75.727 Y 66.205 +G1 X -75.884 Y 66.976 +G1 X -76.033 Y 67.748 +G1 X -76.175 Y 68.522 +G1 X -76.308 Y 69.297 +G1 X -76.433 Y 70.074 +G1 X -76.551 Y 70.851 +G1 X -76.660 Y 71.630 +G1 X -76.762 Y 72.410 +G1 X -76.856 Y 73.191 +G1 X -76.942 Y 73.973 +G1 X -77.019 Y 74.755 +G1 X -77.089 Y 75.539 +G1 X -77.151 Y 76.323 +G1 X -77.205 Y 77.108 +G1 X -77.251 Y 77.893 +G1 X -77.289 Y 78.678 +G1 X -77.319 Y 79.464 +G1 X -77.341 Y 80.251 +G1 X -77.355 Y 81.037 +G1 X -77.361 Y 81.823 +G1 X -77.359 Y 82.610 +G1 X -77.349 Y 83.396 +G1 X -77.331 Y 84.183 +G1 X -77.305 Y 84.969 +G1 X -77.271 Y 85.755 +G1 X -77.229 Y 86.540 +G1 X -77.179 Y 87.325 +G1 X -77.121 Y 88.109 +G1 X -77.055 Y 88.893 +G1 X -76.981 Y 89.676 +G1 X -76.900 Y 90.458 +G1 X -76.810 Y 91.240 +G1 X -76.712 Y 92.020 +G1 X -76.607 Y 92.800 +G1 X -76.493 Y 93.578 +G1 X -76.372 Y 94.355 +G1 X -76.242 Y 95.131 +G1 X -76.105 Y 95.905 +G1 X -75.960 Y 96.678 +G1 X -75.807 Y 97.450 +G1 X -75.646 Y 98.220 +G1 X -75.477 Y 98.988 +G1 X -75.301 Y 99.755 +G1 X -75.117 Y 100.519 +G1 X -74.925 Y 101.282 +G1 X -74.725 Y 102.043 +G1 X -74.518 Y 102.801 +G1 X -74.303 Y 103.558 +G1 X -74.080 Y 104.312 +G1 X -73.849 Y 105.064 +G1 X -73.611 Y 105.814 +G1 X -73.366 Y 106.561 +G1 X -73.112 Y 107.306 +G1 X -72.851 Y 108.048 +G1 X -72.583 Y 108.787 +G1 X -72.307 Y 109.523 +G1 X -72.024 Y 110.257 +G1 X -71.733 Y 110.988 +G1 X -71.435 Y 111.716 +G1 X -71.129 Y 112.441 +G1 X -70.816 Y 113.162 +G1 X -70.496 Y 113.880 +G1 X -70.168 Y 114.596 +G1 X -69.834 Y 115.307 +G1 X -69.492 Y 116.016 +G1 X -69.142 Y 116.720 +G1 X -68.786 Y 117.421 +G1 X -68.423 Y 118.119 +G1 X -68.052 Y 118.813 +G1 X -67.674 Y 119.503 +G1 X -67.290 Y 120.189 +G1 X -66.898 Y 120.871 +G1 X -66.500 Y 121.549 +G1 X -66.095 Y 122.223 +G1 X -65.682 Y 122.893 +G1 X -65.263 Y 123.559 +G1 X -64.838 Y 124.220 +G1 X -64.405 Y 124.877 +G1 X -63.966 Y 125.530 +G1 X -63.521 Y 126.178 +G1 X -63.068 Y 126.821 +G1 X -62.610 Y 127.460 +G1 X -62.144 Y 128.094 +G1 X -61.673 Y 128.724 +G1 X -61.195 Y 129.348 +G1 X -60.710 Y 129.968 +G1 X -60.220 Y 130.583 +G1 X -59.723 Y 131.193 +G1 X -59.220 Y 131.797 +G1 X -58.711 Y 132.397 +G1 X -58.196 Y 132.991 +G1 X -57.674 Y 133.580 +G1 X -57.147 Y 134.164 +G1 X -56.614 Y 134.742 +G1 X -56.075 Y 135.315 +G1 X -55.531 Y 135.882 +G1 X -54.980 Y 136.444 +G1 X -54.424 Y 137.000 +G1 X -53.862 Y 137.551 +G1 X -53.295 Y 138.095 +G1 X -52.722 Y 138.634 +G1 X -52.144 Y 139.167 +G1 X -51.560 Y 139.695 +G1 X -50.971 Y 140.216 +G1 X -50.377 Y 140.731 +G1 X -49.777 Y 141.240 +G1 X -49.172 Y 141.743 +G1 X -48.563 Y 142.240 +G1 X -47.948 Y 142.731 +G1 X -47.328 Y 143.215 +G1 X -46.704 Y 143.693 +G1 X -46.074 Y 144.165 +G1 X -45.440 Y 144.630 +G1 X -44.801 Y 145.089 +G1 X -44.158 Y 145.541 +G1 X -43.509 Y 145.986 +G1 X -42.857 Y 146.425 +G1 X -42.200 Y 146.858 +G1 X -41.539 Y 147.284 +G1 X -40.873 Y 147.702 +G1 X -40.203 Y 148.115 +G1 X -39.529 Y 148.520 +G1 X -38.851 Y 148.918 +G1 X -38.169 Y 149.310 +G1 X -37.483 Y 149.694 +G1 X -36.793 Y 150.072 +G1 X -36.099 Y 150.443 +G1 X -35.401 Y 150.806 +G1 X -34.700 Y 151.162 +G1 X -33.995 Y 151.512 +G1 X -33.287 Y 151.854 +G1 X -32.575 Y 152.189 +G1 X -31.860 Y 152.516 +G1 X -31.142 Y 152.836 +G1 X -30.420 Y 153.149 +G1 X -29.696 Y 153.455 +G1 X -28.968 Y 153.753 +G1 X -28.237 Y 154.044 +G1 X -27.503 Y 154.327 +G1 X -26.767 Y 154.603 +G1 X -26.028 Y 154.872 +G1 X -25.285 Y 155.132 +G1 X -24.541 Y 155.386 +G1 X -23.794 Y 155.631 +G1 X -23.044 Y 155.870 +G1 X -22.292 Y 156.100 +G1 X -21.538 Y 156.323 +G1 X -20.781 Y 156.538 +G1 X -20.023 Y 156.745 +G1 X -19.262 Y 156.945 +G1 X -18.499 Y 157.137 +G1 X -17.734 Y 157.321 +G1 X -16.968 Y 157.498 +G1 X -16.200 Y 157.666 +G1 X -15.430 Y 157.827 +G1 X -14.658 Y 157.980 +G1 X -13.885 Y 158.125 +G1 X -13.111 Y 158.262 +G1 X -12.335 Y 158.392 +G1 X -11.558 Y 158.513 +G1 X -10.780 Y 158.627 +G1 X -10.000 Y 158.732 +G1 X -9.220 Y 158.830 +G1 X -8.438 Y 158.920 +G1 X -7.656 Y 159.002 +G1 X -6.873 Y 159.075 +G1 X -6.089 Y 159.141 +G1 X -5.305 Y 159.199 +G1 X -4.520 Y 159.249 +G1 X -3.735 Y 159.291 +G1 X -2.949 Y 159.325 +G1 X -2.163 Y 159.351 +G1 X -1.376 Y 159.369 +G1 X -0.590 Y 159.379 +G1 X 0.197 Y 159.381 +G1 X 0.983 Y 159.375 +G1 X 1.770 Y 159.361 +G1 X 2.556 Y 159.339 +G1 X 3.342 Y 159.309 +G1 X 4.127 Y 159.271 +G1 X 4.913 Y 159.225 +G1 X 5.697 Y 159.171 +G1 X 6.481 Y 159.109 +G1 X 7.265 Y 159.040 +G1 X 8.047 Y 158.962 +G1 X 8.829 Y 158.876 +G1 X 9.610 Y 158.782 +G1 X 10.390 Y 158.680 +G1 X 11.169 Y 158.571 +G1 X 11.947 Y 158.453 +G1 X 12.723 Y 158.328 +G1 X 13.498 Y 158.195 +G1 X 14.272 Y 158.053 +G1 X 15.044 Y 157.904 +G1 X 15.815 Y 157.748 +G1 X 16.584 Y 157.583 +G1 X 17.351 Y 157.410 +G1 X 18.117 Y 157.230 +G1 X 18.881 Y 157.042 +G1 X 19.642 Y 156.846 +G1 X 20.402 Y 156.643 +G1 X 21.160 Y 156.431 +G1 X 21.915 Y 156.212 +G1 X 22.668 Y 155.986 +G1 X 23.419 Y 155.751 +G1 X 24.168 Y 155.510 +G1 X 24.914 Y 155.260 +G1 X 25.657 Y 155.003 +G1 X 26.398 Y 154.738 +G1 X 27.135 Y 154.466 +G1 X 27.871 Y 154.187 +G1 X 28.603 Y 153.899 +G1 X 29.332 Y 153.605 +G1 X 30.058 Y 153.303 +G1 X 30.782 Y 152.994 +G1 X 31.502 Y 152.677 +G1 X 32.218 Y 152.353 +G1 X 32.932 Y 152.022 +G1 X 33.642 Y 151.684 +G1 X 34.348 Y 151.338 +G1 X 35.051 Y 150.985 +G1 X 35.751 Y 150.625 +G1 X 36.446 Y 150.258 +G1 X 37.138 Y 149.884 +G1 X 37.826 Y 149.503 +G1 X 38.510 Y 149.115 +G1 X 39.190 Y 148.720 +G1 X 39.866 Y 148.318 +G1 X 40.538 Y 147.909 +G1 X 41.206 Y 147.494 +G1 X 41.870 Y 147.072 +G1 X 42.529 Y 146.642 +G1 X 43.184 Y 146.207 +G1 X 43.834 Y 145.764 +G1 X 44.480 Y 145.315 +G1 X 45.121 Y 144.860 +G1 X 45.758 Y 144.398 +G1 X 46.389 Y 143.930 +G1 X 47.017 Y 143.455 +G1 X 47.639 Y 142.974 +G1 X 48.256 Y 142.486 +G1 X 48.868 Y 141.992 +G1 X 49.475 Y 141.492 +G1 X 50.077 Y 140.986 +G1 X 50.674 Y 140.474 +G1 X 51.266 Y 139.956 +G1 X 51.852 Y 139.432 +G1 X 52.433 Y 138.902 +G1 X 53.009 Y 138.366 +G1 X 53.579 Y 137.824 +G1 X 54.144 Y 137.276 +G1 X 54.703 Y 136.723 +G1 X 55.256 Y 136.164 +G1 X 55.804 Y 135.599 +G1 X 56.345 Y 135.029 +G1 X 56.881 Y 134.454 +G1 X 57.412 Y 133.873 +G1 X 57.936 Y 133.286 +G1 X 58.454 Y 132.694 +G1 X 58.966 Y 132.098 +G1 X 59.472 Y 131.495 +G1 X 59.972 Y 130.888 +G1 X 60.466 Y 130.276 +G1 X 60.953 Y 129.659 +G1 X 61.435 Y 129.037 +G1 X 61.909 Y 128.410 +G1 X 62.378 Y 127.778 +G1 X 62.840 Y 127.141 +G1 X 63.295 Y 126.500 +G1 X 63.744 Y 125.854 +G1 X 64.187 Y 125.204 +G1 X 64.622 Y 124.549 +G1 X 65.051 Y 123.890 +G1 X 65.474 Y 123.226 +G1 X 65.889 Y 122.559 +G1 X 66.298 Y 121.887 +G1 X 66.700 Y 121.210 +G1 X 67.095 Y 120.530 +G1 X 67.483 Y 119.846 +G1 X 67.864 Y 119.158 +G1 X 68.238 Y 118.466 +G1 X 68.605 Y 117.771 +G1 X 68.965 Y 117.071 +G1 X 69.318 Y 116.368 +G1 X 69.663 Y 115.662 +G1 X 70.002 Y 114.952 +G1 X 70.333 Y 114.238 +G1 X 70.657 Y 113.522 +G1 X 70.974 Y 112.802 +G1 X 71.283 Y 112.079 +G1 X 71.585 Y 111.352 +G1 X 71.879 Y 110.623 +G1 X 72.166 Y 109.891 +G1 X 72.446 Y 109.156 +G1 X 72.718 Y 108.418 +G1 X 72.983 Y 107.677 +G1 X 73.240 Y 106.934 +G1 X 73.489 Y 106.188 +G1 X 73.731 Y 105.439 +G1 X 73.966 Y 104.688 +G1 X 74.192 Y 103.935 +G1 X 74.411 Y 103.180 +G1 X 74.622 Y 102.422 +G1 X 74.826 Y 101.663 +G1 X 75.022 Y 100.901 +G1 X 75.210 Y 100.137 +G1 X 75.390 Y 99.372 +G1 X 75.563 Y 98.604 +G1 X 75.727 Y 97.835 +G1 X 75.884 Y 97.064 +G1 X 76.033 Y 96.292 +G1 X 76.175 Y 95.518 +G1 X 76.308 Y 94.743 +G1 X 76.433 Y 93.967 +G1 X 76.551 Y 93.189 +G1 X 76.660 Y 92.410 +G1 X 76.762 Y 91.630 +G1 X 76.856 Y 90.849 +G1 X 76.942 Y 90.067 +G1 X 77.019 Y 89.285 +G1 X 77.089 Y 88.501 +G1 X 77.151 Y 87.717 +G1 X 77.205 Y 86.933 +G1 X 77.251 Y 86.147 +G1 X 77.289 Y 85.362 +G1 X 77.319 Y 84.576 +G1 X 77.341 Y 83.790 +G1 X 77.355 Y 83.003 +G1 X 77.361 Y 82.217 +G1 X 77.359 Y 81.430 +G1 X 77.349 Y 80.644 +G1 X 77.331 Y 79.857 +G1 X 77.305 Y 79.071 +G1 X 77.271 Y 78.286 +G1 X 77.229 Y 77.500 +G1 X 77.179 Y 76.715 +G1 X 77.121 Y 75.931 +G1 X 77.055 Y 75.147 +G1 X 76.981 Y 74.364 +G1 X 76.900 Y 73.582 +G1 X 76.810 Y 72.800 +G1 X 76.712 Y 72.020 +G1 X 76.607 Y 71.241 +G1 X 76.493 Y 70.462 +G1 X 76.372 Y 69.685 +G1 X 76.242 Y 68.909 +G1 X 76.105 Y 68.135 +G1 X 75.960 Y 67.362 +G1 X 75.807 Y 66.590 +G1 X 75.646 Y 65.820 +G1 X 75.477 Y 65.052 +G1 X 75.301 Y 64.286 +G1 X 75.117 Y 63.521 +G1 X 74.925 Y 62.758 +G1 X 74.725 Y 61.998 +G1 X 74.518 Y 61.239 +G1 X 74.303 Y 60.482 +G1 X 74.080 Y 59.728 +G1 X 73.849 Y 58.976 +G1 X 73.611 Y 58.226 +G1 X 73.366 Y 57.479 +G1 X 73.112 Y 56.735 +G1 X 72.851 Y 55.993 +G1 X 72.583 Y 55.253 +G1 X 72.307 Y 54.517 +G1 X 72.024 Y 53.783 +G1 X 71.733 Y 53.052 +G1 X 71.435 Y 52.324 +G1 X 71.129 Y 51.600 +G1 X 70.816 Y 50.878 +G1 X 70.496 Y 50.160 +G1 X 70.168 Y 49.445 +G1 X 69.834 Y 48.733 +G1 X 69.492 Y 48.025 +G1 X 69.142 Y 47.320 +G1 X 68.786 Y 46.619 +G1 X 68.423 Y 45.921 +G1 X 68.052 Y 45.228 +G1 X 67.674 Y 44.538 +G1 X 67.290 Y 43.851 +G1 X 66.898 Y 43.169 +G1 X 66.500 Y 42.491 +G1 X 66.095 Y 41.817 +G1 X 65.682 Y 41.147 +G1 X 65.263 Y 40.482 +G1 X 64.838 Y 39.820 +G1 X 64.405 Y 39.163 +G1 X 63.966 Y 38.511 +G1 X 63.521 Y 37.863 +G1 X 63.068 Y 37.219 +G1 X 62.610 Y 36.580 +G1 X 62.144 Y 35.946 +G1 X 61.673 Y 35.317 +G1 X 61.195 Y 34.692 +G1 X 60.710 Y 34.072 +G1 X 60.220 Y 33.457 +G1 X 59.723 Y 32.848 +G1 X 59.220 Y 32.243 +G1 X 58.711 Y 31.644 +G1 X 58.196 Y 31.049 +G1 X 57.674 Y 30.460 +G1 X 57.147 Y 29.877 +G1 X 56.614 Y 29.298 +G1 X 56.075 Y 28.725 +G1 X 55.531 Y 28.158 +G1 X 54.980 Y 27.596 +G1 X 54.424 Y 27.040 +G1 X 53.862 Y 26.490 +G1 X 53.295 Y 25.945 +G1 X 52.722 Y 25.406 +G1 X 52.144 Y 24.873 +G1 X 51.560 Y 24.346 +G1 X 50.971 Y 23.824 +G1 X 50.377 Y 23.309 +G1 X 49.777 Y 22.800 +G1 X 49.172 Y 22.297 +G1 X 48.563 Y 21.800 +G1 X 47.948 Y 21.310 +G1 X 47.328 Y 20.825 +G1 X 46.704 Y 20.347 +G1 X 46.074 Y 19.876 +G1 X 45.440 Y 19.410 +G1 X 44.801 Y 18.952 +G1 X 44.158 Y 18.499 +G1 X 43.509 Y 18.054 +G1 X 42.857 Y 17.615 +G1 X 42.200 Y 17.182 +G1 X 41.539 Y 16.757 +G1 X 40.873 Y 16.338 +G1 X 40.203 Y 15.926 +G1 X 39.529 Y 15.520 +G1 X 38.851 Y 15.122 +G1 X 38.169 Y 14.730 +G1 X 37.483 Y 14.346 +G1 X 36.793 Y 13.968 +G1 X 36.099 Y 13.598 +G1 X 35.401 Y 13.234 +G1 X 34.700 Y 12.878 +G1 X 33.995 Y 12.529 +G1 X 33.287 Y 12.187 +G1 X 32.575 Y 11.852 +G1 X 31.860 Y 11.524 +G1 X 31.142 Y 11.204 +G1 X 30.420 Y 10.891 +G1 X 29.696 Y 10.585 +G1 X 28.968 Y 10.287 +G1 X 28.237 Y 9.996 +G1 X 27.503 Y 9.713 +G1 X 26.767 Y 9.437 +G1 X 26.028 Y 9.169 +G1 X 25.285 Y 8.908 +G1 X 24.541 Y 8.655 +G1 X 23.794 Y 8.409 +G1 X 23.044 Y 8.171 +G1 X 22.292 Y 7.940 +G1 X 21.538 Y 7.717 +G1 X 20.781 Y 7.502 +G1 X 20.023 Y 7.295 +G1 X 19.262 Y 7.095 +G1 X 18.499 Y 6.903 +G1 X 17.734 Y 6.719 +G1 X 16.968 Y 6.543 +G1 X 16.200 Y 6.374 +G1 X 15.430 Y 6.213 +G1 X 14.658 Y 6.060 +G1 X 13.885 Y 5.915 +G1 X 13.111 Y 5.778 +G1 X 12.335 Y 5.649 +G1 X 11.558 Y 5.527 +G1 X 10.780 Y 5.414 +G1 X 10.000 Y 5.308 +G1 X 9.220 Y 5.210 +G1 X 8.438 Y 5.120 +G1 X 7.656 Y 5.039 +G1 X 6.873 Y 4.965 +G1 X 6.089 Y 4.899 +G1 X 5.305 Y 4.841 +G1 X 4.520 Y 4.791 +G1 X 3.735 Y 4.749 +G1 X 2.949 Y 4.715 +G1 X 2.163 Y 4.689 +G1 X 1.376 Y 4.671 +G1 X 0.590 Y 4.661 +G1 X -0.197 Y 4.659 +G1 X -0.983 Y 4.665 +G1 X -1.770 Y 4.679 +G1 X -2.556 Y 4.701 +G1 X -3.342 Y 4.731 +G1 X -4.127 Y 4.769 +G1 X -4.913 Y 4.815 +G1 X -5.697 Y 4.869 +G1 X -6.481 Y 4.931 +G1 X -7.265 Y 5.001 +G1 X -8.047 Y 5.079 +G1 X -8.829 Y 5.164 +G1 X -9.610 Y 5.258 +G1 X -10.390 Y 5.360 +G1 X -11.169 Y 5.469 +G1 X -11.947 Y 5.587 +G1 X -12.723 Y 5.712 +G1 X -13.498 Y 5.846 +G1 X -14.272 Y 5.987 +G1 X -15.044 Y 6.136 +G1 X -15.815 Y 6.293 +G1 X -16.584 Y 6.457 +G1 X -17.351 Y 6.630 +G1 X -18.117 Y 6.810 +G1 X -18.881 Y 6.998 +G1 X -19.642 Y 7.194 +G1 X -20.402 Y 7.398 +G1 X -21.160 Y 7.609 +G1 X -21.915 Y 7.828 +G1 X -22.668 Y 8.055 +G1 X -23.419 Y 8.289 +G1 X -24.168 Y 8.531 +G1 X -24.914 Y 8.780 +G1 X -25.657 Y 9.037 +G1 X -26.398 Y 9.302 +G1 X -27.135 Y 9.574 +G1 X -27.871 Y 9.854 +G1 X -28.603 Y 10.141 +G1 X -29.332 Y 10.435 +G1 X -30.058 Y 10.737 +G1 X -30.782 Y 11.046 +G1 X -31.502 Y 11.363 +G1 X -32.218 Y 11.687 +G1 X -32.932 Y 12.018 +G1 X -33.642 Y 12.357 +G1 X -34.348 Y 12.702 +G1 X -35.051 Y 13.055 +G1 X -35.751 Y 13.415 +G1 X -36.446 Y 13.782 +G1 X -37.138 Y 14.156 +G1 X -37.826 Y 14.537 +G1 X -38.510 Y 14.925 +G1 X -39.190 Y 15.320 +G1 X -39.866 Y 15.722 +G1 X -40.538 Y 16.131 +G1 X -41.206 Y 16.546 +G1 X -41.870 Y 16.969 +G1 X -42.529 Y 17.398 +G1 X -43.184 Y 17.833 +G1 X -43.834 Y 18.276 +G1 X -44.480 Y 18.725 +G1 X -45.121 Y 19.180 +G1 X -45.758 Y 19.642 +G1 X -46.389 Y 20.111 +G1 X -47.017 Y 20.586 +G1 X -47.639 Y 21.067 +G1 X -48.256 Y 21.554 +G1 X -48.868 Y 22.048 +G1 X -49.475 Y 22.548 +G1 X -50.077 Y 23.054 +G1 X -50.674 Y 23.566 +G1 X -51.266 Y 24.084 +G1 X -51.852 Y 24.609 +G1 X -52.433 Y 25.139 +G1 X -53.009 Y 25.675 +G1 X -53.579 Y 26.217 +G1 X -54.144 Y 26.764 +G1 X -54.703 Y 27.317 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 1 *) +G0 X -32.579 Y 103.353 +M3 M8 +G0 Z 34.000 +G1 Z 34.000 +F400 +G1 X -32.776 Y 103.556 +G1 X -32.968 Y 103.765 +G1 X -33.155 Y 103.979 +G1 X -33.335 Y 104.198 +G1 X -33.509 Y 104.422 +G1 X -33.676 Y 104.650 +G1 X -33.837 Y 104.884 +G1 X -33.992 Y 105.121 +G1 X -34.140 Y 105.363 +G1 X -34.281 Y 105.609 +G1 X -34.416 Y 105.859 +G1 X -34.543 Y 106.112 +G1 X -34.663 Y 106.369 +G1 X -34.776 Y 106.629 +G1 X -34.882 Y 106.893 +G1 X -34.981 Y 107.158 +G1 X -35.072 Y 107.427 +G1 X -35.155 Y 107.698 +G1 X -35.231 Y 107.971 +G1 X -35.299 Y 108.247 +G1 X -35.360 Y 108.524 +G1 X -35.413 Y 108.802 +G1 X -35.458 Y 109.082 +G1 X -35.495 Y 109.363 +G1 X -35.525 Y 109.645 +G1 X -35.547 Y 109.928 +G1 X -35.560 Y 110.211 +G1 X -35.566 Y 110.495 +G1 X -35.564 Y 110.779 +G1 X -35.554 Y 111.062 +G1 X -35.537 Y 111.345 +G1 X -35.511 Y 111.627 +G1 X -35.478 Y 111.909 +G1 X -35.436 Y 112.190 +G1 X -35.387 Y 112.469 +G1 X -35.331 Y 112.747 +G1 X -35.266 Y 113.023 +G1 X -35.194 Y 113.297 +G1 X -35.114 Y 113.569 +G1 X -35.027 Y 113.839 +G1 X -34.932 Y 114.107 +G1 X -34.830 Y 114.371 +G1 X -34.721 Y 114.633 +G1 X -34.604 Y 114.891 +G1 X -34.480 Y 115.146 +G1 X -34.349 Y 115.398 +G1 X -34.212 Y 115.646 +G1 X -34.067 Y 115.890 +G1 X -33.916 Y 116.130 +G1 X -33.758 Y 116.365 +G1 X -33.593 Y 116.596 +G1 X -33.422 Y 116.823 +G1 X -33.245 Y 117.044 +G1 X -33.062 Y 117.261 +G1 X -32.873 Y 117.472 +G1 X -32.678 Y 117.678 +G1 X -32.478 Y 117.879 +G1 X -32.272 Y 118.073 +G1 X -32.060 Y 118.263 +G1 X -31.844 Y 118.446 +G1 X -31.622 Y 118.623 +G1 X -31.396 Y 118.794 +G1 X -31.165 Y 118.958 +G1 X -30.929 Y 119.116 +G1 X -30.689 Y 119.267 +G1 X -30.446 Y 119.412 +G1 X -30.198 Y 119.550 +G1 X -29.946 Y 119.681 +G1 X -29.691 Y 119.804 +G1 X -29.432 Y 119.921 +G1 X -29.171 Y 120.031 +G1 X -28.906 Y 120.133 +G1 X -28.639 Y 120.227 +G1 X -28.369 Y 120.315 +G1 X -28.097 Y 120.394 +G1 X -27.823 Y 120.466 +G1 X -27.546 Y 120.531 +G1 X -27.269 Y 120.588 +G1 X -26.989 Y 120.637 +G1 X -26.709 Y 120.678 +G1 X -26.427 Y 120.711 +G1 X -26.145 Y 120.737 +G1 X -25.862 Y 120.755 +G1 X -25.578 Y 120.765 +G1 X -25.295 Y 120.767 +G1 X -25.011 Y 120.761 +G1 X -24.728 Y 120.747 +G1 X -24.445 Y 120.725 +G1 X -24.163 Y 120.696 +G1 X -23.882 Y 120.658 +G1 X -23.602 Y 120.613 +G1 X -23.323 Y 120.560 +G1 X -23.046 Y 120.500 +G1 X -22.771 Y 120.431 +G1 X -22.498 Y 120.355 +G1 X -22.227 Y 120.272 +G1 X -21.958 Y 120.181 +G1 X -21.692 Y 120.082 +G1 X -21.429 Y 119.977 +G1 X -21.169 Y 119.864 +G1 X -20.912 Y 119.743 +G1 X -20.659 Y 119.616 +G1 X -20.409 Y 119.482 +G1 X -20.163 Y 119.340 +G1 X -19.921 Y 119.192 +G1 X -19.683 Y 119.038 +G1 X -19.450 Y 118.877 +G1 X -19.221 Y 118.709 +G1 X -18.997 Y 118.535 +G1 X -18.778 Y 118.355 +G1 X -18.564 Y 118.169 +G1 X -18.356 Y 117.977 +G1 X -18.152 Y 117.779 +G1 X -17.955 Y 117.576 +G1 X -17.763 Y 117.367 +G1 X -17.576 Y 117.153 +G1 X -17.396 Y 116.934 +G1 X -17.222 Y 116.710 +G1 X -17.055 Y 116.481 +G1 X -16.894 Y 116.248 +G1 X -16.739 Y 116.010 +G1 X -16.591 Y 115.768 +G1 X -16.450 Y 115.522 +G1 X -16.315 Y 115.273 +G1 X -16.188 Y 115.019 +G1 X -16.068 Y 114.762 +G1 X -15.955 Y 114.502 +G1 X -15.849 Y 114.239 +G1 X -15.750 Y 113.973 +G1 X -15.659 Y 113.705 +G1 X -15.576 Y 113.434 +G1 X -15.500 Y 113.160 +G1 X -15.432 Y 112.885 +G1 X -15.371 Y 112.608 +G1 X -15.318 Y 112.329 +G1 X -15.273 Y 112.050 +G1 X -15.236 Y 111.768 +G1 X -15.206 Y 111.486 +G1 X -15.184 Y 111.204 +G1 X -15.171 Y 110.920 +G1 X -15.165 Y 110.637 +G1 X -15.167 Y 110.353 +G1 X -15.177 Y 110.070 +G1 X -15.194 Y 109.787 +G1 X -15.220 Y 109.504 +G1 X -15.253 Y 109.223 +G1 X -15.295 Y 108.942 +G1 X -15.344 Y 108.663 +G1 X -15.400 Y 108.385 +G1 X -15.465 Y 108.109 +G1 X -15.537 Y 107.834 +G1 X -15.617 Y 107.562 +G1 X -15.704 Y 107.292 +G1 X -15.799 Y 107.025 +G1 X -15.901 Y 106.761 +G1 X -16.010 Y 106.499 +G1 X -16.127 Y 106.240 +G1 X -16.251 Y 105.985 +G1 X -16.382 Y 105.734 +G1 X -16.519 Y 105.486 +G1 X -16.664 Y 105.242 +G1 X -16.815 Y 105.002 +G1 X -16.973 Y 104.767 +G1 X -17.138 Y 104.536 +G1 X -17.309 Y 104.309 +G1 X -17.486 Y 104.088 +G1 X -17.669 Y 103.871 +G1 X -17.858 Y 103.660 +G1 X -18.053 Y 103.454 +G1 X -18.253 Y 103.253 +G1 X -18.459 Y 103.058 +G1 X -18.671 Y 102.869 +G1 X -18.887 Y 102.686 +G1 X -19.109 Y 102.509 +G1 X -19.335 Y 102.338 +G1 X -19.566 Y 102.174 +G1 X -19.802 Y 102.016 +G1 X -20.042 Y 101.864 +G1 X -20.286 Y 101.720 +G1 X -20.533 Y 101.582 +G1 X -20.785 Y 101.451 +G1 X -21.040 Y 101.327 +G1 X -21.299 Y 101.211 +G1 X -21.560 Y 101.101 +G1 X -21.825 Y 100.999 +G1 X -22.092 Y 100.904 +G1 X -22.362 Y 100.817 +G1 X -22.634 Y 100.737 +G1 X -22.908 Y 100.665 +G1 X -23.185 Y 100.601 +G1 X -23.462 Y 100.544 +G1 X -23.742 Y 100.495 +G1 X -24.022 Y 100.454 +G1 X -24.304 Y 100.420 +G1 X -24.586 Y 100.395 +G1 X -24.869 Y 100.377 +G1 X -25.153 Y 100.367 +G1 X -25.436 Y 100.365 +G1 X -25.720 Y 100.371 +G1 X -26.003 Y 100.385 +G1 X -26.286 Y 100.407 +G1 X -26.568 Y 100.436 +G1 X -26.849 Y 100.473 +G1 X -27.129 Y 100.519 +G1 X -27.408 Y 100.571 +G1 X -27.685 Y 100.632 +G1 X -27.960 Y 100.700 +G1 X -28.233 Y 100.776 +G1 X -28.504 Y 100.860 +G1 X -28.773 Y 100.951 +G1 X -29.039 Y 101.049 +G1 X -29.302 Y 101.155 +G1 X -29.562 Y 101.268 +G1 X -29.819 Y 101.388 +G1 X -30.072 Y 101.516 +G1 X -30.322 Y 101.650 +G1 X -30.568 Y 101.791 +G1 X -30.810 Y 101.939 +G1 X -31.048 Y 102.094 +G1 X -31.281 Y 102.255 +G1 X -31.510 Y 102.423 +G1 X -31.734 Y 102.597 +G1 X -31.953 Y 102.777 +G1 X -32.167 Y 102.963 +G1 X -32.375 Y 103.155 +G1 X -32.579 Y 103.353 +F150 +G1 Z 34.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 2 *) +G0 X 19.468 Y 102.876 +M3 M8 +G0 Z 34.000 +G1 Z 34.000 +F400 +G1 X 19.270 Y 103.079 +G1 X 19.078 Y 103.288 +G1 X 18.892 Y 103.502 +G1 X 18.712 Y 103.721 +G1 X 18.538 Y 103.945 +G1 X 18.370 Y 104.173 +G1 X 18.209 Y 104.407 +G1 X 18.054 Y 104.644 +G1 X 17.906 Y 104.886 +G1 X 17.765 Y 105.132 +G1 X 17.631 Y 105.382 +G1 X 17.503 Y 105.635 +G1 X 17.383 Y 105.892 +G1 X 17.270 Y 106.152 +G1 X 17.164 Y 106.415 +G1 X 17.066 Y 106.681 +G1 X 16.975 Y 106.950 +G1 X 16.891 Y 107.221 +G1 X 16.815 Y 107.494 +G1 X 16.747 Y 107.769 +G1 X 16.686 Y 108.047 +G1 X 16.634 Y 108.325 +G1 X 16.588 Y 108.605 +G1 X 16.551 Y 108.886 +G1 X 16.522 Y 109.168 +G1 X 16.500 Y 109.451 +G1 X 16.486 Y 109.734 +G1 X 16.480 Y 110.018 +G1 X 16.482 Y 110.301 +G1 X 16.492 Y 110.585 +G1 X 16.510 Y 110.868 +G1 X 16.535 Y 111.150 +G1 X 16.569 Y 111.432 +G1 X 16.610 Y 111.713 +G1 X 16.659 Y 111.992 +G1 X 16.716 Y 112.270 +G1 X 16.780 Y 112.546 +G1 X 16.852 Y 112.820 +G1 X 16.932 Y 113.092 +G1 X 17.019 Y 113.362 +G1 X 17.114 Y 113.629 +G1 X 17.216 Y 113.894 +G1 X 17.326 Y 114.156 +G1 X 17.442 Y 114.414 +G1 X 17.566 Y 114.669 +G1 X 17.697 Y 114.921 +G1 X 17.835 Y 115.169 +G1 X 17.979 Y 115.413 +G1 X 18.131 Y 115.653 +G1 X 18.289 Y 115.888 +G1 X 18.453 Y 116.119 +G1 X 18.624 Y 116.345 +G1 X 18.801 Y 116.567 +G1 X 18.984 Y 116.784 +G1 X 19.173 Y 116.995 +G1 X 19.368 Y 117.201 +G1 X 19.569 Y 117.401 +G1 X 19.775 Y 117.596 +G1 X 19.986 Y 117.785 +G1 X 20.203 Y 117.969 +G1 X 20.424 Y 118.146 +G1 X 20.651 Y 118.316 +G1 X 20.882 Y 118.481 +G1 X 21.117 Y 118.639 +G1 X 21.357 Y 118.790 +G1 X 21.601 Y 118.935 +G1 X 21.849 Y 119.073 +G1 X 22.100 Y 119.203 +G1 X 22.356 Y 119.327 +G1 X 22.614 Y 119.444 +G1 X 22.876 Y 119.553 +G1 X 23.140 Y 119.656 +G1 X 23.408 Y 119.750 +G1 X 23.677 Y 119.838 +G1 X 23.950 Y 119.917 +G1 X 24.224 Y 119.989 +G1 X 24.500 Y 120.054 +G1 X 24.778 Y 120.111 +G1 X 25.057 Y 120.160 +G1 X 25.338 Y 120.201 +G1 X 25.619 Y 120.234 +G1 X 25.902 Y 120.260 +G1 X 26.185 Y 120.278 +G1 X 26.468 Y 120.288 +G1 X 26.752 Y 120.289 +G1 X 27.035 Y 120.284 +G1 X 27.319 Y 120.270 +G1 X 27.601 Y 120.248 +G1 X 27.883 Y 120.219 +G1 X 28.165 Y 120.181 +G1 X 28.445 Y 120.136 +G1 X 28.723 Y 120.083 +G1 X 29.000 Y 120.023 +G1 X 29.275 Y 119.954 +G1 X 29.549 Y 119.878 +G1 X 29.820 Y 119.795 +G1 X 30.088 Y 119.704 +G1 X 30.354 Y 119.605 +G1 X 30.617 Y 119.500 +G1 X 30.877 Y 119.387 +G1 X 31.134 Y 119.266 +G1 X 31.388 Y 119.139 +G1 X 31.637 Y 119.005 +G1 X 31.883 Y 118.863 +G1 X 32.125 Y 118.715 +G1 X 32.363 Y 118.561 +G1 X 32.596 Y 118.399 +G1 X 32.825 Y 118.232 +G1 X 33.049 Y 118.058 +G1 X 33.268 Y 117.878 +G1 X 33.482 Y 117.692 +G1 X 33.691 Y 117.500 +G1 X 33.894 Y 117.302 +G1 X 34.092 Y 117.099 +G1 X 34.284 Y 116.890 +G1 X 34.470 Y 116.676 +G1 X 34.650 Y 116.457 +G1 X 34.824 Y 116.233 +G1 X 34.992 Y 116.004 +G1 X 35.153 Y 115.771 +G1 X 35.308 Y 115.533 +G1 X 35.456 Y 115.291 +G1 X 35.597 Y 115.045 +G1 X 35.731 Y 114.796 +G1 X 35.858 Y 114.542 +G1 X 35.979 Y 114.285 +G1 X 36.092 Y 114.025 +G1 X 36.198 Y 113.762 +G1 X 36.296 Y 113.496 +G1 X 36.387 Y 113.228 +G1 X 36.470 Y 112.957 +G1 X 36.546 Y 112.683 +G1 X 36.615 Y 112.408 +G1 X 36.675 Y 112.131 +G1 X 36.728 Y 111.852 +G1 X 36.773 Y 111.572 +G1 X 36.811 Y 111.291 +G1 X 36.840 Y 111.009 +G1 X 36.862 Y 110.726 +G1 X 36.876 Y 110.443 +G1 X 36.882 Y 110.160 +G1 X 36.880 Y 109.876 +G1 X 36.870 Y 109.593 +G1 X 36.852 Y 109.310 +G1 X 36.827 Y 109.027 +G1 X 36.793 Y 108.746 +G1 X 36.752 Y 108.465 +G1 X 36.703 Y 108.186 +G1 X 36.646 Y 107.908 +G1 X 36.582 Y 107.632 +G1 X 36.509 Y 107.357 +G1 X 36.430 Y 107.085 +G1 X 36.342 Y 106.815 +G1 X 36.248 Y 106.548 +G1 X 36.146 Y 106.283 +G1 X 36.036 Y 106.022 +G1 X 35.919 Y 105.763 +G1 X 35.796 Y 105.508 +G1 X 35.665 Y 105.257 +G1 X 35.527 Y 105.009 +G1 X 35.382 Y 104.765 +G1 X 35.231 Y 104.525 +G1 X 35.073 Y 104.289 +G1 X 34.909 Y 104.058 +G1 X 34.738 Y 103.832 +G1 X 34.561 Y 103.610 +G1 X 34.378 Y 103.394 +G1 X 34.189 Y 103.183 +G1 X 33.994 Y 102.977 +G1 X 33.793 Y 102.776 +G1 X 33.587 Y 102.581 +G1 X 33.376 Y 102.392 +G1 X 33.159 Y 102.209 +G1 X 32.938 Y 102.032 +G1 X 32.711 Y 101.861 +G1 X 32.480 Y 101.697 +G1 X 32.245 Y 101.539 +G1 X 32.005 Y 101.387 +G1 X 31.761 Y 101.243 +G1 X 31.513 Y 101.105 +G1 X 31.261 Y 100.974 +G1 X 31.006 Y 100.850 +G1 X 30.748 Y 100.734 +G1 X 30.486 Y 100.624 +G1 X 30.222 Y 100.522 +G1 X 29.954 Y 100.427 +G1 X 29.684 Y 100.340 +G1 X 29.412 Y 100.260 +G1 X 29.138 Y 100.188 +G1 X 28.862 Y 100.124 +G1 X 28.584 Y 100.067 +G1 X 28.305 Y 100.018 +G1 X 28.024 Y 99.977 +G1 X 27.743 Y 99.943 +G1 X 27.460 Y 99.918 +G1 X 27.177 Y 99.900 +G1 X 26.894 Y 99.890 +G1 X 26.610 Y 99.888 +G1 X 26.326 Y 99.894 +G1 X 26.043 Y 99.908 +G1 X 25.760 Y 99.929 +G1 X 25.478 Y 99.959 +G1 X 25.197 Y 99.996 +G1 X 24.917 Y 100.041 +G1 X 24.639 Y 100.094 +G1 X 24.362 Y 100.155 +G1 X 24.086 Y 100.223 +G1 X 23.813 Y 100.299 +G1 X 23.542 Y 100.383 +G1 X 23.274 Y 100.474 +G1 X 23.008 Y 100.572 +G1 X 22.744 Y 100.678 +G1 X 22.484 Y 100.791 +G1 X 22.228 Y 100.911 +G1 X 21.974 Y 101.039 +G1 X 21.724 Y 101.173 +G1 X 21.478 Y 101.314 +G1 X 21.237 Y 101.462 +G1 X 20.999 Y 101.617 +G1 X 20.766 Y 101.778 +G1 X 20.537 Y 101.946 +G1 X 20.313 Y 102.120 +G1 X 20.094 Y 102.300 +G1 X 19.880 Y 102.486 +G1 X 19.671 Y 102.678 +G1 X 19.468 Y 102.876 +F150 +G1 Z 34.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 3 *) +G0 X 31.864 Y 68.340 +M3 M8 +G0 Z 32.000 +G1 Z 32.000 +F400 +G1 X 31.663 Y 67.487 +G1 X 31.454 Y 66.635 +G1 X 31.238 Y 65.785 +G1 X 31.014 Y 64.937 +G1 X 30.808 Y 64.184 +G1 X 30.596 Y 63.432 +G1 X 30.376 Y 62.683 +G1 X 30.150 Y 61.935 +G1 X 29.917 Y 61.190 +G1 X 29.721 Y 60.583 +G1 X 29.520 Y 59.978 +G1 X 29.314 Y 59.375 +G1 X 29.102 Y 58.773 +G1 X 28.885 Y 58.173 +G1 X 28.663 Y 57.576 +G1 X 28.414 Y 56.925 +G1 X 28.157 Y 56.277 +G1 X 27.893 Y 55.632 +G1 X 27.622 Y 54.990 +G1 X 27.343 Y 54.351 +G1 X 27.110 Y 53.832 +G1 X 26.872 Y 53.316 +G1 X 26.628 Y 52.803 +G1 X 26.378 Y 52.292 +G1 X 26.123 Y 51.784 +G1 X 25.863 Y 51.279 +G1 X 25.620 Y 50.821 +G1 X 25.372 Y 50.366 +G1 X 25.118 Y 49.914 +G1 X 24.859 Y 49.465 +G1 X 24.595 Y 49.019 +G1 X 24.326 Y 48.576 +G1 X 24.057 Y 48.145 +G1 X 23.782 Y 47.718 +G1 X 23.502 Y 47.295 +G1 X 23.216 Y 46.875 +G1 X 22.924 Y 46.459 +G1 X 22.627 Y 46.047 +G1 X 22.349 Y 45.673 +G1 X 22.066 Y 45.303 +G1 X 21.777 Y 44.937 +G1 X 21.484 Y 44.574 +G1 X 21.185 Y 44.217 +G1 X 20.882 Y 43.863 +G1 X 20.577 Y 43.519 +G1 X 20.267 Y 43.180 +G1 X 19.952 Y 42.845 +G1 X 19.632 Y 42.516 +G1 X 19.306 Y 42.192 +G1 X 18.976 Y 41.873 +G1 X 18.658 Y 41.576 +G1 X 18.336 Y 41.285 +G1 X 18.009 Y 40.999 +G1 X 17.677 Y 40.719 +G1 X 17.340 Y 40.444 +G1 X 16.999 Y 40.175 +G1 X 16.650 Y 39.909 +G1 X 16.297 Y 39.650 +G1 X 15.938 Y 39.397 +G1 X 15.575 Y 39.150 +G1 X 15.208 Y 38.910 +G1 X 14.836 Y 38.677 +G1 X 14.461 Y 38.451 +G1 X 14.100 Y 38.242 +G1 X 13.735 Y 38.040 +G1 X 13.367 Y 37.845 +G1 X 12.995 Y 37.656 +G1 X 12.620 Y 37.474 +G1 X 12.242 Y 37.299 +G1 X 11.860 Y 37.131 +G1 X 11.476 Y 36.969 +G1 X 11.135 Y 36.833 +G1 X 10.793 Y 36.702 +G1 X 10.448 Y 36.577 +G1 X 10.102 Y 36.457 +G1 X 9.754 Y 36.343 +G1 X 9.404 Y 36.234 +G1 X 9.020 Y 36.121 +G1 X 8.634 Y 36.015 +G1 X 8.246 Y 35.915 +G1 X 7.857 Y 35.821 +G1 X 7.466 Y 35.734 +G1 X 7.074 Y 35.653 +G1 X 6.680 Y 35.579 +G1 X 6.260 Y 35.506 +G1 X 5.839 Y 35.441 +G1 X 5.418 Y 35.382 +G1 X 4.995 Y 35.330 +G1 X 4.571 Y 35.285 +G1 X 4.147 Y 35.246 +G1 X 3.723 Y 35.215 +G1 X 3.300 Y 35.189 +G1 X 2.875 Y 35.170 +G1 X 2.451 Y 35.156 +G1 X 2.026 Y 35.149 +G1 X 1.602 Y 35.148 +G1 X 1.177 Y 35.152 +G1 X 0.705 Y 35.164 +G1 X 0.233 Y 35.183 +G1 X -0.238 Y 35.208 +G1 X -0.709 Y 35.239 +G1 X -1.162 Y 35.275 +G1 X -1.614 Y 35.318 +G1 X -2.065 Y 35.366 +G1 X -2.516 Y 35.420 +G1 X -2.966 Y 35.481 +G1 X -3.422 Y 35.549 +G1 X -3.876 Y 35.623 +G1 X -4.329 Y 35.705 +G1 X -4.781 Y 35.793 +G1 X -5.232 Y 35.887 +G1 X -5.681 Y 35.989 +G1 X -6.129 Y 36.097 +G1 X -6.564 Y 36.210 +G1 X -6.998 Y 36.329 +G1 X -7.429 Y 36.455 +G1 X -7.859 Y 36.588 +G1 X -8.286 Y 36.728 +G1 X -8.711 Y 36.874 +G1 X -9.134 Y 37.027 +G1 X -9.554 Y 37.187 +G1 X -9.965 Y 37.351 +G1 X -10.373 Y 37.522 +G1 X -10.779 Y 37.699 +G1 X -11.181 Y 37.883 +G1 X -11.581 Y 38.073 +G1 X -11.977 Y 38.270 +G1 X -12.371 Y 38.473 +G1 X -12.760 Y 38.683 +G1 X -13.147 Y 38.899 +G1 X -13.530 Y 39.121 +G1 X -13.933 Y 39.364 +G1 X -14.331 Y 39.613 +G1 X -14.726 Y 39.869 +G1 X -15.116 Y 40.132 +G1 X -15.501 Y 40.402 +G1 X -15.882 Y 40.678 +G1 X -16.226 Y 40.935 +G1 X -16.565 Y 41.197 +G1 X -16.901 Y 41.463 +G1 X -17.233 Y 41.735 +G1 X -17.560 Y 42.012 +G1 X -17.884 Y 42.293 +G1 X -18.204 Y 42.579 +G1 X -18.527 Y 42.877 +G1 X -18.846 Y 43.179 +G1 X -19.161 Y 43.485 +G1 X -19.472 Y 43.796 +G1 X -19.778 Y 44.111 +G1 X -20.080 Y 44.431 +G1 X -20.407 Y 44.787 +G1 X -20.730 Y 45.148 +G1 X -21.047 Y 45.513 +G1 X -21.360 Y 45.882 +G1 X -21.667 Y 46.256 +G1 X -21.969 Y 46.634 +G1 X -22.259 Y 47.007 +G1 X -22.545 Y 47.383 +G1 X -22.825 Y 47.762 +G1 X -23.102 Y 48.146 +G1 X -23.373 Y 48.532 +G1 X -23.640 Y 48.922 +G1 X -23.933 Y 49.361 +G1 X -24.221 Y 49.804 +G1 X -24.504 Y 50.250 +G1 X -24.781 Y 50.699 +G1 X -25.053 Y 51.152 +G1 X -25.320 Y 51.608 +G1 X -25.626 Y 52.147 +G1 X -25.925 Y 52.689 +G1 X -26.218 Y 53.235 +G1 X -26.504 Y 53.784 +G1 X -26.783 Y 54.337 +G1 X -27.040 Y 54.860 +G1 X -27.291 Y 55.385 +G1 X -27.537 Y 55.913 +G1 X -27.778 Y 56.443 +G1 X -28.013 Y 56.975 +G1 X -28.243 Y 57.510 +G1 X -28.509 Y 58.146 +G1 X -28.768 Y 58.784 +G1 X -29.020 Y 59.425 +G1 X -29.266 Y 60.068 +G1 X -29.505 Y 60.714 +G1 X -29.743 Y 61.376 +G1 X -29.975 Y 62.040 +G1 X -30.201 Y 62.707 +G1 X -30.421 Y 63.375 +G1 X -30.635 Y 64.046 +G1 X -30.843 Y 64.718 +G1 X -31.060 Y 65.444 +G1 X -31.272 Y 66.172 +G1 X -31.477 Y 66.902 +G1 X -31.677 Y 67.633 +G1 X -31.870 Y 68.366 +F150 +G1 Z 32.000 +G0 Z 100.000 +M9 M5 +G0 X 0.000 Y 0.000 +M2 (Program end) \ No newline at end of file diff --git a/src/jetmax_demos/scripts/gcode/surprise.ngc b/src/jetmax_demos/scripts/gcode/surprise.ngc new file mode 100644 index 0000000..3c119ac --- /dev/null +++ b/src/jetmax_demos/scripts/gcode/surprise.ngc @@ -0,0 +1,1580 @@ +(Generated with: DXF2GCODE, Version: Py3.7.10 PyQt5.10.1, Date: $Date: Fri Oct 25 20:45:56 2019 +0200 $) +(Created from file: /home/lucas/惊讶.dxf) +(Output format description: G-CODE for LinuxCNC) +(Time: Sat Jul 17 10:44:51 2021) +G21 (Units in millimeters) +G90 (Absolute programming) +G64 (Default cutting) G17 (XY plane) G40 (Cancel radius comp.) G49 (Cancel length comp.) +G0 Z 100.000 + +(*** LAYER: 0 ***) +T1 M6 +S6000 + +(* SHAPE Nr: 0 *) +G0 X 75.453 Y 84.477 +M3 M8 +G0 Z 30.000 +F150 +G1 Z 30.000 +F100 +G1 X 75.370 Y 83.724 +G1 X 75.280 Y 82.971 +G1 X 75.183 Y 82.220 +G1 X 75.079 Y 81.469 +G1 X 74.967 Y 80.719 +G1 X 74.848 Y 79.971 +G1 X 74.721 Y 79.224 +G1 X 74.587 Y 78.478 +G1 X 74.446 Y 77.733 +G1 X 74.297 Y 76.990 +G1 X 74.142 Y 76.249 +G1 X 73.978 Y 75.508 +G1 X 73.808 Y 74.770 +G1 X 73.630 Y 74.033 +G1 X 73.446 Y 73.298 +G1 X 73.254 Y 72.565 +G1 X 73.054 Y 71.834 +G1 X 72.848 Y 71.105 +G1 X 72.634 Y 70.378 +G1 X 72.414 Y 69.653 +G1 X 72.186 Y 68.930 +G1 X 71.951 Y 68.209 +G1 X 71.709 Y 67.491 +G1 X 71.460 Y 66.775 +G1 X 71.204 Y 66.062 +G1 X 70.941 Y 65.351 +G1 X 70.671 Y 64.643 +G1 X 70.388 Y 63.923 +G1 X 70.098 Y 63.205 +G1 X 69.801 Y 62.491 +G1 X 69.496 Y 61.779 +G1 X 69.185 Y 61.070 +G1 X 68.867 Y 60.365 +G1 X 68.541 Y 59.663 +G1 X 68.208 Y 58.964 +G1 X 67.869 Y 58.268 +G1 X 67.523 Y 57.576 +G1 X 67.169 Y 56.888 +G1 X 66.809 Y 56.203 +G1 X 66.442 Y 55.521 +G1 X 66.068 Y 54.843 +G1 X 65.688 Y 54.170 +G1 X 65.300 Y 53.499 +G1 X 64.907 Y 52.833 +G1 X 64.506 Y 52.171 +G1 X 64.099 Y 51.513 +G1 X 63.685 Y 50.859 +G1 X 63.265 Y 50.209 +G1 X 62.838 Y 49.563 +G1 X 62.405 Y 48.922 +G1 X 61.965 Y 48.285 +G1 X 61.520 Y 47.652 +G1 X 61.067 Y 47.024 +G1 X 60.609 Y 46.400 +G1 X 60.144 Y 45.781 +G1 X 59.674 Y 45.167 +G1 X 59.197 Y 44.557 +G1 X 58.714 Y 43.953 +G1 X 58.225 Y 43.353 +G1 X 57.730 Y 42.758 +G1 X 57.229 Y 42.168 +G1 X 56.722 Y 41.583 +G1 X 56.210 Y 41.003 +G1 X 55.691 Y 40.428 +G1 X 55.167 Y 39.858 +G1 X 54.638 Y 39.294 +G1 X 54.102 Y 38.735 +G1 X 53.561 Y 38.181 +G1 X 53.015 Y 37.633 +G1 X 52.463 Y 37.091 +G1 X 51.906 Y 36.553 +G1 X 51.355 Y 36.033 +G1 X 50.799 Y 35.518 +G1 X 50.238 Y 35.008 +G1 X 49.672 Y 34.504 +G1 X 49.101 Y 34.005 +G1 X 48.525 Y 33.512 +G1 X 47.944 Y 33.025 +G1 X 47.359 Y 32.543 +G1 X 46.768 Y 32.067 +G1 X 46.174 Y 31.597 +G1 X 45.574 Y 31.133 +G1 X 44.970 Y 30.675 +G1 X 44.362 Y 30.222 +G1 X 43.749 Y 29.776 +G1 X 43.132 Y 29.336 +G1 X 42.510 Y 28.902 +G1 X 41.885 Y 28.474 +G1 X 41.255 Y 28.052 +G1 X 40.621 Y 27.636 +G1 X 39.983 Y 27.227 +G1 X 39.341 Y 26.824 +G1 X 38.695 Y 26.427 +G1 X 38.045 Y 26.037 +G1 X 37.391 Y 25.653 +G1 X 36.734 Y 25.275 +G1 X 36.073 Y 24.904 +G1 X 35.408 Y 24.539 +G1 X 34.761 Y 24.192 +G1 X 34.110 Y 23.851 +G1 X 33.456 Y 23.516 +G1 X 32.799 Y 23.188 +G1 X 32.138 Y 22.866 +G1 X 31.475 Y 22.549 +G1 X 30.809 Y 22.240 +G1 X 30.140 Y 21.936 +G1 X 29.468 Y 21.639 +G1 X 28.793 Y 21.348 +G1 X 28.116 Y 21.064 +G1 X 27.436 Y 20.786 +G1 X 26.754 Y 20.515 +G1 X 26.070 Y 20.250 +G1 X 25.383 Y 19.992 +G1 X 24.693 Y 19.740 +G1 X 24.001 Y 19.495 +G1 X 23.307 Y 19.256 +G1 X 22.611 Y 19.024 +G1 X 21.913 Y 18.798 +G1 X 21.212 Y 18.580 +G1 X 20.509 Y 18.367 +G1 X 19.782 Y 18.155 +G1 X 19.052 Y 17.950 +G1 X 18.321 Y 17.752 +G1 X 17.587 Y 17.561 +G1 X 16.852 Y 17.378 +G1 X 16.115 Y 17.202 +G1 X 15.376 Y 17.033 +G1 X 14.636 Y 16.871 +G1 X 13.894 Y 16.717 +G1 X 13.150 Y 16.569 +G1 X 12.405 Y 16.430 +G1 X 11.659 Y 16.297 +G1 X 10.912 Y 16.172 +G1 X 10.163 Y 16.054 +G1 X 9.413 Y 15.943 +G1 X 8.663 Y 15.840 +G1 X 7.911 Y 15.745 +G1 X 7.158 Y 15.656 +G1 X 6.405 Y 15.575 +G1 X 5.650 Y 15.502 +G1 X 4.895 Y 15.436 +G1 X 4.140 Y 15.377 +G1 X 3.384 Y 15.326 +G1 X 2.627 Y 15.282 +G1 X 1.870 Y 15.245 +G1 X 1.113 Y 15.216 +G1 X 0.355 Y 15.195 +G1 X -0.419 Y 15.180 +G1 X -1.192 Y 15.174 +G1 X -1.966 Y 15.175 +G1 X -2.740 Y 15.184 +G1 X -3.514 Y 15.200 +G1 X -4.288 Y 15.225 +G1 X -5.061 Y 15.257 +G1 X -5.834 Y 15.296 +G1 X -6.606 Y 15.344 +G1 X -7.378 Y 15.399 +G1 X -8.150 Y 15.462 +G1 X -8.921 Y 15.533 +G1 X -9.691 Y 15.611 +G1 X -10.460 Y 15.697 +G1 X -11.228 Y 15.791 +G1 X -11.995 Y 15.892 +G1 X -12.762 Y 16.001 +G1 X -13.527 Y 16.118 +G1 X -14.291 Y 16.242 +G1 X -15.053 Y 16.374 +G1 X -15.815 Y 16.513 +G1 X -16.574 Y 16.660 +G1 X -17.333 Y 16.815 +G1 X -18.090 Y 16.977 +G1 X -18.845 Y 17.147 +G1 X -19.598 Y 17.325 +G1 X -20.350 Y 17.509 +G1 X -21.099 Y 17.702 +G1 X -21.847 Y 17.902 +G1 X -22.593 Y 18.109 +G1 X -23.336 Y 18.324 +G1 X -24.078 Y 18.546 +G1 X -24.817 Y 18.776 +G1 X -25.553 Y 19.012 +G1 X -26.288 Y 19.257 +G1 X -27.020 Y 19.508 +G1 X -27.749 Y 19.767 +G1 X -28.476 Y 20.034 +G1 X -29.200 Y 20.307 +G1 X -29.921 Y 20.588 +G1 X -30.640 Y 20.876 +G1 X -31.355 Y 21.171 +G1 X -32.068 Y 21.473 +G1 X -32.777 Y 21.782 +G1 X -33.469 Y 22.092 +G1 X -34.158 Y 22.408 +G1 X -34.844 Y 22.732 +G1 X -35.526 Y 23.062 +G1 X -36.205 Y 23.398 +G1 X -36.881 Y 23.742 +G1 X -37.554 Y 24.092 +G1 X -38.223 Y 24.448 +G1 X -38.888 Y 24.812 +G1 X -39.550 Y 25.181 +G1 X -40.208 Y 25.557 +G1 X -40.863 Y 25.940 +G1 X -41.513 Y 26.329 +G1 X -42.160 Y 26.724 +G1 X -42.803 Y 27.126 +G1 X -43.442 Y 27.534 +G1 X -44.077 Y 27.948 +G1 X -44.708 Y 28.369 +G1 X -45.334 Y 28.796 +G1 X -45.957 Y 29.228 +G1 X -46.575 Y 29.667 +G1 X -47.189 Y 30.112 +G1 X -47.798 Y 30.563 +G1 X -48.403 Y 31.020 +G1 X -49.003 Y 31.483 +G1 X -49.599 Y 31.952 +G1 X -50.190 Y 32.426 +G1 X -50.759 Y 32.892 +G1 X -51.323 Y 33.363 +G1 X -51.882 Y 33.839 +G1 X -52.437 Y 34.320 +G1 X -52.988 Y 34.807 +G1 X -53.534 Y 35.298 +G1 X -54.075 Y 35.795 +G1 X -54.611 Y 36.297 +G1 X -55.143 Y 36.805 +G1 X -55.670 Y 37.317 +G1 X -56.192 Y 37.834 +G1 X -56.709 Y 38.355 +G1 X -57.220 Y 38.882 +G1 X -57.727 Y 39.413 +G1 X -58.229 Y 39.949 +G1 X -58.726 Y 40.490 +G1 X -59.217 Y 41.036 +G1 X -59.704 Y 41.586 +G1 X -60.185 Y 42.140 +G1 X -60.660 Y 42.700 +G1 X -61.131 Y 43.263 +G1 X -61.596 Y 43.831 +G1 X -62.075 Y 44.428 +G1 X -62.548 Y 45.030 +G1 X -63.016 Y 45.636 +G1 X -63.477 Y 46.247 +G1 X -63.932 Y 46.862 +G1 X -64.381 Y 47.482 +G1 X -64.823 Y 48.106 +G1 X -65.260 Y 48.735 +G1 X -65.690 Y 49.368 +G1 X -66.114 Y 50.005 +G1 X -66.532 Y 50.646 +G1 X -66.943 Y 51.291 +G1 X -67.348 Y 51.941 +G1 X -67.746 Y 52.594 +G1 X -68.138 Y 53.252 +G1 X -68.523 Y 53.913 +G1 X -68.902 Y 54.578 +G1 X -69.274 Y 55.247 +G1 X -69.640 Y 55.919 +G1 X -69.999 Y 56.595 +G1 X -70.351 Y 57.275 +G1 X -70.696 Y 57.957 +G1 X -71.034 Y 58.644 +G1 X -71.366 Y 59.334 +G1 X -71.687 Y 60.017 +G1 X -72.000 Y 60.703 +G1 X -72.307 Y 61.393 +G1 X -72.608 Y 62.085 +G1 X -72.901 Y 62.781 +G1 X -73.188 Y 63.479 +G1 X -73.468 Y 64.180 +G1 X -73.741 Y 64.883 +G1 X -74.007 Y 65.590 +G1 X -74.267 Y 66.298 +G1 X -74.519 Y 67.010 +G1 X -74.764 Y 67.723 +G1 X -75.003 Y 68.439 +G1 X -75.234 Y 69.158 +G1 X -75.459 Y 69.878 +G1 X -75.676 Y 70.601 +G1 X -75.887 Y 71.326 +G1 X -76.096 Y 72.075 +G1 X -76.297 Y 72.825 +G1 X -76.492 Y 73.578 +G1 X -76.678 Y 74.332 +G1 X -76.857 Y 75.088 +G1 X -77.029 Y 75.846 +G1 X -77.193 Y 76.606 +G1 X -77.349 Y 77.367 +G1 X -77.497 Y 78.130 +G1 X -77.638 Y 78.895 +G1 X -77.771 Y 79.660 +G1 X -77.897 Y 80.427 +G1 X -78.015 Y 81.195 +G1 X -78.125 Y 81.965 +G1 X -78.227 Y 82.735 +G1 X -78.322 Y 83.507 +G1 X -78.409 Y 84.279 +G1 X -78.488 Y 85.052 +G1 X -78.559 Y 85.826 +G1 X -78.623 Y 86.600 +G1 X -78.679 Y 87.376 +G1 X -78.727 Y 88.151 +G1 X -78.767 Y 88.927 +G1 X -78.800 Y 89.704 +G1 X -78.825 Y 90.481 +G1 X -78.841 Y 91.258 +G1 X -78.851 Y 92.035 +G1 X -78.852 Y 92.812 +G1 X -78.845 Y 93.589 +G1 X -78.831 Y 94.366 +G1 X -78.810 Y 95.124 +G1 X -78.781 Y 95.881 +G1 X -78.745 Y 96.639 +G1 X -78.701 Y 97.396 +G1 X -78.650 Y 98.152 +G1 X -78.591 Y 98.908 +G1 X -78.525 Y 99.663 +G1 X -78.452 Y 100.417 +G1 X -78.371 Y 101.171 +G1 X -78.282 Y 101.924 +G1 X -78.187 Y 102.676 +G1 X -78.084 Y 103.427 +G1 X -77.973 Y 104.177 +G1 X -77.856 Y 104.926 +G1 X -77.731 Y 105.674 +G1 X -77.598 Y 106.420 +G1 X -77.458 Y 107.165 +G1 X -77.311 Y 107.909 +G1 X -77.157 Y 108.651 +G1 X -76.995 Y 109.392 +G1 X -76.826 Y 110.131 +G1 X -76.650 Y 110.868 +G1 X -76.466 Y 111.604 +G1 X -76.276 Y 112.338 +G1 X -76.078 Y 113.069 +G1 X -75.873 Y 113.799 +G1 X -75.661 Y 114.527 +G1 X -75.448 Y 115.230 +G1 X -75.229 Y 115.932 +G1 X -75.003 Y 116.631 +G1 X -74.771 Y 117.328 +G1 X -74.532 Y 118.023 +G1 X -74.287 Y 118.715 +G1 X -74.035 Y 119.405 +G1 X -73.776 Y 120.093 +G1 X -73.511 Y 120.778 +G1 X -73.240 Y 121.461 +G1 X -72.962 Y 122.141 +G1 X -72.678 Y 122.818 +G1 X -72.387 Y 123.492 +G1 X -72.090 Y 124.163 +G1 X -71.787 Y 124.832 +G1 X -71.478 Y 125.497 +G1 X -71.162 Y 126.160 +G1 X -70.840 Y 126.819 +G1 X -70.512 Y 127.476 +G1 X -70.177 Y 128.129 +G1 X -69.837 Y 128.780 +G1 X -69.490 Y 129.426 +G1 X -69.126 Y 130.091 +G1 X -68.755 Y 130.752 +G1 X -68.377 Y 131.409 +G1 X -67.994 Y 132.063 +G1 X -67.603 Y 132.712 +G1 X -67.207 Y 133.358 +G1 X -66.804 Y 134.000 +G1 X -66.395 Y 134.638 +G1 X -65.979 Y 135.272 +G1 X -65.558 Y 135.901 +G1 X -65.130 Y 136.527 +G1 X -64.696 Y 137.148 +G1 X -64.256 Y 137.765 +G1 X -63.810 Y 138.378 +G1 X -63.358 Y 138.986 +G1 X -62.900 Y 139.590 +G1 X -62.436 Y 140.189 +G1 X -61.966 Y 140.784 +G1 X -61.491 Y 141.374 +G1 X -61.009 Y 141.960 +G1 X -60.522 Y 142.540 +G1 X -60.030 Y 143.116 +G1 X -59.531 Y 143.687 +G1 X -59.027 Y 144.253 +G1 X -58.518 Y 144.814 +G1 X -58.003 Y 145.370 +G1 X -57.482 Y 145.921 +G1 X -56.945 Y 146.478 +G1 X -56.403 Y 147.030 +G1 X -55.855 Y 147.577 +G1 X -55.301 Y 148.118 +G1 X -54.742 Y 148.653 +G1 X -54.178 Y 149.183 +G1 X -53.609 Y 149.707 +G1 X -53.034 Y 150.225 +G1 X -52.454 Y 150.738 +G1 X -51.869 Y 151.245 +G1 X -51.279 Y 151.746 +G1 X -50.684 Y 152.241 +G1 X -50.085 Y 152.730 +G1 X -49.480 Y 153.213 +G1 X -48.870 Y 153.690 +G1 X -48.256 Y 154.161 +G1 X -47.637 Y 154.626 +G1 X -47.014 Y 155.084 +G1 X -46.386 Y 155.537 +G1 X -45.753 Y 155.983 +G1 X -45.116 Y 156.422 +G1 X -44.475 Y 156.856 +G1 X -43.829 Y 157.282 +G1 X -43.179 Y 157.703 +G1 X -42.525 Y 158.117 +G1 X -41.867 Y 158.524 +G1 X -41.205 Y 158.925 +G1 X -40.539 Y 159.319 +G1 X -39.869 Y 159.706 +G1 X -39.195 Y 160.087 +G1 X -38.517 Y 160.461 +G1 X -37.836 Y 160.828 +G1 X -37.151 Y 161.188 +G1 X -36.463 Y 161.542 +G1 X -35.770 Y 161.888 +G1 X -35.075 Y 162.228 +G1 X -34.376 Y 162.560 +G1 X -33.674 Y 162.886 +G1 X -32.969 Y 163.205 +G1 X -32.260 Y 163.516 +G1 X -31.549 Y 163.821 +G1 X -30.834 Y 164.118 +G1 X -30.117 Y 164.408 +G1 X -29.396 Y 164.691 +G1 X -28.688 Y 164.961 +G1 X -27.977 Y 165.225 +G1 X -27.264 Y 165.481 +G1 X -26.548 Y 165.730 +G1 X -25.829 Y 165.972 +G1 X -25.108 Y 166.207 +G1 X -24.385 Y 166.435 +G1 X -23.660 Y 166.656 +G1 X -22.933 Y 166.870 +G1 X -22.204 Y 167.077 +G1 X -21.472 Y 167.276 +G1 X -20.739 Y 167.468 +G1 X -20.004 Y 167.653 +G1 X -19.267 Y 167.831 +G1 X -18.528 Y 168.002 +G1 X -17.788 Y 168.165 +G1 X -17.046 Y 168.321 +G1 X -16.302 Y 168.470 +G1 X -15.558 Y 168.611 +G1 X -14.812 Y 168.745 +G1 X -14.064 Y 168.872 +G1 X -13.315 Y 168.991 +G1 X -12.566 Y 169.103 +G1 X -11.815 Y 169.208 +G1 X -11.063 Y 169.305 +G1 X -10.310 Y 169.395 +G1 X -9.557 Y 169.477 +G1 X -8.826 Y 169.550 +G1 X -8.094 Y 169.616 +G1 X -7.361 Y 169.675 +G1 X -6.629 Y 169.727 +G1 X -5.895 Y 169.772 +G1 X -5.162 Y 169.811 +G1 X -4.427 Y 169.842 +G1 X -3.693 Y 169.866 +G1 X -2.959 Y 169.884 +G1 X -2.224 Y 169.894 +G1 X -1.489 Y 169.898 +G1 X -0.742 Y 169.894 +G1 X 0.005 Y 169.883 +G1 X 0.753 Y 169.865 +G1 X 1.500 Y 169.840 +G1 X 2.246 Y 169.807 +G1 X 2.993 Y 169.768 +G1 X 3.739 Y 169.721 +G1 X 4.498 Y 169.666 +G1 X 5.257 Y 169.603 +G1 X 6.016 Y 169.533 +G1 X 6.773 Y 169.455 +G1 X 7.530 Y 169.370 +G1 X 8.286 Y 169.278 +G1 X 9.041 Y 169.178 +G1 X 9.795 Y 169.070 +G1 X 10.548 Y 168.956 +G1 X 11.300 Y 168.834 +G1 X 12.050 Y 168.704 +G1 X 12.799 Y 168.567 +G1 X 13.547 Y 168.423 +G1 X 14.293 Y 168.271 +G1 X 15.038 Y 168.112 +G1 X 15.781 Y 167.945 +G1 X 16.523 Y 167.772 +G1 X 17.263 Y 167.591 +G1 X 18.001 Y 167.402 +G1 X 18.737 Y 167.207 +G1 X 19.472 Y 167.004 +G1 X 20.204 Y 166.794 +G1 X 20.934 Y 166.577 +G1 X 21.663 Y 166.352 +G1 X 22.388 Y 166.120 +G1 X 23.112 Y 165.882 +G1 X 23.833 Y 165.636 +G1 X 24.552 Y 165.383 +G1 X 25.268 Y 165.123 +G1 X 25.982 Y 164.856 +G1 X 26.693 Y 164.582 +G1 X 27.401 Y 164.301 +G1 X 28.106 Y 164.013 +G1 X 28.809 Y 163.718 +G1 X 29.508 Y 163.416 +G1 X 30.205 Y 163.107 +G1 X 30.898 Y 162.792 +G1 X 31.589 Y 162.469 +G1 X 32.276 Y 162.140 +G1 X 32.960 Y 161.804 +G1 X 33.640 Y 161.462 +G1 X 34.317 Y 161.112 +G1 X 34.991 Y 160.756 +G1 X 35.661 Y 160.394 +G1 X 36.328 Y 160.025 +G1 X 36.991 Y 159.649 +G1 X 37.650 Y 159.267 +G1 X 38.305 Y 158.878 +G1 X 38.957 Y 158.482 +G1 X 39.605 Y 158.081 +G1 X 40.249 Y 157.672 +G1 X 40.890 Y 157.258 +G1 X 41.525 Y 156.837 +G1 X 42.157 Y 156.410 +G1 X 42.785 Y 155.976 +G1 X 43.408 Y 155.537 +G1 X 44.027 Y 155.091 +G1 X 44.641 Y 154.639 +G1 X 45.251 Y 154.182 +G1 X 45.857 Y 153.718 +G1 X 46.457 Y 153.248 +G1 X 47.054 Y 152.772 +G1 X 47.645 Y 152.291 +G1 X 48.232 Y 151.804 +G1 X 48.813 Y 151.311 +G1 X 49.390 Y 150.812 +G1 X 49.951 Y 150.317 +G1 X 50.507 Y 149.818 +G1 X 51.058 Y 149.312 +G1 X 51.605 Y 148.802 +G1 X 52.146 Y 148.286 +G1 X 52.682 Y 147.765 +G1 X 53.213 Y 147.239 +G1 X 53.739 Y 146.708 +G1 X 54.260 Y 146.172 +G1 X 54.776 Y 145.631 +G1 X 55.286 Y 145.085 +G1 X 55.791 Y 144.534 +G1 X 56.291 Y 143.978 +G1 X 56.785 Y 143.417 +G1 X 57.283 Y 142.841 +G1 X 57.776 Y 142.260 +G1 X 58.262 Y 141.674 +G1 X 58.743 Y 141.084 +G1 X 59.218 Y 140.489 +G1 X 59.687 Y 139.889 +G1 X 60.151 Y 139.284 +G1 X 60.608 Y 138.675 +G1 X 61.059 Y 138.061 +G1 X 61.504 Y 137.443 +G1 X 61.943 Y 136.821 +G1 X 62.376 Y 136.195 +G1 X 62.803 Y 135.564 +G1 X 63.223 Y 134.929 +G1 X 63.637 Y 134.290 +G1 X 64.045 Y 133.646 +G1 X 64.447 Y 132.999 +G1 X 64.842 Y 132.348 +G1 X 65.231 Y 131.693 +G1 X 65.613 Y 131.034 +G1 X 65.989 Y 130.371 +G1 X 66.358 Y 129.705 +G1 X 66.721 Y 129.035 +G1 X 67.077 Y 128.361 +G1 X 67.427 Y 127.684 +G1 X 67.769 Y 127.004 +G1 X 68.106 Y 126.320 +G1 X 68.435 Y 125.633 +G1 X 68.757 Y 124.943 +G1 X 69.073 Y 124.249 +G1 X 69.382 Y 123.553 +G1 X 69.684 Y 122.853 +G1 X 69.979 Y 122.151 +G1 X 70.267 Y 121.445 +G1 X 70.549 Y 120.737 +G1 X 70.823 Y 120.026 +G1 X 71.090 Y 119.313 +G1 X 71.350 Y 118.597 +G1 X 71.604 Y 117.878 +G1 X 71.850 Y 117.157 +G1 X 72.089 Y 116.433 +G1 X 72.320 Y 115.708 +G1 X 72.545 Y 114.980 +G1 X 72.762 Y 114.249 +G1 X 72.973 Y 113.517 +G1 X 73.176 Y 112.783 +G1 X 73.372 Y 112.046 +G1 X 73.560 Y 111.308 +G1 X 73.742 Y 110.567 +G1 X 73.916 Y 109.825 +G1 X 74.082 Y 109.081 +G1 X 74.242 Y 108.335 +G1 X 74.394 Y 107.588 +G1 X 74.539 Y 106.839 +G1 X 74.676 Y 106.089 +G1 X 74.806 Y 105.337 +G1 X 74.928 Y 104.584 +G1 X 75.043 Y 103.831 +G1 X 75.151 Y 103.076 +G1 X 75.251 Y 102.320 +G1 X 75.344 Y 101.563 +G1 X 75.429 Y 100.805 +G1 X 75.507 Y 100.046 +G1 X 75.577 Y 99.287 +G1 X 75.640 Y 98.527 +G1 X 75.695 Y 97.766 +G1 X 75.742 Y 97.020 +G1 X 75.782 Y 96.273 +G1 X 75.814 Y 95.526 +G1 X 75.839 Y 94.779 +G1 X 75.858 Y 94.032 +G1 X 75.868 Y 93.284 +G1 X 75.872 Y 92.536 +G1 X 75.869 Y 91.802 +G1 X 75.858 Y 91.068 +G1 X 75.841 Y 90.335 +G1 X 75.816 Y 89.601 +G1 X 75.785 Y 88.868 +G1 X 75.747 Y 88.135 +G1 X 75.702 Y 87.402 +G1 X 75.650 Y 86.670 +G1 X 75.591 Y 85.938 +G1 X 75.525 Y 85.207 +G1 X 75.453 Y 84.477 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 3 *) +G0 X -21.510 Y 116.324 +M3 M8 +G0 Z 34.000 +G1 Z 34.000 +F100 +G1 X -21.625 Y 116.028 +G1 X -21.747 Y 115.734 +G1 X -21.874 Y 115.443 +G1 X -22.007 Y 115.155 +G1 X -22.146 Y 114.869 +G1 X -22.291 Y 114.586 +G1 X -22.441 Y 114.307 +G1 X -22.598 Y 114.029 +G1 X -22.762 Y 113.756 +G1 X -22.932 Y 113.486 +G1 X -23.108 Y 113.221 +G1 X -23.290 Y 112.959 +G1 X -23.479 Y 112.702 +G1 X -23.647 Y 112.485 +G1 X -23.819 Y 112.272 +G1 X -23.997 Y 112.063 +G1 X -24.180 Y 111.858 +G1 X -24.367 Y 111.658 +G1 X -24.559 Y 111.462 +G1 X -24.738 Y 111.289 +G1 X -24.921 Y 111.120 +G1 X -25.109 Y 110.956 +G1 X -25.301 Y 110.796 +G1 X -25.496 Y 110.642 +G1 X -25.696 Y 110.492 +G1 X -25.890 Y 110.355 +G1 X -26.089 Y 110.223 +G1 X -26.291 Y 110.097 +G1 X -26.496 Y 109.976 +G1 X -26.705 Y 109.862 +G1 X -26.917 Y 109.753 +G1 X -27.111 Y 109.661 +G1 X -27.308 Y 109.574 +G1 X -27.507 Y 109.494 +G1 X -27.709 Y 109.419 +G1 X -27.912 Y 109.350 +G1 X -28.118 Y 109.287 +G1 X -28.325 Y 109.231 +G1 X -28.520 Y 109.183 +G1 X -28.717 Y 109.142 +G1 X -28.914 Y 109.107 +G1 X -29.113 Y 109.077 +G1 X -29.312 Y 109.053 +G1 X -29.512 Y 109.036 +G1 X -29.713 Y 109.024 +G1 X -29.860 Y 109.019 +G1 X -30.007 Y 109.018 +G1 X -30.149 Y 109.019 +G1 X -30.290 Y 109.024 +G1 X -30.516 Y 109.037 +G1 X -30.741 Y 109.057 +G1 X -30.966 Y 109.085 +G1 X -31.163 Y 109.116 +G1 X -31.359 Y 109.153 +G1 X -31.554 Y 109.195 +G1 X -31.747 Y 109.243 +G1 X -31.940 Y 109.296 +G1 X -32.171 Y 109.369 +G1 X -32.400 Y 109.448 +G1 X -32.626 Y 109.535 +G1 X -32.849 Y 109.629 +G1 X -33.069 Y 109.731 +G1 X -33.285 Y 109.839 +G1 X -33.491 Y 109.950 +G1 X -33.693 Y 110.066 +G1 X -33.892 Y 110.188 +G1 X -34.087 Y 110.315 +G1 X -34.279 Y 110.447 +G1 X -34.468 Y 110.585 +G1 X -34.680 Y 110.749 +G1 X -34.888 Y 110.919 +G1 X -35.092 Y 111.095 +G1 X -35.290 Y 111.276 +G1 X -35.484 Y 111.463 +G1 X -35.688 Y 111.670 +G1 X -35.887 Y 111.883 +G1 X -36.081 Y 112.101 +G1 X -36.269 Y 112.324 +G1 X -36.451 Y 112.552 +G1 X -36.620 Y 112.773 +G1 X -36.783 Y 112.997 +G1 X -36.942 Y 113.225 +G1 X -37.096 Y 113.456 +G1 X -37.245 Y 113.690 +G1 X -37.389 Y 113.927 +G1 X -37.550 Y 114.206 +G1 X -37.705 Y 114.488 +G1 X -37.854 Y 114.773 +G1 X -37.997 Y 115.061 +G1 X -38.134 Y 115.352 +G1 X -38.264 Y 115.646 +G1 X -38.390 Y 115.947 +G1 X -38.510 Y 116.250 +G1 X -38.624 Y 116.555 +G1 X -38.732 Y 116.862 +G1 X -38.835 Y 117.172 +G1 X -38.931 Y 117.483 +G1 X -39.021 Y 117.796 +G1 X -39.119 Y 118.161 +G1 X -39.209 Y 118.527 +G1 X -39.292 Y 118.895 +G1 X -39.367 Y 119.265 +G1 X -39.435 Y 119.637 +G1 X -39.495 Y 120.009 +G1 X -39.548 Y 120.383 +G1 X -39.593 Y 120.756 +G1 X -39.632 Y 121.131 +G1 X -39.663 Y 121.506 +G1 X -39.688 Y 121.881 +G1 X -39.705 Y 122.257 +G1 X -39.716 Y 122.633 +G1 X -39.719 Y 123.009 +G1 X -39.715 Y 123.408 +G1 X -39.704 Y 123.807 +G1 X -39.684 Y 124.206 +G1 X -39.657 Y 124.604 +G1 X -39.623 Y 124.983 +G1 X -39.582 Y 125.361 +G1 X -39.534 Y 125.739 +G1 X -39.478 Y 126.115 +G1 X -39.415 Y 126.490 +G1 X -39.344 Y 126.864 +G1 X -39.267 Y 127.237 +G1 X -39.184 Y 127.596 +G1 X -39.094 Y 127.954 +G1 X -38.996 Y 128.310 +G1 X -38.891 Y 128.663 +G1 X -38.778 Y 129.015 +G1 X -38.659 Y 129.364 +G1 X -38.532 Y 129.710 +G1 X -38.416 Y 130.006 +G1 X -38.295 Y 130.300 +G1 X -38.167 Y 130.591 +G1 X -38.034 Y 130.880 +G1 X -37.894 Y 131.166 +G1 X -37.749 Y 131.449 +G1 X -37.598 Y 131.728 +G1 X -37.441 Y 132.006 +G1 X -37.277 Y 132.279 +G1 X -37.107 Y 132.549 +G1 X -36.931 Y 132.814 +G1 X -36.748 Y 133.075 +G1 X -36.559 Y 133.332 +G1 X -36.391 Y 133.549 +G1 X -36.218 Y 133.762 +G1 X -36.040 Y 133.970 +G1 X -35.858 Y 134.175 +G1 X -35.670 Y 134.375 +G1 X -35.478 Y 134.570 +G1 X -35.298 Y 134.743 +G1 X -35.115 Y 134.912 +G1 X -34.927 Y 135.076 +G1 X -34.736 Y 135.235 +G1 X -34.540 Y 135.389 +G1 X -34.340 Y 135.538 +G1 X -34.145 Y 135.675 +G1 X -33.947 Y 135.807 +G1 X -33.745 Y 135.933 +G1 X -33.539 Y 136.053 +G1 X -33.330 Y 136.167 +G1 X -33.118 Y 136.275 +G1 X -32.923 Y 136.367 +G1 X -32.726 Y 136.454 +G1 X -32.527 Y 136.535 +G1 X -32.325 Y 136.609 +G1 X -32.121 Y 136.678 +G1 X -31.914 Y 136.740 +G1 X -31.707 Y 136.797 +G1 X -31.512 Y 136.844 +G1 X -31.315 Y 136.885 +G1 X -31.118 Y 136.920 +G1 X -30.920 Y 136.949 +G1 X -30.720 Y 136.973 +G1 X -30.521 Y 136.990 +G1 X -30.320 Y 137.002 +G1 X -30.175 Y 137.007 +G1 X -30.029 Y 137.008 +G1 X -29.900 Y 137.007 +G1 X -29.771 Y 137.003 +G1 X -29.560 Y 136.992 +G1 X -29.349 Y 136.974 +G1 X -29.138 Y 136.949 +G1 X -28.929 Y 136.918 +G1 X -28.720 Y 136.880 +G1 X -28.514 Y 136.835 +G1 X -28.308 Y 136.785 +G1 X -28.104 Y 136.728 +G1 X -27.902 Y 136.665 +G1 X -27.687 Y 136.590 +G1 X -27.474 Y 136.509 +G1 X -27.263 Y 136.421 +G1 X -27.055 Y 136.327 +G1 X -26.850 Y 136.227 +G1 X -26.648 Y 136.121 +G1 X -26.426 Y 135.995 +G1 X -26.208 Y 135.863 +G1 X -25.994 Y 135.725 +G1 X -25.784 Y 135.580 +G1 X -25.578 Y 135.429 +G1 X -25.366 Y 135.264 +G1 X -25.158 Y 135.093 +G1 X -24.955 Y 134.917 +G1 X -24.757 Y 134.735 +G1 X -24.564 Y 134.548 +G1 X -24.364 Y 134.344 +G1 X -24.170 Y 134.135 +G1 X -23.980 Y 133.921 +G1 X -23.796 Y 133.703 +G1 X -23.618 Y 133.480 +G1 X -23.421 Y 133.223 +G1 X -23.232 Y 132.961 +G1 X -23.049 Y 132.694 +G1 X -22.872 Y 132.422 +G1 X -22.702 Y 132.147 +G1 X -22.535 Y 131.862 +G1 X -22.375 Y 131.573 +G1 X -22.221 Y 131.281 +G1 X -22.073 Y 130.986 +G1 X -21.932 Y 130.687 +G1 X -21.798 Y 130.386 +G1 X -21.674 Y 130.094 +G1 X -21.557 Y 129.800 +G1 X -21.445 Y 129.504 +G1 X -21.338 Y 129.206 +G1 X -21.237 Y 128.906 +G1 X -21.142 Y 128.604 +G1 X -21.052 Y 128.301 +G1 X -20.962 Y 127.973 +G1 X -20.877 Y 127.644 +G1 X -20.799 Y 127.313 +G1 X -20.727 Y 126.981 +G1 X -20.661 Y 126.647 +G1 X -20.601 Y 126.313 +G1 X -20.547 Y 125.977 +G1 X -20.499 Y 125.641 +G1 X -20.452 Y 125.266 +G1 X -20.413 Y 124.891 +G1 X -20.381 Y 124.516 +G1 X -20.356 Y 124.140 +G1 X -20.339 Y 123.763 +G1 X -20.328 Y 123.386 +G1 X -20.324 Y 123.009 +G1 X -20.328 Y 122.652 +G1 X -20.337 Y 122.296 +G1 X -20.353 Y 121.939 +G1 X -20.375 Y 121.583 +G1 X -20.402 Y 121.237 +G1 X -20.436 Y 120.891 +G1 X -20.476 Y 120.547 +G1 X -20.522 Y 120.203 +G1 X -20.574 Y 119.860 +G1 X -20.632 Y 119.517 +G1 X -20.697 Y 119.176 +G1 X -20.767 Y 118.837 +G1 X -20.850 Y 118.471 +G1 X -20.941 Y 118.108 +G1 X -21.040 Y 117.746 +G1 X -21.146 Y 117.387 +G1 X -21.260 Y 117.030 +G1 X -21.381 Y 116.676 +G1 X -21.510 Y 116.324 +F150 +G1 Z 34.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 2 *) +G0 X 33.298 Y 135.420 +M3 M8 +G0 Z 35.000 +G1 Z 35.000 +F400 +G1 X 33.510 Y 135.256 +G1 X 33.718 Y 135.085 +G1 X 33.921 Y 134.909 +G1 X 34.119 Y 134.728 +G1 X 34.313 Y 134.541 +G1 X 34.517 Y 134.333 +G1 X 34.716 Y 134.120 +G1 X 34.909 Y 133.901 +G1 X 35.097 Y 133.678 +G1 X 35.279 Y 133.450 +G1 X 35.447 Y 133.229 +G1 X 35.610 Y 133.005 +G1 X 35.769 Y 132.777 +G1 X 35.923 Y 132.545 +G1 X 36.072 Y 132.311 +G1 X 36.216 Y 132.073 +G1 X 36.376 Y 131.795 +G1 X 36.531 Y 131.512 +G1 X 36.680 Y 131.227 +G1 X 36.823 Y 130.938 +G1 X 36.959 Y 130.647 +G1 X 37.089 Y 130.353 +G1 X 37.215 Y 130.052 +G1 X 37.335 Y 129.749 +G1 X 37.449 Y 129.443 +G1 X 37.557 Y 129.136 +G1 X 37.659 Y 128.826 +G1 X 37.755 Y 128.515 +G1 X 37.846 Y 128.202 +G1 X 37.943 Y 127.837 +G1 X 38.033 Y 127.471 +G1 X 38.116 Y 127.102 +G1 X 38.191 Y 126.732 +G1 X 38.259 Y 126.361 +G1 X 38.319 Y 125.988 +G1 X 38.371 Y 125.615 +G1 X 38.417 Y 125.241 +G1 X 38.455 Y 124.866 +G1 X 38.487 Y 124.491 +G1 X 38.511 Y 124.115 +G1 X 38.529 Y 123.739 +G1 X 38.539 Y 123.363 +G1 X 38.543 Y 122.986 +G1 X 38.539 Y 122.588 +G1 X 38.527 Y 122.189 +G1 X 38.507 Y 121.791 +G1 X 38.480 Y 121.393 +G1 X 38.446 Y 121.014 +G1 X 38.405 Y 120.636 +G1 X 38.356 Y 120.259 +G1 X 38.300 Y 119.883 +G1 X 38.237 Y 119.508 +G1 X 38.166 Y 119.135 +G1 X 38.088 Y 118.763 +G1 X 38.005 Y 118.403 +G1 X 37.915 Y 118.046 +G1 X 37.817 Y 117.690 +G1 X 37.712 Y 117.337 +G1 X 37.599 Y 116.986 +G1 X 37.479 Y 116.638 +G1 X 37.352 Y 116.292 +G1 X 37.236 Y 115.996 +G1 X 37.114 Y 115.702 +G1 X 36.986 Y 115.411 +G1 X 36.852 Y 115.123 +G1 X 36.713 Y 114.837 +G1 X 36.567 Y 114.554 +G1 X 36.416 Y 114.275 +G1 X 36.258 Y 113.998 +G1 X 36.094 Y 113.724 +G1 X 35.923 Y 113.455 +G1 X 35.746 Y 113.190 +G1 X 35.563 Y 112.929 +G1 X 35.374 Y 112.673 +G1 X 35.206 Y 112.456 +G1 X 35.033 Y 112.243 +G1 X 34.854 Y 112.035 +G1 X 34.671 Y 111.830 +G1 X 34.483 Y 111.631 +G1 X 34.290 Y 111.435 +G1 X 34.111 Y 111.262 +G1 X 33.927 Y 111.094 +G1 X 33.739 Y 110.930 +G1 X 33.546 Y 110.771 +G1 X 33.350 Y 110.617 +G1 X 33.150 Y 110.469 +G1 X 32.955 Y 110.331 +G1 X 32.756 Y 110.200 +G1 X 32.553 Y 110.074 +G1 X 32.347 Y 109.954 +G1 X 32.138 Y 109.840 +G1 X 31.925 Y 109.732 +G1 X 31.730 Y 109.640 +G1 X 31.532 Y 109.554 +G1 X 31.332 Y 109.473 +G1 X 31.130 Y 109.399 +G1 X 30.925 Y 109.330 +G1 X 30.718 Y 109.268 +G1 X 30.510 Y 109.211 +G1 X 30.315 Y 109.165 +G1 X 30.118 Y 109.124 +G1 X 29.920 Y 109.089 +G1 X 29.722 Y 109.060 +G1 X 29.522 Y 109.037 +G1 X 29.322 Y 109.020 +G1 X 29.122 Y 109.008 +G1 X 28.976 Y 109.004 +G1 X 28.831 Y 109.003 +G1 X 28.690 Y 109.004 +G1 X 28.549 Y 109.009 +G1 X 28.323 Y 109.022 +G1 X 28.098 Y 109.043 +G1 X 27.874 Y 109.071 +G1 X 27.677 Y 109.102 +G1 X 27.480 Y 109.139 +G1 X 27.285 Y 109.182 +G1 X 27.092 Y 109.230 +G1 X 26.899 Y 109.284 +G1 X 26.668 Y 109.356 +G1 X 26.439 Y 109.436 +G1 X 26.213 Y 109.523 +G1 X 25.990 Y 109.618 +G1 X 25.770 Y 109.720 +G1 X 25.554 Y 109.829 +G1 X 25.348 Y 109.940 +G1 X 25.146 Y 110.056 +G1 X 24.948 Y 110.178 +G1 X 24.752 Y 110.305 +G1 X 24.560 Y 110.438 +G1 X 24.372 Y 110.576 +G1 X 24.159 Y 110.740 +G1 X 23.951 Y 110.911 +G1 X 23.748 Y 111.087 +G1 X 23.550 Y 111.268 +G1 X 23.356 Y 111.455 +G1 X 23.152 Y 111.663 +G1 X 22.953 Y 111.876 +G1 X 22.759 Y 112.095 +G1 X 22.572 Y 112.318 +G1 X 22.390 Y 112.546 +G1 X 22.221 Y 112.767 +G1 X 22.058 Y 112.991 +G1 X 21.899 Y 113.219 +G1 X 21.745 Y 113.451 +G1 X 21.596 Y 113.685 +G1 X 21.452 Y 113.923 +G1 X 21.292 Y 114.201 +G1 X 21.137 Y 114.483 +G1 X 20.988 Y 114.769 +G1 X 20.845 Y 115.057 +G1 X 20.709 Y 115.349 +G1 X 20.579 Y 115.643 +G1 X 20.453 Y 115.944 +G1 X 20.333 Y 116.247 +G1 X 20.219 Y 116.552 +G1 X 20.111 Y 116.860 +G1 X 20.009 Y 117.169 +G1 X 19.912 Y 117.481 +G1 X 19.822 Y 117.794 +G1 X 19.725 Y 118.159 +G1 X 19.635 Y 118.525 +G1 X 19.552 Y 118.894 +G1 X 19.477 Y 119.264 +G1 X 19.409 Y 119.635 +G1 X 19.349 Y 120.008 +G1 X 19.296 Y 120.381 +G1 X 19.251 Y 120.755 +G1 X 19.212 Y 121.129 +G1 X 19.181 Y 121.504 +G1 X 19.157 Y 121.880 +G1 X 19.139 Y 122.256 +G1 X 19.129 Y 122.632 +G1 X 19.125 Y 123.009 +G1 X 19.129 Y 123.407 +G1 X 19.141 Y 123.806 +G1 X 19.161 Y 124.204 +G1 X 19.189 Y 124.602 +G1 X 19.223 Y 124.981 +G1 X 19.265 Y 125.359 +G1 X 19.314 Y 125.736 +G1 X 19.370 Y 126.112 +G1 X 19.434 Y 126.487 +G1 X 19.505 Y 126.861 +G1 X 19.583 Y 127.233 +G1 X 19.667 Y 127.592 +G1 X 19.757 Y 127.950 +G1 X 19.856 Y 128.305 +G1 X 19.961 Y 128.658 +G1 X 20.074 Y 129.009 +G1 X 20.195 Y 129.358 +G1 X 20.322 Y 129.704 +G1 X 20.439 Y 130.000 +G1 X 20.561 Y 130.293 +G1 X 20.689 Y 130.584 +G1 X 20.823 Y 130.873 +G1 X 20.963 Y 131.158 +G1 X 21.108 Y 131.441 +G1 X 21.260 Y 131.721 +G1 X 21.418 Y 131.998 +G1 X 21.582 Y 132.271 +G1 X 21.753 Y 132.540 +G1 X 21.930 Y 132.805 +G1 X 22.114 Y 133.066 +G1 X 22.303 Y 133.323 +G1 X 22.472 Y 133.540 +G1 X 22.645 Y 133.752 +G1 X 22.823 Y 133.961 +G1 X 23.007 Y 134.165 +G1 X 23.195 Y 134.365 +G1 X 23.388 Y 134.560 +G1 X 23.568 Y 134.733 +G1 X 23.752 Y 134.902 +G1 X 23.940 Y 135.066 +G1 X 24.132 Y 135.225 +G1 X 24.328 Y 135.378 +G1 X 24.529 Y 135.527 +G1 X 24.724 Y 135.665 +G1 X 24.923 Y 135.796 +G1 X 25.126 Y 135.922 +G1 X 25.332 Y 136.042 +G1 X 25.542 Y 136.156 +G1 X 25.754 Y 136.264 +G1 X 25.951 Y 136.357 +G1 X 26.150 Y 136.444 +G1 X 26.351 Y 136.525 +G1 X 26.555 Y 136.599 +G1 X 26.761 Y 136.668 +G1 X 26.969 Y 136.731 +G1 X 27.179 Y 136.787 +G1 X 27.374 Y 136.833 +G1 X 27.570 Y 136.874 +G1 X 27.767 Y 136.908 +G1 X 27.965 Y 136.937 +G1 X 28.164 Y 136.960 +G1 X 28.364 Y 136.977 +G1 X 28.564 Y 136.988 +G1 X 28.704 Y 136.992 +G1 X 28.844 Y 136.993 +G1 X 28.984 Y 136.991 +G1 X 29.125 Y 136.987 +G1 X 29.336 Y 136.975 +G1 X 29.548 Y 136.956 +G1 X 29.758 Y 136.930 +G1 X 29.968 Y 136.898 +G1 X 30.173 Y 136.860 +G1 X 30.377 Y 136.816 +G1 X 30.579 Y 136.766 +G1 X 30.780 Y 136.710 +G1 X 30.979 Y 136.648 +G1 X 31.193 Y 136.574 +G1 X 31.406 Y 136.493 +G1 X 31.616 Y 136.406 +G1 X 31.823 Y 136.313 +G1 X 32.027 Y 136.214 +G1 X 32.229 Y 136.108 +G1 X 32.450 Y 135.983 +G1 X 32.668 Y 135.852 +G1 X 32.882 Y 135.714 +G1 X 33.092 Y 135.570 +G1 X 33.298 Y 135.420 +F150 +G1 Z 35.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 1 *) +G0 X -31.181 Y 64.121 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F400 +G1 X -31.109 Y 64.596 +G1 X -31.030 Y 65.070 +G1 X -30.943 Y 65.542 +G1 X -30.849 Y 66.013 +G1 X -30.747 Y 66.482 +G1 X -30.637 Y 66.950 +G1 X -30.520 Y 67.416 +G1 X -30.396 Y 67.879 +G1 X -30.264 Y 68.341 +G1 X -30.125 Y 68.801 +G1 X -29.978 Y 69.258 +G1 X -29.824 Y 69.713 +G1 X -29.663 Y 70.165 +G1 X -29.495 Y 70.615 +G1 X -29.320 Y 71.062 +G1 X -29.137 Y 71.506 +G1 X -28.947 Y 71.947 +G1 X -28.750 Y 72.385 +G1 X -28.547 Y 72.820 +G1 X -28.336 Y 73.252 +G1 X -28.118 Y 73.680 +G1 X -27.900 Y 74.094 +G1 X -27.674 Y 74.505 +G1 X -27.443 Y 74.912 +G1 X -27.205 Y 75.316 +G1 X -26.961 Y 75.716 +G1 X -26.711 Y 76.112 +G1 X -26.455 Y 76.504 +G1 X -26.193 Y 76.893 +G1 X -25.925 Y 77.277 +G1 X -25.651 Y 77.657 +G1 X -25.371 Y 78.032 +G1 X -25.085 Y 78.404 +G1 X -24.794 Y 78.771 +G1 X -24.497 Y 79.133 +G1 X -24.194 Y 79.491 +G1 X -23.886 Y 79.844 +G1 X -23.573 Y 80.192 +G1 X -23.246 Y 80.543 +G1 X -22.914 Y 80.889 +G1 X -22.577 Y 81.230 +G1 X -22.234 Y 81.566 +G1 X -21.886 Y 81.896 +G1 X -21.533 Y 82.221 +G1 X -21.175 Y 82.540 +G1 X -20.811 Y 82.853 +G1 X -20.443 Y 83.161 +G1 X -20.070 Y 83.462 +G1 X -19.693 Y 83.758 +G1 X -19.310 Y 84.048 +G1 X -18.924 Y 84.332 +G1 X -18.532 Y 84.609 +G1 X -18.137 Y 84.881 +G1 X -17.737 Y 85.146 +G1 X -17.333 Y 85.405 +G1 X -16.925 Y 85.657 +G1 X -16.513 Y 85.903 +G1 X -16.092 Y 86.145 +G1 X -15.667 Y 86.381 +G1 X -15.238 Y 86.609 +G1 X -14.806 Y 86.831 +G1 X -14.370 Y 87.046 +G1 X -13.931 Y 87.253 +G1 X -13.488 Y 87.454 +G1 X -13.042 Y 87.647 +G1 X -12.593 Y 87.833 +G1 X -12.141 Y 88.012 +G1 X -11.687 Y 88.183 +G1 X -11.230 Y 88.347 +G1 X -10.770 Y 88.504 +G1 X -10.308 Y 88.653 +G1 X -9.843 Y 88.794 +G1 X -9.376 Y 88.928 +G1 X -8.907 Y 89.055 +G1 X -8.436 Y 89.174 +G1 X -7.964 Y 89.285 +G1 X -7.489 Y 89.388 +G1 X -7.013 Y 89.484 +G1 X -6.535 Y 89.572 +G1 X -6.056 Y 89.653 +G1 X -5.576 Y 89.725 +G1 X -5.098 Y 89.790 +G1 X -4.619 Y 89.846 +G1 X -4.139 Y 89.896 +G1 X -3.658 Y 89.938 +G1 X -3.177 Y 89.972 +G1 X -2.696 Y 89.998 +G1 X -2.214 Y 90.017 +G1 X -1.731 Y 90.029 +G1 X -1.249 Y 90.033 +G1 X -0.766 Y 90.029 +G1 X -0.284 Y 90.017 +G1 X 0.198 Y 89.998 +G1 X 0.680 Y 89.972 +G1 X 1.162 Y 89.938 +G1 X 1.642 Y 89.896 +G1 X 2.122 Y 89.846 +G1 X 2.602 Y 89.789 +G1 X 3.080 Y 89.725 +G1 X 3.555 Y 89.653 +G1 X 4.028 Y 89.574 +G1 X 4.501 Y 89.487 +G1 X 4.972 Y 89.392 +G1 X 5.441 Y 89.290 +G1 X 5.908 Y 89.181 +G1 X 6.374 Y 89.064 +G1 X 6.838 Y 88.940 +G1 X 7.300 Y 88.808 +G1 X 7.759 Y 88.669 +G1 X 8.217 Y 88.522 +G1 X 8.672 Y 88.368 +G1 X 9.124 Y 88.207 +G1 X 9.574 Y 88.039 +G1 X 10.021 Y 87.863 +G1 X 10.465 Y 87.681 +G1 X 10.906 Y 87.491 +G1 X 11.344 Y 87.294 +G1 X 11.779 Y 87.090 +G1 X 12.210 Y 86.880 +G1 X 12.638 Y 86.662 +G1 X 13.053 Y 86.443 +G1 X 13.464 Y 86.218 +G1 X 13.871 Y 85.987 +G1 X 14.275 Y 85.749 +G1 X 14.675 Y 85.505 +G1 X 15.071 Y 85.255 +G1 X 15.463 Y 84.999 +G1 X 15.851 Y 84.736 +G1 X 16.235 Y 84.468 +G1 X 16.615 Y 84.194 +G1 X 16.991 Y 83.914 +G1 X 17.362 Y 83.629 +G1 X 17.729 Y 83.337 +G1 X 18.091 Y 83.040 +G1 X 18.449 Y 82.738 +G1 X 18.802 Y 82.430 +G1 X 19.150 Y 82.116 +G1 X 19.502 Y 81.790 +G1 X 19.848 Y 81.458 +G1 X 20.189 Y 81.120 +G1 X 20.525 Y 80.778 +G1 X 20.855 Y 80.430 +G1 X 21.179 Y 80.077 +G1 X 21.498 Y 79.718 +G1 X 21.812 Y 79.355 +G1 X 22.119 Y 78.987 +G1 X 22.421 Y 78.614 +G1 X 22.717 Y 78.236 +G1 X 23.007 Y 77.854 +G1 X 23.290 Y 77.467 +G1 X 23.568 Y 77.076 +G1 X 23.839 Y 76.680 +G1 X 24.104 Y 76.281 +G1 X 24.363 Y 75.877 +G1 X 24.616 Y 75.469 +G1 X 24.861 Y 75.057 +G1 X 25.104 Y 74.636 +G1 X 25.339 Y 74.211 +G1 X 25.568 Y 73.782 +G1 X 25.790 Y 73.350 +G1 X 26.004 Y 72.914 +G1 X 26.212 Y 72.474 +G1 X 26.412 Y 72.032 +G1 X 26.606 Y 71.586 +G1 X 26.792 Y 71.137 +G1 X 26.970 Y 70.685 +G1 X 27.142 Y 70.231 +G1 X 27.306 Y 69.773 +G1 X 27.462 Y 69.314 +G1 X 27.611 Y 68.851 +G1 X 27.753 Y 68.387 +G1 X 27.887 Y 67.920 +G1 X 28.013 Y 67.451 +G1 X 28.132 Y 66.980 +G1 X 28.243 Y 66.507 +G1 X 28.347 Y 66.033 +G1 X 28.443 Y 65.556 +G1 X 28.531 Y 65.079 +G1 X 28.611 Y 64.600 +G1 X 28.684 Y 64.120 +G1 X 28.748 Y 63.642 +G1 X 28.805 Y 63.162 +G1 X 28.854 Y 62.683 +G1 X 28.896 Y 62.202 +G1 X 28.930 Y 61.721 +G1 X 28.957 Y 61.239 +G1 X 28.976 Y 60.757 +G1 X 28.987 Y 60.275 +G1 X 28.991 Y 59.793 +G1 X 28.991 Y 59.140 +G1 X 28.986 Y 58.748 +G1 X 28.974 Y 58.355 +G1 X 28.953 Y 57.964 +G1 X 28.924 Y 57.572 +G1 X 28.887 Y 57.181 +G1 X 28.843 Y 56.792 +G1 X 28.791 Y 56.403 +G1 X 28.733 Y 56.031 +G1 X 28.668 Y 55.661 +G1 X 28.596 Y 55.291 +G1 X 28.516 Y 54.924 +G1 X 28.429 Y 54.558 +G1 X 28.335 Y 54.194 +G1 X 28.234 Y 53.832 +G1 X 28.126 Y 53.472 +G1 X 28.011 Y 53.114 +G1 X 27.888 Y 52.758 +G1 X 27.759 Y 52.405 +G1 X 27.622 Y 52.055 +G1 X 27.479 Y 51.707 +G1 X 27.329 Y 51.362 +G1 X 27.172 Y 51.020 +G1 X 27.008 Y 50.682 +G1 X 26.838 Y 50.346 +G1 X 26.661 Y 50.015 +G1 X 26.474 Y 49.681 +G1 X 26.281 Y 49.351 +G1 X 26.081 Y 49.025 +G1 X 25.875 Y 48.702 +G1 X 25.663 Y 48.384 +G1 X 25.444 Y 48.071 +G1 X 25.219 Y 47.761 +G1 X 24.988 Y 47.457 +G1 X 24.751 Y 47.156 +G1 X 24.508 Y 46.861 +G1 X 24.259 Y 46.571 +G1 X 24.005 Y 46.285 +G1 X 23.745 Y 46.005 +G1 X 23.479 Y 45.729 +G1 X 23.208 Y 45.460 +G1 X 22.932 Y 45.195 +G1 X 22.651 Y 44.936 +G1 X 22.364 Y 44.683 +G1 X 22.073 Y 44.435 +G1 X 21.776 Y 44.194 +G1 X 21.475 Y 43.958 +G1 X 21.170 Y 43.728 +G1 X 20.859 Y 43.504 +G1 X 20.545 Y 43.287 +G1 X 20.226 Y 43.076 +G1 X 19.903 Y 42.871 +G1 X 19.576 Y 42.673 +G1 X 19.245 Y 42.481 +G1 X 18.941 Y 42.312 +G1 X 18.634 Y 42.149 +G1 X 18.324 Y 41.992 +G1 X 18.012 Y 41.840 +G1 X 17.696 Y 41.694 +G1 X 17.378 Y 41.554 +G1 X 17.058 Y 41.420 +G1 X 16.735 Y 41.291 +G1 X 16.409 Y 41.168 +G1 X 16.068 Y 41.047 +G1 X 15.725 Y 40.932 +G1 X 15.379 Y 40.824 +G1 X 15.032 Y 40.722 +G1 X 14.682 Y 40.627 +G1 X 14.331 Y 40.539 +G1 X 13.978 Y 40.457 +G1 X 13.624 Y 40.382 +G1 X 13.268 Y 40.314 +G1 X 12.911 Y 40.252 +G1 X 12.553 Y 40.198 +G1 X 12.164 Y 40.146 +G1 X 11.774 Y 40.102 +G1 X 11.383 Y 40.067 +G1 X 10.992 Y 40.039 +G1 X 10.600 Y 40.019 +G1 X 10.208 Y 40.007 +G1 X 9.815 Y 40.003 +G1 X -12.313 Y 40.003 +G1 X -12.706 Y 40.007 +G1 X -13.099 Y 40.019 +G1 X -13.491 Y 40.039 +G1 X -13.883 Y 40.067 +G1 X -14.275 Y 40.103 +G1 X -14.665 Y 40.147 +G1 X -15.055 Y 40.199 +G1 X -15.427 Y 40.256 +G1 X -15.798 Y 40.321 +G1 X -16.168 Y 40.393 +G1 X -16.536 Y 40.472 +G1 X -16.902 Y 40.558 +G1 X -17.267 Y 40.652 +G1 X -17.630 Y 40.753 +G1 X -17.990 Y 40.861 +G1 X -18.349 Y 40.976 +G1 X -18.705 Y 41.098 +G1 X -19.058 Y 41.227 +G1 X -19.410 Y 41.363 +G1 X -19.758 Y 41.506 +G1 X -20.103 Y 41.656 +G1 X -20.445 Y 41.813 +G1 X -20.785 Y 41.976 +G1 X -21.120 Y 42.146 +G1 X -21.453 Y 42.323 +G1 X -21.791 Y 42.512 +G1 X -22.125 Y 42.707 +G1 X -22.456 Y 42.909 +G1 X -22.782 Y 43.118 +G1 X -23.104 Y 43.333 +G1 X -23.421 Y 43.554 +G1 X -23.735 Y 43.782 +G1 X -24.043 Y 44.016 +G1 X -24.347 Y 44.256 +G1 X -24.645 Y 44.502 +G1 X -24.939 Y 44.755 +G1 X -25.228 Y 45.013 +G1 X -25.511 Y 45.276 +G1 X -25.789 Y 45.546 +G1 X -26.062 Y 45.821 +G1 X -26.329 Y 46.101 +G1 X -26.590 Y 46.387 +G1 X -26.846 Y 46.678 +G1 X -27.096 Y 46.973 +G1 X -27.339 Y 47.274 +G1 X -27.577 Y 47.580 +G1 X -27.808 Y 47.890 +G1 X -28.033 Y 48.205 +G1 X -28.252 Y 48.525 +G1 X -28.464 Y 48.849 +G1 X -28.670 Y 49.177 +G1 X -28.869 Y 49.509 +G1 X -29.060 Y 49.841 +G1 X -29.244 Y 50.178 +G1 X -29.420 Y 50.517 +G1 X -29.591 Y 50.861 +G1 X -29.754 Y 51.208 +G1 X -29.910 Y 51.558 +G1 X -30.059 Y 51.911 +G1 X -30.201 Y 52.267 +G1 X -30.328 Y 52.604 +G1 X -30.448 Y 52.943 +G1 X -30.562 Y 53.285 +G1 X -30.670 Y 53.628 +G1 X -30.771 Y 53.974 +G1 X -30.865 Y 54.321 +G1 X -30.953 Y 54.670 +G1 X -31.034 Y 55.021 +G1 X -31.109 Y 55.373 +G1 X -31.177 Y 55.727 +G1 X -31.238 Y 56.082 +G1 X -31.292 Y 56.438 +G1 X -31.344 Y 56.827 +G1 X -31.388 Y 57.218 +G1 X -31.424 Y 57.609 +G1 X -31.452 Y 58.001 +G1 X -31.472 Y 58.393 +G1 X -31.485 Y 58.786 +G1 X -31.489 Y 59.179 +G1 X -31.489 Y 59.793 +G1 X -31.485 Y 60.275 +G1 X -31.474 Y 60.758 +G1 X -31.455 Y 61.240 +G1 X -31.428 Y 61.722 +G1 X -31.394 Y 62.203 +G1 X -31.352 Y 62.684 +G1 X -31.303 Y 63.164 +G1 X -31.246 Y 63.643 +G1 X -31.181 Y 64.121 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 +G0 X 0.000 Y 0.000 +M2 (Program end) diff --git a/src/jetmax_demos/scripts/gcode/tony.ngc b/src/jetmax_demos/scripts/gcode/tony.ngc new file mode 100644 index 0000000..a3fc03a --- /dev/null +++ b/src/jetmax_demos/scripts/gcode/tony.ngc @@ -0,0 +1,797 @@ +(Generated with: DXF2GCODE, Version: Py3.7.10 PyQt5.10.1, Date: $Date: Fri Oct 25 20:45:56 2019 +0200 $) +(Created from file: /home/lucas/钢铁侠.dxf) +(Output format description: G-CODE for LinuxCNC) +(Time: Mon Jul 19 18:04:03 2021) +G21 (Units in millimeters) +G90 (Absolute programming) +G64 (Default cutting) G17 (XY plane) G40 (Cancel radius comp.) G49 (Cancel length comp.) +G0 Z 100.000 + +(*** LAYER: _U+56FE_U+5C42 1 ***) +T1 M6 +S6000 + +(* SHAPE Nr: 8 *) +G0 X -2.861 Y 159.590 +M3 M8 +G0 Z 30.000 +F150 +G1 Z 30.000 +F300 +G1 X -3.860 Y 159.567 +G1 X -4.581 Y 159.539 +G1 X -5.302 Y 159.502 +G1 X -6.023 Y 159.457 +G1 X -6.743 Y 159.404 +G1 X -7.529 Y 159.337 +G1 X -8.315 Y 159.261 +G1 X -9.100 Y 159.177 +G1 X -9.883 Y 159.083 +G1 X -10.666 Y 158.982 +G1 X -11.425 Y 158.874 +G1 X -12.182 Y 158.759 +G1 X -12.938 Y 158.636 +G1 X -13.693 Y 158.505 +G1 X -14.446 Y 158.366 +G1 X -15.198 Y 158.219 +G1 X -15.949 Y 158.064 +G1 X -16.697 Y 157.902 +G1 X -17.533 Y 157.710 +G1 X -18.366 Y 157.507 +G1 X -19.196 Y 157.295 +G1 X -20.024 Y 157.071 +G1 X -20.849 Y 156.838 +G1 X -21.671 Y 156.594 +G1 X -22.474 Y 156.345 +G1 X -23.273 Y 156.084 +G1 X -24.069 Y 155.814 +G1 X -24.861 Y 155.532 +G1 X -25.650 Y 155.241 +G1 X -26.348 Y 154.972 +G1 X -27.042 Y 154.695 +G1 X -27.733 Y 154.409 +G1 X -28.420 Y 154.114 +G1 X -29.103 Y 153.810 +G1 X -29.782 Y 153.498 +G1 X -30.424 Y 153.193 +G1 X -31.061 Y 152.880 +G1 X -31.694 Y 152.559 +G1 X -32.322 Y 152.229 +G1 X -32.947 Y 151.891 +G1 X -33.567 Y 151.545 +G1 X -34.158 Y 151.204 +G1 X -34.744 Y 150.856 +G1 X -35.326 Y 150.500 +G1 X -35.903 Y 150.136 +G1 X -36.476 Y 149.764 +G1 X -36.998 Y 149.414 +G1 X -37.517 Y 149.057 +G1 X -38.031 Y 148.694 +G1 X -38.539 Y 148.324 +G1 X -39.043 Y 147.947 +G1 X -39.542 Y 147.564 +G1 X -40.036 Y 147.174 +G1 X -40.546 Y 146.761 +G1 X -41.049 Y 146.340 +G1 X -41.546 Y 145.912 +G1 X -42.037 Y 145.477 +G1 X -42.521 Y 145.035 +G1 X -43.000 Y 144.586 +G1 X -43.471 Y 144.130 +G1 X -43.930 Y 143.674 +G1 X -44.382 Y 143.211 +G1 X -44.827 Y 142.742 +G1 X -45.265 Y 142.266 +G1 X -45.696 Y 141.783 +G1 X -46.120 Y 141.295 +G1 X -46.545 Y 140.789 +G1 X -46.964 Y 140.277 +G1 X -47.374 Y 139.759 +G1 X -47.777 Y 139.234 +G1 X -48.171 Y 138.704 +G1 X -48.558 Y 138.168 +G1 X -48.936 Y 137.626 +G1 X -49.307 Y 137.078 +G1 X -49.676 Y 136.514 +G1 X -50.036 Y 135.945 +G1 X -50.389 Y 135.371 +G1 X -50.732 Y 134.791 +G1 X -51.067 Y 134.206 +G1 X -51.394 Y 133.617 +G1 X -51.711 Y 133.023 +G1 X -52.020 Y 132.424 +G1 X -52.321 Y 131.817 +G1 X -52.615 Y 131.206 +G1 X -52.899 Y 130.590 +G1 X -53.175 Y 129.971 +G1 X -53.442 Y 129.348 +G1 X -53.701 Y 128.722 +G1 X -53.950 Y 128.092 +G1 X -54.208 Y 127.413 +G1 X -54.457 Y 126.731 +G1 X -54.696 Y 126.046 +G1 X -54.925 Y 125.358 +G1 X -55.145 Y 124.666 +G1 X -55.355 Y 123.971 +G1 X -55.569 Y 123.229 +G1 X -55.772 Y 122.484 +G1 X -55.965 Y 121.736 +G1 X -56.149 Y 120.986 +G1 X -56.322 Y 120.233 +G1 X -56.489 Y 119.460 +G1 X -56.646 Y 118.684 +G1 X -56.793 Y 117.906 +G1 X -56.930 Y 117.126 +G1 X -57.062 Y 116.318 +G1 X -57.184 Y 115.508 +G1 X -57.295 Y 114.696 +G1 X -57.397 Y 113.883 +G1 X -57.494 Y 113.025 +G1 X -57.580 Y 112.166 +G1 X -57.656 Y 111.306 +G1 X -57.722 Y 110.445 +G1 X -57.778 Y 109.588 +G1 X -57.824 Y 108.731 +G1 X -57.861 Y 107.873 +G1 X -57.889 Y 107.015 +G1 X -57.910 Y 105.985 +G1 X -57.919 Y 104.955 +G1 X -57.020 Y 88.762 +G1 X -56.125 Y 72.637 +G1 X -44.895 Y 27.857 +G1 X -21.616 Y 6.856 +G1 X -2.849 Y 6.856 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 3 *) +G0 X -2.615 Y 161.590 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F300 +G1 X -2.093 Y 161.581 +G1 X -1.572 Y 161.566 +G1 X -0.977 Y 161.544 +G1 X -0.381 Y 161.515 +G1 X 0.214 Y 161.482 +G1 X 0.808 Y 161.443 +G1 X 1.403 Y 161.398 +G1 X 2.076 Y 161.341 +G1 X 2.750 Y 161.278 +G1 X 3.422 Y 161.209 +G1 X 4.094 Y 161.133 +G1 X 4.766 Y 161.051 +G1 X 5.436 Y 160.963 +G1 X 6.129 Y 160.866 +G1 X 6.821 Y 160.762 +G1 X 7.512 Y 160.652 +G1 X 8.202 Y 160.535 +G1 X 8.891 Y 160.411 +G1 X 9.578 Y 160.282 +G1 X 10.265 Y 160.145 +G1 X 10.950 Y 160.003 +G1 X 11.633 Y 159.854 +G1 X 12.279 Y 159.706 +G1 X 12.923 Y 159.553 +G1 X 13.565 Y 159.394 +G1 X 14.206 Y 159.229 +G1 X 14.845 Y 159.058 +G1 X 15.483 Y 158.880 +G1 X 16.119 Y 158.697 +G1 X 16.753 Y 158.508 +G1 X 17.443 Y 158.294 +G1 X 18.131 Y 158.073 +G1 X 18.817 Y 157.844 +G1 X 19.499 Y 157.607 +G1 X 20.180 Y 157.363 +G1 X 20.857 Y 157.112 +G1 X 21.476 Y 156.874 +G1 X 22.092 Y 156.630 +G1 X 22.705 Y 156.379 +G1 X 23.316 Y 156.122 +G1 X 23.923 Y 155.858 +G1 X 24.528 Y 155.587 +G1 X 25.130 Y 155.310 +G1 X 25.700 Y 155.040 +G1 X 26.267 Y 154.763 +G1 X 26.831 Y 154.480 +G1 X 27.392 Y 154.190 +G1 X 27.949 Y 153.895 +G1 X 28.503 Y 153.593 +G1 X 29.054 Y 153.285 +G1 X 29.566 Y 152.990 +G1 X 30.075 Y 152.690 +G1 X 30.581 Y 152.384 +G1 X 31.084 Y 152.073 +G1 X 31.582 Y 151.756 +G1 X 32.078 Y 151.433 +G1 X 32.554 Y 151.115 +G1 X 33.028 Y 150.791 +G1 X 33.497 Y 150.462 +G1 X 33.963 Y 150.127 +G1 X 34.425 Y 149.787 +G1 X 34.882 Y 149.442 +G1 X 35.336 Y 149.092 +G1 X 35.786 Y 148.736 +G1 X 36.252 Y 148.359 +G1 X 36.713 Y 147.976 +G1 X 37.169 Y 147.587 +G1 X 37.619 Y 147.192 +G1 X 38.065 Y 146.792 +G1 X 38.506 Y 146.386 +G1 X 38.942 Y 145.975 +G1 X 39.372 Y 145.558 +G1 X 39.784 Y 145.150 +G1 X 40.190 Y 144.736 +G1 X 40.591 Y 144.318 +G1 X 40.986 Y 143.894 +G1 X 41.376 Y 143.466 +G1 X 41.761 Y 143.033 +G1 X 42.141 Y 142.594 +G1 X 42.497 Y 142.172 +G1 X 42.849 Y 141.745 +G1 X 43.196 Y 141.314 +G1 X 43.537 Y 140.879 +G1 X 43.873 Y 140.440 +G1 X 44.204 Y 139.997 +G1 X 44.529 Y 139.550 +G1 X 44.849 Y 139.099 +G1 X 45.164 Y 138.644 +G1 X 45.473 Y 138.186 +G1 X 45.782 Y 137.716 +G1 X 46.085 Y 137.242 +G1 X 46.383 Y 136.764 +G1 X 46.675 Y 136.283 +G1 X 46.961 Y 135.798 +G1 X 47.242 Y 135.310 +G1 X 47.516 Y 134.819 +G1 X 47.785 Y 134.325 +G1 X 48.048 Y 133.827 +G1 X 48.305 Y 133.326 +G1 X 48.581 Y 132.774 +G1 X 48.849 Y 132.217 +G1 X 49.111 Y 131.658 +G1 X 49.366 Y 131.096 +G1 X 49.614 Y 130.530 +G1 X 49.855 Y 129.961 +G1 X 50.089 Y 129.390 +G1 X 50.316 Y 128.815 +G1 X 50.546 Y 128.212 +G1 X 50.769 Y 127.606 +G1 X 50.984 Y 126.997 +G1 X 51.193 Y 126.386 +G1 X 51.394 Y 125.772 +G1 X 51.588 Y 125.156 +G1 X 51.774 Y 124.537 +G1 X 51.959 Y 123.897 +G1 X 52.137 Y 123.255 +G1 X 52.307 Y 122.611 +G1 X 52.470 Y 121.965 +G1 X 52.626 Y 121.318 +G1 X 52.775 Y 120.668 +G1 X 52.914 Y 120.029 +G1 X 53.046 Y 119.389 +G1 X 53.172 Y 118.747 +G1 X 53.291 Y 118.104 +G1 X 53.403 Y 117.460 +G1 X 53.512 Y 116.794 +G1 X 53.615 Y 116.127 +G1 X 53.711 Y 115.458 +G1 X 53.801 Y 114.789 +G1 X 53.884 Y 114.119 +G1 X 53.964 Y 113.414 +G1 X 54.038 Y 112.708 +G1 X 54.105 Y 112.001 +G1 X 54.165 Y 111.293 +G1 X 54.218 Y 110.585 +G1 X 54.264 Y 109.883 +G1 X 54.305 Y 109.179 +G1 X 54.339 Y 108.476 +G1 X 54.367 Y 107.772 +G1 X 54.389 Y 107.068 +G1 X 54.405 Y 106.355 +G1 X 54.415 Y 105.643 +G1 X 54.419 Y 104.930 +G1 X 54.418 Y 104.873 +G1 X 53.518 Y 88.652 +G1 X 52.618 Y 72.431 +G1 X 52.612 Y 72.367 +G1 X 52.603 Y 72.305 +G1 X 52.589 Y 72.243 +G1 X 41.261 Y 27.075 +G1 X 41.237 Y 26.994 +G1 X 41.207 Y 26.915 +G1 X 41.169 Y 26.839 +G1 X 41.126 Y 26.767 +G1 X 41.077 Y 26.699 +G1 X 41.022 Y 26.635 +G1 X 40.961 Y 26.576 +G1 X 17.177 Y 5.114 +G1 X 17.115 Y 5.061 +G1 X 17.048 Y 5.015 +G1 X 16.978 Y 4.973 +G1 X 16.904 Y 4.938 +G1 X 16.828 Y 4.909 +G1 X 16.750 Y 4.886 +G1 X 16.670 Y 4.869 +G1 X 16.589 Y 4.859 +G1 X 16.507 Y 4.856 +G1 X -2.627 Y 4.856 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 5 *) +G0 X -2.873 Y 104.578 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F250 +G1 X -10.366 Y 104.578 +G1 X -24.711 Y 143.327 +G1 X -24.746 Y 143.412 +G1 X -24.790 Y 143.492 +G1 X -24.840 Y 143.569 +G1 X -24.898 Y 143.640 +G1 X -24.961 Y 143.706 +G1 X -25.030 Y 143.766 +G1 X -25.105 Y 143.819 +G1 X -25.184 Y 143.866 +G1 X -25.267 Y 143.904 +G1 X -25.353 Y 143.935 +G1 X -25.442 Y 143.958 +G1 X -25.532 Y 143.973 +G1 X -25.624 Y 143.980 +G1 X -25.715 Y 143.978 +G1 X -25.806 Y 143.967 +G1 X -25.896 Y 143.949 +G1 X -25.984 Y 143.922 +G1 X -26.069 Y 143.888 +G1 X -26.150 Y 143.845 +G1 X -50.654 Y 129.649 +G1 X -50.734 Y 129.597 +G1 X -50.810 Y 129.538 +G1 X -50.879 Y 129.471 +G1 X -50.941 Y 129.399 +G1 X -50.997 Y 129.320 +G1 X -51.044 Y 129.237 +G1 X -51.083 Y 129.150 +G1 X -51.114 Y 129.059 +G1 X -51.136 Y 128.966 +G1 X -51.149 Y 128.871 +G1 X -51.153 Y 128.775 +G1 X -50.837 Y 94.283 +G1 X -55.807 Y 85.169 +G1 X -55.847 Y 85.085 +G1 X -55.880 Y 84.998 +G1 X -55.904 Y 84.909 +G1 X -55.920 Y 84.817 +G1 X -55.928 Y 84.725 +G1 X -55.927 Y 84.632 +G1 X -55.917 Y 84.540 +G1 X -53.529 Y 68.844 +G1 X -53.510 Y 68.749 +G1 X -53.482 Y 68.657 +G1 X -53.445 Y 68.567 +G1 X -53.400 Y 68.482 +G1 X -53.346 Y 68.402 +G1 X -25.866 Y 31.016 +G1 X -25.807 Y 30.943 +G1 X -25.742 Y 30.876 +G1 X -25.670 Y 30.815 +G1 X -25.594 Y 30.762 +G1 X -25.512 Y 30.716 +G1 X -25.427 Y 30.677 +G1 X -25.338 Y 30.647 +G1 X -25.247 Y 30.626 +G1 X -25.154 Y 30.612 +G1 X -25.061 Y 30.608 +G1 X -2.873 Y 30.608 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 0 *) +G0 X -2.627 Y 104.578 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F350 +G1 X 4.867 Y 104.578 +G1 X 19.212 Y 143.327 +G1 X 19.245 Y 143.407 +G1 X 19.286 Y 143.484 +G1 X 19.333 Y 143.558 +G1 X 19.386 Y 143.626 +G1 X 19.445 Y 143.690 +G1 X 19.510 Y 143.749 +G1 X 19.579 Y 143.801 +G1 X 19.653 Y 143.848 +G1 X 19.730 Y 143.888 +G1 X 19.811 Y 143.921 +G1 X 19.894 Y 143.947 +G1 X 19.979 Y 143.965 +G1 X 20.065 Y 143.976 +G1 X 20.152 Y 143.980 +G1 X 20.239 Y 143.976 +G1 X 20.325 Y 143.964 +G1 X 20.410 Y 143.945 +G1 X 20.493 Y 143.919 +G1 X 20.574 Y 143.886 +G1 X 20.651 Y 143.845 +G1 X 45.155 Y 129.649 +G1 X 45.229 Y 129.602 +G1 X 45.298 Y 129.548 +G1 X 45.363 Y 129.489 +G1 X 45.422 Y 129.424 +G1 X 45.475 Y 129.354 +G1 X 45.522 Y 129.279 +G1 X 45.562 Y 129.201 +G1 X 45.595 Y 129.120 +G1 X 45.621 Y 129.036 +G1 X 45.640 Y 128.950 +G1 X 45.650 Y 128.863 +G1 X 45.653 Y 128.775 +G1 X 45.338 Y 94.283 +G1 X 50.307 Y 85.169 +G1 X 50.343 Y 85.096 +G1 X 50.373 Y 85.020 +G1 X 50.397 Y 84.943 +G1 X 50.414 Y 84.863 +G1 X 50.425 Y 84.783 +G1 X 50.429 Y 84.702 +G1 X 50.427 Y 84.621 +G1 X 50.418 Y 84.540 +G1 X 48.036 Y 68.844 +G1 X 48.021 Y 68.765 +G1 X 47.999 Y 68.687 +G1 X 47.971 Y 68.612 +G1 X 47.938 Y 68.539 +G1 X 47.898 Y 68.468 +G1 X 47.853 Y 68.402 +G1 X 20.373 Y 31.016 +G1 X 20.320 Y 30.949 +G1 X 20.261 Y 30.888 +G1 X 20.197 Y 30.831 +G1 X 20.129 Y 30.781 +G1 X 20.057 Y 30.736 +G1 X 19.981 Y 30.697 +G1 X 19.902 Y 30.665 +G1 X 19.820 Y 30.640 +G1 X 19.737 Y 30.622 +G1 X 19.652 Y 30.612 +G1 X 19.567 Y 30.608 +G1 X -2.627 Y 30.608 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 6 *) +G0 X -2.873 Y 78.520 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +G1 X -6.994 Y 78.520 +G1 X -48.778 Y 94.695 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 1 *) +G0 X -2.627 Y 78.520 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +G1 X 1.495 Y 78.520 +G1 X 43.284 Y 94.695 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 7 *) +G0 X -6.159 Y 77.374 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F200 +G1 X -6.202 Y 77.070 +G1 X -6.226 Y 76.921 +G1 X -6.281 Y 76.613 +G1 X -6.343 Y 76.306 +G1 X -6.413 Y 76.001 +G1 X -6.490 Y 75.698 +G1 X -6.575 Y 75.397 +G1 X -6.667 Y 75.098 +G1 X -6.766 Y 74.801 +G1 X -6.873 Y 74.507 +G1 X -6.986 Y 74.216 +G1 X -7.107 Y 73.928 +G1 X -7.235 Y 73.643 +G1 X -7.370 Y 73.361 +G1 X -7.512 Y 73.083 +G1 X -7.661 Y 72.808 +G1 X -7.816 Y 72.537 +G1 X -7.979 Y 72.269 +G1 X -8.147 Y 72.006 +G1 X -8.322 Y 71.748 +G1 X -8.504 Y 71.493 +G1 X -8.692 Y 71.243 +G1 X -8.885 Y 70.999 +G1 X -9.085 Y 70.759 +G1 X -9.290 Y 70.524 +G1 X -9.501 Y 70.294 +G1 X -9.717 Y 70.069 +G1 X -9.939 Y 69.850 +G1 X -10.166 Y 69.636 +G1 X -10.398 Y 69.428 +G1 X -10.636 Y 69.225 +G1 X -10.878 Y 69.028 +G1 X -11.125 Y 68.838 +G1 X -11.376 Y 68.653 +G1 X -11.632 Y 68.475 +G1 X -11.892 Y 68.303 +G1 X -12.157 Y 68.137 +G1 X -12.425 Y 67.978 +G1 X -12.697 Y 67.825 +G1 X -12.973 Y 67.679 +G1 X -13.252 Y 67.540 +G1 X -13.535 Y 67.407 +G1 X -13.820 Y 67.282 +G1 X -14.109 Y 67.164 +G1 X -14.400 Y 67.052 +G1 X -14.694 Y 66.948 +G1 X -14.989 Y 66.852 +G1 X -15.286 Y 66.763 +G1 X -15.586 Y 66.681 +G1 X -15.887 Y 66.607 +G1 X -16.190 Y 66.540 +G1 X -16.494 Y 66.480 +G1 X -16.800 Y 66.428 +G1 X -17.107 Y 66.383 +G1 X -17.415 Y 66.346 +G1 X -17.724 Y 66.317 +G1 X -18.034 Y 66.295 +G1 X -18.344 Y 66.281 +G1 X -18.654 Y 66.274 +G1 X -18.964 Y 66.276 +G1 X -19.283 Y 66.284 +G1 X -19.602 Y 66.301 +G1 X -19.919 Y 66.326 +G1 X -20.237 Y 66.359 +G1 X -20.553 Y 66.399 +G1 X -20.868 Y 66.447 +G1 X -20.869 Y 66.448 +G1 X -31.669 Y 68.248 +G1 X -31.960 Y 68.300 +G1 X -32.250 Y 68.358 +G1 X -32.539 Y 68.423 +G1 X -32.826 Y 68.495 +G1 X -33.112 Y 68.574 +G1 X -33.395 Y 68.659 +G1 X -33.679 Y 68.752 +G1 X -33.960 Y 68.851 +G1 X -34.239 Y 68.956 +G1 X -34.516 Y 69.068 +G1 X -34.789 Y 69.187 +G1 X -35.060 Y 69.312 +G1 X -35.328 Y 69.444 +G1 X -35.592 Y 69.581 +G1 X -35.854 Y 69.725 +G1 X -36.111 Y 69.875 +G1 X -36.366 Y 70.031 +G1 X -36.616 Y 70.193 +G1 X -36.862 Y 70.361 +G1 X -37.105 Y 70.535 +G1 X -37.354 Y 70.722 +G1 X -37.597 Y 70.915 +G1 X -37.837 Y 71.114 +G1 X -38.071 Y 71.318 +G1 X -38.300 Y 71.529 +G1 X -38.524 Y 71.744 +G1 X -38.742 Y 71.966 +G1 X -38.956 Y 72.192 +G1 X -39.163 Y 72.424 +G1 X -39.365 Y 72.660 +G1 X -39.561 Y 72.902 +G1 X -39.751 Y 73.148 +G1 X -39.936 Y 73.399 +G1 X -40.114 Y 73.654 +G1 X -40.285 Y 73.913 +G1 X -40.451 Y 74.177 +G1 X -40.610 Y 74.444 +G1 X -40.762 Y 74.715 +G1 X -40.908 Y 74.990 +G1 X -41.046 Y 75.268 +G1 X -41.179 Y 75.550 +G1 X -41.304 Y 75.835 +G1 X -41.422 Y 76.122 +G1 X -41.528 Y 76.399 +G1 X -41.628 Y 76.678 +G1 X -41.721 Y 76.959 +G1 X -41.807 Y 77.242 +G1 X -41.887 Y 77.527 +G1 X -41.960 Y 77.814 +G1 X -42.026 Y 78.103 +G1 X -42.086 Y 78.393 +G1 X -42.138 Y 78.684 +G1 X -42.184 Y 78.977 +G1 X -42.223 Y 79.270 +G1 X -42.256 Y 79.565 +G1 X -42.281 Y 79.860 +G1 X -42.299 Y 80.155 +G1 X -42.311 Y 80.457 +G1 X -42.315 Y 80.760 +G1 X -42.313 Y 81.062 +G1 X -42.303 Y 81.364 +G1 X -42.286 Y 81.666 +G1 X -42.262 Y 81.967 +G1 X -42.262 Y 81.973 +G1 X -42.260 Y 81.994 +G1 X -41.428 Y 90.487 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 2 *) +G0 X 0.660 Y 77.374 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F200 +G1 X 0.793 Y 76.552 +G1 X 0.871 Y 76.184 +G1 X 0.959 Y 75.819 +G1 X 1.058 Y 75.457 +G1 X 1.168 Y 75.098 +G1 X 1.275 Y 74.778 +G1 X 1.391 Y 74.462 +G1 X 1.515 Y 74.149 +G1 X 1.647 Y 73.840 +G1 X 1.787 Y 73.534 +G1 X 1.936 Y 73.232 +G1 X 2.092 Y 72.934 +G1 X 2.257 Y 72.640 +G1 X 2.429 Y 72.351 +G1 X 2.609 Y 72.067 +G1 X 2.796 Y 71.787 +G1 X 2.991 Y 71.513 +G1 X 3.193 Y 71.243 +G1 X 3.395 Y 70.988 +G1 X 3.603 Y 70.738 +G1 X 3.818 Y 70.493 +G1 X 4.039 Y 70.254 +G1 X 4.266 Y 70.021 +G1 X 4.499 Y 69.793 +G1 X 4.737 Y 69.572 +G1 X 4.981 Y 69.357 +G1 X 5.231 Y 69.147 +G1 X 5.485 Y 68.945 +G1 X 5.745 Y 68.749 +G1 X 6.010 Y 68.559 +G1 X 6.280 Y 68.377 +G1 X 6.554 Y 68.201 +G1 X 6.832 Y 68.032 +G1 X 7.115 Y 67.871 +G1 X 7.401 Y 67.716 +G1 X 7.692 Y 67.569 +G1 X 7.986 Y 67.430 +G1 X 8.284 Y 67.298 +G1 X 8.584 Y 67.174 +G1 X 8.888 Y 67.057 +G1 X 9.195 Y 66.948 +G1 X 9.513 Y 66.845 +G1 X 9.833 Y 66.750 +G1 X 10.156 Y 66.663 +G1 X 10.481 Y 66.585 +G1 X 10.808 Y 66.516 +G1 X 11.136 Y 66.455 +G1 X 11.466 Y 66.403 +G1 X 11.798 Y 66.360 +G1 X 12.130 Y 66.325 +G1 X 12.463 Y 66.300 +G1 X 12.797 Y 66.283 +G1 X 13.131 Y 66.275 +G1 X 13.465 Y 66.276 +G1 X 13.848 Y 66.287 +G1 X 14.230 Y 66.310 +G1 X 14.611 Y 66.345 +G1 X 14.991 Y 66.390 +G1 X 15.369 Y 66.447 +G1 X 26.169 Y 68.248 +G1 X 26.507 Y 68.308 +G1 X 26.843 Y 68.378 +G1 X 27.177 Y 68.456 +G1 X 27.509 Y 68.544 +G1 X 27.838 Y 68.640 +G1 X 28.150 Y 68.741 +G1 X 28.460 Y 68.849 +G1 X 28.768 Y 68.966 +G1 X 29.071 Y 69.090 +G1 X 29.372 Y 69.223 +G1 X 29.669 Y 69.363 +G1 X 29.962 Y 69.511 +G1 X 30.252 Y 69.666 +G1 X 30.537 Y 69.829 +G1 X 30.818 Y 69.999 +G1 X 31.094 Y 70.176 +G1 X 31.366 Y 70.361 +G1 X 31.633 Y 70.552 +G1 X 31.897 Y 70.752 +G1 X 32.156 Y 70.959 +G1 X 32.409 Y 71.172 +G1 X 32.656 Y 71.392 +G1 X 32.898 Y 71.618 +G1 X 33.134 Y 71.851 +G1 X 33.364 Y 72.089 +G1 X 33.587 Y 72.333 +G1 X 33.804 Y 72.583 +G1 X 34.015 Y 72.839 +G1 X 34.219 Y 73.100 +G1 X 34.416 Y 73.366 +G1 X 34.606 Y 73.637 +G1 X 34.789 Y 73.913 +G1 X 34.965 Y 74.194 +G1 X 35.133 Y 74.479 +G1 X 35.294 Y 74.768 +G1 X 35.447 Y 75.062 +G1 X 35.593 Y 75.359 +G1 X 35.731 Y 75.660 +G1 X 35.861 Y 75.964 +G1 X 35.987 Y 76.280 +G1 X 36.103 Y 76.600 +G1 X 36.212 Y 76.922 +G1 X 36.311 Y 77.247 +G1 X 36.402 Y 77.575 +G1 X 36.484 Y 77.905 +G1 X 36.557 Y 78.237 +G1 X 36.621 Y 78.571 +G1 X 36.676 Y 78.906 +G1 X 36.722 Y 79.243 +G1 X 36.759 Y 79.581 +G1 X 36.787 Y 79.920 +G1 X 36.806 Y 80.259 +G1 X 36.815 Y 80.601 +G1 X 36.816 Y 80.943 +G1 X 36.807 Y 81.285 +G1 X 36.790 Y 81.626 +G1 X 36.763 Y 81.967 +G1 X 36.759 Y 82.013 +G1 X 35.962 Y 90.149 +G1 X 35.929 Y 90.487 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 9 *) +G0 X -26.050 Y 31.463 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F200 +G1 X -22.342 Y 6.197 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 4 *) +G0 X 18.578 Y 31.753 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F200 +G1 X 14.864 Y 6.487 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 +G0 X 0.000 Y 0.000 +M2 (Program end) \ No newline at end of file diff --git a/src/jetmax_demos/scripts/gcode/tony1.ngc b/src/jetmax_demos/scripts/gcode/tony1.ngc new file mode 100644 index 0000000..150fcff --- /dev/null +++ b/src/jetmax_demos/scripts/gcode/tony1.ngc @@ -0,0 +1,314 @@ +(Generated with: DXF2GCODE, Version: Py3.7.10 PyQt5.10.1, Date: $Date: Fri Oct 25 20:45:56 2019 +0200 $) +(Created from file: /home/lucas/钢铁侠.dxf) +(Output format description: G-CODE for LinuxCNC) +(Time: Mon Jul 19 18:04:03 2021) +G21 (Units in millimeters) +G90 (Absolute programming) +G64 (Default cutting) G17 (XY plane) G40 (Cancel radius comp.) G49 (Cancel length comp.) +G0 Z 100.000 + +(*** LAYER: _U+56FE_U+5C42 1 ***) +T1 M6 +S6000 + +(* SHAPE Nr: 7 *) +G0 X -6.159 Y 77.374 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F200 +G1 X -6.202 Y 77.070 +G1 X -6.226 Y 76.921 +G1 X -6.281 Y 76.613 +G1 X -6.343 Y 76.306 +G1 X -6.413 Y 76.001 +G1 X -6.490 Y 75.698 +G1 X -6.575 Y 75.397 +G1 X -6.667 Y 75.098 +G1 X -6.766 Y 74.801 +G1 X -6.873 Y 74.507 +G1 X -6.986 Y 74.216 +G1 X -7.107 Y 73.928 +G1 X -7.235 Y 73.643 +G1 X -7.370 Y 73.361 +G1 X -7.512 Y 73.083 +G1 X -7.661 Y 72.808 +G1 X -7.816 Y 72.537 +G1 X -7.979 Y 72.269 +G1 X -8.147 Y 72.006 +G1 X -8.322 Y 71.748 +G1 X -8.504 Y 71.493 +G1 X -8.692 Y 71.243 +G1 X -8.885 Y 70.999 +G1 X -9.085 Y 70.759 +G1 X -9.290 Y 70.524 +G1 X -9.501 Y 70.294 +G1 X -9.717 Y 70.069 +G1 X -9.939 Y 69.850 +G1 X -10.166 Y 69.636 +G1 X -10.398 Y 69.428 +G1 X -10.636 Y 69.225 +G1 X -10.878 Y 69.028 +G1 X -11.125 Y 68.838 +G1 X -11.376 Y 68.653 +G1 X -11.632 Y 68.475 +G1 X -11.892 Y 68.303 +G1 X -12.157 Y 68.137 +G1 X -12.425 Y 67.978 +G1 X -12.697 Y 67.825 +G1 X -12.973 Y 67.679 +G1 X -13.252 Y 67.540 +G1 X -13.535 Y 67.407 +G1 X -13.820 Y 67.282 +G1 X -14.109 Y 67.164 +G1 X -14.400 Y 67.052 +G1 X -14.694 Y 66.948 +G1 X -14.989 Y 66.852 +G1 X -15.286 Y 66.763 +G1 X -15.586 Y 66.681 +G1 X -15.887 Y 66.607 +G1 X -16.190 Y 66.540 +G1 X -16.494 Y 66.480 +G1 X -16.800 Y 66.428 +G1 X -17.107 Y 66.383 +G1 X -17.415 Y 66.346 +G1 X -17.724 Y 66.317 +G1 X -18.034 Y 66.295 +G1 X -18.344 Y 66.281 +G1 X -18.654 Y 66.274 +G1 X -18.964 Y 66.276 +G1 X -19.283 Y 66.284 +G1 X -19.602 Y 66.301 +G1 X -19.919 Y 66.326 +G1 X -20.237 Y 66.359 +G1 X -20.553 Y 66.399 +G1 X -20.868 Y 66.447 +G1 X -20.869 Y 66.448 +G1 X -31.669 Y 68.248 +G1 X -31.960 Y 68.300 +G1 X -32.250 Y 68.358 +G1 X -32.539 Y 68.423 +G1 X -32.826 Y 68.495 +G1 X -33.112 Y 68.574 +G1 X -33.395 Y 68.659 +G1 X -33.679 Y 68.752 +G1 X -33.960 Y 68.851 +G1 X -34.239 Y 68.956 +G1 X -34.516 Y 69.068 +G1 X -34.789 Y 69.187 +G1 X -35.060 Y 69.312 +G1 X -35.328 Y 69.444 +G1 X -35.592 Y 69.581 +G1 X -35.854 Y 69.725 +G1 X -36.111 Y 69.875 +G1 X -36.366 Y 70.031 +G1 X -36.616 Y 70.193 +G1 X -36.862 Y 70.361 +G1 X -37.105 Y 70.535 +G1 X -37.354 Y 70.722 +G1 X -37.597 Y 70.915 +G1 X -37.837 Y 71.114 +G1 X -38.071 Y 71.318 +G1 X -38.300 Y 71.529 +G1 X -38.524 Y 71.744 +G1 X -38.742 Y 71.966 +G1 X -38.956 Y 72.192 +G1 X -39.163 Y 72.424 +G1 X -39.365 Y 72.660 +G1 X -39.561 Y 72.902 +G1 X -39.751 Y 73.148 +G1 X -39.936 Y 73.399 +G1 X -40.114 Y 73.654 +G1 X -40.285 Y 73.913 +G1 X -40.451 Y 74.177 +G1 X -40.610 Y 74.444 +G1 X -40.762 Y 74.715 +G1 X -40.908 Y 74.990 +G1 X -41.046 Y 75.268 +G1 X -41.179 Y 75.550 +G1 X -41.304 Y 75.835 +G1 X -41.422 Y 76.122 +G1 X -41.528 Y 76.399 +G1 X -41.628 Y 76.678 +G1 X -41.721 Y 76.959 +G1 X -41.807 Y 77.242 +G1 X -41.887 Y 77.527 +G1 X -41.960 Y 77.814 +G1 X -42.026 Y 78.103 +G1 X -42.086 Y 78.393 +G1 X -42.138 Y 78.684 +G1 X -42.184 Y 78.977 +G1 X -42.223 Y 79.270 +G1 X -42.256 Y 79.565 +G1 X -42.281 Y 79.860 +G1 X -42.299 Y 80.155 +G1 X -42.311 Y 80.457 +G1 X -42.315 Y 80.760 +G1 X -42.313 Y 81.062 +G1 X -42.303 Y 81.364 +G1 X -42.286 Y 81.666 +G1 X -42.262 Y 81.967 +G1 X -42.262 Y 81.973 +G1 X -42.260 Y 81.994 +G1 X -41.428 Y 90.487 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 2 *) +G0 X 0.660 Y 77.374 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F200 +G1 X 0.793 Y 76.552 +G1 X 0.871 Y 76.184 +G1 X 0.959 Y 75.819 +G1 X 1.058 Y 75.457 +G1 X 1.168 Y 75.098 +G1 X 1.275 Y 74.778 +G1 X 1.391 Y 74.462 +G1 X 1.515 Y 74.149 +G1 X 1.647 Y 73.840 +G1 X 1.787 Y 73.534 +G1 X 1.936 Y 73.232 +G1 X 2.092 Y 72.934 +G1 X 2.257 Y 72.640 +G1 X 2.429 Y 72.351 +G1 X 2.609 Y 72.067 +G1 X 2.796 Y 71.787 +G1 X 2.991 Y 71.513 +G1 X 3.193 Y 71.243 +G1 X 3.395 Y 70.988 +G1 X 3.603 Y 70.738 +G1 X 3.818 Y 70.493 +G1 X 4.039 Y 70.254 +G1 X 4.266 Y 70.021 +G1 X 4.499 Y 69.793 +G1 X 4.737 Y 69.572 +G1 X 4.981 Y 69.357 +G1 X 5.231 Y 69.147 +G1 X 5.485 Y 68.945 +G1 X 5.745 Y 68.749 +G1 X 6.010 Y 68.559 +G1 X 6.280 Y 68.377 +G1 X 6.554 Y 68.201 +G1 X 6.832 Y 68.032 +G1 X 7.115 Y 67.871 +G1 X 7.401 Y 67.716 +G1 X 7.692 Y 67.569 +G1 X 7.986 Y 67.430 +G1 X 8.284 Y 67.298 +G1 X 8.584 Y 67.174 +G1 X 8.888 Y 67.057 +G1 X 9.195 Y 66.948 +G1 X 9.513 Y 66.845 +G1 X 9.833 Y 66.750 +G1 X 10.156 Y 66.663 +G1 X 10.481 Y 66.585 +G1 X 10.808 Y 66.516 +G1 X 11.136 Y 66.455 +G1 X 11.466 Y 66.403 +G1 X 11.798 Y 66.360 +G1 X 12.130 Y 66.325 +G1 X 12.463 Y 66.300 +G1 X 12.797 Y 66.283 +G1 X 13.131 Y 66.275 +G1 X 13.465 Y 66.276 +G1 X 13.848 Y 66.287 +G1 X 14.230 Y 66.310 +G1 X 14.611 Y 66.345 +G1 X 14.991 Y 66.390 +G1 X 15.369 Y 66.447 +G1 X 26.169 Y 68.248 +G1 X 26.507 Y 68.308 +G1 X 26.843 Y 68.378 +G1 X 27.177 Y 68.456 +G1 X 27.509 Y 68.544 +G1 X 27.838 Y 68.640 +G1 X 28.150 Y 68.741 +G1 X 28.460 Y 68.849 +G1 X 28.768 Y 68.966 +G1 X 29.071 Y 69.090 +G1 X 29.372 Y 69.223 +G1 X 29.669 Y 69.363 +G1 X 29.962 Y 69.511 +G1 X 30.252 Y 69.666 +G1 X 30.537 Y 69.829 +G1 X 30.818 Y 69.999 +G1 X 31.094 Y 70.176 +G1 X 31.366 Y 70.361 +G1 X 31.633 Y 70.552 +G1 X 31.897 Y 70.752 +G1 X 32.156 Y 70.959 +G1 X 32.409 Y 71.172 +G1 X 32.656 Y 71.392 +G1 X 32.898 Y 71.618 +G1 X 33.134 Y 71.851 +G1 X 33.364 Y 72.089 +G1 X 33.587 Y 72.333 +G1 X 33.804 Y 72.583 +G1 X 34.015 Y 72.839 +G1 X 34.219 Y 73.100 +G1 X 34.416 Y 73.366 +G1 X 34.606 Y 73.637 +G1 X 34.789 Y 73.913 +G1 X 34.965 Y 74.194 +G1 X 35.133 Y 74.479 +G1 X 35.294 Y 74.768 +G1 X 35.447 Y 75.062 +G1 X 35.593 Y 75.359 +G1 X 35.731 Y 75.660 +G1 X 35.861 Y 75.964 +G1 X 35.987 Y 76.280 +G1 X 36.103 Y 76.600 +G1 X 36.212 Y 76.922 +G1 X 36.311 Y 77.247 +G1 X 36.402 Y 77.575 +G1 X 36.484 Y 77.905 +G1 X 36.557 Y 78.237 +G1 X 36.621 Y 78.571 +G1 X 36.676 Y 78.906 +G1 X 36.722 Y 79.243 +G1 X 36.759 Y 79.581 +G1 X 36.787 Y 79.920 +G1 X 36.806 Y 80.259 +G1 X 36.815 Y 80.601 +G1 X 36.816 Y 80.943 +G1 X 36.807 Y 81.285 +G1 X 36.790 Y 81.626 +G1 X 36.763 Y 81.967 +G1 X 36.759 Y 82.013 +G1 X 35.962 Y 90.149 +G1 X 35.929 Y 90.487 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 9 *) +G0 X -26.050 Y 31.463 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F200 +G1 X -22.342 Y 6.197 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 + +(* SHAPE Nr: 4 *) +G0 X 18.578 Y 31.753 +M3 M8 +G0 Z 30.000 +G1 Z 30.000 +F200 +G1 X 14.864 Y 6.487 +F150 +G1 Z 30.000 +G0 Z 100.000 +M9 M5 +G0 X 0.000 Y 0.000 +M2 (Program end) diff --git a/src/jetmax_demos/scripts/hand_gesture.py b/src/jetmax_demos/scripts/hand_gesture.py new file mode 100755 index 0000000..a74f190 --- /dev/null +++ b/src/jetmax_demos/scripts/hand_gesture.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import threading +import numpy as np +import rospy +import queue +from sensor_msgs.msg import Image +import hiwonder +import mediapipe as mp + +ROS_NODE_NAME = "hand_gesture" + + +class HandGesture: + def __init__(self): + self.moving_color = None + self.target_colors = {} + self.lock = threading.RLock + self.position = 0, 0, 0 + self.runner = None + self.count = 0 + self.gesture_str = '' + + +ps = (-205, 0 + 10, 150), (-205, 0 + 10, 120), (-205, 0 + 10, 190) + + +def vector_2d_angle(v1, v2): + """ + Solve the angle between two vector + """ + v1_x = v1[0] + v1_y = v1[1] + v2_x = v2[0] + v2_y = v2[1] + try: + angle_ = math.degrees(math.acos( + (v1_x * v2_x + v1_y * v2_y) / (((v1_x ** 2 + v1_y ** 2) ** 0.5) * ((v2_x ** 2 + v2_y ** 2) ** 0.5)))) + except: + angle_ = 65535. + if angle_ > 180.: + angle_ = 65535. + return angle_ + + +def hand_angle(hand_): + """ + Obtain the angle of the corresponding hand-related vector, and determine the gesture according to the angle + """ + angle_list = [] + # ---------------------------- thumb + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[2][0])), (int(hand_[0][1]) - int(hand_[2][1]))), + ((int(hand_[3][0]) - int(hand_[4][0])), (int(hand_[3][1]) - int(hand_[4][1]))) + ) + angle_list.append(angle_) + # ---------------------------- index + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[6][0])), (int(hand_[0][1]) - int(hand_[6][1]))), + ((int(hand_[7][0]) - int(hand_[8][0])), (int(hand_[7][1]) - int(hand_[8][1]))) + ) + angle_list.append(angle_) + # ---------------------------- middle + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[10][0])), (int(hand_[0][1]) - int(hand_[10][1]))), + ((int(hand_[11][0]) - int(hand_[12][0])), (int(hand_[11][1]) - int(hand_[12][1]))) + ) + angle_list.append(angle_) + # ---------------------------- ring + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[14][0])), (int(hand_[0][1]) - int(hand_[14][1]))), + ((int(hand_[15][0]) - int(hand_[16][0])), (int(hand_[15][1]) - int(hand_[16][1]))) + ) + angle_list.append(angle_) + # ---------------------------- pink + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[18][0])), (int(hand_[0][1]) - int(hand_[18][1]))), + ((int(hand_[19][0]) - int(hand_[20][0])), (int(hand_[19][1]) - int(hand_[20][1]))) + ) + angle_list.append(angle_) + return angle_list + + +def h_gesture(angle_list): + """ + Use the angle of the corresponding hand-related to define the gesture + + """ + thr_angle = 65. + thr_angle_thumb = 53. + thr_angle_s = 49. + gesture_str = None + if 65535. not in angle_list: + if (angle_list[0] > thr_angle_thumb) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] > thr_angle): + gesture_str = "fist" + elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] > thr_angle): + gesture_str = "hand_heart" + elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] < thr_angle_s): + gesture_str = "nico-nico-ni" + elif (angle_list[0] < thr_angle_s) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] > thr_angle): + gesture_str = "hand_heart" + elif (angle_list[0] > 5) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] > thr_angle): + gesture_str = "one" + elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] > thr_angle) and (angle_list[4] > thr_angle): + gesture_str = "two" + elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] < thr_angle_s) and (angle_list[4] > thr_angle): + gesture_str = "three" + elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] > thr_angle) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s): + gesture_str = "OK" + elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s): + gesture_str = "four" + elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s): + gesture_str = "five" + elif (angle_list[0] < thr_angle_s) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] < thr_angle_s): + gesture_str = "six" + else: + "none" + return gesture_str + + +ngcs = { + 'one': 'gcode/1.ngc', + 'two': 'gcode/2.ngc', + 'three': 'gcode/3.ngc', + 'four': 'gcode/4.ngc', + 'five': 'gcode/5.ngc', + 'six': 'gcode/6.ngc', + 'hand_heart': 'ngcs/hand_heart.ngc', +} + + +def draw_num(num): + all_num = ['one', 'two', 'three', 'four', 'five', 'six', 'fist', 'hand_heart', 'nico-nico-ni', "OK"] + try: + i = all_num.index(num) + except: + state.runner = None + if i < 5: + for i in range(i + 1): + hiwonder.buzzer.on() + rospy.sleep(0.1) + hiwonder.buzzer.off() + rospy.sleep(0.3) + else: + hiwonder.buzzer.on() + rospy.sleep(1) + hiwonder.buzzer.off() + state.runner = None + + +def image_proc_a(img): + img_ret = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) + if state.runner is not None: + cv2.putText(img, state.gesture_str, (0, 200), 0, 1.5, (100, 100, 255), 5) + return img_ret + + results = hands.process(img) + if results.multi_handedness: + for label in results.multi_handedness: + print(label) + if results.multi_hand_landmarks: + for hand_landmarks in results.multi_hand_landmarks: + # rospy.logdebug('hand_landmarks:', hand_landmarks) + mp_drawing.draw_landmarks(img_ret, hand_landmarks, mp_hands.HAND_CONNECTIONS) + hand_local = [] + for i in range(21): + x = hand_landmarks.landmark[i].x * img.shape[1] + y = hand_landmarks.landmark[i].y * img.shape[0] + hand_local.append((x, y)) + if hand_local: + angle_list = hand_angle(hand_local) + gesture_str = h_gesture(angle_list) + cv2.putText(img_ret, gesture_str, (0, 200), 0, 1.5, (100, 100, 255), 5) + if gesture_str != state.gesture_str: + state.count = 0 + state.gesture_str = gesture_str + state.count += 1 + else: + state.count = 0 + + if state.count > 10: + state.count = 0 + state.runner = threading.Thread(target=draw_num, args=(state.gesture_str,), daemon=True) + state.runner.start() + return img_ret + + +def image_proc_b(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + image = cv2.flip(image, 1) + image = image_proc_a(image) + image = cv2.resize(image, (1024, 768)) + cv2.imshow(ROS_NODE_NAME, image) + cv2.waitKey(1) + + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + rospy.sleep(0.2) + state = HandGesture() + image_queue = queue.Queue(maxsize=1) + mp_drawing = mp.solutions.drawing_utils + mp_hands = mp.solutions.hands + hands = mp_hands.Hands( + static_image_mode=False, + max_num_hands=2, + min_detection_confidence=0.75, + min_tracking_confidence=0.5) + + jetmax = hiwonder.JetMax() + jetmax.go_home() + rospy.sleep(1) + hiwonder.motor2.set_speed(0) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback, queue_size=1) + while not rospy.is_shutdown(): + image_proc_b() diff --git a/src/jetmax_demos/scripts/hand_trakcing.py b/src/jetmax_demos/scripts/hand_trakcing.py new file mode 100755 index 0000000..f7d0578 --- /dev/null +++ b/src/jetmax_demos/scripts/hand_trakcing.py @@ -0,0 +1,219 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import threading +import numpy as np +import rospy +import queue +from sensor_msgs.msg import Image +import hiwonder +import mediapipe as mp +import hiwonder + +ROS_NODE_NAME = "hand_gesture" + + +class HandGesture: + def __init__(self): + self.moving_color = None + self.target_colors = {} + self.lock = threading.RLock + self.position = 0, 0, 0 + self.runner = None + self.count = 0 + self.gesture_str = '' + self.servo_x = 500 + self.pid_x = hiwonder.PID(0.10, 0, 0.01) + self.pid_z = hiwonder.PID(0.13, 0, 0.015) + + + +def vector_2d_angle(v1, v2): + """ + Solve the angle between two vector + """ + v1_x = v1[0] + v1_y = v1[1] + v2_x = v2[0] + v2_y = v2[1] + try: + angle_ = math.degrees(math.acos( + (v1_x * v2_x + v1_y * v2_y) / (((v1_x ** 2 + v1_y ** 2) ** 0.5) * ((v2_x ** 2 + v2_y ** 2) ** 0.5)))) + except: + angle_ = 65535. + if angle_ > 180.: + angle_ = 65535. + return angle_ + + +def hand_angle(hand_): + """ + Obtain the angle of the corresponding hand-related vector, and determine the gesture according to the angle + """ + angle_list = [] + # ---------------------------- thumb + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[2][0])), (int(hand_[0][1]) - int(hand_[2][1]))), + ((int(hand_[3][0]) - int(hand_[4][0])), (int(hand_[3][1]) - int(hand_[4][1]))) + ) + angle_list.append(angle_) + # ---------------------------- index + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[6][0])), (int(hand_[0][1]) - int(hand_[6][1]))), + ((int(hand_[7][0]) - int(hand_[8][0])), (int(hand_[7][1]) - int(hand_[8][1]))) + ) + angle_list.append(angle_) + # ---------------------------- middle + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[10][0])), (int(hand_[0][1]) - int(hand_[10][1]))), + ((int(hand_[11][0]) - int(hand_[12][0])), (int(hand_[11][1]) - int(hand_[12][1]))) + ) + angle_list.append(angle_) + # ---------------------------- ring + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[14][0])), (int(hand_[0][1]) - int(hand_[14][1]))), + ((int(hand_[15][0]) - int(hand_[16][0])), (int(hand_[15][1]) - int(hand_[16][1]))) + ) + angle_list.append(angle_) + # ---------------------------- pink + angle_ = vector_2d_angle( + ((int(hand_[0][0]) - int(hand_[18][0])), (int(hand_[0][1]) - int(hand_[18][1]))), + ((int(hand_[19][0]) - int(hand_[20][0])), (int(hand_[19][1]) - int(hand_[20][1]))) + ) + angle_list.append(angle_) + return angle_list + + +def h_gesture(angle_list): + """ + Use the angle of the corresponding hand-related to define the gesture + + """ + thr_angle = 65. + thr_angle_thumb = 53. + thr_angle_s = 49. + gesture_str = None + if 65535. not in angle_list: + if (angle_list[0] > thr_angle_thumb) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] > thr_angle): + gesture_str = "fist" + elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] > thr_angle): + gesture_str = "hand_heart" + elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] < thr_angle_s): + gesture_str = "nico-nico-ni" + elif (angle_list[0] < thr_angle_s) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] > thr_angle): + gesture_str = "hand_heart" + elif (angle_list[0] > 5) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] > thr_angle): + gesture_str = "one" + elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] > thr_angle) and (angle_list[4] > thr_angle): + gesture_str = "two" + elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] < thr_angle_s) and (angle_list[4] > thr_angle): + gesture_str = "three" + elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] > thr_angle) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s): + gesture_str = "OK" + elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s): + gesture_str = "four" + elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and ( + angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s): + gesture_str = "five" + elif (angle_list[0] < thr_angle_s) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and ( + angle_list[3] > thr_angle) and (angle_list[4] < thr_angle_s): + gesture_str = "six" + else: + "none" + return gesture_str + + + + +def image_proc(img): + ret_img = np.copy(img) + if state.runner is not None: + return img_ret + + results = hands.process(img) + if results.multi_handedness: + for label in results.multi_handedness: + print(label) + if results.multi_hand_landmarks: + for hand_landmarks in results.multi_hand_landmarks: + mp_drawing.draw_landmarks(ret_img, hand_landmarks, mp_hands.HAND_CONNECTIONS) + hand_local = [(landmark.x * ret_img.shape[1], landmark.y * ret_img.shape[0]) for landmark in hand_landmarks.landmark] + if hand_local: + angle_list = hand_angle(hand_local) + gesture_str = h_gesture(angle_list) + if gesture_str == 'fist': + hiwonder.buzzer.on() + else: + hiwonder.buzzer.off() + print(hand_local[0]) + x, y = hand_local[0] + if abs(320 - x) > 0: + e = 320 - x + state.pid_x.update(e) + state.servo_x += state.pid_x.output + jetmax.set_servo(1, state.servo_x, 0.01) + if abs(300 - y) > 0: + e = 300 - y + state.pid_z.update(e) + cx, cy, cz = jetmax.position + cz -= state.pid_z.output + jetmax.set_position((cx, cy, cz), 0.01) + else: + state.count = 0 + + return ret_img + + +def image_proc_b(): + image = image_queue.get(block=True) + image = image_proc(image) + image = cv2.resize(image, (1024, 768)) + image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) + cv2.imshow(ROS_NODE_NAME, image) + cv2.waitKey(1) + + +def image_callback(ros_image): + try: + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + image = cv2.flip(image, 1) + image_queue.put_nowait(image) + except: + pass + + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + rospy.sleep(0.2) + state = HandGesture() + image_queue = queue.Queue(maxsize=1) + mp_drawing = mp.solutions.drawing_utils + mp_hands = mp.solutions.hands + hands = mp_hands.Hands( + static_image_mode=False, + max_num_hands=1, + min_detection_confidence=0.70, + min_tracking_confidence=0.3) + + jetmax = hiwonder.JetMax() + jetmax.go_home() + rospy.sleep(1) + hiwonder.motor2.set_speed(0) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback, queue_size=1) + while True: + try: + image_proc_b() + except Exception as e: + print(e) + sys.exit() diff --git a/src/jetmax_demos/scripts/kill_app_funcs.sh b/src/jetmax_demos/scripts/kill_app_funcs.sh new file mode 100755 index 0000000..5f463f9 --- /dev/null +++ b/src/jetmax_demos/scripts/kill_app_funcs.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +sudo kill -9 $(ps -elf|grep -v grep|grep python3|grep alphabetically|awk '{print $4}') >/dev/null 2>&1 +sudo systemctl stop alphabetically.service + +sudo kill -9 $(ps -elf|grep -v grep|grep python3|grep waste_classification|awk '{print $4}') >/dev/null 2>&1 +sudo systemctl stop waste_classification.service + +sudo kill -9 $(ps -elf|grep -v grep|grep python3|grep object_tracking|awk '{print $4}') >/dev/null 2>&1 +sudo systemctl stop object_tracking.service + +sudo kill -9 $(ps -elf|grep -v grep|grep python3|grep color_sorting|awk '{print $4}') >/dev/null 2>&1 +sudo systemctl stop color_sorting.service + + diff --git a/src/jetmax_demos/scripts/line_interpolation.py b/src/jetmax_demos/scripts/line_interpolation.py new file mode 100644 index 0000000..900c01b --- /dev/null +++ b/src/jetmax_demos/scripts/line_interpolation.py @@ -0,0 +1,52 @@ +import sys +import math + + +def linear_interpolation(x_start, y_start, x_end, y_end): + points = [] + distance = 0 + x_err, y_err = 0, 0 + inc_x, inc_y = 0, 0 + delta_x, delta_y = 0, 0 + u_row, u_col = x_start, y_start + delta_x = x_end - x_start #计算坐标增量 + delta_y = y_end - y_start + + if delta_x > 0 : + inc_x = 1 #设置单步方向 + elif delta_x == 0: + inc_x = 0 #垂直线 + else: + inc_x = -1 + delta_x = -delta_x + + + if delta_y > 0: + inc_y = 1 + elif delta_y == 0: + inc_y = 0 #水平线 + else: + inc_y = -1 + delta_y = -delta_y + + if delta_x > delta_y: + distance = delta_x #选取基本增量坐标轴 + else: + distance = delta_y + + for i in range(int(distance) + 1 + 1): #画线输出 + points.append([u_row, u_col]) + x_err += delta_x + y_err += delta_y + #print(x_err, y_err) + if x_err > distance: + x_err -= distance + u_row += inc_x + + if y_err > distance: + y_err -= distance + u_col += inc_y + + return points[1:] + +sys.modules[__name__] = linear_interpolation diff --git a/src/jetmax_demos/scripts/mecanum_ball_tracking.py b/src/jetmax_demos/scripts/mecanum_ball_tracking.py new file mode 100755 index 0000000..7ca9fdc --- /dev/null +++ b/src/jetmax_demos/scripts/mecanum_ball_tracking.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python3 +import math +import rospy +import time +import queue +import threading +from sensor_msgs.msg import Image +import cv2 +import numpy as np +import hiwonder +import sys + +ROS_NODE_NAME = 'mecanum_ball_tracking' +DEFAULT_X, DEFAULT_Y, DEFAULT_Z = 0, 100 + 8.14, 0 +ORG_PIXEL_X, ORG_PIXEL_Y = 320, 240 + +en_mot = hiwonder.motor.EncoderMotorController(1, 3) +hiwonder.pwm_servo1.set_position(50, 100) +hiwonder.pwm_servo1.set_position(50, 100) + + +class BallTracking: + def __init__(self): + self.lock = threading.RLock() + self.servo_x = 500 + self.servo_y = 500 + + self.color_x_pid = hiwonder.PID(0.15, 0.005, 0.0005) + self.color_y_pid = hiwonder.PID(0.15, 0.005, 0.0005) + + self.target_color_range = None + self.target_color_name = None + self.last_color_circle = None + self.lost_target_count = 0 + + self.is_running = False + + self.fps = 0.0 + self.tic = time.time() + + +def ball_tracking(image): + org_image = np.copy(image) + image = cv2.resize(image, (320, 240)) + image = cv2.cvtColor(image, cv2.COLOR_RGB2LAB) # RGB转LAB空间 + image = cv2.GaussianBlur(image, (5, 5), 5) + + with state.lock: + target_color_range = state.target_color_range + target_color_name = state.target_color_name + + if target_color_range is not None: + mask = cv2.inRange(image, tuple(target_color_range['min']), tuple(target_color_range['max'])) # 二值化 + eroded = cv2.erode(mask, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) # 腐蚀 + dilated = cv2.dilate(eroded, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) # 膨胀 + contours = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] # 找出轮廓 + contour_area = map(lambda c: (c, math.fabs(cv2.contourArea(c))), contours) # 计算各个轮廓的面积 + contour_area = list(filter(lambda c: c[1] > 100, contour_area)) # 剔除>面积过小的轮廓 + circle = None + if len(contour_area) > 0: + if state.last_color_circle is None: + contour, area = max(contour_area, key=lambda c_a: c_a[1]) + circle = cv2.minEnclosingCircle(contour) + else: + (last_x, last_y), last_r = state.last_color_circle + circles = map(lambda c: cv2.minEnclosingCircle(c[0]), contour_area) + circle_dist = list(map(lambda c: (c, math.sqrt(((c[0][0] - last_x) ** 2) + ((c[0][1] - last_y) ** 2))), + circles)) + circle, dist = min(circle_dist, key=lambda c: c[1]) + if dist < 100: + circle = circle + + if circle is not None: + state.lost_target_count = 0 + (x, y), r = circle + x = x / 320 * 640 + y = y / 240 * 480 + r = r / 320 * 640 + org_image = cv2.circle(org_image, (int(x), int(y)), int(r), (255, 0, 0), 2) + vx = 0 + vy = 0 + vw = 0 + if abs(x - ORG_PIXEL_X) > 20: + state.color_x_pid.update(x - ORG_PIXEL_X) + vx = state.color_x_pid.output + print(circle) + if abs(r - 50) > 5: + if r - 50 < 0: + state.color_y_pid.setKp(3.0) + else: + state.color_y_pid.setKp(0.8) + state.color_y_pid.update(r - 50) + vy = -state.color_y_pid.output + # 计算合速度 + vw1 = vy - vx + vw * (1 + 2) + vw2 = vy + vx - vw * (1 + 2) + vw3 = vy - vx - vw * (1 + 2) + vw4 = vy + vx + vw * (1 + 2) + + vw1 = 100 if vw1 > 100 else vw1 + vw2 = 100 if vw1 > 100 else vw2 + vw3 = 100 if vw1 > 100 else vw3 + vw4 = 100 if vw1 > 100 else vw4 + vw1 = -100 if vw1 < -100 else vw1 + vw2 = -100 if vw1 < -100 else vw2 + vw3 = -100 if vw1 < -100 else vw3 + vw4 = -100 if vw1 < -100 else vw4 + + en_mot.set_speed(int(vw1), 1) + en_mot.set_speed(int(-vw4), 2) + en_mot.set_speed(int(-vw2), 3) + en_mot.set_speed(int(vw3), 4) + + else: + state.lost_target_count += 1 + if state.lost_target_count > 2: + state.color_x_pid.update(0) + state.color_y_pid.update(0) + en_mot.set_speed(int(0), 1) + en_mot.set_speed(int(0), 2) + en_mot.set_speed(int(0), 3) + en_mot.set_speed(int(0), 4) + state.lost_target_count = 0 + state.last_color_circle = None + return org_image + + +def image_callback(ros_image): + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = ball_tracking(image) + toc = time.time() + curr_fps = 1.0 / (state.tic - toc) + state.fps = curr_fps if state.fps == 0.0 else (state.fps * 0.95 + curr_fps * 0.05) + state.tic = toc + frame_result = cv2.cvtColor(frame_result, cv2.COLOR_RGB2BGR) + cv2.imshow(ROS_NODE_NAME, frame_result) + cv2.waitKey(1) + + +def set_target(color_name): + color_ranges = rospy.get_param('/lab_config_manager/color_range_list', {}) + rospy.logdebug(color_ranges) + with state.lock: + if color_name in color_ranges: + state.target_color_name = color_name + state.target_color_range = color_ranges[color_name] + else: + state.target_color_name = None + state.target_color_range = None + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + state = BallTracking() + jetmax = hiwonder.JetMax() + jetmax.set_position((jetmax.ORIGIN[0], -100, 0), 1.5) + rospy.sleep(1.5) + image_queue = queue.Queue(maxsize=3) + set_target('tennis') + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) # 订阅摄像头画面 + try: + rospy.spin() + except: + sys.exit(0) diff --git a/src/jetmax_demos/scripts/mediapipe b/src/jetmax_demos/scripts/mediapipe new file mode 120000 index 0000000..9d5750b --- /dev/null +++ b/src/jetmax_demos/scripts/mediapipe @@ -0,0 +1 @@ +/usr/local/lib/python3.6/dist-packages/mediapipe \ No newline at end of file diff --git a/src/jetmax_demos/scripts/models b/src/jetmax_demos/scripts/models new file mode 120000 index 0000000..ec57a6d --- /dev/null +++ b/src/jetmax_demos/scripts/models @@ -0,0 +1 @@ +/home/hiwonder/models \ No newline at end of file diff --git a/src/jetmax_demos/scripts/mouse_control.py b/src/jetmax_demos/scripts/mouse_control.py new file mode 100755 index 0000000..402903a --- /dev/null +++ b/src/jetmax_demos/scripts/mouse_control.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 + +import sys +import math +import re +import sys +import math +from PyQt5.QtWidgets import (QApplication, QWidget) +from PyQt5.QtGui import (QPainter, QPen) +from PyQt5.QtCore import Qt +import time +import hiwonder + +jetmax = hiwonder.JetMax() +sucker = hiwonder.Sucker() + +class Example(QWidget): + def __init__(self): + super(Example, self).__init__() + + #resize设置宽高,move设置位置 + self.resize(1200, 900) + self.move(100, 100) + self.setWindowTitle("简单的画板4.0") + + #setMouseTracking设置为False,否则不按下鼠标时也会跟踪鼠标事件 + self.setMouseTracking(False) + self.enable = False + + def mouseMoveEvent(self, event): + ''' + 按住鼠标移动事件:将当前点添加到pos_xy列表中 + 调用update()函数在这里相当于调用paintEvent()函数 + 每次update()时,之前调用的paintEvent()留下的痕迹都会清空 + ''' + #中间变量pos_tmp提取当前点 + x, y = (event.pos().x(), event.pos().y()) + if self.enable: + new_x = hiwonder.misc.val_map(x, 0, 1200, -120, 120) + new_y = hiwonder.misc.val_map(y, 0, 900, -200, -40) + old_x, old_y, old_z = list(jetmax.position) + t = math.sqrt((new_x - old_x) ** 2 + (new_y - old_y) ** 2) / 150 + print(t) + jetmax.set_position((new_x, new_y, old_z), t) + time.sleep(t) + + def mousePressEvent(self, event): + if(event.button() == Qt.RightButton): + sucker.set_state(True) + if(event.button() == Qt.LeftButton): + self.enable = True + + + def mouseReleaseEvent(self, event): + if(event.button() == Qt.RightButton): + sucker.release(2) + if(event.button() == Qt.LeftButton): + self.enable = False + + def wheelEvent(self, event): + pos = list(jetmax.position) + delta = event.angleDelta().y() + if delta < 0: + pos[2] = pos[2] - 1 + else: + pos[2] = pos[2] + 1 + jetmax.set_position(pos, 0.05) + + +if __name__ == "__main__": + jetmax.go_home(1) + time.sleep(1) + app = QApplication(sys.argv) + pyqt_learn = Example() + pyqt_learn.show() + app.exec_() diff --git a/src/jetmax_demos/scripts/obj_classification.py b/src/jetmax_demos/scripts/obj_classification.py new file mode 100755 index 0000000..77f8eaa --- /dev/null +++ b/src/jetmax_demos/scripts/obj_classification.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python3 +import os +import sys +import cv2 +import math +import rospy +import time +import numpy as np +from sensor_msgs.msg import Image +import queue +import hiwonder +from yolov5_tensorrt import Yolov5TensorRT +import random +import threading + +ROS_NODE_NAME = "virtual_calculator" +DEFAULT_X, DEFAULT_Y, DEFAULT_Z = 0 + 10, 138 + 8.14, 84 + 128.4 - 5 +TRT_ENGINE_PATH = os.path.join(sys.path[0], "models/obj_classifcation.trt") +TRT_INPUT_SIZE = 160 +TRT_CLASS_NAMES = ('banana', 'potato', 'apple', 'lettuce', 'lemon') +TRT_NUM_CLASSES = 5 +COLORS = [(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) for i in range(TRT_NUM_CLASSES)] + +# 将所有分类又再分为水果和蔬菜 +vg = ["potato", "lettuce"] # 蔬菜 +fu = ["banana", "apple", "lemon"] # 水果 + +class Classification: + def __init__(self): + self.position = DEFAULT_X, DEFAULT_Y, DEFAULT_X + self.lock = threading.RLock() + self.fps = 0.0 + self.last_class = 3 + self.args = [0] * 10 + self.count = 0 + self.tic = time.time() + self.runner = None + + +state = Classification() + +def move_1(name): + """ + 水果搬运过程 + :param name: 水果的名字 + :return: + """ + # 不同的水果, 有不同的大小, 根据大小有不同的爪子开合程度 + if name == "banana": + jetmax.set_position((10, -200, 50), 1) + rospy.sleep(1.2) + hiwonder.pwm_servo2.set_position(75, 0.1) + rospy.sleep(1) + elif name == "lemon": + jetmax.set_position((10, -200, 50), 1) + rospy.sleep(1.2) + hiwonder.pwm_servo2.set_position(70, 0.1) + rospy.sleep(1) + elif name == "apple": + jetmax.set_position((10, -200, 50), 1) + rospy.sleep(1.2) + hiwonder.pwm_servo2.set_position(70, 0.1) + rospy.sleep(1) + + # 前往目标位置 + jetmax.set_position((10, -220, 180), 1) + rospy.sleep(1.2) + jetmax.set_position((180, -40, 180), 2) + rospy.sleep(2.1) + # 松开爪子 + hiwonder.pwm_servo2.set_position(0, 0.1) + rospy.sleep(1) + # 回初位 + jetmax.go_home(2) + rospy.sleep(2.2) + + +def move_2(name): + """ + 蔬菜搬运 + :param name: 蔬菜的名字 + :return: + """ + # 不同的蔬菜, 有不同的大小, 根据大小有不同的爪子开合程度 + if name == "lettuce": + jetmax.set_position((10, -200, 50), 1) + rospy.sleep(1.2) + hiwonder.pwm_servo2.set_position(60, 0.1) + rospy.sleep(1) + elif name == "potato": + jetmax.set_position((10, -200, 50), 1) + rospy.sleep(1.2) + hiwonder.pwm_servo2.set_position(70, 0.1) + rospy.sleep(1) + + # 前往目标位置 + jetmax.set_position((10, -220, 180), 1) + rospy.sleep(1) + jetmax.set_position((-180, -20, 220), 2) + rospy.sleep(2.1) + # 松开爪子 + hiwonder.pwm_servo2.set_position(0, 0.1) + rospy.sleep(1) + # 回初位 + jetmax.go_home(2) + rospy.sleep(2.2) + +def image_proc_a(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + outputs = yolov5.detect(image) + boxes, confs, classes = yolov5.post_process(image, outputs, 0.6) + width = image.shape[1] + height = image.shape[0] + for box, cls_conf, cls_id in zip(boxes, confs, classes): + x1 = int(box[0] / TRT_INPUT_SIZE * width) + y1 = int(box[1] / TRT_INPUT_SIZE * height) + x2 = int(box[2] / TRT_INPUT_SIZE * width) + y2 = int(box[3] / TRT_INPUT_SIZE * height) + card_name = str(TRT_CLASS_NAMES[cls_id]) + cv2.putText(image, card_name + " " + str(float(cls_conf))[:4], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, + 0.7, COLORS[cls_id], 2) + cv2.rectangle(image, (x1, y1), (x2, y2), COLORS[cls_id], 2) + #print(x1, y1, x2, y2, card_name) + # 这次识别的结果与上次结果相同则增加计数 + if state.last_class == cls_id: + state.count += 1 + else: + state.last_class = cls_id + state.count = 0 + # 计数到一定值认为识别结果可靠 + if state.count > 10 and (state.runner is None or not state.runner.isAlive()): + # 根据识别的结果判断是否在水果的分类内, 如果在就启动搬运动作,搬运到水果篮中 + if TRT_CLASS_NAMES[cls_id] in fu: + state.count = 0 + state.runner = threading.Thread(target=move_1, args=(TRT_CLASS_NAMES[state.last_class],), daemon=True) + state.runner.start() + # 如果结果在蔬菜分类内就搬运到蔬菜篮中 + elif TRT_CLASS_NAMES[cls_id] in vg: + state.count = 0 + state.runner = threading.Thread(target=move_2, args=(TRT_CLASS_NAMES[state.last_class],), daemon=True) + state.runner.start() + else: + pass + image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) + cv2.imshow(ROS_NODE_NAME, image) + cv2.waitKey(1) + + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + yolov5 = Yolov5TensorRT(TRT_ENGINE_PATH, TRT_INPUT_SIZE, TRT_NUM_CLASSES) + jetmax = hiwonder.JetMax() + hiwonder.pwm_servo2.set_position(0, 0.1) + rospy.sleep(0.3) + hiwonder.pwm_servo1.set_position(90, 1) + jetmax.go_home(2) + rospy.sleep(2) + image_queue = queue.Queue(maxsize=1) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback, queue_size=1) # Subscribe to the camera + while not rospy.is_shutdown(): + image_proc_a() + diff --git a/src/jetmax_demos/scripts/restart_app_funcs.sh b/src/jetmax_demos/scripts/restart_app_funcs.sh new file mode 100755 index 0000000..38f6dbf --- /dev/null +++ b/src/jetmax_demos/scripts/restart_app_funcs.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +sudo kill -9 $(ps -elf|grep -v grep|grep python3|grep alphabetically|awk '{print $4}') >/dev/null 2>&1 +sudo systemctl restart alphabetically.service + +sudo kill -9 $(ps -elf|grep -v grep|grep python3|grep waste_classification|awk '{print $4}') >/dev/null 2>&1 +sudo systemctl restart waste_classification.service + +sudo kill -9 $(ps -elf|grep -v grep|grep python3|grep object_tracking|awk '{print $4}') >/dev/null 2>&1 +sudo systemctl restart object_tracking.service + +sudo kill -9 $(ps -elf|grep -v grep|grep python3|grep color_sorting|awk '{print $4}') >/dev/null 2>&1 +sudo systemctl restart color_sorting.service + + diff --git a/src/jetmax_demos/scripts/screw_nut.py b/src/jetmax_demos/scripts/screw_nut.py new file mode 100755 index 0000000..25e74af --- /dev/null +++ b/src/jetmax_demos/scripts/screw_nut.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python3 +import os +import sys +import cv2 +import math +import rospy +import numpy as np +import threading +import queue +import hiwonder +from sensor_msgs.msg import Image +from yolov5_tensorrt import Yolov5TensorRT + +ROS_NODE_NAME = "screw_nut_classification" + +TRT_ENGINE_PATH = os.path.join(sys.path[0], "models/screw_nut_v5_160.trt") +TRT_INPUT_SIZE = 160 +TRT_NUM_CLASSES = 2 +TRT_CLASS_NAMES = ("Screw", "Nut") +COLORS = {'Screw': (0, 0, 255), "Nut": (0, 255, 0)} +TARGET_POSITION = {"Screw": (120, -0, 140), "Nut": (-120, -0, 140)} + + +def camera_to_world(cam_mtx, r, t, img_points): + inv_k = np.asmatrix(cam_mtx).I + r_mat = np.zeros((3, 3), dtype=np.float64) + cv2.Rodrigues(r, r_mat) + # invR * T + inv_r = np.asmatrix(r_mat).I # 3*3 + transPlaneToCam = np.dot(inv_r, np.asmatrix(t)) # 3*3 dot 3*1 = 3*1 + world_pt = [] + coords = np.zeros((3, 1), dtype=np.float64) + for img_pt in img_points: + coords[0][0] = img_pt[0][0] + coords[1][0] = img_pt[0][1] + coords[2][0] = 1.0 + worldPtCam = np.dot(inv_k, coords) # 3*3 dot 3*1 = 3*1 + # [x,y,1] * invR + worldPtPlane = np.dot(inv_r, worldPtCam) # 3*3 dot 3*1 = 3*1 + # zc + scale = transPlaneToCam[2][0] / worldPtPlane[2][0] + # zc * [x,y,1] * invR + scale_worldPtPlane = np.multiply(scale, worldPtPlane) + # [X,Y,Z]=zc*[x,y,1]*invR - invR*T + worldPtPlaneReproject = np.asmatrix(scale_worldPtPlane) - np.asmatrix(transPlaneToCam) # 3*1 dot 1*3 = 3*3 + pt = np.zeros((3, 1), dtype=np.float64) + pt[0][0] = worldPtPlaneReproject[0][0] + pt[1][0] = worldPtPlaneReproject[1][0] + pt[2][0] = 0 + world_pt.append(pt.T.tolist()) + return world_pt + + +class ScrewNutClassification: + def __init__(self): + self.lock = threading.RLock() + self.moving_obj = None + self.runner = None + self.count = 0 + self.camera_params = None + self.K = None + self.R = None + self.T = None + + def reset(self): + self.moving_obj = None + self.runner = None + self.count = 0 + + def load_camera_params(self): + self.camera_params = rospy.get_param('/camera_cal/card_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + + +def moving(): + try: + c_x, c_y, cls_name = state.moving_obj + cur_x, cur_y, cur_z = jetmax.position + + x, y, _ = camera_to_world(state.K, state.R, state.T, np.array([c_x, c_y]).reshape((1, 1, 2)))[0][0] + print("dist", x, y) + + t = math.sqrt(x * x + y * y + 140 * 140) / 140 + + new_x, new_y = cur_x + x - 15, cur_y + y + jetmax.set_position((new_x, new_y, 100), t) + rospy.sleep(t + 0.2) + + sucker.set_state(True) + jetmax.set_position((new_x, new_y, 65), 0.8) + rospy.sleep(0.85) + + x, y, z = TARGET_POSITION[cls_name] + cur_x, cur_y, cur_z = jetmax.position + jetmax.set_position((cur_x, cur_y, 140), 0.8) + rospy.sleep(0.8) + + cur_x, cur_y, cur_z = jetmax.position + t = math.sqrt((cur_x - x) ** 2 + (cur_y - y) ** 2) / 160 + jetmax.set_position((x, y, 160), t) + rospy.sleep(t) + + jetmax.set_position((x, y, z), 0.8) + rospy.sleep(0.8) + + #sucker.release(3) + hiwonder.motor1.set_speed(-40) + rospy.sleep(0.2) + hiwonder.motor1.set_speed(0) + + jetmax.set_position((x, y, z + 50), 0.8) + rospy.sleep(0.9) + + finally: + cur_x, cur_y, cur_z = jetmax.position + t = math.sqrt((cur_x - jetmax.ORIGIN[0]) ** 2 + (cur_y - jetmax.ORIGIN[1]) ** 2) / 140 + jetmax.go_home(t) + rospy.sleep(t + 0.2) + state.moving_obj = None + state.runner = None + print("FINISHED") + + +def image_proc_a(): + ros_image = image_queue.get(block=True) + img = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + img_ret = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) + if state.runner is not None: + return img_ret + outputs = yolov5.detect(img) + boxes, confs, classes = yolov5.post_process(img, outputs, 0.85) + height, width = img.shape[:2] + objs = [] + for box, cls_conf, cls_id in zip(boxes, confs, classes): + x1 = int(box[0] / TRT_INPUT_SIZE * width) + y1 = int(box[1] / TRT_INPUT_SIZE * height) + x2 = int(box[2] / TRT_INPUT_SIZE * width) + y2 = int(box[3] / TRT_INPUT_SIZE * height) + cls_name = TRT_CLASS_NAMES[cls_id] + if cls_conf < 0.85: + continue + objs.append((cls_conf, x1, y1, x2, y2, cls_name)) + cv2.putText(img_ret, cls_name + " " + str(float(cls_conf))[:4], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, + COLORS[cls_name], 2) + cv2.rectangle(img_ret, (x1, y1), (x2, y2), COLORS[cls_name], 3) + + if len(objs) == 0: + state.count = 0 + state.moving_obj = None + else: + if state.moving_obj is None: + moving_box = max(objs, key=lambda obj: obj[0]) + conf, x1, y1, x2, y2, cls_name = moving_box + c_x, c_y = (x1 + x2) / 2, (y1 + y2) / 2 + state.moving_obj = c_x, c_y, cls_name + else: + l_c_x, l_c_y, l_waste_class_name = state.moving_obj + moving_obj = min(objs, key=lambda card: math.sqrt((l_c_x - card[1]) ** 2 + (l_c_y - card[2]) ** 2)) + + conf, x1, y1, x2, y2, cls_name = moving_obj + c_x, c_y = (x1 + x2) / 2, (y1 + y2) / 2 + + cv2.rectangle(img_ret, (x1, y1), (x2, y2), (255, 255, 255), 6) + cv2.circle(img_ret, (int(c_x), int(c_y)), 1, (255, 255, 255), 10) + + if math.sqrt((l_c_x - c_x) ** 2 + (l_c_y - c_y) ** 2) > 30: + state.count = 0 + else: + c_x = l_c_x * 0.2 + c_x * 0.8 + c_y = l_c_y * 0.2 + c_y * 0.8 + state.count += 1 + state.moving_obj = c_x, c_y, cls_name + if state.count > 10: + state.count = 0 + state.runner = threading.Thread(target=moving, daemon=True) + state.runner.start() + return img_ret + +def image_proc(): + a = image_proc_a() + cv2.imshow('img', a) + cv2.waitKey(1) + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + image_queue = queue.Queue(maxsize=2) + state = ScrewNutClassification() + state.load_camera_params() + if state.camera_params is None: + rospy.logerr("Can not load camera parameters") + sys.exit(-1) + jetmax = hiwonder.JetMax() + sucker = hiwonder.Sucker() + jetmax.go_home() + sucker.release() + yolov5 = Yolov5TensorRT(TRT_ENGINE_PATH, TRT_INPUT_SIZE, TRT_NUM_CLASSES) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) + while True: + try: + image_proc() + if rospy.is_shutdown(): + sys.exit(0) + except Exception as e: + print(e) + break diff --git a/src/jetmax_demos/scripts/shape_detection.py b/src/jetmax_demos/scripts/shape_detection.py new file mode 100755 index 0000000..18dbbcb --- /dev/null +++ b/src/jetmax_demos/scripts/shape_detection.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import time +import rospy +import numpy as np +import threading +from sensor_msgs.msg import Image +from std_msgs.msg import Bool +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from std_srvs.srv import Empty +from jetmax_control.msg import SetServo +import hiwonder +import apriltag +import yaml + +ROS_NODE_NAME = "shape_detector" +IMAGE_PROC_SIZE = 640, 480 +TAG_SIZE = 33.30 +TARGET_POSITIONS = (((238, -70, 95), -18), ((238, -70, 135), -18), ((238, -70, 185), -18)) + + +def camera_to_world(cam_mtx, r, t, img_points): + inv_k = np.asmatrix(cam_mtx).I + r_mat = np.zeros((3, 3), dtype=np.float64) + cv2.Rodrigues(r, r_mat) + # invR * T + inv_r = np.asmatrix(r_mat).I # 3*3 + transPlaneToCam = np.dot(inv_r, np.asmatrix(t)) # 3*3 dot 3*1 = 3*1 + world_pt = [] + coords = np.zeros((3, 1), dtype=np.float64) + for img_pt in img_points: + coords[0][0] = img_pt[0][0] + coords[1][0] = img_pt[0][1] + coords[2][0] = 1.0 + worldPtCam = np.dot(inv_k, coords) # 3*3 dot 3*1 = 3*1 + # [x,y,1] * invR + worldPtPlane = np.dot(inv_r, worldPtCam) # 3*3 dot 3*1 = 3*1 + # zc + scale = transPlaneToCam[2][0] / worldPtPlane[2][0] + # zc * [x,y,1] * invR + scale_worldPtPlane = np.multiply(scale, worldPtPlane) + # [X,Y,Z]=zc*[x,y,1]*invR - invR*T + worldPtPlaneReproject = np.asmatrix(scale_worldPtPlane) - np.asmatrix(transPlaneToCam) # 3*1 dot 1*3 = 3*3 + pt = np.zeros((3, 1), dtype=np.float64) + pt[0][0] = worldPtPlaneReproject[0][0] + pt[1][0] = worldPtPlaneReproject[1][0] + pt[2][0] = 0 + world_pt.append(pt.T.tolist()) + return world_pt + + +class ShapDetect: + def __init__(self): + self.is_running = False + self.moving_block = None + self.image_sub = None + self.runner = None + self.count = 0 + self.level = 0 + self.lock = threading.RLock() + self.camera_params = None + self.K = None + self.R = None + self.T = None + + def reset(self): + self.is_running = False + self.moving_block = None + self.image_sub = None + self.runner = None + self.count = 0 + self.level = 0 + + def load_camera_params(self): + self.camera_params = rospy.get_param('/camera_cal/block_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + + +def rotation_mtx_to_euler(R): + sy = math.sqrt(R[0, 0] * R[0, 0] + R[1, 0] * R[1, 0]) + singular = sy < 1e-6 + if not singular: + x = math.atan2(R[2, 1], R[2, 2]) + y = math.atan2(-R[2, 0], sy) + z = math.atan2(R[1, 0], R[0, 0]) + else: + x = math.atan2(-R[1, 2], R[1, 1]) + y = math.atan2(-R[2, 0], sy) + z = 0 + return np.array([x, y, z]) + + +def image_proc(img): + frame_gray = cv2.cvtColor(np.copy(img), cv2.COLOR_RGB2GRAY) # 将画面转为灰度图 + _, thresh = cv2.threshold(frame_gray, 127, 255, cv2.THRESH_BINARY) # 二值化 + # 平滑 + eroded = cv2.erode(thresh, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) + dilated = cv2.dilate(eroded, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) + # 获取轮廓 + contours = cv2.findContours(dilated, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[-2] + # 去除小面积轮廓 + contours = list(filter(lambda c: math.fabs(cv2.contourArea(c)) > 500, contours)) + + # 遍历所有轮廓 + for contour in contours: + approx = cv2.approxPolyDP(contour, 0.02 * cv2.arcLength(contour, True), True) # 对轮廓曲线进行多边形拟合 + cv2.drawContours(img, [approx], 0, (0, 0, 255), 2) # 画出轮廓 + x = approx.ravel()[0] + y = approx.ravel()[1] - 5 + # 根据输出的点数判断形状 + if len(approx) == 3: + cv2.putText(img, "Triangle", (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 2) # 三角形 + elif len(approx) == 4: + x, y, w, h = cv2.boundingRect(approx) + aspect_ratio = float(w) / h + print(aspect_ratio) + # 计算长宽比来1确定时正方形还是长方形 + if 0.90 <= aspect_ratio < 1.1: + cv2.putText(img, "square", (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 2) # 正方形 + else: + cv2.putText(img, "rectangle", (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 2) # 长方形 + elif len(approx) == 5: + cv2.putText(img, "pentagon", (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 2) # #五边形 + elif len(approx) == 10: + cv2.putText(img, "star", (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 2) # 五角星 + else: + cv2.putText(img, "circle", (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 2) # 圆形 + + img_h, img_w = img.shape[:2] + cv2.line(img, (int(img_w / 2 - 10), int(img_h / 2)), (int(img_w / 2 + 10), int(img_h / 2)), (0, 255, 255), 2) + cv2.line(img, (int(img_w / 2), int(img_h / 2 - 10)), (int(img_w / 2), int(img_h / 2 + 10)), (0, 255, 255), 2) + return img + + +def image_callback(ros_image): + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = image.copy() + frame_result = image_proc(frame_result) + bgr_image = cv2.cvtColor(frame_result, cv2.COLOR_RGB2BGR) + cv2.imshow('result', bgr_image) + cv2.waitKey(1) + + +if __name__ == '__main__': + state = ShapDetect() + jetmax = hiwonder.JetMax() + sucker = hiwonder.Sucker() + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + jetmax.go_home() + state.load_camera_params() + if state.camera_params is None: + rospy.logerr('Can not load camera parameters') + sys.exit(-1) + rospy.ServiceProxy('/jetmax/go_home', Empty)() + rospy.Publisher('/jetmax/end_effector/sucker/command', Bool, queue_size=1).publish(data=False) + rospy.Publisher('/jetmax/end_effector/servo1/command', SetServo, queue_size=1).publish(data=90, duration=0.5) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) + try: + rospy.spin() + except KeyboardInterrupt: + sys.exit(0) diff --git a/src/jetmax_demos/scripts/simple_draw.py b/src/jetmax_demos/scripts/simple_draw.py new file mode 100644 index 0000000..8db16a2 --- /dev/null +++ b/src/jetmax_demos/scripts/simple_draw.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 + +import sys +import re +import math +import time +import hiwonder +import line_interpolation + +DEFAULT_X, DEFAULT_Y, DEFAULT_Z = 0, 0, 100 +OFFSET_X, OFFSET_Y, OFFSET_Z = 0, -120, 7 +jetmax = hiwonder.JetMax() +jetmax.L4 = 28 + +speed = 80 +current_pos = [DEFAULT_X, DEFAULT_Y, DEFAULT_Z] + +def move_to_pos(x, y, z, t): + end_x = -x + OFFSET_X + end_x = end_x + end_y = -y + OFFSET_Y + end_z = z + OFFSET_Z + jetmax.set_position((end_x, end_y, end_z), t) + + +fake_points = [] + + +def draw(points): + global speed, current_pos + for i, (x, y, z) in enumerate(points): + c_x, c_y, c_z = current_pos + t = math.sqrt((c_x - x) ** 2 + (c_y - y) ** 2 + (c_z - z) ** 2) / speed + t = t * 2 + move_to_pos(x, y, z, t) + fake_points.append((x, y)) + time.sleep(t + 0.001) + current_pos = [x, y, z] + + +def get_param(cmd, param_name): + try: + i = cmd.index(param_name) + return float(cmd[i + 1]) + except Exception as e: + # print(e) + return None + + +def draw_ngc(path, speed_l=80): + global speed, current_pos + speed = speed_l + move_to_pos(DEFAULT_X, DEFAULT_Y, DEFAULT_Z, 1) + time.sleep(1) + gcodes = [] + with open(path, 'r') as f: + gcodes = f.readlines() + space = re.compile(' +') + for gcode in gcodes: + if gcode == '': + continue + gcode = space.sub(' ', gcode) + gcode = gcode.strip().split(' ') + instruct = gcode[0] + if len(instruct) < 2: + continue + if instruct[0] == 'G': + code = int(instruct[1:]) + if code == 0: + c_x, c_y, c_z = current_pos + x = get_param(gcode, 'X') + y = get_param(gcode, 'Y') + z = get_param(gcode, 'Z') + x = c_x if x is None else x + y = c_y if y is None else y + z = c_z if z is None else z + t = math.sqrt((c_x - x) ** 2 + (c_y - y) ** 2 + (c_z - z) ** 2) / speed + move_to_pos(x, y, z, t) + current_pos = [x, y, z] + time.sleep(t) + elif code == 1: + c_x, c_y, c_z = current_pos + x = get_param(gcode, 'X') + y = get_param(gcode, 'Y') + z = get_param(gcode, 'Z') + x = c_x if x is None else x + y = c_y if y is None else y + z = c_z if z is None else z + if z != c_z: + t = math.sqrt((c_x - x) ** 2 + (c_y - y) ** 2 + (c_z - z) ** 2) / speed + move_to_pos(x, y, z, t) + current_pos = [x, y, z] + time.sleep(t) + else: + points = line_interpolation(c_x, c_y, x, y) + tmp = [] + for p in points: + p.append(c_z) + tmp.append(p) + draw(tmp) + + else: + pass + # print("INVALID G CODE") + elif instruct[0] == 'M': + code = int(instruct[1:]) + if code == 0: + pass + elif code == 1: + pass + elif code == 2: + pass + else: + pass + elif instruct[0] == 'F': + speed = int(instruct[1:]) diff --git a/src/jetmax_demos/scripts/smart_store.py b/src/jetmax_demos/scripts/smart_store.py new file mode 100755 index 0000000..2759c6e --- /dev/null +++ b/src/jetmax_demos/scripts/smart_store.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 +import sys +import cv2 +import math +import time +import rospy +import numpy as np +import threading +from sensor_msgs.msg import Image +from std_msgs.msg import Bool +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from std_srvs.srv import Empty +from jetmax_control.msg import SetServo +import hiwonder +import queue +import pupil_apriltags as apriltag +import yaml + + +""" +智慧仓储 +""" + +ROS_NODE_NAME = "smart_store" +TAG_SIZE = 33.30 + + +class AprilTagDetect: + def __init__(self): + self.camera_params = None + self.runner = None + self.K = None + self.R = None + self.T = None + + + def load_camera_params(self): + self.camera_params = rospy.get_param('/camera_cal/block_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + + +def moving(tag_id, distance): + for i in range(tag_id): + hiwonder.buzzer.on() + rospy.sleep(0.1) + hiwonder.buzzer.off() + rospy.sleep(0.1) + rospy.sleep(0.8) + hiwonder.pwm_servo1.set_position(100, 0.5) + rospy.sleep(2) + jetmax.set_position((120, 0, 180), 1.5) + rospy.sleep(1.6) + if tag_id == 1: + jetmax.set_position((120, 0, 150), 0.7) + rospy.sleep(0.7) + elif tag_id == 2: + jetmax.set_position((120, 0, 50), 1.2) + rospy.sleep(1.2) + else: + pass + cur = list(jetmax.position) + cur[0] += 70 + jetmax.set_position(cur, 1) + rospy.sleep(1) + hiwonder.pwm_servo1.set_position(130, 0.5) + rospy.sleep(1) + cur = list(jetmax.position) + cur[0] -= 70 + jetmax.set_position(cur, 1) + rospy.sleep(1) + jetmax.go_home(2) + rospy.sleep(2) + state.runner = None + + +def image_proc_a(img): + if state.runner is not None: + return img + frame_gray = cv2.cvtColor(np.copy(img), cv2.COLOR_RGB2GRAY) # 将画面转为灰度图 + params = [state.K[0][0], state.K[1][1], state.K[0][2], state.K[1][2]] # 相机内参 + tags = at_detector.detect(frame_gray, estimate_tag_pose=True, camera_params=params, tag_size=TAG_SIZE) # 进行AprilTag的检测 + if not tags: + hiwonder.buzzer.off() + for tag in tags: + corners = tag.corners.reshape(1, -1, 2).astype(int) # 检测到的AprilTag的四个角的点 + center = tag.center.astype(int) # AprilTag中心点 + + cv2.drawContours(img, corners, -1, (255, 0, 0), 3) # 画出外框 + cv2.circle(img, tuple(center), 5, (255, 255, 0), 10) # 画出中心点 + + point_3d = np.array([[16.65, -16.65, 0], + [-16.65,-16.65, 0], + [-16.65, 16.65, 0], + [16.65, 16.65, 0]], dtype=np.double) + point_2d = np.array([tag.corners[0].astype(int), + tag.corners[1].astype(int), + tag.corners[2].astype(int), + tag.corners[3].astype(int)], + dtype=np.double) + + dist_coefs = np.array([0,0,0,0], dtype=np.double) + found, rvec, tvec = cv2.solvePnP(point_3d, point_2d, state.K, None) + rotM = cv2.Rodrigues(rvec)[0] + camera_position = -np.matrix(rotM).T * np.matrix(tvec) + distance = -camera_position.T.tolist()[0][2] + print("TAG_ID:{}, Distance: {:0.2f}mm".format(tag.tag_id, distance)) + if distance < 100 and tag.tag_id < 3: + state.runner = threading.Thread(target=moving, args=(tag.tag_id, distance), daemon=True) + state.runner.start() + break + + + img_h, img_w = img.shape[:2] + cv2.line(img, (int(img_w / 2 - 10), int(img_h / 2)), (int(img_w / 2 + 10), int(img_h / 2)), (0, 255, 255), 2) + cv2.line(img, (int(img_w / 2), int(img_h / 2 - 10)), (int(img_w / 2), int(img_h / 2 + 10)), (0, 255, 255), 2) + return img + + +def image_proc_b(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = image.copy() + frame_result = image_proc_a(frame_result) + bgr_image = cv2.cvtColor(frame_result, cv2.COLOR_RGB2BGR) + cv2.imshow('result', bgr_image) + cv2.waitKey(1) + + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +if __name__ == '__main__': + state = AprilTagDetect() + jetmax = hiwonder.JetMax() + sucker = hiwonder.Sucker() + at_detector = apriltag.Detector() + image_queue = queue.Queue(maxsize=1) + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + jetmax.go_home() + hiwonder.pwm_servo1.set_position(130, 0.5) + rospy.sleep(1) + state.load_camera_params() + if state.camera_params is None: + rospy.logerr('Can not load camera parameters') + sys.exit(-1) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) + while not rospy.is_shutdown(): + image_proc_b() diff --git a/src/jetmax_demos/scripts/tm1640.py b/src/jetmax_demos/scripts/tm1640.py new file mode 100644 index 0000000..3445f22 --- /dev/null +++ b/src/jetmax_demos/scripts/tm1640.py @@ -0,0 +1,123 @@ +import Jetson.GPIO as GPIO +import time +TM1640_CMD1 = (64) # 0x40 data command +TM1640_CMD2 = (192) # 0xC0 address command +TM1640_CMD3 = (128) # 0x80 display control command +TM1640_DSP_ON = (8) # 0x08 display on +TM1640_DELAY = (10) # 10us delay between clk/dio pulses + +def sleep_us(t): + time.sleep(t / 1000000) + +class TM1640(object): + """Library for LED matrix display modules based on the TM1640 LED driver.""" + def __init__(self, clk, dio, brightness=7): + self.clk_p = clk + self.dio_p = dio + + if not 0 <= brightness <= 7: + raise ValueError("Brightness out of range") + self._brightness = brightness + GPIO.setmode(GPIO.BCM) + GPIO.setup(clk, GPIO.OUT) + GPIO.output(clk, 0) + GPIO.setup(dio, GPIO.OUT) + GPIO.output(dio, 0) + sleep_us(TM1640_DELAY) + + self._write_data_cmd() + self._write_dsp_ctrl() + + def dio(self, n_s): + GPIO.output(self.dio_p, n_s) + + def clk(self, n_s): + GPIO.output(self.clk_p, n_s) + + def _start(self): + self.dio(0) + sleep_us(TM1640_DELAY) + self.clk(0) + sleep_us(TM1640_DELAY) + + def _stop(self): + self.dio(0) + sleep_us(TM1640_DELAY) + self.clk(1) + sleep_us(TM1640_DELAY) + self.dio(1) + + def _write_data_cmd(self): + # automatic address increment, normal mode + self._start() + self._write_byte(TM1640_CMD1) + self._stop() + + def _write_dsp_ctrl(self): + # display on, set brightness + self._start() + self._write_byte(TM1640_CMD3 | TM1640_DSP_ON | self._brightness) + self._stop() + + def _write_byte(self, b): + for i in range(8): + self.dio((b >> i) & 1) + sleep_us(TM1640_DELAY) + self.clk(1) + sleep_us(TM1640_DELAY) + self.clk(0) + sleep_us(TM1640_DELAY) + + def brightness(self, val=None): + """Set the display brightness 0-7.""" + # brightness 0 = 1/16th pulse width + # brightness 7 = 14/16th pulse width + if val is None: + return self._brightness + if not 0 <= val <= 7: + raise ValueError("Brightness out of range") + + self._brightness = val + self._write_data_cmd() + self._write_dsp_ctrl() + + def write(self, rows, pos=0): + if not 0 <= pos <= 7: + raise ValueError("Position out of range") + + self._write_data_cmd() + self._start() + + self._write_byte(TM1640_CMD2 | pos) + for row in rows: + self._write_byte(row) + + self._stop() + self._write_dsp_ctrl() + + def write_int(self, int, pos=0, len=8): + self.write(int.to_bytes(len, 'big'), pos) + + def write_hmsb(self, buf, pos=0): + self._write_data_cmd() + self._start() + + self._write_byte(TM1640_CMD2 | pos) + for i in range(7-pos, -1, -1): + self._write_byte(buf[i]) + + self._stop() + self._write_dsp_ctrl() + + +display = TM1640(dio=9, clk=4) +display_buf = [0] * 16 + +def set_bit(x, y, s): + display_buf[x] = (display_buf[x] & (~(0x01 << y))) | (s << y) + +def update_display(): + display.write(display_buf) + +update_display() + diff --git a/src/jetmax_demos/scripts/visual_calculator.py b/src/jetmax_demos/scripts/visual_calculator.py new file mode 100755 index 0000000..307469c --- /dev/null +++ b/src/jetmax_demos/scripts/visual_calculator.py @@ -0,0 +1,265 @@ +#!/usr/bin/env python3 +import os +import sys +import cv2 +import math +import rospy +import numpy as np +from sensor_msgs.msg import Image +import queue +import hiwonder +from yolov5_tensorrt import Yolov5TensorRT +import random +import threading + +ROS_NODE_NAME = "virtual_calculator" +TRT_ENGINE_PATH = os.path.join(sys.path[0], "models/numbers_v5_160.trt") +TRT_INPUT_SIZE = 160 +TRT_CLASS_NAMES = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', '*', '/', '=') +TRT_NUM_CLASSES = 15 +COLORS = [(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) for i in range(TRT_NUM_CLASSES)] + + +class VisualCalculator: + def __init__(self): + self.moving_box = None + self.is_moving = False + self.is_running = False + self.runner = None + self.count = 0 + self.lock = threading.RLock() + self.step = 0 + self.eq_box = 0, 0, 0, 0 + self.ans_step = 0 + self.answer = "" + self.line = 0 + self.string = "" + self.camera_params = None + self.K = None + self.R = None + self.T = None + + def load_camera_params(self): + self.camera_params = rospy.get_param('/camera_cal/block_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + + +def camera_to_world(cam_mtx, r, t, img_points): + inv_k = np.asmatrix(cam_mtx).I + r_mat = np.zeros((3, 3), dtype=np.float64) + cv2.Rodrigues(r, r_mat) + # invR * T + inv_r = np.asmatrix(r_mat).I # 3*3 + transPlaneToCam = np.dot(inv_r, np.asmatrix(t)) # 3*3 dot 3*1 = 3*1 + world_pt = [] + coords = np.zeros((3, 1), dtype=np.float64) + for img_pt in img_points: + coords[0][0] = img_pt[0][0] + coords[1][0] = img_pt[0][1] + coords[2][0] = 1.0 + worldPtCam = np.dot(inv_k, coords) # 3*3 dot 3*1 = 3*1 + # [x,y,1] * invR + worldPtPlane = np.dot(inv_r, worldPtCam) # 3*3 dot 3*1 = 3*1 + # zc + scale = transPlaneToCam[2][0] / worldPtPlane[2][0] + # zc * [x,y,1] * invR + scale_worldPtPlane = np.multiply(scale, worldPtPlane) + # [X,Y,Z]=zc*[x,y,1]*invR - invR*T + worldPtPlaneReproject = np.asmatrix(scale_worldPtPlane) - np.asmatrix(transPlaneToCam) # 3*1 dot 1*3 = 3*3 + pt = np.zeros((3, 1), dtype=np.float64) + pt[0][0] = worldPtPlaneReproject[0][0] + pt[1][0] = worldPtPlaneReproject[1][0] + pt[2][0] = 0 + world_pt.append(pt.T.tolist()) + return world_pt + + +def moving(start): + # Calculate the x, y axis distance between the current position of the robotic arm and the target position + _, _, c_x, c_y = start + cur_x, cur_y, cur_z = jetmax.position + + x, y, _ = camera_to_world(state.K, state.R, state.T, np.array([c_x, c_y]).reshape((1, 1, 2)))[0][0] + + # Calculate the Euclidean distance between the current position and the target position to control the movement speed + t = math.sqrt(x * x + y * y + 70 * 70) / 80 + + # The angle of the relative initial position of the robotic arm when picking up the card + new_x, new_y = cur_x + y, cur_y - x + arm_angle = math.atan(new_y / new_x) * 180 / math.pi + print(arm_angle) + + hiwonder.pwm_servo1.set_position(90 + arm_angle, 0.1) + jetmax.set_position((new_x, new_y, 70), t) + rospy.sleep(t + 0.4) + + sucker.set_state(True) + jetmax.set_position((new_x, new_y, 60), 1) # Move jetmax down to pick up the card + rospy.sleep(1) + + jetmax.set_position((new_x, new_y, 120), 1) + rospy.sleep(0.2) + hiwonder.pwm_servo1.set_position(90, 0.8) + rospy.sleep(0.8) + + _, _, c_x, c_y = state.eq_box + print(c_x, c_y) + cur_x, cur_y, cur_z = jetmax.position + + x, y, _ = camera_to_world(state.K, state.R, state.T, np.array([c_x, c_y]).reshape((1, 1, 2)))[0][0] + z = 60 + + t = math.sqrt((cur_x - x) ** 2 + (cur_y - y) ** 2) / 100 + t1 = math.sqrt((cur_x - x) ** 2 + (cur_y - y) ** 2) / 100 + + # Calculate the angle between the robotic arm and the central axis when placing the card + state.ans_step += 1 + new_x, new_y = jetmax.ORIGIN[0] + x - (state.ans_step * 45), jetmax.ORIGIN[1] + y + angle = math.atan(new_x / new_y) * 180 / math.pi + print(angle) + + hiwonder.pwm_servo1.set_position(90 - angle, t) + jetmax.set_position((new_x, new_y, cur_z), t) + rospy.sleep(t + 0.3) + + # Move jetmax down to the target position + jetmax.set_position((new_x, new_y, z), 0.8) + rospy.sleep(0.8) + + sucker.release(3) + jetmax.set_position((new_x, new_y, z + 30), 0.8) + rospy.sleep(0.2) + hiwonder.pwm_servo1.set_position(90, 0.5) + rospy.sleep(0.5) + + # Back to the initial position + if state.ans_step >= len(state.answer): + jetmax.set_position(tuple(jetmax.ORIGIN), t1) + else: + jetmax.set_position((jetmax.ORIGIN[1], jetmax.ORIGIN[0], jetmax.ORIGIN[2]), t1) + rospy.sleep(t1 + 0.2) + state.runner = None + + +def pos_a(): + jetmax.set_position((jetmax.ORIGIN[1], jetmax.ORIGIN[0], jetmax.ORIGIN[2]), 2) + rospy.sleep(2.2) + state.runner = None + + +def pos_b(): + jetmax.set_position((jetmax.ORIGIN[0], jetmax.ORIGIN[1], jetmax.ORIGIN[2]), 2) + rospy.sleep(2.2) + state.runner = None + + +def image_proc(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + outputs = yolov5.detect(image) + boxes, confs, classes = yolov5.post_process(image, outputs, 0.65) + width = image.shape[1] + height = image.shape[0] + cards = [] + for box, cls_conf, cls_id in zip(boxes, confs, classes): + x1 = int(box[0] / TRT_INPUT_SIZE * width) + y1 = int(box[1] / TRT_INPUT_SIZE * height) + x2 = int(box[2] / TRT_INPUT_SIZE * width) + y2 = int(box[3] / TRT_INPUT_SIZE * height) + card_name = str(TRT_CLASS_NAMES[cls_id]) + image = cv2.putText(image, card_name + " " + str(float(cls_conf))[:4], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, + 0.7, COLORS[cls_id], 2) + image = cv2.rectangle(image, (x1, y1), (x2, y2), COLORS[cls_id], 2) + if state.step == 1: + if state.ans_step < len(state.answer) and state.answer[state.ans_step] == TRT_CLASS_NAMES[cls_id]: + cards.append((cls_id, cls_conf, (x1 + x2) / 2, (y1 + y2) / 2)) + else: + cards.append((cls_id, cls_conf, (x1 + x2) / 2, (y1 + y2) / 2)) + + if state.runner is None: + if state.step == 0: + if len(cards) > 0: + cards.sort(key=lambda x: x[2]) + ext = "" + for c in cards: + ext += str(TRT_CLASS_NAMES[c[0]]) + # print(ext) + if ext[-1] == '=': + try: + a = eval(ext[:-1]) + state.count += 1 + if state.count > 30: + rospy.loginfo("answer:" + str(a)) + state.answer = str(int(a)) + state.string = ext + state.answer + state.step = 1 + state.ans_step = 0 + state.count = 0 + i, c, x, y = cards[-1] + state.eq_box = i, c, x, y + state.runner = threading.Thread(target=pos_a, daemon=True) + state.runner.start() + except Exception as e: + rospy.logerr((e, ext[:-1])) + state.count = 0 + else: + state.count = 0 + elif state.step == 1: + if state.ans_step >= len(state.answer): + rospy.loginfo("finished answer") + state.step = 0 + state.runner = threading.Thread(target=pos_b) + state.runner.start() + state.string = "" + else: + if len(cards) > 0: + cls_id, cls_conf, x, y = cards[0] + state.count += 1 + if state.count > 10: + state.runner = threading.Thread(target=moving, args=(cards[0],), daemon=True) + state.runner.start() + else: + state.count = 0 + rospy.logwarn("can not find \'" + state.answer[state.ans_step] + "\'") + else: + pass + + else: + pass + image = cv2.putText(image, state.string, (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (205, 120, 120), 3) + image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) + cv2.imshow(ROS_NODE_NAME, image) + cv2.waitKey(1) + + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + state = VisualCalculator() + state.load_camera_params() + if state.camera_params is None: + rospy.logerr("Can not load camera parameters!") + yolov5 = Yolov5TensorRT(TRT_ENGINE_PATH, TRT_INPUT_SIZE, TRT_NUM_CLASSES) + jetmax = hiwonder.JetMax() + sucker = hiwonder.Sucker() + jetmax.go_home(2) + sucker.release() + rospy.sleep(2) + image_queue = queue.Queue(maxsize=1) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) # Subscribe to the camera + while True: + try: + image_proc() + if rospy.is_shutdown(): + sys.exit(0) + except KeyboardInterrupt: + break diff --git a/src/jetmax_demos/scripts/voice_control.py b/src/jetmax_demos/scripts/voice_control.py new file mode 100755 index 0000000..fe3d93b --- /dev/null +++ b/src/jetmax_demos/scripts/voice_control.py @@ -0,0 +1,496 @@ +#!/usr/bin/env python3 +# encoding: utf-8 +import smbus2 +import cv2 +import sys +import math +import threading +import numpy as np +import rospy +from sensor_msgs.msg import Image +from std_msgs.msg import Bool +from std_srvs.srv import Empty +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from color_sorting.srv import SetTarget, SetTargetResponse, SetTargetRequest +from std_msgs.msg import Bool +from jetmax_control.msg import SetServo +import hiwonder + +ROS_NODE_NAME = "color_sorting_1" +IMAGE_PROC_SIZE = 640, 480 +unit_block_corners = np.asarray([[0, 0, 0], + [20, -20, 0], # TAG_SIZE = 33.30mm + [-20, -20, 0], + [-20, 20, 0], + [20, 20, 0]], + dtype=np.float64) +unit_block_img_pts = None + + +class Voice: + TTS_MODULE_I2C_ADDR = 0x40 + + def __init__(self, bus=1): + self.address = self.TTS_MODULE_I2C_ADDR + self.bus = smbus2.SMBus(1) + + def TTSModuleSpeak(self, sign, words): + head = [0xFD, 0x00, 0x00, 0x01, 0x00] + wordslist = words.encode("gb2312") + signdata = sign.encode("gb2312") + length = len(signdata) + len(wordslist) + 2 + head[1] = length >> 8 + head[2] = length + head.extend(list(signdata)) + head.extend(list(wordslist)) + self.bus.write_i2c_block_data(self.address, 0, head) + rospy.sleep(0.05) + + +class ASR: + # Global Variables + address = None + bus = None + + ASR_RESULT_ADDR = 100 + # 识别结果存放处,通过不断读取此地址的值判断是否识别到语音,不同的值对应不同的语音 + + ASR_WORDS_ERASE_ADDR = 101 + # 擦除所有词条 + + ASR_MODE_ADDR = 102 + # 识别模式设置,值范围1~3 + # 1:循环识别模式。状态灯常亮(默认模式) + # 2:口令模式,以第一个词条为口令。状态灯常灭,当识别到口令词>时常亮,等待识别到新的语音,并且读取识别结果后即灭掉 + # 3:按键模式,按下开始识别,不按不识别。支持掉电保存。状态灯>随按键按下而亮起,不按不亮 + ASR_ADD_WORDS_ADDR = 160 + + # 词条添加的地址,支持掉电保存 + + def __init__(self, address, bus=1): + self.address = address + self.bus = smbus2.SMBus(1) + + def readByte(self): + return self.bus.read_byte(self.address) + + def writeByte(self, val): + value = self.bus.write_byte(self.address, val) + if value != 0: + return False + return True + + def writeData(self, reg, val): + self.bus.write_byte(self.address, reg) + self.bus.write_byte(self.address, val) + + def getResult(self): + if ASR.writeByte(self, self.ASR_RESULT_ADDR): + return -1 + value = self.bus.read_byte(self.address) + return value + + ''' + * 添加词条函数, + * idNum:词条对应的识别号,1~255随意设置。识别到该号码对应的>词条语音时, + * 会将识别号存放到ASR_RESULT_ADDR处,等待主机读取,读>取后清0 + * words:要识别汉字词条的拼音,汉字之间用空格隔开 + * + * 执行该函数,词条是自动往后排队添加的。 + ''' + + def addWords(self, idNum, words): + buf = [idNum] + for i in range(0, len(words)): + buf.append(eval(hex(ord(words[i])))) + self.bus.write_i2c_block_data(self.address, self.ASR_ADD_WORDS_ADDR, buf) + rospy.sleep(0.05) + + def eraseWords(self): + result = self.bus.write_byte_data(self.address, self.ASR_WORDS_ERASE_ADDR, 0) + rospy.sleep(0.06) + if result != 0: + return False + return True + + def setMode(self, mode): + result = self.bus.write_byte_data(self.address, self.ASR_MODE_ADDR, mode) + if result != 0: + return False + return True + + +def camera_to_world(cam_mtx, r, t, img_points): + inv_k = np.asmatrix(cam_mtx).I + r_mat = np.zeros((3, 3), dtype=np.float64) + cv2.Rodrigues(r, r_mat) + # invR * T + inv_r = np.asmatrix(r_mat).I # 3*3 + transPlaneToCam = np.dot(inv_r, np.asmatrix(t)) # 3*3 dot 3*1 = 3*1 + world_pt = [] + coords = np.zeros((3, 1), dtype=np.float64) + for img_pt in img_points: + coords[0][0] = img_pt[0][0] + coords[1][0] = img_pt[0][1] + coords[2][0] = 1.0 + worldPtCam = np.dot(inv_k, coords) # 3*3 dot 3*1 = 3*1 + # [x,y,1] * invR + worldPtPlane = np.dot(inv_r, worldPtCam) # 3*3 dot 3*1 = 3*1 + # zc + scale = transPlaneToCam[2][0] / worldPtPlane[2][0] + # zc * [x,y,1] * invR + scale_worldPtPlane = np.multiply(scale, worldPtPlane) + # [X,Y,Z]=zc*[x,y,1]*invR - invR*T + worldPtPlaneReproject = np.asmatrix(scale_worldPtPlane) - np.asmatrix(transPlaneToCam) # 3*1 dot 1*3 = 3*3 + pt = np.zeros((3, 1), dtype=np.float64) + pt[0][0] = worldPtPlaneReproject[0][0] + pt[1][0] = worldPtPlaneReproject[1][0] + pt[2][0] = 0 + world_pt.append(pt.T.tolist()) + return world_pt + + +class ColorSortingState: + def __init__(self): + self.target_colors = {} + self.target_positions = { + 'red': ((232, -25, 95), -5), + 'green': ((233, 25, 95), 8), + 'blue': ((237, 75, 95), 18) + } + self.is_running = False + self.image_sub = None + self.moving_color = None + self.lock = threading.RLock() + self.runner = None + self.count = 0 + self.camera_params = None + self.K = None + self.R = None + self.T = None + self.WIDTH = None + self.no_none_count = 0 + + def reset(self): + self.target_colors = {} + self.is_running = False + self.moving_color = None + self.count = 0 + + def load_camera_params(self): + global unit_block_img_pts + self.camera_params = rospy.get_param('/camera_cal/block_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + img_pts, jac = cv2.projectPoints(unit_block_corners, self.R, self.T, self.K, None) + unit_block_img_pts = img_pts.reshape(5, 2) + l_p1 = unit_block_img_pts[-1] + l_p2 = unit_block_img_pts[-2] + self.WIDTH = math.sqrt((l_p1[0] - l_p2[0]) ** 2 + (l_p1[1] - l_p2[1]) ** 2) + print(unit_block_img_pts) + + +def moving(): + rect, box, color_name = state.moving_color + cur_x, cur_y, cur_z = jetmax.position + try: + x, y, _ = camera_to_world(state.K, state.R, state.T, np.array(rect[0]).reshape((1, 1, 2)))[0][0] + # Calculate the distance between the current position and the target position to control the movement speed + t = math.sqrt(x * x + y * y + 120 * 120) / 140 + angle = rect[2] + if angle < -45: # ccw -45 ~ -90 + angle = -(-90 - angle) + + new_x, new_y = cur_x + x, cur_y + y + arm_angle = math.atan(new_y / new_x) * 180 / math.pi + if arm_angle > 0: + arm_angle = (90 - arm_angle) + elif arm_angle < 0: + arm_angle = (-90 - arm_angle) + else: + pass + + angle = angle + -arm_angle + + # Pick up the block + hiwonder.pwm_servo1.set_position(90 + angle, 0.1) + jetmax.set_position((new_x, new_y, 120), t) + rospy.sleep(t) + sucker.set_state(True) # Turn on the air pump + jetmax.set_position((new_x, new_y, 85), 1) + rospy.sleep(1.05) + + cur_x, cur_y, cur_z = jetmax.position + jetmax.set_position((cur_x, cur_y, 180), 0.8) + rospy.sleep(0.8) + hiwonder.pwm_servo1.set_position(90, 0.1) + + # Go to the target position + (x, y, z), angle = state.target_positions[color_name] + cur_x, cur_y, cur_z = jetmax.position + t = math.sqrt(((cur_x - x) ** 2 + (cur_y - y) ** 2)) / 180.0 + hiwonder.pwm_servo1.set_position(90 + angle, 0.5) + jetmax.set_position((x, y, 180), t) + rospy.sleep(t) + jetmax.set_position((x, y, z), 1) + rospy.sleep(1) + + # Put down the block + sucker.release(3) # Turn off the air pump + jetmax.set_position((x, y, 140), 0.8) + rospy.sleep(0.8) + except Exception as e: + rospy.logerr("ERROR") + finally: + # Go home + sucker.release(3) + hiwonder.pwm_servo1.set_position(90, 0.5) + jetmax.go_home(2) + rospy.sleep(2.5) + state.moving_color = None + state.runner = None + + +def point_xy(pt_a, pt_b, r): + x_a, y_a = pt_a + x_b, y_b = pt_b + if x_a == x_b: + return x_a, y_a + (r / abs((y_b - y_a))) * (y_b - y_a) + k = (y_a - y_b) / (x_a - x_b) + b = y_a - k * x_a + A = k ** 2 + 1 + B = 2 * ((b - y_a) * k - x_a) + C = (b - y_a) ** 2 + x_a ** 2 - r ** 2 + x1 = (-B + math.sqrt(B ** 2 - 4 * A * C)) / (2 * A) + x2 = (-B - math.sqrt(B ** 2 - 4 * A * C)) / (2 * A) + y1 = k * x1 + b + y2 = k * x2 + b + dist_1 = math.sqrt((x1 - x_b) ** 2 + (y1 - y_b) ** 2) + dist_2 = math.sqrt((x2 - x_b) ** 2 + (y2 - y_b) ** 2) + if dist_1 <= dist_2: + return x1, y1 + else: + return x2, y2 + + +def image_proc(img): + if state.runner is not None: + return img + img_h, img_w = img.shape[:2] + frame_gb = cv2.GaussianBlur(np.copy(img), (5, 5), 5) + frame_lab = cv2.cvtColor(frame_gb, cv2.COLOR_RGB2LAB) # Convert rgb to lab + + blocks = [] + for color_name, color in state.target_colors.items(): # Loop through all selected colors + frame_mask = cv2.inRange(frame_lab, tuple(color['min']), tuple(color['max'])) + eroded = cv2.erode(frame_mask, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) + dilated = cv2.dilate(eroded, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))) + contours = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] + contour_area = map(lambda c: (c, math.fabs(cv2.contourArea(c))), contours) + contour_area = list(filter(lambda c: c[1] > 1000, contour_area)) # Eliminate contours that are too small + + if len(contour_area) > 0: + for contour, area in contour_area: # Loop through all the contours found + rect = cv2.minAreaRect(contour) + center_x, center_y = rect[0] + box = cv2.boxPoints(rect) # The four vertices of the minimum-area-rectangle + box_list = box.tolist() + box = np.int0(box) + ap = max(box_list, key=lambda p: math.sqrt((p[0] - state.K[0][2]) ** 2 + (p[1] - state.K[1][2]) ** 2)) + index_ap = box_list.index(ap) + p1 = box_list[index_ap - 1 if index_ap - 1 >= 0 else 3] + p2 = box_list[index_ap + 1 if index_ap + 1 <= 3 else 0] + n_p1 = point_xy(ap, p1, state.WIDTH) + n_p2 = point_xy(ap, p2, state.WIDTH) + + c_x, c_y = None, None + if n_p1 and n_p2: + x_1, y_1 = n_p1 + x_2, y_2 = n_p2 + c_x = (x_1 + x_2) / 2 + c_y = (y_1 + y_2) / 2 + cv2.circle(img, (int(n_p1[0]), int(n_p1[1])), 2, (255, 255, 0), 10) + cv2.circle(img, (int(n_p2[0]), int(n_p2[1])), 2, (255, 255, 0), 10) + cv2.circle(img, (int(c_x), int(c_y)), 2, (0, 0, 0), 10) + + cv2.circle(img, (int(ap[0]), int(ap[1])), 2, (0, 255, 255), 10) + cv2.drawContours(img, [box], -1, hiwonder.COLORS[color_name.upper()], 2) + cv2.circle(img, (int(center_x), int(center_y)), 1, hiwonder.COLORS[color_name.upper()], 5) + rect = list(rect) + if c_x: + rect[0] = c_x, c_y + else: + rect[0] = (center_x, center_y) + blocks.append((rect, box, color_name)) + + if len(blocks) > 0: + if state.moving_color is None: + # Choose the contour with the largest area as the next target + state.moving_color = max(blocks, key=lambda tmp: tmp[0][1][0] * tmp[0][1][1]) + else: + # Find the rectangle with the smallest distance from the last rectangle and update the data + rect, _, _ = state.moving_color + moving_x, moving_y = rect[0] + blocks = list(map(lambda tmp: (tmp, math.sqrt((moving_x - tmp[0][0][0]) ** 2 + + (moving_y - tmp[0][0][1]) ** 2)), blocks)) + blocks.sort(key=lambda tmp: tmp[1]) + moving_color, _ = blocks[0] + x, y = moving_color[0][0] + cv2.drawContours(img, [moving_color[1]], -1, (255, 255, 255), 2) + cv2.circle(img, (int(x), int(y)), 1, (255, 255, 255), 5) + + state.count += 1 + if state.count > 5: + rect, box, color_name = moving_color + (x, y), (w, h), angle = rect + (o_x, o_y), _, o_angle = state.moving_color[0] + o_x = x * 0.2 + o_x * 0.8 + o_y = y * 0.2 + o_y * 0.8 + o_angle = angle * 0.2 + o_angle * 0.8 + rect = (o_x, o_y), (w, h), o_angle + moving_color = rect, box, color_name + if state.count > 30: + state.count = 0 + state.moving_color = moving_color + state.runner = threading.Thread(target=moving, daemon=True) # Move block + state.runner.start() + state.moving_color = moving_color + else: + state.moving_color = None + state.count = 0 + print(state.moving_color) + if state.moving_color is not None: + state.no_none_count = 0 + else: + state.no_none_count += 1 + + cv2.line(img, (int(img_w / 2 - 10), int(img_h / 2)), (int(img_w / 2 + 10), int(img_h / 2)), (0, 255, 255), 2) + cv2.line(img, (int(img_w / 2), int(img_h / 2 - 10)), (int(img_w / 2), int(img_h / 2 + 10)), (0, 255, 255), 2) + return img + + +def image_callback(ros_image): + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = np.copy(image) + with state.lock: + frame_result = image_proc(frame_result) + frame_result = cv2.cvtColor(frame_result, cv2.COLOR_RGB2BGR) + cv2.imshow("result", frame_result) + cv2.waitKey(1) + + +def enter_func(msg): + rospy.loginfo("Enter color sorting") + exit_func(msg) + jetmax.go_home() + state.reset() + state.load_camera_params() + state.image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) + state.running = True + return TriggerResponse(success=True) + + +def exit_func(msg): + rospy.loginfo("Exit color sorting") + state.is_running = False + if isinstance(state.runner, threading.Thread): # If the arm is moving, wait for it to complete + state.runner.join() + if isinstance(state.image_sub, rospy.Subscriber): + state.image_sub.unregister() + state.image_sub = None + rospy.ServiceProxy('/jetmax/go_home', Empty)() + rospy.Publisher('/jetmax/end_effector/sucker/command', Bool, queue_size=1).publish(data=False) + rospy.Publisher('/jetmax/end_effector/servo1/command', SetServo, queue_size=1).publish(data=90, duration=0.5) + return TriggerResponse(success=True) + + +def set_target_cb(msg: SetTargetRequest): + try: + if msg.is_enable: + color_ranges = rospy.get_param('/lab_config_manager/color_range_list', {}) + with state.lock: + state.target_colors[msg.color_name] = color_ranges[msg.color_name] + rospy.logdebug('set target color ' + str(msg)) + else: + with state.lock: + del (state.target_colors[msg.color_name]) + rospy.loginfo('disable target color: ' + msg.color_name) + except Exception as e: + rospy.logerr(e) + return SetTargetResponse(success=False, message=str(e)) + return SetTargetResponse(success=True) + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + addr = 0x79 # 传感器iic地址 + asr = ASR(addr) + + # 添加的词条和识别模式是可以掉电保存的,第一次设置完成后,可以将1改为0 + if 1: + asr.eraseWords() + asr.setMode(2) + asr.addWords(1, 'kai shi') + asr.addWords(2, 'feng jian hong se') + asr.addWords(3, 'feng jian lv se') + asr.addWords(4, 'feng jian lan se') + asr.addWords(5, 'ting zhi feng jian') + + state = ColorSortingState() + state.load_camera_params() + if state.camera_params is None: + rospy.logerr("Can not load camera params") + sys.exit(-1) + jetmax = hiwonder.JetMax() + sucker = hiwonder.Sucker() + rospy.sleep(0.2) + image_pub = rospy.Publisher('/%s/image_result' % ROS_NODE_NAME, Image, queue_size=1) # register image publisher + voice = Voice() + enter_func(None) + voice.TTSModuleSpeak("[v10]", "颜色分拣启动") + state.no_none_count = 10000 + while not rospy.is_shutdown(): + data = asr.getResult() + if data == 2: + voice.TTSModuleSpeak("[v10]", "开始分拣红色") + rospy.sleep(0.5) + set_target_cb(SetTargetRequest(is_enable=True, color_name="red")) + set_target_cb(SetTargetRequest(is_enable=False, color_name="green")) + set_target_cb(SetTargetRequest(is_enable=False, color_name="blue")) + state.no_none_count = 0 + elif data == 3: + voice.TTSModuleSpeak("[v10]", "开始分拣绿色") + rospy.sleep(0.5) + set_target_cb(SetTargetRequest(is_enable=False, color_name="red")) + set_target_cb(SetTargetRequest(is_enable=True, color_name="green")) + set_target_cb(SetTargetRequest(is_enable=False, color_name="blue")) + state.no_none_count = 0 + elif data == 4: + voice.TTSModuleSpeak("[v10]", "开始分拣蓝色") + rospy.sleep(0.5) + set_target_cb(SetTargetRequest(is_enable=False, color_name="red")) + set_target_cb(SetTargetRequest(is_enable=False, color_name="green")) + set_target_cb(SetTargetRequest(is_enable=True, color_name="blue")) + state.no_none_count = 0 + elif data == 5: + voice.TTSModuleSpeak("[v10]", "停止分拣") + set_target_cb(SetTargetRequest(is_enable=False, color_name="red")) + set_target_cb(SetTargetRequest(is_enable=False, color_name="green")) + set_target_cb(SetTargetRequest(is_enable=False, color_name="blue")) + state.no_none_count = 0 + else: + pass + if 200 < state.no_none_count < 1000: + strs = {"red": "未找到红色,停止分拣", + "green": "未找到绿色,停止分拣", + "blue": "未找到蓝色,停止分拣"} + voice.TTSModuleSpeak("[v10]", strs[list(state.target_colors.keys())[0]]) + + set_target_cb(SetTargetRequest(is_enable=False, color_name="red")) + set_target_cb(SetTargetRequest(is_enable=False, color_name="green")) + set_target_cb(SetTargetRequest(is_enable=False, color_name="blue")) + state.no_none_count = 10000 + rospy.sleep(0.1) diff --git a/src/jetmax_demos/scripts/yolov5_tensorrt.py b/src/jetmax_demos/scripts/yolov5_tensorrt.py new file mode 100644 index 0000000..4533795 --- /dev/null +++ b/src/jetmax_demos/scripts/yolov5_tensorrt.py @@ -0,0 +1,207 @@ +import cv2 +import sys +import os +import tensorrt as trt +import pycuda.autoinit +import pycuda.driver as cuda +import numpy as np +import math + + +# Simple helper data class that's a little nicer to use than a 2-tuple. +class HostDeviceMem: + def __init__(self, host_mem, device_mem): + self.host = host_mem + self.device = device_mem + + def __str__(self): + return "Host:\n" + str(self.host) + "\nDevice:\n" + str(self.device) + + def __repr__(self): + return self.__str__() + + +def sigmoid_v(array): + return np.reciprocal(np.exp(-array) + 1.0) + + +def sigmoid(x): + return 1 / (1 + math.exp(-x)) + + +def non_max_suppression(boxes, confs, classes, iou_thres=0.6): + x1 = boxes[:, 0] + y1 = boxes[:, 1] + x2 = boxes[:, 2] + y2 = boxes[:, 3] + areas = (x2 - x1 + 1) * (y2 - y1 + 1) + order = confs.flatten().argsort()[::-1] + keep = [] + while order.size > 0: + i = order[0] + keep.append(i) + xx1 = np.maximum(x1[i], x1[order[1:]]) + yy1 = np.maximum(y1[i], y1[order[1:]]) + xx2 = np.minimum(x2[i], x2[order[1:]]) + yy2 = np.minimum(y2[i], y2[order[1:]]) + w = np.maximum(0.0, xx2 - xx1 + 1) + h = np.maximum(0.0, yy2 - yy1 + 1) + inter = w * h + ovr = inter / (areas[i] + areas[order[1:]] - inter) + inds = np.where(ovr <= iou_thres)[0] + order = order[inds + 1] + boxes = boxes[keep] + confs = confs[keep] + classes = classes[keep] + return boxes, confs, classes + + +def xywh2xyxy(x): + # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right + y = np.zeros_like(x) + y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x + y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y + y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x + y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y + return y + + +def nms(pred, iou_thres=0.6): + boxes = xywh2xyxy(pred[..., 0:4]) + # best class only + confs = np.amax(pred[:, 5:], 1, keepdims=True) + classes = np.argmax(pred[:, 5:], axis=-1) + return non_max_suppression(boxes, confs, classes, iou_thres) + + +def make_grid(nx, ny): + """ + Create scaling tensor based on box location + Source: https://github.com/ultralytics/yolov5/blob/master/models/yolo.py + Arguments + nx: x-axis num boxes + ny: y-axis num boxes + Returns + grid: tensor of shape (1, 1, nx, ny, 80) + """ + nx_vec = np.arange(nx) + ny_vec = np.arange(ny) + yv, xv = np.meshgrid(ny_vec, nx_vec) + grid = np.stack((yv, xv), axis=2) + grid = grid.reshape(1, 1, ny, nx, 2) + return grid + + +def pre_process(img_in, w, h): + img_in = cv2.resize(img_in, (w, h), interpolation=cv2.INTER_LINEAR) + # img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + # img = img.transpose((2, 0, 1)).astype(np.float16) + img_in = np.transpose(img_in, (2, 0, 1)).astype(np.float32) + img_in = np.expand_dims(img_in, axis=0) + img_in /= 255.0 + img_in = np.ascontiguousarray(img_in) + return img_in + + +class Yolov5TensorRT: + def __init__(self, model, input_size, classes_num): + # load tensorrt engine + self.input_size = input_size + TRT_LOGGER = trt.Logger(trt.Logger.INFO) + with open(model, 'rb') as f, trt.Runtime(TRT_LOGGER) as runtime: + engine = runtime.deserialize_cuda_engine(f.read()) + self.context = engine.create_execution_context() + # allocate memory + inputs, outputs, bindings = [], [], [] + stream = cuda.Stream() + for binding in engine: + size = trt.volume(engine.get_binding_shape(binding)) + dtype = trt.nptype(engine.get_binding_dtype(binding)) + host_mem = cuda.pagelocked_empty(size, dtype) + device_mem = cuda.mem_alloc(host_mem.nbytes) + bindings.append(int(device_mem)) + if engine.binding_is_input(binding): + inputs.append(HostDeviceMem(host_mem, device_mem)) + else: + outputs.append(HostDeviceMem(host_mem, device_mem)) + # save to class + self.inputs = inputs + self.outputs = outputs + self.bindings = bindings + self.stream = stream + # post processing config + self.strides = np.array([8., 16., 32.]) + anchors = np.array([ + [[10, 13], [16, 30], [33, 23]], + [[30, 61], [62, 45], [59, 119]], + [[116, 90], [156, 198], [373, 326]], + ]) + self.nl = len(anchors) + self.nc = classes_num # classes + self.no = self.nc + 5 # outputs per anchor + self.na = len(anchors[0]) + a = anchors.copy().astype(np.float32) + a = a.reshape(self.nl, -1, 2) + self.anchors = a.copy() + self.anchor_grid = a.copy().reshape(self.nl, 1, -1, 1, 1, 2) + self.output_shapes = [ + (1, 3, int(input_size / 8), int(input_size / 8), self.nc + 5), + (1, 3, int(input_size / 16), int(input_size / 16), self.nc + 5), + (1, 3, int(input_size / 32), int(input_size / 32), self.nc + 5) + ] + + def detect(self, img): + shape_orig_WH = (img.shape[1], img.shape[0]) + resized = pre_process(img, self.input_size, self.input_size) + outputs = self.inference(resized) + # reshape from flat to (1, 3, x, y, 85) + reshaped = [] + for output, shape in zip(outputs, self.output_shapes): + reshaped.append(output.reshape(shape)) + return reshaped + + def inference(self, img): + # copy img to input memory + # self.inputs[0]['host'] = np.ascontiguousarray(img) + self.inputs[0].host = np.ravel(img) + # transfer data to the gpu + [cuda.memcpy_htod_async(inp.device, inp.host, self.stream) for inp in self.inputs] + # run inference + self.context.execute_async_v2(bindings=self.bindings, stream_handle=self.stream.handle) + # fetch outputs from gpu + [cuda.memcpy_dtoh_async(out.host, out.device, self.stream) for out in self.outputs] + # synchronize stream + self.stream.synchronize() + return [out.host for out in self.outputs] + + def post_process(self, image, outputs, conf_thres=0.2, nms_thres=0.6): + """ + Transforms raw output into boxes, confs, classes + Applies NMS thresholding on bounding boxes and confs + Parameters: + output: raw output tensor + Returns: + boxes: x1,y1,x2,y2 tensor (dets, 4) + confs: class * obj prob tensor (dets, 1) + classes: class type tensor (dets, 1) + """ + scaled = [] + grids = [] + for out in outputs: + out = sigmoid_v(out) + _, _, width, height, _ = out.shape + grid = make_grid(width, height) + grids.append(grid) + scaled.append(out) + z = [] + for out, grid, stride, anchor in zip(scaled, grids, self.strides, self.anchor_grid): + _, _, width, height, _ = out.shape + out[..., 0:2] = (out[..., 0:2] * 2. - 0.5 + grid) * stride + out[..., 2:4] = (out[..., 2:4] * 2) ** 2 * anchor + + out = out.reshape((1, 3 * width * height, self.no)) + z.append(out) + pred = np.concatenate(z, 1) + xc = pred[..., 4] > conf_thres + pred = pred[xc] + return nms(pred, nms_thres) diff --git a/src/stepper/CMakeLists.txt b/src/stepper/CMakeLists.txt new file mode 100644 index 0000000..e51baa2 --- /dev/null +++ b/src/stepper/CMakeLists.txt @@ -0,0 +1,206 @@ +cmake_minimum_required(VERSION 3.0.2) +project(stepper) + +## 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 + rospy + std_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 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 +# ) + +################################################ +## 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 stepper +# CATKIN_DEPENDS roscpp rospy std_msgs +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( +# include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/stepper.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/stepper_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_stepper.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/stepper/package.xml b/src/stepper/package.xml new file mode 100644 index 0000000..8c01df9 --- /dev/null +++ b/src/stepper/package.xml @@ -0,0 +1,68 @@ + + + stepper + 0.0.0 + The stepper package + + + + + hiwonder + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + roscpp + rospy + std_msgs + roscpp + rospy + std_msgs + roscpp + rospy + std_msgs + + + + + + + + diff --git a/src/stepper/scripts/apriltag_sorting_stepper.py b/src/stepper/scripts/apriltag_sorting_stepper.py new file mode 100755 index 0000000..7fcf6b2 --- /dev/null +++ b/src/stepper/scripts/apriltag_sorting_stepper.py @@ -0,0 +1,249 @@ +#!/usr/bin/python3 +# coding=utf8 +import sys +import cv2 +import math +import time +import yaml +import rospy +import hiwonder +import apriltag +import threading +import numpy as np +from sensor_msgs.msg import Image + +ROS_NODE_NAME = "ApriltagSorting_stepper" + +if sys.version_info.major == 2: + print('Please run this program with python3!') + sys.exit(0) + +TARGET_POSITIONS = { + 1: (0, -180, 35, 5200), + 2: (0, -180, 35, 4200), + 3: (0, -180, 35, 3200), +} + +IMAGE_PROC_SIZE = 640, 480 +TAG_SIZE = 33.30 +stepper_position = 0 +jetmax = hiwonder.JetMax() +sucker = hiwonder.Sucker() +stepper = hiwonder.Stepper(1) +at_detector = apriltag.Detector(apriltag.DetectorOptions(families='tag36h11')) + +class ApriltagSorting: + def __init__(self): + self.lock = threading.RLock() + self.moving_box = None + self.moving_block = None + self.index = 0 + self.level = 0 + self.pos_add = 0 + self.tag_id = None + self.runner = None + self.moving_count = 0 + self.count = 0 + self.fps_t0 = time.time() + self.fps = 0 + self.camera_params = None + self.K = None + self.R = None + self.T = None + + + def load_camera_params(self): + self.camera_params = rospy.get_param('/camera_cal/block_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + +# 现实坐标转换函数 +def camera_to_world(cam_mtx, r, t, img_points): + inv_k = np.asmatrix(cam_mtx).I + r_mat = np.zeros((3, 3), dtype=np.float64) + cv2.Rodrigues(r, r_mat) + # invR * T + inv_r = np.asmatrix(r_mat).I # 3*3 + transPlaneToCam = np.dot(inv_r, np.asmatrix(t)) # 3*3 dot 3*1 = 3*1 + world_pt = [] + coords = np.zeros((3, 1), dtype=np.float64) + for img_pt in img_points: + coords[0][0] = img_pt[0][0] + coords[1][0] = img_pt[0][1] + coords[2][0] = 1.0 + worldPtCam = np.dot(inv_k, coords) # 3*3 dot 3*1 = 3*1 + # [x,y,1] * invR + worldPtPlane = np.dot(inv_r, worldPtCam) # 3*3 dot 3*1 = 3*1 + # zc + scale = transPlaneToCam[2][0] / worldPtPlane[2][0] + # zc * [x,y,1] * invR + scale_worldPtPlane = np.multiply(scale, worldPtPlane) + # [X,Y,Z]=zc*[x,y,1]*invR - invR*T + worldPtPlaneReproject = np.asmatrix(scale_worldPtPlane) - np.asmatrix(transPlaneToCam) # 3*1 dot 1*3 = 3*3 + pt = np.zeros((3, 1), dtype=np.float64) + pt[0][0] = worldPtPlaneReproject[0][0] + pt[1][0] = worldPtPlaneReproject[1][0] + pt[2][0] = 0 + world_pt.append(pt.T.tolist()) + return world_pt + + +def rotation_mtx_to_euler(R): + sy = math.sqrt(R[0, 0] * R[0, 0] + R[1, 0] * R[1, 0]) + singular = sy < 1e-6 + if not singular: + x = math.atan2(R[2, 1], R[2, 2]) + y = math.atan2(-R[2, 0], sy) + z = math.atan2(R[1, 0], R[0, 0]) + else: + x = math.atan2(-R[1, 2], R[1, 1]) + y = math.atan2(-R[2, 0], sy) + z = 0 + return np.array([x, y, z]) + +# 移动控制函数 +def moving(): + try: + tag = state.moving_block + params = np.array([state.K[0][0], state.K[1][1], state.K[0][2], state.K[1][2]]) + pose_mtx, a, b = at_detector.detection_pose(tag, camera_params=params, tag_size=TAG_SIZE) + angle = rotation_mtx_to_euler(pose_mtx)[2] * (180 / math.pi) + + cur_x, cur_y, cur_z = jetmax.position # 当前的机械臂位置 + rect_x, rect_y = state.moving_block.center + p = np.asarray([rect_x, rect_y]).reshape((1, 1, 2)) + w = camera_to_world(state.K, state.R, state.T, p)[0][0] #转换成现实距离 + x, y, _ = w + print(w) + if angle < -45: # ccw -45 ~ -90 + angle = -(-90 - angle) + if angle > 45: + angle = -(90 - angle) + + new_x, new_y = cur_x + x, cur_y + y #目标的现实坐标 + arm_angle = math.atan(new_y / new_x) * 180 / math.pi # 计算偏转角 + if arm_angle > 0: + arm_angle = (90 - arm_angle) + elif arm_angle < 0: + arm_angle = (-90 - arm_angle) + else: + pass + + angle = angle + -arm_angle + + dist = math.sqrt(x * x + y * y + 120 * 120) #计算两坐标点的直线距离 + t = dist / 140 + hiwonder.pwm_servo1.set_position(90 + angle, 0.1) #角度补偿 + jetmax.set_position((new_x, new_y, 100), t) # 移动到目标上方 + rospy.sleep(t + 0.1) + + sucker.set_state(True) # 打开气泵 + jetmax.set_position((new_x, new_y, 30), 1) # 吸取目标 + rospy.sleep(1) + jetmax.set_position((new_x, new_y, 100), 1) # 移动到目标上方 + rospy.sleep(1) + + x, y, z, stepper_position = TARGET_POSITIONS[state.tag_id] # 读取放置坐标 + + + hiwonder.pwm_servo1.set_position(90, 0.5) #角度回正 + cur_x, cur_y, cur_z = jetmax.position # 当前的机械臂位置 + t = math.sqrt((cur_x - x) ** 2 + (cur_y - y) ** 2) / 120 # 计算需要的时间 + jetmax.set_position((x, y, 100), t) # 移动到放置坐标上方 + rospy.sleep(t + 0.1) + + stepper.set_mode(stepper.SLEEP) # 设置滑轨使能 + stepper.goto(stepper_position) # 驱动滑轨移动到放置位置 + stepper_time = stepper_position/1000 # 计算需要的时间 + rospy.sleep(stepper_time) + + jetmax.set_position((x, y, z), 1) # 到放置位置 + rospy.sleep(1) + + sucker.release(3) + jetmax.set_position((x, y, 100), 0.5) + rospy.sleep(0.5) + + # Go home + jetmax.go_home(2,2) # 机械臂回到初始位置 jetmax.go_home(a,b): a:设置运行时间; b: 1 机械臂模式,2 滑轨模式,3 小车底盘模式 + stepper.goto(-stepper_position) # 滑轨回到初始位置 + stepper_time = stepper_position/1000 + rospy.sleep(stepper_time) + stepper.set_mode(stepper.EN) # 解除滑轨锁定 + + finally: + + with state.lock: + state.tag_id = None + state.moving_block = None + state.runner = None + + +def image_proc(img): + if state.runner is not None: + return img + frame_gray = cv2.cvtColor(np.copy(img), cv2.COLOR_RGB2GRAY) + tags = at_detector.detect(frame_gray) + for tag in tags: + corners = tag.corners.reshape(1, -1, 2).astype(int) + center = tag.center.astype(int) + cv2.drawContours(img, corners, -1, (255, 0, 0), 3) + cv2.circle(img, tuple(center), 5, (255, 255, 0), 10) + cv2.putText(img, "id:%d" % tag.tag_id, + (center[0], center[1] - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2) + if len(tags) > 0: + if state.moving_block is None: + state.moving_block = tags[0] + else: + new_tag = tags[0] + if new_tag.tag_id != state.moving_block.tag_id: + state.count = 0 + else: + state.count += 1 + if state.count > 50: + state.count = 0 + state.tag_id = new_tag.tag_id + state.runner = threading.Thread(target=moving, daemon=True) + state.runner.start() + state.moving_block = tags[0] + else: + state.count = 0 + if state.moving_block is not None: + state.moving_block = None + img_h, img_w = img.shape[:2] + cv2.line(img, (int(img_w / 2 - 10), int(img_h / 2)), (int(img_w / 2 + 10), int(img_h / 2)), (0, 255, 255), 2) + cv2.line(img, (int(img_w / 2), int(img_h / 2 - 10)), (int(img_w / 2), int(img_h / 2 + 10)), (0, 255, 255), 2) + return img + + +def image_callback(ros_image): + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + frame_result = np.copy(image) + frame_result = image_proc(frame_result) # apriltag检测 + image_bgr = cv2.cvtColor(frame_result, cv2.COLOR_RGB2BGR) + cv2.imshow("result", image_bgr) + cv2.waitKey(1) + + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + state = ApriltagSorting() + state.load_camera_params() + jetmax = hiwonder.JetMax() + sucker = hiwonder.Sucker() + stepper = hiwonder.Stepper(1) + jetmax.go_home(2,2) + stepper.go_home(True) + stepper.set_mode(stepper.EN) + stepper.set_div(stepper.DIV_1_4) + rospy.sleep(1) + image_sub = rospy.Subscriber("/usb_cam/image_rect_color", Image, image_callback, queue_size=1) + + try: + rospy.spin() + except KeyboardInterrupt: + sys.exit(0) + + diff --git a/src/stepper/scripts/models b/src/stepper/scripts/models new file mode 120000 index 0000000..a7d09c9 --- /dev/null +++ b/src/stepper/scripts/models @@ -0,0 +1 @@ +/home/hiwonder/models/ \ No newline at end of file diff --git a/src/stepper/scripts/waste_classification_stepper.py b/src/stepper/scripts/waste_classification_stepper.py new file mode 100755 index 0000000..6a4b2b1 --- /dev/null +++ b/src/stepper/scripts/waste_classification_stepper.py @@ -0,0 +1,283 @@ +#!/usr/bin/env python3 +import os +import sys +import cv2 +import math +import time +import rospy +import numpy as np +import threading +import queue +import hiwonder +from sensor_msgs.msg import Image +from std_srvs.srv import SetBool, SetBoolResponse, SetBoolRequest +from std_srvs.srv import Trigger, TriggerResponse, TriggerRequest +from std_srvs.srv import Empty +from std_msgs.msg import Bool +from jetmax_control.msg import SetServo +from yolov5_tensorrt import Yolov5TensorRT + +ROS_NODE_NAME = "waste_classification_stepper" + +TRT_ENGINE_PATH = os.path.join(sys.path[0], "models/waste_v5_160.trt") +TRT_INPUT_SIZE = 160 +TRT_CLASS_NAMES = ('Banana Peel', 'Broken Bones', 'Cigarette End', 'Disposable Chopsticks', + 'Ketchup', 'Marker', 'Oral Liquid Bottle', 'Plate', + 'Plastic Bottle', 'Storage Battery', 'Toothbrush', 'Umbrella') +TRT_NUM_CLASSES = 12 +WASTE_CLASSES = { + 'food_waste': ('Banana Peel', 'Broken Bones', 'Ketchup'), + 'hazardous_waste': ('Marker', 'Oral Liquid Bottle', 'Storage Battery'), + 'recyclable_waste': ('Plastic Bottle', 'Toothbrush', 'Umbrella'), + 'residual_waste': ('Plate', 'Cigarette End', 'Disposable Chopsticks'), +} +COLORS = { + 'recyclable_waste': (0, 0, 255), + 'hazardous_waste': (255, 0, 0), + 'food_waste': (0, 255, 0), + 'residual_waste': (80, 80, 80) +} + +TARGET_POSITION = { + 'recyclable_waste': (0, -180, 5, 5200), + 'hazardous_waste': (0, -180, 5, 4400), + 'food_waste': (0, -180, 5, 3600), + 'residual_waste': (0, -180, 5, 2800) +} + +# 现实坐标转换函数 +def camera_to_world(cam_mtx, r, t, img_points): + inv_k = np.asmatrix(cam_mtx).I + r_mat = np.zeros((3, 3), dtype=np.float64) + cv2.Rodrigues(r, r_mat) + # invR * T + inv_r = np.asmatrix(r_mat).I # 3*3 + transPlaneToCam = np.dot(inv_r, np.asmatrix(t)) # 3*3 dot 3*1 = 3*1 + world_pt = [] + coords = np.zeros((3, 1), dtype=np.float64) + for img_pt in img_points: + coords[0][0] = img_pt[0][0] + coords[1][0] = img_pt[0][1] + coords[2][0] = 1.0 + worldPtCam = np.dot(inv_k, coords) # 3*3 dot 3*1 = 3*1 + # [x,y,1] * invR + worldPtPlane = np.dot(inv_r, worldPtCam) # 3*3 dot 3*1 = 3*1 + # zc + scale = transPlaneToCam[2][0] / worldPtPlane[2][0] + # zc * [x,y,1] * invR + scale_worldPtPlane = np.multiply(scale, worldPtPlane) + # [X,Y,Z]=zc*[x,y,1]*invR - invR*T + worldPtPlaneReproject = np.asmatrix(scale_worldPtPlane) - np.asmatrix(transPlaneToCam) # 3*1 dot 1*3 = 3*3 + pt = np.zeros((3, 1), dtype=np.float64) + pt[0][0] = worldPtPlaneReproject[0][0] + pt[1][0] = worldPtPlaneReproject[1][0] + pt[2][0] = 0 + world_pt.append(pt.T.tolist()) + return world_pt + + +class WasteClassification: + def __init__(self): + self.lock = threading.RLock() + self.is_running = False + self.moving_box = None + self.image_sub = None + self.heartbeat_timer = None + self.runner = None + self.count = 0 + self.camera_params = None + self.fps_t0 = time.time() + self.fps = 0 + self.K = None + self.R = None + self.T = None + + def reset(self): + self.is_running = False + self.moving_box = None + self.image_sub = None + self.heartbeat_timer = None + self.runner = None + self.count = 0 + + def load_camera_params(self): + self.camera_params = rospy.get_param('/camera_cal/card_params', self.camera_params) + if self.camera_params is not None: + self.K = np.array(self.camera_params['K'], dtype=np.float64).reshape(3, 3) + self.R = np.array(self.camera_params['R'], dtype=np.float64).reshape(3, 1) + self.T = np.array(self.camera_params['T'], dtype=np.float64).reshape(3, 1) + +# 移动控制函数 +def moving(): + try: + c_x, c_y, waste_class_name = state.moving_box # 目标的画面坐标 + x, y, _ = camera_to_world(state.K, state.R, state.T, np.array([c_x, c_y]).reshape((1, 1, 2)))[0][0] #转换成现实距离 + cur_x, cur_y, cur_z = jetmax.position # 当前的机械臂位置 + t = math.sqrt(x * x + y * y + 140 * 140) / 140 #计算移动的时间 + new_x, new_y = cur_x + x, cur_y + y #目标的现实坐标 + arm_angle = math.atan(new_y / new_x) * 180 / math.pi # 计算偏转角 + if arm_angle > 0: + arm_angle = (90 - arm_angle) + elif arm_angle < 0: + arm_angle = (-90 - arm_angle) + else: + pass + hiwonder.pwm_servo1.set_position(90 - arm_angle, 0.1) #角度补偿 + + x, y, z, stepper_position = TARGET_POSITION[waste_class_name] # 读取放置坐标 + jetmax.set_position((new_x, new_y, 50), t) # 移动到目标上方 + rospy.sleep(t + 0.2) + + sucker.set_state(True) # 打开气泵 + jetmax.set_position((new_x, new_y, -12), 0.8) # 吸取目标 + rospy.sleep(0.8) + jetmax.set_position((new_x, new_y, 30), 0.3) + rospy.sleep(0.3) + t = abs(new_x)/120.0 + abs(new_y-cur_y)/120.0 + hiwonder.pwm_servo1.set_position(90, 0.5) #角度回正 + jetmax.set_position((x, y, 50), t) # 移动到放置坐标上方 + rospy.sleep(t) + + stepper.set_mode(stepper.SLEEP) # 设置滑轨使能 + stepper.goto(stepper_position) # 驱动滑轨移动到放置位置 + stepper_time = stepper_position/1000 # 计算需要的时间 + rospy.sleep(stepper_time) + + jetmax.set_position((x, y, z), 0.5) # 到放置位置 + rospy.sleep(0.5) + + sucker.release(3) + jetmax.set_position((x, y, z + 50), 0.5) + rospy.sleep(1) + + finally: + jetmax.set_position((cur_x, cur_y, cur_z), 1) # 机械臂回到初始位置 + stepper.goto(-stepper_position) # 滑轨回到初始位置 + stepper_time = stepper_position/1000 + rospy.sleep(stepper_time) + stepper.set_mode(stepper.EN) # 解除滑轨锁定 + state.moving_box = None + state.runner = None + print("FINISHED") + +# 图像处理函数 +def image_proc(image): + if state.runner is not None: + return image + + outputs = yolov5.detect(image) # 模型推理 + boxes, confs, classes = yolov5.post_process(image, outputs, 0.5) + width = image.shape[1] + height = image.shape[0] + cards = [] + waste_name = 'None' + for box, cls_conf, cls_id in zip(boxes, confs, classes): + x1 = int(box[0] / TRT_INPUT_SIZE * width) + y1 = int(box[1] / TRT_INPUT_SIZE * height) + x2 = int(box[2] / TRT_INPUT_SIZE * width) + y2 = int(box[3] / TRT_INPUT_SIZE * height) + waste_name = TRT_CLASS_NAMES[cls_id] # 得到检测到的分类名称 + + waste_class_name = '' + for k, v in WASTE_CLASSES.items(): + if waste_name in v: + waste_class_name = k + break + cards.append((cls_conf, x1, y1, x2, y2, waste_class_name)) + cv2.putText(image, waste_class_name, (x1, y1 - 25), + cv2.FONT_HERSHEY_SIMPLEX, 0.7, COLORS[waste_class_name], 2) + cv2.putText(image, waste_name + "{:0.2f}".format(float(cls_conf)), (x1, y1 - 5), + cv2.FONT_HERSHEY_SIMPLEX, 0.7, COLORS[waste_class_name], 2) + cv2.rectangle(image, (x1, y1), (x2, y2), COLORS[waste_class_name], 3) + + if len(cards) == 0: + state.count = 0 + state.moving_box = None + else: + if state.moving_box is None: + moving_box = max(cards, key=lambda card: card[0]) + conf, x1, y1, x2, y2, waste_class_name = moving_box + c_x, c_y = (x1 + x2) / 2, (y1 + y2) / 2 + state.moving_box = c_x, c_y, waste_class_name + else: + l_c_x, l_c_y, l_waste_class_name = state.moving_box + moving_box = min(cards, key=lambda card: math.sqrt((l_c_x - card[1]) ** 2 + (l_c_y - card[2]) ** 2)) + + conf, x1, y1, x2, y2, waste_class_name = moving_box + c_x, c_y = (x1 + x2) / 2, (y1 + y2) / 2 + # 在画面中标记出来 + image = cv2.rectangle(image, (x1, y1), (x2, y2), (255, 255, 255), 6) + image = cv2.circle(image, (int(c_x), int(c_y)), 1, (255, 255, 255), 10) + + if math.sqrt((l_c_x - c_x) ** 2 + (l_c_y - c_y) ** 2) > 30: + state.count = 0 + else: + c_x = l_c_x * 0.2 + c_x * 0.8 + c_y = l_c_y * 0.2 + c_y * 0.8 + state.count += 1 + state.moving_box = c_x, c_y, waste_class_name + if state.count > 50: #多次检测 + state.count = 0 + print(waste_name,waste_class_name) + state.runner = threading.Thread(target=moving, daemon=True) #开启移动子线程 + state.runner.start() + + return image + + +def show_fps(img, fps): + """Draw fps number at top-left corner of the image.""" + font = cv2.FONT_HERSHEY_PLAIN + line = cv2.LINE_AA + fps_text = 'FPS: {:.2f}'.format(fps) + cv2.putText(img, fps_text, (11, 20), font, 1.0, (32, 32, 32), 4, line) + cv2.putText(img, fps_text, (10, 20), font, 1.0, (240, 240, 240), 1, line) + return img + + +def image_proc_b(): + ros_image = image_queue.get(block=True) + image = np.ndarray(shape=(ros_image.height, ros_image.width, 3), dtype=np.uint8, buffer=ros_image.data) + result_img = image_proc(image) + # fps cal + fps_t1 = time.time() + fps_cur = (1.0 / (fps_t1 - state.fps_t0)) + state.fps = fps_cur if state.fps == 0.0 else (state.fps * 0.8 + fps_cur * 0.2) + state.fps_t0 = fps_t1 + show_fps(result_img, state.fps) + image_bgr = cv2.cvtColor(result_img, cv2.COLOR_RGB2BGR) + cv2.imshow(ROS_NODE_NAME, image_bgr) + cv2.waitKey(1) + + +def image_callback(ros_image): + try: + image_queue.put_nowait(ros_image) + except queue.Full: + pass + +if __name__ == '__main__': + rospy.init_node(ROS_NODE_NAME, log_level=rospy.DEBUG) + image_queue = queue.Queue(maxsize=2) + state = WasteClassification() + state.load_camera_params() + jetmax = hiwonder.JetMax() + sucker = hiwonder.Sucker() + stepper = hiwonder.Stepper(1) + jetmax.go_home(2,2) + stepper.go_home(True) + stepper.set_mode(stepper.EN) + stepper.set_div(stepper.DIV_1_4) + hiwonder.pwm_servo1.set_position(90, 0.5) + rospy.sleep(1) + yolov5 = Yolov5TensorRT(TRT_ENGINE_PATH, TRT_INPUT_SIZE, TRT_NUM_CLASSES) + image_sub = rospy.Subscriber('/usb_cam/image_rect_color', Image, image_callback) # 订阅摄像头画面 + + while True: + try: + image_proc_b() + if rospy.is_shutdown(): + sys.exit(0) + except KeyboardInterrupt: + break + diff --git a/src/stepper/scripts/yolov5_tensorrt.py b/src/stepper/scripts/yolov5_tensorrt.py new file mode 100644 index 0000000..4533795 --- /dev/null +++ b/src/stepper/scripts/yolov5_tensorrt.py @@ -0,0 +1,207 @@ +import cv2 +import sys +import os +import tensorrt as trt +import pycuda.autoinit +import pycuda.driver as cuda +import numpy as np +import math + + +# Simple helper data class that's a little nicer to use than a 2-tuple. +class HostDeviceMem: + def __init__(self, host_mem, device_mem): + self.host = host_mem + self.device = device_mem + + def __str__(self): + return "Host:\n" + str(self.host) + "\nDevice:\n" + str(self.device) + + def __repr__(self): + return self.__str__() + + +def sigmoid_v(array): + return np.reciprocal(np.exp(-array) + 1.0) + + +def sigmoid(x): + return 1 / (1 + math.exp(-x)) + + +def non_max_suppression(boxes, confs, classes, iou_thres=0.6): + x1 = boxes[:, 0] + y1 = boxes[:, 1] + x2 = boxes[:, 2] + y2 = boxes[:, 3] + areas = (x2 - x1 + 1) * (y2 - y1 + 1) + order = confs.flatten().argsort()[::-1] + keep = [] + while order.size > 0: + i = order[0] + keep.append(i) + xx1 = np.maximum(x1[i], x1[order[1:]]) + yy1 = np.maximum(y1[i], y1[order[1:]]) + xx2 = np.minimum(x2[i], x2[order[1:]]) + yy2 = np.minimum(y2[i], y2[order[1:]]) + w = np.maximum(0.0, xx2 - xx1 + 1) + h = np.maximum(0.0, yy2 - yy1 + 1) + inter = w * h + ovr = inter / (areas[i] + areas[order[1:]] - inter) + inds = np.where(ovr <= iou_thres)[0] + order = order[inds + 1] + boxes = boxes[keep] + confs = confs[keep] + classes = classes[keep] + return boxes, confs, classes + + +def xywh2xyxy(x): + # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right + y = np.zeros_like(x) + y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x + y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y + y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x + y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y + return y + + +def nms(pred, iou_thres=0.6): + boxes = xywh2xyxy(pred[..., 0:4]) + # best class only + confs = np.amax(pred[:, 5:], 1, keepdims=True) + classes = np.argmax(pred[:, 5:], axis=-1) + return non_max_suppression(boxes, confs, classes, iou_thres) + + +def make_grid(nx, ny): + """ + Create scaling tensor based on box location + Source: https://github.com/ultralytics/yolov5/blob/master/models/yolo.py + Arguments + nx: x-axis num boxes + ny: y-axis num boxes + Returns + grid: tensor of shape (1, 1, nx, ny, 80) + """ + nx_vec = np.arange(nx) + ny_vec = np.arange(ny) + yv, xv = np.meshgrid(ny_vec, nx_vec) + grid = np.stack((yv, xv), axis=2) + grid = grid.reshape(1, 1, ny, nx, 2) + return grid + + +def pre_process(img_in, w, h): + img_in = cv2.resize(img_in, (w, h), interpolation=cv2.INTER_LINEAR) + # img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + # img = img.transpose((2, 0, 1)).astype(np.float16) + img_in = np.transpose(img_in, (2, 0, 1)).astype(np.float32) + img_in = np.expand_dims(img_in, axis=0) + img_in /= 255.0 + img_in = np.ascontiguousarray(img_in) + return img_in + + +class Yolov5TensorRT: + def __init__(self, model, input_size, classes_num): + # load tensorrt engine + self.input_size = input_size + TRT_LOGGER = trt.Logger(trt.Logger.INFO) + with open(model, 'rb') as f, trt.Runtime(TRT_LOGGER) as runtime: + engine = runtime.deserialize_cuda_engine(f.read()) + self.context = engine.create_execution_context() + # allocate memory + inputs, outputs, bindings = [], [], [] + stream = cuda.Stream() + for binding in engine: + size = trt.volume(engine.get_binding_shape(binding)) + dtype = trt.nptype(engine.get_binding_dtype(binding)) + host_mem = cuda.pagelocked_empty(size, dtype) + device_mem = cuda.mem_alloc(host_mem.nbytes) + bindings.append(int(device_mem)) + if engine.binding_is_input(binding): + inputs.append(HostDeviceMem(host_mem, device_mem)) + else: + outputs.append(HostDeviceMem(host_mem, device_mem)) + # save to class + self.inputs = inputs + self.outputs = outputs + self.bindings = bindings + self.stream = stream + # post processing config + self.strides = np.array([8., 16., 32.]) + anchors = np.array([ + [[10, 13], [16, 30], [33, 23]], + [[30, 61], [62, 45], [59, 119]], + [[116, 90], [156, 198], [373, 326]], + ]) + self.nl = len(anchors) + self.nc = classes_num # classes + self.no = self.nc + 5 # outputs per anchor + self.na = len(anchors[0]) + a = anchors.copy().astype(np.float32) + a = a.reshape(self.nl, -1, 2) + self.anchors = a.copy() + self.anchor_grid = a.copy().reshape(self.nl, 1, -1, 1, 1, 2) + self.output_shapes = [ + (1, 3, int(input_size / 8), int(input_size / 8), self.nc + 5), + (1, 3, int(input_size / 16), int(input_size / 16), self.nc + 5), + (1, 3, int(input_size / 32), int(input_size / 32), self.nc + 5) + ] + + def detect(self, img): + shape_orig_WH = (img.shape[1], img.shape[0]) + resized = pre_process(img, self.input_size, self.input_size) + outputs = self.inference(resized) + # reshape from flat to (1, 3, x, y, 85) + reshaped = [] + for output, shape in zip(outputs, self.output_shapes): + reshaped.append(output.reshape(shape)) + return reshaped + + def inference(self, img): + # copy img to input memory + # self.inputs[0]['host'] = np.ascontiguousarray(img) + self.inputs[0].host = np.ravel(img) + # transfer data to the gpu + [cuda.memcpy_htod_async(inp.device, inp.host, self.stream) for inp in self.inputs] + # run inference + self.context.execute_async_v2(bindings=self.bindings, stream_handle=self.stream.handle) + # fetch outputs from gpu + [cuda.memcpy_dtoh_async(out.host, out.device, self.stream) for out in self.outputs] + # synchronize stream + self.stream.synchronize() + return [out.host for out in self.outputs] + + def post_process(self, image, outputs, conf_thres=0.2, nms_thres=0.6): + """ + Transforms raw output into boxes, confs, classes + Applies NMS thresholding on bounding boxes and confs + Parameters: + output: raw output tensor + Returns: + boxes: x1,y1,x2,y2 tensor (dets, 4) + confs: class * obj prob tensor (dets, 1) + classes: class type tensor (dets, 1) + """ + scaled = [] + grids = [] + for out in outputs: + out = sigmoid_v(out) + _, _, width, height, _ = out.shape + grid = make_grid(width, height) + grids.append(grid) + scaled.append(out) + z = [] + for out, grid, stride, anchor in zip(scaled, grids, self.strides, self.anchor_grid): + _, _, width, height, _ = out.shape + out[..., 0:2] = (out[..., 0:2] * 2. - 0.5 + grid) * stride + out[..., 2:4] = (out[..., 2:4] * 2) ** 2 * anchor + + out = out.reshape((1, 3 * width * height, self.no)) + z.append(out) + pred = np.concatenate(z, 1) + xc = pred[..., 4] > conf_thres + pred = pred[xc] + return nms(pred, nms_thres) diff --git a/test.jpg b/test.jpg new file mode 100644 index 0000000..2e50bc3 Binary files /dev/null and b/test.jpg differ