first_commit

This commit is contained in:
Robofish 2025-12-15 02:33:20 +08:00
commit cc767394b8
220 changed files with 120900 additions and 0 deletions

21
.clang-format Normal file
View File

@ -0,0 +1,21 @@
# https://github.com/ament/ament_lint/blob/rolling/ament_clang_format/ament_clang_format/configuration/.clang-format
---
Language: Cpp
BasedOnStyle: Google
AccessModifierOffset: -2
AlignAfterOpenBracket: AlwaysBreak
BraceWrapping:
AfterClass: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterEnum: true
BreakBeforeBraces: Custom
ColumnLimit: 100
ConstructorInitializerIndentWidth: 0
ContinuationIndentWidth: 2
DerivePointerAlignment: false
PointerAlignment: Middle
ReflowComments: false
...

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
.vscode/
.github/
build/
Camera/
logs/
assets/img_with_q/
records/
records_auto_buff_big/
records_new/
imgs/
MvSdkLog/
testvideos/
watchdog.sh
records_24/
records_25/

131
CMakeLists.txt Normal file
View File

@ -0,0 +1,131 @@
cmake_minimum_required(VERSION 3.16.3)
project(sp_vision)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_BUILD_TYPE Release)
message(STATUS "--------------------CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}--------------------")
find_package(OpenCV REQUIRED)
find_package(fmt REQUIRED)
find_package(Eigen3 REQUIRED)
find_package(spdlog REQUIRED)
find_package(yaml-cpp REQUIRED)
find_package(nlohmann_json REQUIRED)
set(OpenVINO_DIR "/opt/intel/openvino_2024.6.0/runtime/cmake/")
find_package(OpenVINO REQUIRED)
include_directories(${EIGEN3_INCLUDE_DIR})
include_directories(${OpenCV_INCLUDE_DIRS})
include_directories(${PROJECT_SOURCE_DIR})
add_subdirectory(tools)
add_subdirectory(io)
add_subdirectory(tasks/auto_aim)
add_subdirectory(tasks/auto_buff)
add_subdirectory(tasks/omniperception)
####################src###################
add_executable(standard src/standard.cpp)
add_executable(mt_standard src/mt_standard.cpp)
add_executable(standard_mpc src/standard_mpc.cpp)
add_executable(auto_aim_debug_mpc src/auto_aim_debug_mpc.cpp)
add_executable(mt_auto_aim_debug src/mt_auto_aim_debug.cpp)
add_executable(auto_buff_debug src/auto_buff_debug.cpp)
add_executable(auto_buff_debug_mpc src/auto_buff_debug_mpc.cpp)
add_executable(uav src/uav.cpp)
add_executable(uav_debug src/uav_debug.cpp)
target_link_libraries(standard ${OpenCV_LIBS} fmt::fmt yaml-cpp auto_aim auto_buff tools io)
target_link_libraries(mt_standard ${OpenCV_LIBS} fmt::fmt yaml-cpp auto_aim auto_buff tools io)
target_link_libraries(standard_mpc ${OpenCV_LIBS} fmt::fmt yaml-cpp auto_aim auto_buff tools io)
target_link_libraries(auto_aim_debug_mpc ${OpenCV_LIBS} fmt::fmt yaml-cpp auto_aim auto_buff tools io)
target_link_libraries(mt_auto_aim_debug ${OpenCV_LIBS} fmt::fmt yaml-cpp auto_aim auto_buff tools io)
target_link_libraries(auto_buff_debug ${OpenCV_LIBS} fmt::fmt yaml-cpp auto_buff tools io ${CERES_LIBRARIES})
target_link_libraries(auto_buff_debug_mpc ${OpenCV_LIBS} fmt::fmt yaml-cpp auto_buff tools io ${CERES_LIBRARIES})
target_link_libraries(uav ${OpenCV_LIBS} fmt::fmt yaml-cpp auto_aim auto_buff tools io)
target_link_libraries(uav_debug ${OpenCV_LIBS} fmt::fmt yaml-cpp auto_aim tools io)
##################calibration################
add_executable(capture calibration/capture.cpp)
add_executable(calibrate_camera calibration/calibrate_camera.cpp)
add_executable(calibrate_handeye calibration/calibrate_handeye.cpp)
add_executable(calibrate_robotworld_handeye calibration/calibrate_robotworld_handeye.cpp)
add_executable(split_video calibration/split_video.cpp)
target_link_libraries(capture ${OpenCV_LIBS} fmt::fmt tools io)
target_link_libraries(calibrate_camera ${OpenCV_LIBS} fmt::fmt yaml-cpp tools)
target_link_libraries(calibrate_handeye ${OpenCV_LIBS} fmt::fmt yaml-cpp tools)
target_link_libraries(calibrate_robotworld_handeye ${OpenCV_LIBS} fmt::fmt yaml-cpp tools)
target_link_libraries(split_video ${OpenCV_LIBS} fmt::fmt tools)
##################tests##################
add_executable(auto_aim_test tests/auto_aim_test.cpp)
add_executable(auto_buff_test tests/auto_buff_test.cpp)
add_executable(camera_detect_test tests/camera_detect_test.cpp)
add_executable(camera_test tests/camera_test.cpp)
add_executable(camera_thread_test tests/camera_thread_test.cpp)
add_executable(cboard_test tests/cboard_test.cpp)
add_executable(fire_test tests/fire_test.cpp)
add_executable(detector_video_test tests/detector_video_test.cpp)
add_executable(gimbal_response_test tests/gimbal_response_test.cpp)
add_executable(multi_usbcamera_test tests/multi_usbcamera_test.cpp)
add_executable(usbcamera_detect_test tests/usbcamera_detect_test.cpp)
add_executable(usbcamera_test tests/usbcamera_test.cpp)
add_executable(handeye_test tests/handeye_test.cpp)
add_executable(dm_test tests/dm_test.cpp)
add_executable(minimum_vision_system tests/minimum_vision_system.cpp)
target_link_libraries(auto_aim_test ${OpenCV_LIBS} fmt::fmt yaml-cpp tools io auto_aim)
target_link_libraries(auto_buff_test ${OpenCV_LIBS} fmt::fmt yaml-cpp auto_buff tools io)
target_link_libraries(camera_detect_test ${OpenCV_LIBS} fmt::fmt yaml-cpp tools auto_aim io)
target_link_libraries(camera_test ${OpenCV_LIBS} fmt::fmt tools io)
target_link_libraries(camera_thread_test ${OpenCV_LIBS} fmt::fmt auto_aim tools io)
target_link_libraries(cboard_test ${OpenCV_LIBS} fmt::fmt tools io)
target_link_libraries(fire_test ${OpenCV_LIBS} fmt::fmt tools io)
target_link_libraries(detector_video_test ${OpenCV_LIBS} fmt::fmt yaml-cpp tools auto_aim)
target_link_libraries(gimbal_response_test ${OpenCV_LIBS} fmt::fmt yaml-cpp tools io)
target_link_libraries(multi_usbcamera_test ${OpenCV_LIBS} fmt::fmt tools io)
target_link_libraries(usbcamera_detect_test ${OpenCV_LIBS} fmt::fmt yaml-cpp tools io auto_aim)
target_link_libraries(usbcamera_test ${OpenCV_LIBS} fmt::fmt yaml-cpp tools io)
target_link_libraries(handeye_test ${OpenCV_LIBS} fmt::fmt yaml-cpp tools io auto_aim)
target_link_libraries(dm_test ${OpenCV_LIBS} fmt::fmt yaml-cpp tools io)
target_link_libraries(minimum_vision_system ${OpenCV_LIBS} fmt::fmt yaml-cpp tools io auto_aim)
add_executable(gimbal_test tests/gimbal_test.cpp)
target_link_libraries(gimbal_test ${OpenCV_LIBS} fmt::fmt yaml-cpp auto_aim tools io)
add_executable(planner_test tests/planner_test.cpp)
target_link_libraries(planner_test ${OpenCV_LIBS} fmt::fmt yaml-cpp auto_aim tools io)
add_executable(planner_test_offline tests/planner_test_offline.cpp)
target_link_libraries(planner_test_offline ${OpenCV_LIBS} fmt::fmt yaml-cpp auto_aim tools io)
# ROS
find_package(ament_cmake QUIET)
find_package(rclcpp QUIET)
find_package(std_msgs QUIET)
find_package(rosidl_typesupport_cpp QUIET)
find_package(sp_msgs QUIET)
# ROS sentry publish_test
if(ament_cmake_FOUND AND rclcpp_FOUND AND std_msgs_FOUND AND rosidl_typesupport_cpp_FOUND AND sp_msgs_FOUND)
# sentry publish_test
add_executable(sentry src/sentry.cpp)
add_executable(sentry_bp src/sentry_bp.cpp)
add_executable(sentry_debug src/sentry_debug.cpp)
add_executable(sentry_multithread src/sentry_multithread.cpp)
add_executable(publish_test tests/publish_test.cpp)
add_executable(subscribe_test tests/subscribe_test.cpp)
add_executable(topic_loop_test tests/topic_loop_test.cpp)
target_link_libraries(sentry ${OpenCV_LIBS} fmt::fmt yaml-cpp auto_aim omniperception tools io)
target_link_libraries(sentry_bp ${OpenCV_LIBS} fmt::fmt yaml-cpp auto_aim omniperception tools io)
target_link_libraries(sentry_debug ${OpenCV_LIBS} fmt::fmt yaml-cpp auto_aim omniperception tools io)
target_link_libraries(sentry_multithread ${OpenCV_LIBS} fmt::fmt yaml-cpp auto_aim omniperception tools io)
target_link_libraries(publish_test ${OpenCV_LIBS} fmt::fmt tools io auto_aim)
target_link_libraries(subscribe_test ${OpenCV_LIBS} fmt::fmt tools io)
target_link_libraries(topic_loop_test ${OpenCV_LIBS} fmt::fmt tools io)
else()
message(STATUS "ROS2 environment not found, skipping ROS2-related code.")
endif()

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 TongjiSuperPower
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.

BIN
assets/best2-sim.onnx Normal file

Binary file not shown.

BIN
assets/demo/demo.avi Normal file

Binary file not shown.

620
assets/demo/demo.txt Normal file
View File

@ -0,0 +1,620 @@
0.752677887 0.5014435722929029 0.02327065116579723 0.0019472255628188646 0.8648751522116124
25.824433869 0.4044806118882999 -0.019203333238947136 0.007353485765453223 0.9143153683746531
25.897933452 0.3983196747926323 -0.0436570165419713 0.018327136925283163 0.9160238084416079
25.937844162 0.4060992801021506 -0.060038428432863424 0.024035605927579317 0.911537740008345
25.971199735 0.41094740236919536 -0.05302595072734453 0.022424116638938174 0.9098393484722648
26.004610259 0.40968966344416635 -0.06222787384895668 0.026676178451042067 0.9097089935174283
26.038064416 0.4052178756282984 -0.06004722598623817 0.025247798677895384 0.9118965690167756
26.077887404 0.40238001786745814 -0.05878320483250864 0.02484137457076296 0.9132457293412537
26.111296109 0.40071966107416385 -0.060104792050292295 0.025001993365346215 0.91388515007574
26.14465991 0.40002642058153615 -0.05785093696523309 0.02402514483049273 0.9143603908442461
26.178099861 0.39929477459454044 -0.057247371909738026 0.02370218810986068 0.9147265316310269
26.218006534 0.39592077215767296 -0.05910142357447336 0.024000578101308977 0.916066447456922
26.258174622 0.3914227776785776 -0.06137418865489941 0.024358413852926662 0.9178388125133461
26.297970237 0.3855702178436289 -0.06842624749883933 0.02654238434945672 0.9197548355938607
26.331391866 0.37864028600252797 -0.07377439499650759 0.027719254342318013 0.9221824740242731
26.364852852 0.36916508135424514 -0.08236062699653302 0.030084141809927266 0.9252182522199894
26.398257869 0.35781284168321736 -0.09010595648555406 0.031602689105865805 0.9288983566427934
26.438065898 0.3423988381374929 -0.094062894882146 0.031306837908086714 0.9343099535746594
26.471630757 0.3284589912585138 -0.100292321321941 0.03340331127965669 0.9385842317772286
26.511411364 0.30648004432504633 -0.10372794354937309 0.02920252880446784 0.9457577430129557
26.544782875 0.2877371342097568 -0.10816547583833148 0.03136957635674919 0.9510644148072316
26.578234048 0.27056379547459847 -0.11476815782525768 0.028758032907769022 0.9554038298390122
26.618249467 0.24702723299386736 -0.11930861794076049 0.029647629255281208 0.9611784526943998
26.65819223 0.22474004532143046 -0.12747277314000643 0.02684990433599021 0.9656716247120788
26.691595323 0.20478718291793538 -0.1354562932082495 0.026679200858173283 0.9690211672530101
26.731533578 0.18464779929792222 -0.14656507828977644 0.02557516004343661 0.9714781414057131
26.764973543 0.16962745445697788 -0.15571367025164942 0.024602979225598506 0.9728178005178726
26.804876967 0.15668079501547813 -0.165082270044186 0.021902446350445876 0.9735087341335167
26.838271933 0.14948108929914852 -0.17336450566714282 0.023865026107513124 0.973154978739571
26.878294766 0.14670414846347568 -0.17732779299413426 0.022900647578824766 0.9728865848576116
26.918471623 0.16793725762402759 -0.1556833711631501 0.024272873455547277 0.9731241406209225
26.958307164 0.18634764447388283 -0.14828721348713966 0.02716398992035998 0.9708488941987118
26.991752292 0.19135093840176348 -0.1409333380258021 0.02560205317865002 0.9710134641078398
27.031645647 0.19548121140962427 -0.13017912492072262 0.024075762752732745 0.9717308521749091
27.065002019 0.2030810496528304 -0.11954184165675422 0.022601603668929358 0.9715744968229708
27.098378842 0.21533477553100352 -0.10884752288991607 0.02217154034270757 0.9702018212756423
27.138566887 0.2309530705457854 -0.10363395684749488 0.023384977600967825 0.9671472612876528
27.178444982 0.2610574165126007 -0.07534989163557612 0.01975464577855268 0.9621752299266685
27.211783938 0.28189139816589925 -0.06455159511978166 0.01934054677327865 0.9570769428097602
27.251917112 0.30344756555078894 -0.05920441836657583 0.018158406704229697 0.9508336784491486
27.285291209 0.3197638072317074 -0.052305763630237506 0.0190128093844623 0.9458613681481295
27.325135927 0.34050741054630956 -0.04356369533756827 0.01739493407681777 0.9390709899044084
27.358476022 0.36074398179533307 -0.043177686734943606 0.017975353795504252 0.9314914672838361
27.391868412 0.3787823021316463 -0.03624523535416737 0.01568693148279716 0.9246427259685901
27.42522498 0.3984670274873839 -0.04007924788396457 0.017989448735969783 0.9161299370878566
27.465429627 0.4195406147954505 -0.03692008972117208 0.01825845120939563 0.9068016367825271
27.505361927 0.4428245058408616 -0.03847256797862454 0.01988862267960126 0.8955617015191278
27.538757471 0.46230490758180315 -0.03792234735216942 0.02220157131743785 0.8856315025043535
27.578597084 0.4838649748930099 -0.04076880357753215 0.02443333342290202 0.8738510187351668
27.612003127 0.5029620477890874 -0.04332278759451557 0.027400941729415852 0.8627870553915313
27.645609807 0.5164711925243503 -0.04852694340232439 0.03269867674780466 0.8543028968670572
27.685514463 0.5346476087719997 -0.052552062589177925 0.03330828442595869 0.8427815691747212
27.725445945 0.5483503022201482 -0.05677974866673668 0.04052650103918396 0.833334032012335
27.758780308 0.5604878399036811 -0.058961518326285545 0.04247728364422499 0.824968242449958
27.798875869 0.571417869922125 -0.06320457473969693 0.046910106558344385 0.8168759034078068
27.83230702 0.5793812677133586 -0.06757245519538539 0.048605247049575986 0.8107951898482002
27.87214098 0.5939104023850323 -0.06534585789781365 0.0508035152165781 0.800262054352252
27.912176896 0.5854053622748845 -0.0647026264982299 0.04940118779555409 0.806643449479651
27.945738619 0.5484893523181781 -0.06296952524452691 0.04326309904847135 0.8326599387173533
27.985561072 0.5023457335699482 -0.06007586355282575 0.036143248490428076 0.861819772441438
28.025565824 0.48265743343532164 -0.05297786338571968 0.02931557823091408 0.873713765951813
28.058924678 0.47321784897275215 -0.04940209718149981 0.027201154723416898 0.87913844040025
28.098993169 0.454826580318603 -0.04068404964729429 0.020584409203952665 0.8894120934851888
28.138865086 0.43209180787629975 -0.03808694033648821 0.018506465746383264 0.9008349267582678
28.172422693 0.4146567620523134 -0.028721650974283558 0.012880152825570333 0.9094333060278761
28.212409768 0.4165125396419987 -0.04340323269539244 0.021428768549504835 0.9078404439057637
28.245832927 0.4084996986948947 -0.04176063927302493 0.019259226597509577 0.9115992142189211
28.285655953 0.3837377360348871 -0.04162778955717806 0.01723239944012399 0.9223424101107672
28.319103435 0.34663020129947947 -0.05575000855977064 0.020189405315549035 0.9361259680222915
28.359132216 0.3215898402058671 -0.06694038194132015 0.02121937972090072 0.9442715170257839
28.39893612 0.3191246191429412 -0.0856146732825442 0.02549929462302405 0.9434931855341215
28.432387406 0.311282249380152 -0.10399925402143416 0.03281288350827445 0.9440396342631439
28.472413896 0.3027637644227617 -0.1442911954492042 0.042430382176946085 0.9411236988497933
28.512438655 0.2792311437803485 -0.19292151186743026 0.0530538305086665 0.9391467136024387
28.552487544 0.25399677541556676 -0.2227387876177815 0.054100275930032804 0.9396521860312725
28.586039756 0.2565817998246983 -0.24347813752778957 0.06245154897650981 0.9332652252040423
28.625817307 0.29769257489780704 -0.2354296157143852 0.072967502762912 0.9222948392113202
28.65918369 0.31398004396575024 -0.23344648938751542 0.07823336000621821 0.9169508219997666
28.692535692 0.31150059834170446 -0.23627797301834827 0.07734464473301211 0.9171466091254031
28.725869117 0.30290876772937103 -0.22655739560738158 0.07226151040671558 0.922873934533864
28.765799969 0.30123134447545497 -0.187413394701377 0.05712519180985434 0.9332055556267885
28.799252042 0.3041879950337558 -0.1657474708904943 0.05170527857763309 0.9366557551939549
28.83281661 0.31099686973283364 -0.12893354694262157 0.03941615610368397 0.9407993697527565
28.872692948 0.315227209620526 -0.12035272852321002 0.037414039040739464 0.9406100237263759
28.912720524 0.3154260116678618 -0.10679714618271541 0.032446845303020014 0.9423629889593582
28.952760607 0.31613276095486886 -0.1045108304959943 0.03200331651551979 0.9423976610179468
28.992661348 0.3156462155986657 -0.10589643353602368 0.03231755011857671 0.9423953458591169
29.032576927 0.314815368087299 -0.10450510154105064 0.031801552430673785 0.9428460261521774
29.066041179 0.3148639043329818 -0.10515409891927241 0.03220150564769405 0.9427440799404091
29.105976656 0.3148248942489635 -0.10505843638464234 0.032002530546273285 0.9427745483116193
29.139375245 0.31452325985513124 -0.10510777300723144 0.032002366662525275 0.942869727794651
29.172731973 0.3148245305089792 -0.10500818203126688 0.03220250915625518 0.9427734590559551
29.206294979 0.31525741283153325 -0.10510685476651474 0.032002087084000694 0.9426246226139687
29.246181549 0.3146354063412599 -0.10531185088281841 0.03210361266228367 0.9428060952253837
29.279588728 0.31492782510257605 -0.10460924263489824 0.032202845247071926 0.9427832985843075
29.319473832 0.3292795253786904 -0.05527650227395744 0.01743693655655526 0.9424518320350724
29.359443762 0.3567154861057565 -0.023190959454469157 0.008381725248960104 0.9338875671373755
29.392987327 0.360946593189094 -0.04470723120881977 0.014463611798745599 0.9314019670778901
29.432980661 0.34577297778749766 -0.11129112511418768 0.03910734338753012 0.9308737556704211
29.472866367 0.3310136170867147 -0.13852117797464425 0.046104784748342106 0.932264027719077
29.50637431 0.32634270221054634 -0.15144298392210845 0.0499821024659049 0.9317012679865658
29.546290163 0.32651364207192 -0.17929210883548183 0.05979575993220456 0.9261034760459471
29.586258229 0.3207882708899325 -0.2109358301925009 0.07033174620624963 0.920681490134361
29.626251253 0.3173645078894013 -0.22428208807123948 0.07354740778710415 0.9184596305283756
29.659858131 0.3149299011405167 -0.2271949905143246 0.07391106915404334 0.9185525284431624
29.699635647 0.3159754663811358 -0.2325000272672274 0.07614490269132208 0.9166816218077525
29.733141129 0.31843723826828896 -0.22883963567773133 0.07558358435495449 0.91679728850112
29.773035006 0.32315472577674303 -0.1966484277758075 0.06518853581097142 0.9233909647924237
29.806553861 0.3255257062845889 -0.18414720918973623 0.0617048727427316 0.925373075346022
29.846479871 0.324835280905318 -0.15337750844106096 0.0502745022225885 0.9318958389272088
29.886403411 0.3248880692958557 -0.12357078512198329 0.04067624659138025 0.9367622144689576
29.926389194 0.3264593571862328 -0.08671084772300566 0.028153929331478582 0.9408043756572922
29.959840492 0.3283675311496364 -0.05622802944971049 0.01805900866458588 0.9427019918282487
29.999770493 0.3307567180131652 -0.010821135472014803 0.002527329810063534 0.9436506287394117
30.033161415 0.3320567726442118 0.0025965095322532357 -0.0018482956263382029 0.9432540175809679
30.066523885 0.3342815614753687 0.025411818591313442 -0.01012335377226029 0.942076214985748
30.106499966 0.3382845206792486 0.044224933480299655 -0.0165699225687323 0.9398580616207644
30.139866396 0.3401183879702809 0.05720737205044044 -0.021252432746559503 0.9384003052268968
30.179989005 0.34256937750165134 0.06619532394759138 -0.02430110224744672 0.9368424932266702
30.219842067 0.344623430236308 0.059878104556614964 -0.022311130314846956 0.9365636750327987
30.253276402 0.34522447628295433 0.05522026732492536 -0.02065964087518999 0.9366664092891513
30.286641332 0.3451187515838374 0.04860151789103361 -0.018292598243356377 0.9371212945042965
30.326675126 0.3438457407107739 0.04832093668524092 -0.01830201934721479 0.9376034501646922
30.366667361 0.3429318533799306 0.03413163782197401 -0.013270694643356435 0.9386461867501932
30.400078661 0.34099087160867003 0.009880972929028852 -0.004427041687738833 0.9400042516688052
30.439933789 0.3337466350949278 -0.04479772856893368 0.015465943953540087 0.9414707386082178
30.473359852 0.327502001625859 -0.04822546446444369 0.01554501461772024 0.9434909093514253
30.506713728 0.32742515100044156 -0.05396348614326533 0.017189703551363827 0.9431782582033048
30.540067363 0.32762673246303753 -0.0692522807086646 0.022457088218536425 0.9419981555082719
30.580183256 0.3211706030541114 -0.13150514868757188 0.04340804157037819 0.936841278728442
30.620118924 0.3156623157618935 -0.15152403620692897 0.048945734663551704 0.935415460593658
30.653556381 0.31251469315972596 -0.17233735877100592 0.055033408585554396 0.9325265279178772
30.693612598 0.30707801890832764 -0.201591008905681 0.06279686470201684 0.9279658987351438
30.733401342 0.3070144936742045 -0.2180656699052845 0.06916985484325372 0.9237992181549487
30.766763122 0.307516455225731 -0.2285795236638387 0.07338757315311484 0.9207601724845129
30.800130476 0.30685308901421826 -0.2363146033564864 0.07590469062529547 0.9188226531512906
30.833570583 0.31304294798738397 -0.18654854721808672 0.059324835261395314 0.9293461767110238
30.873680288 0.3179267616358679 -0.1587133597722939 0.051604343820103114 0.9333111139188353
30.913521915 0.31398354851894233 -0.15394153937504743 0.04853342238545297 0.9356072042400321
31.080372626 0.31321944996563716 -0.1506093523781129 0.047502949787253404 0.9364581511744019
31.113758022 0.3088298470777448 -0.0974729465717457 0.028097697739777907 0.9456921643020432
31.15368512 0.28208488208503557 -0.085771531000141 0.022564467961138535 0.9552812196178643
31.18702301 0.2616628145118343 -0.08315458740030784 0.01818988565662334 0.9613984679391939
31.220453011 0.247896361568307 -0.06999324306994446 0.014566461258688601 0.9661449984614866
31.260330085 0.23110617691853164 -0.07257634513517928 0.013824733687868419 0.9701193152676527
31.293733821 0.2202888951997949 -0.06696486874124245 0.012200800488341431 0.973056858294296
31.327167668 0.2112520306738455 -0.06458384143320492 0.011464277138012064 0.9752282180657049
31.36052945 0.19972929183072463 -0.058442444889792354 0.009600770030694117 0.9780595666087617
31.393946942 0.195298987116921 -0.06071821612280596 0.008800591361365616 0.9788228406885789
31.427284711 0.1884055201932333 -0.056530448392185614 0.007963294597824626 0.9804306473710642
31.467105136 0.1809636017918513 -0.058018052413492005 0.0074003701882794995 0.9817491099775655
31.507183596 0.17685620474810448 -0.05806968583402605 0.007400621854908224 0.9824942876299052
31.547212613 0.16466045534051527 -0.059204781976887055 0.006700193527206321 0.9845490519241901
57.646185138 0.3648277315793616 0.0025002234819031127 -0.001300098824158909 0.9310707733014958
57.679691503 0.35939410032381164 0.003681914957301948 -0.002094031130928149 0.9331762637295851
57.71305164 0.3601129890279416 -0.03938227313049235 0.014928919849971368 0.9319575092505827
57.753067919 0.36876978940305033 -0.07447976382732267 0.028640860117576963 0.926089255058918
57.793093463 0.3755303499851984 -0.06476356468277647 0.025402052968372942 0.924195527274703
57.833076037 0.37505547533571193 -0.0693647513044173 0.027802568360908445 0.9239853564260185
57.872958251 0.371648935723233 -0.0685273769739429 0.02712443229489106 0.9254433166615551
57.906291651 0.3698817896467579 -0.06704118431847518 0.026201377701737485 0.926286364522019
57.946298377 0.36883775196533913 -0.06956436196205014 0.026960001241541888 0.9264948303164049
57.979743529 0.36771210408958105 -0.06789539441821965 0.02590238061688819 0.9270960525216282
58.01307696 0.3660305216376218 -0.06936753172424923 0.026583477045683517 0.9276330748309578
58.052974633 0.3643509402540849 -0.06872859753131956 0.02640199542584913 0.9283467600282103
58.086505113 0.36332175280535794 -0.06870977841227453 0.02625440421377999 0.928755606469408
58.126570832 0.3621776022579473 -0.06945023327718987 0.026402468538066267 0.9291431316947484
58.166469941 0.3597280954018862 -0.07164803946981183 0.02704955467844082 0.9299089081250711
58.199900426 0.35647340016840284 -0.07736889913395652 0.029023119575736042 0.9306440925237048
58.239864087 0.3514784440798335 -0.08366090281104806 0.03073943108649393 0.9319435841640515
58.273396205 0.34623189094108586 -0.09170006766039057 0.03309975448491024 0.933069655245244
58.313314371 0.3374310922974114 -0.10038541388923851 0.03489764152998602 0.9353315889271071
58.353324331 0.327247779651809 -0.10840353029644155 0.03620402773962069 0.9380015105039321
58.386708159 0.32084967489258137 -0.11230649023244715 0.036469268088100394 0.9397407785438027
58.420110256 0.31312522948248706 -0.11724194944659518 0.037205319884909466 0.9417126313922755
58.459890547 0.2934158767140341 -0.1388722335495908 0.040950048927314096 0.9449575226082564
58.493474575 0.28391013881347704 -0.1474430651071003 0.04211535504946051 0.946510365764577
58.533395611 0.2799214687055404 -0.15989369219174132 0.044500901904946585 0.9455673684538147
58.573331218 0.2763304265699522 -0.1738098073833949 0.047902215360459445 0.9440005423582
58.613252003 0.274635833710138 -0.1851832836280359 0.05059342615452792 0.9421903287218684
58.646809776 0.27439578896301897 -0.19183288427053158 0.05277666438157558 0.9408090769165474
58.68670508 0.2734499045567866 -0.1939459675217642 0.05350264945124146 0.9406102157012908
58.726659999 0.2703606687750818 -0.19308909508172478 0.05220484193570918 0.9417517531804647
58.760194601 0.26848646144490124 -0.18647101365306806 0.04989948326164886 0.9437444689417859
58.800091022 0.2672177509023071 -0.1748348539570433 0.04656774141441302 0.9464982265720799
58.840027909 0.26672276279028617 -0.15613398075798654 0.041341451714856106 0.9501431640717569
58.873411026 0.26730627161015935 -0.1377186299679909 0.03640504803532092 0.9530244533038811
58.913491169 0.267306647262335 -0.11594112896747992 0.0303817542261305 0.9561285269006772
58.953486966 0.26760993558545765 -0.09298748317700264 0.023696524552685096 0.9587370468864119
58.986896014 0.2684987185719504 -0.07613944241148507 0.018971515054979834 0.9600788014798616
59.026930521 0.27147298641603634 -0.0537368583379652 0.013143257657024324 0.9608548394427148
59.066903569 0.2757755204858268 -0.034311853833894984 0.007947104326678526 0.9605765989862931
59.100260082 0.2789962725356336 -0.02058850829599111 0.004222067172057051 0.9600621685006462
59.133635337 0.280729665148298 -0.0076084474944423655 0.0006737538540854326 0.9597564861402046
59.167015679 0.28310252320476503 0.0024970573964317837 -0.00216577863043965 0.9590839564200719
59.206883378 0.28586696886309737 0.01334532404459 -0.005048480852492831 0.9581630817769238
59.240381069 0.2874075173807805 0.022003848343924756 -0.007651018322476242 0.9575250448576805
59.280263498 0.2883515447825343 0.025640446260136892 -0.008839736495476532 0.9571404354616921
59.31368658 0.2890182194808034 0.02821762825440461 -0.009516449346823212 0.9568603197205283
59.347298376 0.2889153881977819 0.026502940620754204 -0.009000426936712078 0.9569453928599765
59.387020221 0.28713766647345373 0.023147914945962314 -0.008216010472606861 0.9575743478695261
59.420461592 0.28566612440829653 0.017049436942301356 -0.006449856983485678 0.9581558231365015
59.460346171 0.2847212276456365 0.007801813220703021 -0.0037008916980609337 0.9585714671525907
59.493884887 0.28489390344878146 0.0004908958586388112 -0.001553619322662375 0.958557671225875
59.533705066 0.2830206185816189 -0.019982702000005712 0.0040246109056272066 0.9588971913534396
59.567245962 0.28142431079927405 -0.03430018739554989 0.008371431959058652 0.9589336648396168
59.60708867 0.280308255851015 -0.049880761174041555 0.01276013983733152 0.9585282312993145
59.640467299 0.2787649308114513 -0.06437196433450137 0.016457017644675297 0.958058208110367
59.673882936 0.2771935994115264 -0.07916682342006238 0.020737205304306502 0.9573224591698588
59.713885138 0.2746909690270775 -0.09632564400615011 0.02518388503298312 0.9563639546618281
59.753815901 0.2741171465659534 -0.11080133999916107 0.029125424141915345 0.9548479264686516
59.787474612 0.27420963270161186 -0.12284048621704814 0.03281320968003316 0.9532274574046325
59.827247797 0.2746074941695586 -0.13359023495548616 0.0361976740755462 0.951543010936434
59.860695477 0.2750936394584554 -0.1406197928985947 0.03807247857911732 0.9503157631805864
59.90054314 0.2747201705490309 -0.14527095340460258 0.03940289304562001 0.9496697268050954
59.934049841 0.2750193586155686 -0.148949280473019 0.040502850996111006 0.9489667977829562
59.973959253 0.27412126356538025 -0.15448185688784744 0.042073137352098666 0.9482735575070906
60.007318902 0.2740216010757454 -0.15461521604839573 0.042205345545121356 0.9482747523358459
60.047302748 0.27431062504513654 -0.1480072023983457 0.040102043145115986 0.949336281388818
60.087423516 0.27462680180856897 -0.13146965567843455 0.034409525993149566 0.9518990670680993
60.120785661 0.27542878501884666 -0.13352188907119297 0.03580374184340854 0.9513301117866041
60.154181941 0.2742236561334814 -0.13677340081460995 0.0367031662293901 0.9511820545169732
60.1940437 0.2750566903523599 -0.10277152530977768 0.026483886164914996 0.9555524237065759
60.227515539 0.27754067726615284 -0.062063430532637034 0.015683429985613236 0.9585788090068819
60.267432144 0.2774233745832361 -0.0598201423342465 0.014705573070768592 0.9587708630984884
60.307483302 0.2770237550885866 -0.04626981951180268 0.01089239699100195 0.9596865626894827
60.347437713 0.27681844922520893 -0.029758710987930707 0.006486096043002889 0.9604394285154105
60.381027699 0.277412988347121 -0.019566489315750134 0.0035415591196058336 0.960544972268961
60.420908029 0.2785889332634186 0.01006048009946837 -0.005028237337328633 0.9603445786969375
60.46097436 0.28091585121888696 0.017085858088799973 -0.007085293787664801 0.9595541446939199
60.50093872 0.2822986613948781 0.021347961278119 -0.007982704177122624 0.9590557891791012
60.534317552 0.28345973360606685 0.02364509443060165 -0.008600484591643576 0.9586540150638991
60.567686078 0.28392580334411344 0.024721410965704366 -0.008800799821867556 0.9584871078724847
60.601134895 0.28369488034782964 0.026191995964036263 -0.009400105294010322 0.9585107366286056
60.64098427 0.2845070080118677 0.02567377340725567 -0.00941870582720424 0.958283834639669
60.681035995 0.2852300783730423 0.012649299246872954 -0.005412466437362554 0.9583603199355323
60.721056573 0.28443123442982315 0.007414061375186405 -0.004000247986348545 0.9586594299284287
60.760950423 0.2845019932975103 -0.0008613114356811632 -0.001579706486831008 0.9586737601915314
60.794346753 0.2848613354630318 -0.024229759872585188 0.005311685742634968 0.9582477363862157
60.827683646 0.284014202386103 -0.032295726940009144 0.007338011729121775 0.9582479180505772
60.861059918 0.2845095607832369 -0.045307837181211605 0.01156023760536584 0.9575321773284687
60.894418265 0.2844159262635979 -0.06201152709322005 0.016353332129045144 0.9565535635412497
60.927853232 0.28329829541775264 -0.07787573172405092 0.020758259805666403 0.9556393361889619
60.967822384 0.28230882822833464 -0.09547560242921625 0.026050133702126322 0.954205179916366
61.007852874 0.28180987820301423 -0.10726356102589757 0.029254292491293066 0.9530067719560443
61.047793891 0.28092241133537277 -0.12055656628538143 0.033044621526746 0.9515549201823047
61.081297135 0.28131808585239404 -0.13162044158457847 0.03630638562412605 0.9498515885612542
61.121126465 0.2827108332999337 -0.14174546260265558 0.03957752898837435 0.9478483147453451
61.154576236 0.283791753554629 -0.14830510399666721 0.0416675929157472 0.9464310056435885
61.194722847 0.2854004613278448 -0.15143880308621713 0.04312906788465369 0.9453849740169706
61.234615585 0.2865944179029341 -0.15324757293495053 0.04403714683332024 0.9446901876886443
61.268036279 0.2866302970700691 -0.15064630796320014 0.04337631566709277 0.9451281701111915
61.307955206 0.2860798252793477 -0.14874561154348634 0.04223665641173193 0.9456474720898108
61.341304937 0.28563435663316866 -0.14678701439683384 0.0414955630347826 0.9461208722798826
61.374700703 0.28531184809918114 -0.12376644738366559 0.03455950353679075 0.9497813730283127
61.408128753 0.285867897914429 -0.11584382382246575 0.03246127675785646 0.9506871298883902
61.441511647 0.28593200766477295 -0.10514477186184161 0.02907645558108238 0.9520199702074295
61.481396216 0.28582490808609917 -0.0905523414362669 0.024889725185378877 0.9536691758456803
61.514803789 0.2871992313567452 -0.07691973477045909 0.020965768695799105 0.9545472185564899
61.554684279 0.28852221790137245 -0.05970025097906658 0.016157145254836726 0.9554735770640252
61.588075195 0.28921573339151685 -0.05026073817264798 0.013231578080056611 0.9558519985325442
61.621566899 0.28902458829576755 -0.03861862231306294 0.00967663376576401 0.956493466851743
61.661394915 0.28920964147309014 -0.028077574915538837 0.006492429401688862 0.9568318982069594
61.694815738 0.28931478822671375 -0.022769474428963054 0.005223037165444572 0.9569489141173259
61.734797182 0.2886196224288099 -0.018122548407617643 0.0037215693259306628 0.9572650817354705
61.774938242 0.2877273086742173 -0.020184227380927657 0.004100389174710778 0.9574908770409997
61.814938254 0.28860733071930167 -0.020200513099549178 0.004400111764258237 0.95722431380636
61.84847218 0.28875919295377667 -0.02466856135980777 0.0056226707181293 0.9570673832803606
61.888382085 0.2868986877286922 -0.035891258963021734 0.008758331470854126 0.9572482708991699
61.928269187 0.2848074621127248 -0.04726902322872832 0.01215780260011114 0.9573413898938286
61.968318182 0.28381385518873375 -0.057337360004308904 0.014956490296768757 0.9570467209852649
62.008424942 0.2834565449505991 -0.07891109639227538 0.021222548942302456 0.9554972681317461
62.041827025 0.2827147524815781 -0.09533837404096494 0.026079160563548875 0.9540979197906292
62.081712008 0.2835224224197247 -0.11310352924741736 0.03136085550925628 0.9517558113291231
62.121640667 0.28516155946180044 -0.13185773876604248 0.03695805643671476 0.9486466801698306
62.161637419 0.2885637616404501 -0.14642537987815493 0.0419411640547271 0.9452679526743653
62.195031152 0.2918918358347289 -0.15595855502800993 0.04568280976347906 0.9425439863362987
62.228512856 0.2947915046390717 -0.16447734235562703 0.049135778232572196 0.9400164083364405
62.268405621 0.2973761095573238 -0.17183142899332057 0.05231330381434036 0.9377124973672327
62.308522313 0.29812810348935065 -0.18173747143537178 0.05543336138117255 0.9354241112095116
62.341934684 0.29801463716053067 -0.18514483088932002 0.056202760430945714 0.9347459105837181
62.381822543 0.2979245286258951 -0.18514487503268026 0.05616388755648625 0.9347769617543609
62.421928382 0.2995523883022208 -0.18661466857341408 0.056872414930442684 0.9339212282391112
62.461770589 0.3007365446583887 -0.18039157304908446 0.05517915728209339 0.9348645204955892
62.495282167 0.30022041504782776 -0.16600290707915755 0.049898563917465326 0.9379876707871769
62.535280767 0.2978254459637583 -0.1628123460742277 0.048302961138273384 0.9393928718313593
62.575271511 0.2927147726873752 -0.15690826899251742 0.045402425878007635 0.9421446155961101
62.608663599 0.286404822110078 -0.1521919670442699 0.04302991809568021 0.9449647131972545
62.648664754 0.2792963135003527 -0.14883539420674555 0.040629007611222547 0.9477293276231155
62.688583807 0.27650900443530846 -0.14507150809035033 0.03900127006501638 0.949197518401677
62.722013011 0.2757161863938473 -0.1437084366514177 0.03850226034154197 0.9496557511773573
62.76204976 0.27562033538357833 -0.14227281164287617 0.03830282599851614 0.9499077698970579
62.801974933 0.275125992387055 -0.14077764179702965 0.03790358092137181 0.9502897781395117
62.835410443 0.2737120039082373 -0.14101231850801518 0.037403267462409705 0.9506830494590017
62.875370115 0.27308301603726287 -0.13395448039718916 0.035370276453400545 0.9519615575626577
62.915414692 0.2658904368289764 -0.12701364460125542 0.03250157604817458 0.9550463115694375
62.948840307 0.26166074146074464 -0.12881301053463154 0.03180321222827083 0.9559965587737133
62.98220057 0.2612686416605179 -0.1278545635588067 0.03105491294941914 0.9562570260362844
63.022028478 0.26644026275902405 -0.12811085776695608 0.03264199356153755 0.9547416900709038
63.055412647 0.26884135554383154 -0.1278137534498672 0.03280352983689863 0.9541026665976002
63.095569362 0.27101884188485453 -0.12780888558259929 0.03340232221016288 0.9534662872805177
63.135472554 0.2700953628187982 -0.12709006175872004 0.03308657714580149 0.9538353577000181
63.175458795 0.26795909854581584 -0.129350491791601 0.03340080623526233 0.9541230308102929
63.208911137 0.26435129431231846 -0.13191133229816376 0.03330286099718616 0.954782023844253
63.248792856 0.2628103336504036 -0.13040512750385322 0.03262339091024838 0.9554375676164218
63.282240414 0.26311020327320933 -0.13050506091658615 0.03275020240941291 0.9553370474606495
63.315635148 0.26339183339590566 -0.13045815523136886 0.03287699510500992 0.9552614903924668
63.355570487 0.26351772633217535 -0.13035070600370108 0.03282317673298574 0.9552432886035959
63.389101183 0.25931271446282833 -0.14020103785137325 0.03480109946876105 0.954929038504476
63.428970599 0.2551229596991654 -0.1395125553823347 0.03401113070096952 0.9561860516204315
63.46898607 0.2560003571369712 -0.13890487248862282 0.0341925765899839 0.956033535630838
63.502432967 0.2572087388153544 -0.13940473635637793 0.034301165401892125 0.9556324681646682
63.536008704 0.2577122609524792 -0.13840658484991508 0.03420162718112064 0.9556454659145871
63.575632014 0.25821791987023207 -0.1386262079074321 0.03450239440558873 0.9554663076840424
63.60921073 0.25822738085573405 -0.13841467664769014 0.03420362674386562 0.955505159055915
63.649086326 0.25810946063986767 -0.13840429321403241 0.03430125726442255 0.9555350237946283
63.682468557 0.2581284147957332 -0.1385494421287691 0.034403787171535145 0.9555051820838569
63.715828042 0.2580193803659286 -0.13833647818762831 0.034228658435329226 0.9555717749598635
63.755707572 0.2578230534211806 -0.13858943437308835 0.034303067231755226 0.9555854443131813
63.789079711 0.2569187840801675 -0.14606903584460204 0.036091826850644285 0.9546486029889636
63.822464671 0.24362501333806216 -0.17087707394123441 0.040672210528031806 0.953831038375285
63.855833243 0.23758004409366493 -0.16754055393694606 0.03816990524571669 0.9560486095217577
63.895896852 0.23794496569337004 -0.17022896998692733 0.03940256580395416 0.9554327443030388
63.929355883 0.23881305941020078 -0.17830975080753264 0.04149134794591114 0.9536521501405671
63.9692235 0.23912270819126671 -0.17639606135460537 0.040795027248123984 0.9539604424281342
64.009199932 0.2403130344044474 -0.1769099918860005 0.04130198195602294 0.9535442551621433
64.042571409 0.2409098335335081 -0.17726412159570387 0.041701702193222445 0.9533104695407204
64.082558493 0.24111473617741602 -0.1762107694502725 0.04160254261709045 0.9534582723830295
64.115950647 0.24021800141042882 -0.1773132874690634 0.041803132635120414 0.9534714510603781
64.155900702 0.24082688018823045 -0.1763196801378116 0.04170465491631732 0.9535064267917729
64.18924529 0.2409076773069191 -0.1766128860660676 0.041901335322374056 0.9534231262079821
64.222754713 0.2404164794523016 -0.1765327440663529 0.041823510363253796 0.9535653625531181
64.262702332 0.24062498750884803 -0.17609446986537078 0.0417043307527804 0.9535990257260457
64.30275806 0.24092503341152474 -0.17671836199176597 0.041904354088596454 0.9533990633092841
64.342809314 0.24083320204607145 -0.1759146992861333 0.04170348470853757 0.953579680325913
64.382700693 0.2405170352223008 -0.17641249485743807 0.04170295371629915 0.9535675388127394
64.416184431 0.24056521230446204 -0.17590893625023213 0.04170211848570028 0.9536484457545273
64.456125522 0.24061449264735138 -0.17631061950842913 0.041802517841476663 0.9535574344939715
64.496032895 0.24062297337195407 -0.17611681467498388 0.04180399121757141 0.9535910436831182
64.529717853 0.24070870538774838 -0.1763063762353969 0.041801511779010724 0.9535344851982471
64.569622489 0.24071819416869888 -0.17611331114710377 0.041703152043351656 0.9535720737010984
64.609475668 0.24070890132552572 -0.17630651974943992 0.04178206820719111 0.9535352613788483
64.643018115 0.240713953388724 -0.17621021432111827 0.04170241735068463 0.9535552744335203
237.224652599 -0.7398448860850116 0.02880199027778505 0.02600172727781124 0.6716575764989666
237.26459653 -0.7372147911859329 0.029190583961903285 0.025722260357686447 0.6745373427666818
237.304577638 -0.719774213481204 0.024585925767784924 0.021717065753797272 0.6934327529881326
237.338274005 -0.7065618911623412 0.02311168683405692 0.021108277492017914 0.7069586865652762
237.377909861 -0.7029157775106044 0.0202262565466694 0.017676291691649994 0.7107656836010039
237.411334506 -0.7065108557314751 0.01991394273749358 0.019157448950281628 0.707162525709574
237.444759512 -0.7066496268974564 0.021287525981304834 0.020379923502217845 0.7069496479674665
237.484615802 -0.7085189490191697 0.02103443639616331 0.020916670756841563 0.7050680422843719
237.518174235 -0.7032733386680614 0.019396886854743087 0.02049211851203453 0.7103593773421388
237.558096176 -0.7011389792290881 0.022573860527453183 0.025281284609096007 0.7122186527148762
237.591439633 -0.7116380918435294 0.020814186798997172 0.02342727837692802 0.7018469623023575
237.624809877 -0.7142359766518366 0.0244222614330849 0.02459588541984571 0.6990461824680148
237.664758513 -0.6883823330947716 0.02078155641383355 0.023101642546811355 0.7246821403261273
237.698193782 -0.6418943843669256 0.018006441479894 0.02266905587123676 0.7662463580920589
237.731617528 -0.6067771801183071 0.01863711239024718 0.023073335359475672 0.7943184077716052
237.771560356 -0.5912876062541214 0.02099286459940562 0.022800858396953828 0.8058649931486939
237.811430199 -0.6152911676118697 0.029743209425535877 0.027543034522966206 0.787256947763027
237.844900693 -0.6516273881691241 0.02733493544917675 0.02600113227053243 0.757600481396709
237.885046453 -0.6636923427193527 0.026877123905247095 0.027106730051557944 0.747031003113118
237.924951961 -0.6568099397047276 0.02603639084756669 0.026168119409953988 0.7531520689630026
237.965042646 -0.6534747112605533 0.02540290429448739 0.025666812022707472 0.7560864427808057
237.998432626 -0.6509603119699333 0.023112637992068807 0.02398122870212651 0.75838076114508
238.038373687 -0.6518610896148515 0.024282998066971213 0.026792872097090355 0.7574758067792048
238.071807186 -0.6523312880969664 0.023697992628947867 0.02406036089311443 0.7571812165847778
238.111745652 -0.6541333862571794 0.023704463170307794 0.026628799095168607 0.7555385618671443
238.151660619 -0.6551582775796915 0.026902393019224084 0.025929784086878592 0.7545671201860434
238.185055706 -0.6539363742338972 0.027039839756743497 0.028388807721200768 0.7555330178859974
238.224994003 -0.652245341533551 0.02883335334408795 0.02866763586874644 0.7569166525030437
238.258337377 -0.6492631197767772 0.027507326320962183 0.024420982651544156 0.7596738536390019
238.291777781 -0.6463246800306472 0.030203130788683277 0.028002902717984494 0.7619501403065756
238.331816336 -0.6417429834184132 0.02973726885534526 0.02591589327909385 0.7659046967800928
238.371776423 -0.6364593181664243 0.02849356837761892 0.027223983453827823 0.7703028674522419
238.411753748 -0.6290274181709601 0.0316022530027864 0.02614681523754289 0.776300295534697
238.445094107 -0.621693604302577 0.031118363054238585 0.026102653773446564 0.7822067254352133
238.478469514 -0.617013808729699 0.03326661036518229 0.025589466936078956 0.7858323432218917
238.518569694 -0.6131338818246268 0.03307181434644744 0.026436454278204645 0.78884359155646
238.558465278 -0.6292927738169665 0.030655855388338288 0.021713493844222557 0.776259845372176
238.591893193 -0.6378941040430138 0.03199957415778331 0.021558830862241703 0.769156912530034
238.631944176 -0.6271538701270035 0.03323997536894822 0.026351955926561813 0.7777394818581849
238.665330098 -0.5905127439272005 0.03290102473176915 0.023453149952717144 0.8060162353131998
238.70531927 -0.5733654448877479 0.03278302238490831 0.025601998148518296 0.8182431654115963
238.858595665 -0.6130995875387844 0.03594102126302643 0.022020851374104526 0.7888803590248035
238.891960809 -0.5880713019710265 0.03769197803191883 0.02311304540425028 0.8075996816011534
238.925379419 -0.5734855512032803 0.03682319432298265 0.022278843954877052 0.818084364862791
238.965553319 -0.5569114281884976 0.03934392474727085 0.02327021473008288 0.8293130975964054
239.005490219 -0.5481361669675943 0.04184904788369592 0.025048255195668417 0.8349658583229344
239.04536653 -0.5485901390509745 0.040902715418226786 0.023647850247542943 0.8347554171049852
239.078977707 -0.5491597841097845 0.040132500891461004 0.0229317141831777 0.8344381644995109
239.119176823 -0.5473186385746069 0.04160296761048178 0.022751179345660618 0.8355799691191871
239.158778348 -0.5445705381193571 0.04157381085158515 0.022324953055749167 0.837386496030793
239.192218698 -0.550261828806127 0.04060233999774576 0.022601435837753075 0.8336981137340519
239.225675996 -0.5547888547499716 0.039830711121631945 0.020129149871999628 0.8307933909355507
239.259023645 -0.5568821236861582 0.04090318897651194 0.02436319252774728 0.8292259428528524
239.298827899 -0.5666330578628691 0.03909509744202021 0.020062966517381382 0.8227976838005171
239.332263476 -0.5756114966686485 0.040498957890201776 0.02240038010407117 0.816412556422229
239.372266675 -0.5810681018589907 0.034107145619721294 0.01710974908846781 0.8129599129759072
239.405604515 -0.5936616049119721 0.04081131010694034 0.021719302649958704 0.8033857154026927
239.438948668 -0.627638922925641 0.04232908794896426 0.020738562164078395 0.7770762786120272
239.472315909 -0.6432891548836509 0.040580441231301535 0.020878436195524163 0.7642619851206658
239.505813017 -0.6415426694839114 0.040304059466855356 0.021763165689755417 0.7657185844950543
239.54560886 -0.6325430527964304 0.036403340116676834 0.019860130466871854 0.7734142863984094
239.578950703 -0.6249371039304736 0.038236719767479194 0.02133236741719445 0.7794462774898561
239.612357077 -0.6262389018208373 0.038079984561546563 0.021600614098840124 0.7784010316620714
239.64572434 -0.6294433047169053 0.03891086160143383 0.020487595873406907 0.7758010888184054
239.679065633 -0.6327580022048975 0.03972190072611971 0.02002299569503784 0.7730708640815328
239.712583156 -0.635157093496259 0.04406319601429506 0.02342248780517333 0.7707692835105762
239.752536358 -0.636784906242236 0.04345734208913995 0.020565576239353314 0.7695410968067642
239.792381657 -0.639159534914996 0.04638397560371163 0.022496762458775955 0.7673444542142165
239.825895897 -0.6423973545820866 0.04518489070093774 0.023649082539650847 0.7646729270566037
239.865988228 -0.6435476610183528 0.046117123960465585 0.023415442678233086 0.7636565562604728
239.905810086 -0.6479926071669341 0.04708001288789257 0.025347004697747352 0.7597674531041243
239.939230309 -0.6538293515860074 0.04695267676296676 0.02326001572880971 0.7548255406500957
239.972745715 -0.6557733073619862 0.04713364913710568 0.023501531331391216 0.7531184943258411
240.012586389 -0.6582987223720739 0.04786685633500892 0.02444960263871173 0.7508353835020748
240.05252711 -0.6700262578599798 0.04300530392524151 0.017322349472025912 0.7408881790265104
240.085969655 -0.7001708375552325 0.044196381582831165 0.019186952256127054 0.7123477654596175
240.119389433 -0.7210171826308943 0.043655057963665735 0.02040226519295533 0.6912396153579402
240.159243469 -0.7292553754727438 0.04315211551348799 0.022799589687022344 0.682498843208486
240.199351733 -0.7328958141178934 0.03984653537153811 0.020058966915709527 0.6788767318988252
240.239255958 -0.7392580145346286 0.040533371904498364 0.01993244109385431 0.6719057459944888
240.272685278 -0.7440371721386948 0.04237320511099688 0.02124227062326568 0.6664547725864403
240.306045977 -0.7491917310420214 0.040609613752215425 0.017808660763861464 0.6608672037640793
240.346166128 -0.7535554430214993 0.040696543331009145 0.01900139803239348 0.6558482541917708
240.386025549 -0.7563236059040115 0.04090972361520709 0.01872382837338613 0.652648769183797
240.419548684 -0.7572022343054041 0.03799379700621332 0.02113207278048279 0.6517320640047987
240.459425203 -0.7588321903106341 0.03810428629021577 0.01760080560694561 0.6499322902862001
240.492855212 -0.7606906238959252 0.03776501398651325 0.01996377356278154 0.6477075159210062
240.532733447 -0.7616749154204283 0.03730218337940114 0.017870713111560747 0.6466378491453291
240.566139425 -0.7619988154362971 0.03600061610258555 0.019400489625791807 0.646285836078893
240.599512374 -0.7639172030025358 0.0369748529559444 0.016244060771824553 0.6440492975660405
240.63955173 -0.7619946257186881 0.03763024234044501 0.018282317981459534 0.6462305409731581
240.673226409 -0.7627946315747083 0.03747640716029538 0.018868154977860513 0.645278127379886
240.712977483 -0.7874763771384581 0.036703365723037104 0.019842236049353017 0.6149309750387045
240.752841427 -0.7932514643598876 0.03650291347851922 0.019138810554269938 0.6074976193608018
240.786276718 -0.7873101904571339 0.039632257426235176 0.022001393176875588 0.6148885158074824
240.826387453 -0.7807397286608538 0.03861306972099767 0.019150943750093352 0.6233680680711665
240.866407073 -0.7780167852440415 0.04018876600093528 0.01977046881212255 0.6266449341762831
240.90626368 -0.7770544034990937 0.040793166763709254 0.02110658808902222 0.6277554328616332
240.939623332 -0.773756269311581 0.03873000636236827 0.022850093583271003 0.6318853499895617
240.972990291 -0.7705633609395449 0.040243112752171024 0.021782805146814233 0.6357185761431742
241.006524855 -0.7649289126254382 0.0406568845388112 0.024278660844678453 0.6423716393154758
241.046515904 -0.7585653724527895 0.041864354220823456 0.02236362999526692 0.6498660012761625
241.086410399 -0.7590491325849261 0.0423037432165785 0.025020245235346746 0.6491754731660002
241.126376736 -0.7608761501913889 0.04051535304488624 0.02207799609793322 0.6472546271181681
241.159723766 -0.763111740906569 0.042180996459945566 0.024841424643631663 0.6444099146117063
241.193190873 -0.7657056982338764 0.0412532437792336 0.02205006662221007 0.6414879173700928
241.226680258 -0.7800509523526011 0.04082885668824386 0.021754262779086094 0.6240034200597536
241.266542382 -0.7878570149977546 0.04050294899629278 0.02490181308660963 0.6140201419712802
241.306530322 -0.7937301074622842 0.040448216200342994 0.023779360466155745 0.6064577481819666
241.34648746 -0.7953611626425902 0.04038263266062048 0.0270381090412026 0.6041844127405975
241.379869979 -0.7979080359031728 0.04169295130797545 0.025582584389363262 0.6007911412698537
241.419866053 -0.8020346459463255 0.04031729865444801 0.027801714424672327 0.5952663326663196
241.453324024 -0.8021744889231099 0.040203733268556315 0.02767496999175672 0.595091459515404
241.486664985 -0.8021993865822173 0.04015406314749203 0.027802583829647017 0.5950553013899271
241.519999899 -0.8006753898767827 0.040994413663027834 0.027608897116518285 0.5970562175323998
241.553356735 -0.800629081395388 0.04167112845056958 0.02740393024429167 0.5970809121758955
241.593333504 -0.8000552981777835 0.039282366786158714 0.02970205294485021 0.5979014998878972
241.626691213 -0.799600529840944 0.04018235251939279 0.025221509036599372 0.5986553655535093
241.660145009 -0.8006425422975403 0.04079847331279591 0.02910947405960326 0.5970424126966609
241.700003673 -0.8004875900298837 0.04099529348393601 0.026387724774763914 0.5973631157859731
242.720558703 -0.794450343530368 0.021729453520980112 0.03624393879652909 0.6058571278896314
242.760454466 -0.7950640377780425 0.024836050594316345 0.034944504321129055 0.6050084528671501
242.794103122 -0.7819008218387371 0.02060918070083504 0.03545406344966234 0.6220525507251421
242.83403055 -0.7629413999181803 0.028900595538859982 0.04050008098162014 0.6445501681862077
242.873829245 -0.7580740197433834 0.02470217157341355 0.03871078036053453 0.6505498126919601
242.907301163 -0.758829264307354 0.02860248727435542 0.03957688868944677 0.6494564767820422
242.947372815 -0.7623713427443437 0.02649413019336018 0.03832578769088851 0.6454604022133013
242.987461621 -0.7637815838681922 0.02730291638025618 0.03640388850700824 0.6438687752970303
243.027253869 -0.7616177267712572 0.027439704419571852 0.036416624517971244 0.6464203975338854
243.060659886 -0.7604374493482504 0.030908341136354635 0.03497066186737446 0.6477318989253837
243.09401031 -0.7735665648355493 0.033803728624669155 0.0376081341625404 0.6316943136869367
243.127388229 -0.791929356078706 0.031169605853374218 0.03485865020635539 0.6088195341457948
243.16074622 -0.7959355246960755 0.030774438423373705 0.034264996897322 0.6036269414581621
243.194248473 -0.7929810467862657 0.03296087825419788 0.035888063432670286 0.6072945634908344
243.233985182 -0.78504977820596 0.034002198937717595 0.03440189434575279 0.617541258436711
243.267587731 -0.7785228240679044 0.03312143077675334 0.033703783679774224 0.6258348329985337
243.307450961 -0.7743803674115186 0.03242764746757066 0.037178671653781824 0.6307941348977342
243.340870149 -0.7748086221488291 0.028920749638342725 0.03282099712563151 0.6306805621167253
243.374236749 -0.7759793421386333 0.03359608267896157 0.03408935798259871 0.6289398059234736
243.407665296 -0.7772879387144771 0.032521657399209696 0.03450307063968944 0.6273558322399183
243.447583812 -0.7788086853502265 0.03432244926460159 0.03554459571356544 0.6253123881829706
243.487506729 -0.7818954694066684 0.03255672619385175 0.0353467846351223 0.6215546149107273
243.520864347 -0.784278968627682 0.032986754940516415 0.03357024721393656 0.6186205718118247
243.554311235 -0.7868957125355791 0.03698578020564404 0.036168606278630576 0.6149138326428871
243.594197731 -0.7902765231685532 0.035827896450185366 0.03318934555182752 0.6108009873161794
243.627636256 -0.7934598347217816 0.035382648985657204 0.03566265088442944 0.606545739549736
243.661027148 -0.8052147827536443 0.038174259153005104 0.03720337355739193 0.5905825840380581
243.700991524 -0.8291901340181825 0.037995973170304405 0.03515571618560939 0.5565645544671588
243.734370962 -0.83509730954713 0.04003248448780763 0.036922347441520044 0.5473998758058738
243.774402322 -0.8198314283616239 0.03764953561266079 0.032976020427303285 0.5704134672458818
243.814480121 -0.8054633799247986 0.038357166197690716 0.03364830924751279 0.5904449700744229
243.847913394 -0.8028464662978672 0.03550362042066799 0.03260220003156211 0.5942340793350336
243.887739277 -0.8105031136087074 0.04011207707689189 0.03300265080081505 0.5834265584829745
243.92769101 -0.8185163084845994 0.037888173152325906 0.032675454248351755 0.5723004925470424
243.961154419 -0.823418853455404 0.03692683561043423 0.03360259745697052 0.5652332846092247
244.001043379 -0.8268167768205759 0.034092419986228 0.032927749161793134 0.5604707733706146
244.03450406 -0.8301858796962555 0.03593063620207311 0.034086782132382455 0.5552823478366015
244.074515133 -0.8322518736899639 0.03527525947168676 0.03269428096774672 0.5523074857366608
244.114529925 -0.8349697708900148 0.03588213317955448 0.03596343772328037 0.5479457868854224
244.154597694 -0.834974971113073 0.035574076353461645 0.034544866154355945 0.5480492084919919
244.188142254 -0.8341544866192296 0.03522830925146127 0.03421536706050674 0.5493401199049707
244.2278879 -0.8339667080706517 0.037112152092703826 0.03520268466225661 0.5494387945799042
244.261326426 -0.8338501520547195 0.03582483636170743 0.03121369300777566 0.549942006385032
244.294858025 -0.8336788367480741 0.03572444280238121 0.03482435768593056 0.5499914776217899
244.33459512 -0.8333759764707798 0.032271374510706746 0.031734460715658185 0.5508502194169032
244.374535448 -0.8338381907472637 0.03687101017793684 0.034501580212018 0.5496944980829462
244.407988351 -0.8334485181807082 0.03500440691503399 0.030701787266795948 0.5506320543680081
244.441348514 -0.8343814765829702 0.03518358394791308 0.03570219247145967 0.5489034709386829
244.474893758 -0.8336025385320821 0.0354563778747961 0.03449439015292214 0.5501452445207959
244.514606905 -0.8334164674511001 0.03513605823197383 0.033270832259868106 0.5505229340490589
261.742808571 -0.492390337246879 0.02761474303904702 0.02918992189195911 0.8694464504572628
261.776378882 -0.48682071379739567 0.029633345065584637 0.031439369275732446 0.8724328189250805
261.816359221 -0.46278316432593464 0.042966379369456555 0.039929856322520406 0.8845288235181586
261.856255245 -0.4364826657557189 0.039018122632218266 0.03889695019679967 0.8980242178618716
261.889617012 -0.40534723562500025 0.05057737482168146 0.040945473304809334 0.9118437453550706
261.92301596 -0.4110476949285202 0.05790648721927345 0.04770811563288436 0.9085210877765215
261.963055751 -0.4528477920897629 0.053507990588702134 0.04520407847818043 0.888832022055644
262.00313968 -0.4702518066407381 0.06310344281097734 0.05529647924120107 0.8785348560188441
262.036483884 -0.4761414437583875 0.060736790013897105 0.05157378623604043 0.8757513987700879
262.076405694 -0.4812953535919647 0.06598484871490432 0.05747814962520306 0.8721794796178821
262.109740578 -0.4876601820802172 0.0667707860672644 0.058342405950877044 0.8685190686503734
262.143299317 -0.4919022542838608 0.07434590779148013 0.0632902792169759 0.8651584818874252
262.183013211 -0.4984287966872071 0.07269072338000834 0.06320437753256815 0.8615625340206912
262.216442071 -0.5067808238927949 0.08285415137576507 0.0707274172226619 0.8551643225645895
262.256639628 -0.5185293751509472 0.0817992261845819 0.07073329780268191 0.8481939485065483
262.29649362 -0.5277778670740825 0.0909772739298654 0.0791509258262726 0.8407786805074605
262.329980071 -0.5379426006928065 0.09243346559147012 0.08101851306186507 0.8339723096961043
262.369948234 -0.5494691869768229 0.0989374779731067 0.08267584488145745 0.8255057193554068
262.409808927 -0.5576234483276423 0.1040292906370292 0.08986680595659953 0.8186317571117704
262.449800633 -0.5633853831281898 0.10419232251821237 0.0906687360471637 0.8145674007160939
262.489861551 -0.5671783877908197 0.10166763029185129 0.090148851798643 0.8123087798942176
262.529911177 -0.5756197916112045 0.10696082555957338 0.09720520317847695 0.8048430814612989
262.56997375 -0.5687882709979508 0.09596812028204671 0.08556701867675583 0.8123720256012412
262.609853522 -0.5615109406583646 0.08894432496118791 0.08335492231888024 0.8184414013864222
262.643276813 -0.5621995622183242 0.09236672514071978 0.08203435753785487 0.8177226941400458
262.68331509 -0.5652046223756785 0.09149095540931225 0.0792894395324198 0.8160185811010021
262.716713959 -0.5792666486301181 0.07541814343364919 0.07346740403770038 0.8083098378529203
262.756684576 -0.6327026201780289 0.07314176725312356 0.07318043642833083 0.7674518226098013
262.796721622 -0.6867117743077357 0.07253510126562135 0.07413523648881502 0.7194925745428198
262.836624835 -0.7026505013220113 0.07255152169512319 0.07050692745189623 0.7043062706471819
262.869991225 -0.6961192155330221 0.07078602036596023 0.07135737268391958 0.7108554722656977
262.903445924 -0.6896244783031741 0.06977794592203947 0.0636563069737576 0.7179811917943524
262.936843485 -0.6974285771125298 0.06741535042046969 0.061791339797198495 0.7107955969760537
262.976781499 -0.7175640009150057 0.07108412266598935 0.05977200750756993 0.6902725977569812
263.01015257 -0.7339481096858896 0.0708928757550175 0.05636305072004498 0.6731400886659645
263.050089341 -0.7488010480670951 0.07039084133393367 0.04925384282377272 0.6572033009936971
263.083433029 -0.7650276565384505 0.06608428793880212 0.046159723792380945 0.6389325719653987
263.123580477 -0.759769112365214 0.07120439637288271 0.051619252283097564 0.6442175739815563
263.163652675 -0.7395908309264311 0.08969193491507335 0.03875318628266474 0.6659271357841506
263.203570002 -0.7138426882345714 0.08041083482311241 0.03470125541199424 0.6948082735330102
263.243520895 -0.6905059060909539 0.0680043831659756 0.033929833028546276 0.719323129027825
263.276978085 -0.6735392545108225 0.07094116690038248 0.05053340002649777 0.7340017704022106
263.310351264 -0.6535198118300644 0.08169482521562137 0.048827371442678846 0.7509019236069282
263.350348329 -0.6285031016449124 0.06540252568789343 0.033638237266481574 0.7743221744532267
263.390215901 -0.597597759975782 0.08041849222986115 0.045151379258440816 0.7964741906241932
263.423631479 -0.5855794838506132 0.06666940243972289 0.03496655077367687 0.8071116398606649
263.463657246 -0.5845601318882496 0.07226772360141404 0.034338932523008195 0.8073956069024912
263.497184693 -0.589325291486152 0.06999637263091353 0.035476477527406215 0.8040756358549386
263.537050353 -0.5931609242298242 0.07129197916553609 0.03660375961357539 0.8010853490456764
263.577229306 -0.590704120917637 0.0705189697772078 0.036731944054572675 0.8029610704875143
263.617137181 -0.5877951213932916 0.06688175186599517 0.03978050132459503 0.8052584915714612
263.650505531 -0.5885396442081441 0.06680449997128976 0.03910127750133417 0.80475420848648
263.690427283 -0.5860902186568708 0.06565280929277087 0.040128839421852636 0.8065839326898123
263.730486075 -0.5916245608673145 0.06052850817983245 0.03809646185305764 0.8030350791032479
263.764034955 -0.5954060180692134 0.06401254344918918 0.04038745934692126 0.7998518119349546
263.803941131 -0.6009381353312887 0.06158764547490287 0.038086154078189126 0.7960086458682116
263.843968779 -0.601188718705783 0.06170522943653155 0.03720362711233978 0.7958520461057882
263.883795881 -0.6041257681638235 0.06243057055249998 0.03910166782851432 0.793476867762374
263.917149503 -0.6057301358239046 0.0590029354690612 0.03650181601052091 0.7926394347928458
263.950528031 -0.6080634013365945 0.06048437618307217 0.03908286242362899 0.7906156272535295
263.98395776 -0.6115813643241973 0.0615029372596799 0.03869753532337942 0.7878376255800946
264.02402125 -0.6096917676270661 0.06497343686839953 0.04135971642311708 0.7888876820224101
264.057500051 -0.6052202428728259 0.06308817907674807 0.03760298037333147 0.7926628256357054
264.097336955 -0.5926158386131634 0.06392423657699592 0.04070258960181896 0.80191237613755
264.137350425 -0.5713310415499188 0.06501045153289282 0.03998309797578019 0.8171632848025134
264.177556814 -0.5624531659050787 0.06614190727716705 0.0404084276423265 0.8231882185992262
264.217318908 -0.5494980844410502 0.06670474225761372 0.03930034106594068 0.8319001236615261
264.250654226 -0.5335587415490124 0.06444960489227361 0.040048110162840045 0.8423523411365634
264.284025954 -0.5079092288151696 0.06365611557014426 0.035546367802650525 0.8583196199382481
264.317373401 -0.48606852198966877 0.0629840680658517 0.03542041845945029 0.8709281216362305
264.350790037 -0.4737681769746858 0.06021818663254122 0.030406992407089835 0.8780620133552792
264.390799451 -0.46115125378317784 0.059743582610039564 0.029793664094503413 0.8848065116458765
264.424157809 -0.45145793664761047 0.056941380067110955 0.026838732954425747 0.8900691507334337
264.464123518 -0.4375945786764074 0.05598087255134386 0.02476207947184981 0.8970863760205243
264.497628602 -0.4232633740128462 0.0557021561900418 0.02447444228530421 0.9039614967961107
264.537516814 -0.40976446304231784 0.051697068436898794 0.020471949480633984 0.9104951384972542
264.570953282 -0.394404762834615 0.05649619527227564 0.022199131234126868 0.9169298018635768
347.143468116 0.4730519346282629 -0.06221664456394384 -0.021076123747344584 -0.8785822404826131
347.18332169 0.4648592034940948 -0.06187319382945125 -0.013535347229064071 -0.8831163135100425
347.216678041 0.44476200771752367 -0.0750702575895775 -0.02079571159351462 -0.8922548690233253
347.250059703 0.4365460120904825 -0.04296919106067979 -0.015423656303356275 -0.8985228649142565
347.28996064 0.43028404268218046 -0.06387543895312994 -0.04280942086964046 -0.899412544051077
347.323446715 0.44809170396511877 -0.04104020887525186 -0.05126545982605537 -0.8915724192245604
347.356899921 0.48925795075881234 -0.04803711142677635 -0.059733227690227084 -0.8687640848094301
347.396893155 0.5239674490283242 -0.03998553782005044 -0.053927633452822386 -0.84908838142691
347.43697453 0.5315155721034144 -0.021464538394438206 -0.058758469653814725 -0.8447354097272327
347.470330691 0.5037041385344577 -0.030576215470486272 -0.06966944538685836 -0.8605192643109448
347.510236723 0.4545578437293535 -0.029488655136588736 -0.0791907512372356 -0.8866997298075816
347.543585399 0.43450533757488047 -0.034308086723568595 -0.08974978294096142 -0.8955294764921797
347.583513418 0.393449902051833 -0.014749737676544522 -0.08293897946586651 -0.9154784243765862
347.616963521 0.38354208486947444 -0.02777757660563286 -0.077284434012173 -0.919864659409912
347.65041836 0.38698802213408134 -0.03715615252394913 -0.08295334299492432 -0.9175938284122966
347.690161084 0.3983786712713217 -0.007501916893747665 -0.07418855541829539 -0.9141849997478422
347.723539363 0.40259613132462235 -0.021110313238303816 -0.07665253807862202 -0.9119183615453379
347.756932275 0.40113316061560916 -0.013092739112825628 -0.07180545208523943 -0.9131071923317052
347.796937718 0.3819278328053421 -0.022587278562296493 -0.060477766673134876 -0.9219345883054795
349.31776045 0.40910432265814306 0.01678086795843859 -0.005840281520681834 -0.9123146095315708
349.357902582 0.40562481581795595 0.02008156672452735 -0.004100331383478491 -0.9138098416810159
349.3977756 0.37812767583828616 0.020411226141690005 -0.002022521124874527 -0.9255262027737672
349.431331935 0.3660248648532596 0.01859780583343839 -0.004765823635339921 -0.930407011394697
349.470994107 0.3639449660241751 0.01633510706619165 -0.004409753837888614 -0.9312667609519237
349.504374961 0.36648487325138274 0.008994882729107818 -0.006562673605771192 -0.9303573835240689
349.537824176 0.36488204611016994 0.00864716930228317 -0.007275381984313243 -0.9309851705083685
349.577759027 0.3635893202800476 0.004373257049036545 -0.008436823042478997 -0.9315108699408859
349.61780063 0.3554795000826525 0.005240242412714433 -0.005117332223630488 -0.9346553791592689
349.657798937 0.3473621577382386 0.0036648960411413793 -0.005554370365892558 -0.9377074431176715
349.691153707 0.34494037906991837 0.004945084104685389 -0.002184370522349425 -0.9386090291253968

BIN
assets/standard_fanblade.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
assets/tiny_resnet.onnx Normal file

Binary file not shown.

BIN
assets/yolo11.bin Normal file

Binary file not shown.

23449
assets/yolo11.xml Normal file

File diff suppressed because it is too large Load Diff

BIN
assets/yolo11_buff_int8.bin Normal file

Binary file not shown.

23068
assets/yolo11_buff_int8.xml Normal file

File diff suppressed because it is too large Load Diff

BIN
assets/yolov5.bin Normal file

Binary file not shown.

12795
assets/yolov5.xml Normal file

File diff suppressed because it is too large Load Diff

BIN
assets/yolov8.bin Normal file

Binary file not shown.

25211
assets/yolov8.xml Normal file

File diff suppressed because it is too large Load Diff

8
autostart.sh Executable file
View File

@ -0,0 +1,8 @@
sleep 5
cd ~/Desktop/sp_vision_25/
screen \
-L \
-Logfile logs/$(date "+%Y-%m-%d_%H-%M-%S").screenlog \
-d \
-m \
bash -c "./watchdog.sh"

177
buff_layout.xml Normal file
View File

@ -0,0 +1,177 @@
<?xml version='1.0' encoding='UTF-8'?>
<root>
<tabbed_widget name="Main Window" parent="main_window">
<Tab containers="1" tab_name="tab1">
<Container>
<DockSplitter orientation="-" count="2" sizes="0.5;0.5">
<DockArea name="...">
<plot mode="TimeSeries" flip_y="false" style="Lines" flip_x="false">
<range right="30.649625" top="155.851536" bottom="144.739548" left="0.000000"/>
<limitY/>
<curve name="/gimbal_yaw" color="#1f77b4"/>
<curve name="/cmd_yaw" color="#d62728"/>
</plot>
</DockArea>
<DockArea name="...">
<plot mode="TimeSeries" flip_y="false" style="Lines" flip_x="false">
<range right="30.649625" top="18.307670" bottom="-18.813059" left="0.000000"/>
<limitY/>
<curve name="/gimbal_pitch" color="#1ac938"/>
<curve name="/cmd_pitch" color="#ff7f0e"/>
</plot>
</DockArea>
</DockSplitter>
</Container>
</Tab>
<Tab containers="1" tab_name="tab2">
<Container>
<DockSplitter orientation="-" count="4" sizes="0.25072;0.24928;0.25072;0.24928">
<DockArea name="...">
<plot mode="TimeSeries" flip_y="false" style="Lines" flip_x="false">
<range right="30.649625" top="2.667341" bottom="2.652464" left="0.000000"/>
<limitY/>
<curve name="/buff_R_yaw" color="#f14cc1"/>
<curve name="/R_yaw" color="#1f77b4"/>
</plot>
</DockArea>
<DockArea name="...">
<plot mode="TimeSeries" flip_y="false" style="Lines" flip_x="false">
<range right="30.649625" top="0.063579" bottom="-0.021388" left="0.000000"/>
<limitY/>
<curve name="/R_V_yaw" color="#d62728"/>
</plot>
</DockArea>
<DockArea name="...">
<plot mode="TimeSeries" flip_y="false" style="Lines" flip_x="false">
<range right="30.649625" top="0.155296" bottom="0.139135" left="0.000000"/>
<limitY/>
<curve name="/buff_R_pitch" color="#9467bd"/>
<curve name="/R_pitch" color="#1f77b4"/>
</plot>
</DockArea>
<DockArea name="...">
<plot mode="TimeSeries" flip_y="false" style="Lines" flip_x="false">
<range right="30.649625" top="9.257444" bottom="7.987190" left="0.000000"/>
<limitY/>
<curve name="/buff_R_dis" color="#17becf"/>
<curve name="/R_dis" color="#bcbd22"/>
</plot>
</DockArea>
</DockSplitter>
</Container>
</Tab>
<Tab containers="1" tab_name="tab3">
<Container>
<DockSplitter orientation="-" count="3" sizes="0.333813;0.332374;0.333813">
<DockArea name="...">
<plot mode="TimeSeries" flip_y="false" style="Lines" flip_x="false">
<range right="30.649625" top="172.996997" bottom="116.017715" left="0.000000"/>
<limitY/>
<curve name="/buff_yaw" color="#ff7f0e"/>
<curve name="/yaw" color="#9467bd"/>
</plot>
</DockArea>
<DockArea name="...">
<plot mode="TimeSeries" flip_y="false" style="Lines" flip_x="false">
<range right="30.649625" top="17.228124" bottom="-36.584246" left="0.000000"/>
<limitY/>
<curve name="/buff_pitch" color="#d62728"/>
<curve name="/pitch" color="#f14cc1"/>
</plot>
</DockArea>
<DockArea name="...">
<plot mode="TimeSeries" flip_y="false" style="Lines" flip_x="false">
<range right="30.649625" top="135.724246" bottom="-160.304721" left="0.000000"/>
<limitY/>
<curve name="/buff_roll" color="#1ac938"/>
<curve name="/angle" color="#17becf"/>
</plot>
</DockArea>
</DockSplitter>
</Container>
</Tab>
<Tab containers="1" tab_name="tab4">
<Container>
<DockSplitter orientation="-" count="2" sizes="0.5;0.5">
<DockArea name="...">
<plot mode="TimeSeries" flip_y="false" style="Lines" flip_x="false">
<range right="30.649625" top="3.467481" bottom="-1.709189" left="0.000000"/>
<limitY/>
<curve name="/spd" color="#bcbd22"/>
<curve name="/fi" color="#1ac938"/>
<curve name="/spd0" color="#1f77b4"/>
</plot>
</DockArea>
<DockArea name="...">
<plot mode="TimeSeries" flip_y="false" style="Lines" flip_x="false">
<range right="0.000000" top="0.100000" bottom="-0.100000" left="0.000000"/>
<limitY/>
<curve name="/iou" color="#1f77b4"/>
</plot>
</DockArea>
</DockSplitter>
</Container>
</Tab>
<Tab containers="1" tab_name="tab2">
<Container>
<DockSplitter orientation="-" count="1" sizes="1">
<DockArea name="...">
<plot mode="TimeSeries" flip_y="false" style="Lines" flip_x="false">
<range right="30.649625" top="2.270898" bottom="0.803537" left="0.000000"/>
<limitY/>
<curve name="/a" color="#1f77b4"/>
<curve name="/w" color="#d62728"/>
</plot>
</DockArea>
</DockSplitter>
</Container>
</Tab>
<currentTabIndex index="3"/>
</tabbed_widget>
<use_relative_time_offset enabled="1"/>
<!-- - - - - - - - - - - - - - - -->
<!-- - - - - - - - - - - - - - - -->
<Plugins>
<plugin ID="DataLoad CSV">
<parameters time_axis="" delimiter="0"/>
</plugin>
<plugin ID="DataLoad MCAP"/>
<plugin ID="DataLoad ROS2 bags">
<use_header_stamp value="false"/>
<discard_large_arrays value="true"/>
<max_array_size value="100"/>
<boolean_strings_to_number value="true"/>
<remove_suffix_from_strings value="true"/>
<selected_topics value=""/>
</plugin>
<plugin ID="DataLoad ULog"/>
<plugin ID="MQTT Subscriber (Mosquitto)"/>
<plugin ID="ROS2 Topic Subscriber">
<use_header_stamp value="false"/>
<discard_large_arrays value="true"/>
<max_array_size value="100"/>
<boolean_strings_to_number value="true"/>
<remove_suffix_from_strings value="true"/>
<selected_topics value=""/>
</plugin>
<plugin ID="UDP Server"/>
<plugin ID="WebSocket Server"/>
<plugin ID="ZMQ Subscriber"/>
<plugin ID="Fast Fourier Transform"/>
<plugin ID="Quaternion to RPY"/>
<plugin ID="Reactive Script Editor">
<library code="--[[ Helper function to create a series from arrays&#xa;&#xa; new_series: a series previously created with ScatterXY.new(name)&#xa; prefix: prefix of the timeseries, before the index of the array&#xa; suffix_X: suffix to complete the name of the series containing the X value. If [nil], use the index of the array.&#xa; suffix_Y: suffix to complete the name of the series containing the Y value&#xa; timestamp: usually the tracker_time variable&#xa; &#xa; Example:&#xa; &#xa; Assuming we have multiple series in the form:&#xa; &#xa; /trajectory/node.{X}/position/x&#xa; /trajectory/node.{X}/position/y&#xa; &#xa; where {N} is the index of the array (integer). We can create a reactive series from the array with:&#xa; &#xa; new_series = ScatterXY.new(&quot;my_trajectory&quot;) &#xa; CreateSeriesFromArray( new_series, &quot;/trajectory/node&quot;, &quot;position/x&quot;, &quot;position/y&quot;, tracker_time );&#xa;--]]&#xa;&#xa;function CreateSeriesFromArray( new_series, prefix, suffix_X, suffix_Y, timestamp )&#xa; &#xa; --- clear previous values&#xa; new_series:clear()&#xa; &#xa; --- Append points to new_series&#xa; index = 0&#xa; while(true) do&#xa;&#xa; x = index;&#xa; -- if not nil, get the X coordinate from a series&#xa; if suffix_X ~= nil then &#xa; series_x = TimeseriesView.find( string.format( &quot;%s.%d/%s&quot;, prefix, index, suffix_X) )&#xa; if series_x == nil then break end&#xa; x = series_x:atTime(timestamp)&#x9; &#xa; end&#xa; &#xa; series_y = TimeseriesView.find( string.format( &quot;%s.%d/%s&quot;, prefix, index, suffix_Y) )&#xa; if series_y == nil then break end &#xa; y = series_y:atTime(timestamp)&#xa; &#xa; new_series:push_back(x,y)&#xa; index = index+1&#xa; end&#xa;end&#xa;&#xa;--[[ Similar to the built-in function GetSeriesNames(), but select only the names with a give prefix. --]]&#xa;&#xa;function GetSeriesNamesByPrefix(prefix)&#xa; -- GetSeriesNames(9 is a built-in function&#xa; all_names = GetSeriesNames()&#xa; filtered_names = {}&#xa; for i, name in ipairs(all_names) do&#xa; -- check the prefix&#xa; if name:find(prefix, 1, #prefix) then&#xa; table.insert(filtered_names, name);&#xa; end&#xa; end&#xa; return filtered_names&#xa;end&#xa;&#xa;--[[ Modify an existing series, applying offsets to all their X and Y values&#xa;&#xa; series: an existing timeseries, obtained with TimeseriesView.find(name)&#xa; delta_x: offset to apply to each x value&#xa; delta_y: offset to apply to each y value &#xa; &#xa;--]]&#xa;&#xa;function ApplyOffsetInPlace(series, delta_x, delta_y)&#xa; -- use C++ indeces, not Lua indeces&#xa; for index=0, series:size()-1 do&#xa; x,y = series:at(index)&#xa; series:set(index, x + delta_x, y + delta_y)&#xa; end&#xa;end&#xa;"/>
<scripts/>
</plugin>
<plugin ID="CSV Exporter"/>
<plugin ID="ROS2 Topic Re-Publisher"/>
</Plugins>
<!-- - - - - - - - - - - - - - - -->
<previouslyLoaded_Datafiles/>
<previouslyLoaded_Streamer name="UDP Server"/>
<!-- - - - - - - - - - - - - - - -->
<customMathEquations/>
<snippets/>
<!-- - - - - - - - - - - - - - - -->
</root>

View File

@ -0,0 +1,130 @@
#include <fmt/core.h>
#include <yaml-cpp/yaml.h>
#include <fstream>
#include <opencv2/opencv.hpp>
#include "tools/img_tools.hpp"
const std::string keys =
"{help h usage ? | | 输出命令行参数说明}"
"{config-path c | configs/calibration.yaml | yaml配置文件路径 }"
"{@input-folder | assets/img_with_q | 输入文件夹路径 }";
std::vector<cv::Point3f> centers_3d(const cv::Size & pattern_size, const float center_distance)
{
std::vector<cv::Point3f> centers_3d;
for (int i = 0; i < pattern_size.height; i++)
for (int j = 0; j < pattern_size.width; j++)
centers_3d.push_back({j * center_distance, i * center_distance, 0});
return centers_3d;
}
void load(
const std::string & input_folder, const std::string & config_path, cv::Size & img_size,
std::vector<std::vector<cv::Point3f>> & obj_points,
std::vector<std::vector<cv::Point2f>> & img_points)
{
// 读取yaml参数
auto yaml = YAML::LoadFile(config_path);
auto pattern_cols = yaml["pattern_cols"].as<int>();
auto pattern_rows = yaml["pattern_rows"].as<int>();
auto center_distance_mm = yaml["center_distance_mm"].as<double>();
cv::Size pattern_size(pattern_cols, pattern_rows);
for (int i = 1; true; i++) {
// 读取图片
auto img_path = fmt::format("{}/{}.jpg", input_folder, i);
auto img = cv::imread(img_path);
if (img.empty()) break;
// 设置图片尺寸
img_size = img.size();
// 识别标定板
std::vector<cv::Point2f> centers_2d;
auto success = cv::findCirclesGrid(img, pattern_size, centers_2d, cv::CALIB_CB_SYMMETRIC_GRID);
// 显示识别结果
auto drawing = img.clone();
cv::drawChessboardCorners(drawing, pattern_size, centers_2d, success);
cv::resize(drawing, drawing, {}, 0.5, 0.5); // 缩小图片尺寸便于显示完全
cv::imshow("Press any to continue", drawing);
cv::waitKey(0);
// 输出识别结果
fmt::print("[{}] {}\n", success ? "success" : "failure", img_path);
if (!success) continue;
// 记录所需的数据
img_points.emplace_back(centers_2d);
obj_points.emplace_back(centers_3d(pattern_size, center_distance_mm));
}
}
void print_yaml(const cv::Mat & camera_matrix, const cv::Mat & distort_coeffs, double error)
{
YAML::Emitter result;
std::vector<double> camera_matrix_data(
camera_matrix.begin<double>(), camera_matrix.end<double>());
std::vector<double> distort_coeffs_data(
distort_coeffs.begin<double>(), distort_coeffs.end<double>());
result << YAML::BeginMap;
result << YAML::Comment(fmt::format("重投影误差: {:.4f}px", error));
result << YAML::Key << "camera_matrix";
result << YAML::Value << YAML::Flow << camera_matrix_data;
result << YAML::Key << "distort_coeffs";
result << YAML::Value << YAML::Flow << distort_coeffs_data;
result << YAML::Newline;
result << YAML::EndMap;
fmt::print("\n{}\n", result.c_str());
}
int main(int argc, char * argv[])
{
// 读取命令行参数
cv::CommandLineParser cli(argc, argv, keys);
if (cli.has("help")) {
cli.printMessage();
return 0;
}
auto input_folder = cli.get<std::string>(0);
auto config_path = cli.get<std::string>("config-path");
// 从输入文件夹中加载标定所需的数据
cv::Size img_size;
std::vector<std::vector<cv::Point3f>> obj_points;
std::vector<std::vector<cv::Point2f>> img_points;
load(input_folder, config_path, img_size, obj_points, img_points);
// 相机标定
cv::Mat camera_matrix, distort_coeffs;
std::vector<cv::Mat> rvecs, tvecs;
auto criteria = cv::TermCriteria(
cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 100,
DBL_EPSILON); // 默认迭代次数(30)有时会导致结果发散故设为100
cv::calibrateCamera(
obj_points, img_points, img_size, camera_matrix, distort_coeffs, rvecs, tvecs, cv::CALIB_FIX_K3,
criteria); // 由于视场角较小不需要考虑k3
// 重投影误差
double error_sum = 0;
size_t total_points = 0;
for (size_t i = 0; i < obj_points.size(); i++) {
std::vector<cv::Point2f> reprojected_points;
cv::projectPoints(
obj_points[i], rvecs[i], tvecs[i], camera_matrix, distort_coeffs, reprojected_points);
total_points += reprojected_points.size();
for (size_t j = 0; j < reprojected_points.size(); j++)
error_sum += cv::norm(img_points[i][j] - reprojected_points[j]);
}
auto error = error_sum / total_points;
// 输出yaml
print_yaml(camera_matrix, distort_coeffs, error);
}

View File

@ -0,0 +1,168 @@
#include <fmt/core.h>
#include <yaml-cpp/yaml.h>
#include <Eigen/Dense> // 必须在opencv2/core/eigen.hpp上面
#include <fstream>
#include <opencv2/core/eigen.hpp>
#include <opencv2/opencv.hpp>
#include "tools/img_tools.hpp"
#include "tools/math_tools.hpp"
const std::string keys =
"{help h usage ? | | 输出命令行参数说明}"
"{config-path c | configs/calibration.yaml | yaml配置文件路径 }"
"{@input-folder | assets/img_with_q | 输入文件夹路径 }";
std::vector<cv::Point3f> centers_3d(const cv::Size & pattern_size, const float center_distance)
{
std::vector<cv::Point3f> centers_3d;
for (int i = 0; i < pattern_size.height; i++)
for (int j = 0; j < pattern_size.width; j++)
centers_3d.push_back({j * center_distance, i * center_distance, 0});
return centers_3d;
}
Eigen::Quaterniond read_q(const std::string & q_path)
{
std::ifstream q_file(q_path);
double w, x, y, z;
q_file >> w >> x >> y >> z;
return {w, x, y, z};
}
void load(
const std::string & input_folder, const std::string & config_path,
std::vector<double> & R_gimbal2imubody_data, std::vector<cv::Mat> & R_gimbal2world_list,
std::vector<cv::Mat> & t_gimbal2world_list, std::vector<cv::Mat> & rvecs,
std::vector<cv::Mat> & tvecs)
{
// 读取yaml参数
auto yaml = YAML::LoadFile(config_path);
auto pattern_cols = yaml["pattern_cols"].as<int>();
auto pattern_rows = yaml["pattern_rows"].as<int>();
auto center_distance_mm = yaml["center_distance_mm"].as<double>();
R_gimbal2imubody_data = yaml["R_gimbal2imubody"].as<std::vector<double>>();
auto camera_matrix_data = yaml["camera_matrix"].as<std::vector<double>>();
auto distort_coeffs_data = yaml["distort_coeffs"].as<std::vector<double>>();
cv::Size pattern_size(pattern_cols, pattern_rows);
Eigen::Matrix<double, 3, 3, Eigen::RowMajor> R_gimbal2imubody(R_gimbal2imubody_data.data());
cv::Matx33d camera_matrix(camera_matrix_data.data());
cv::Mat distort_coeffs(distort_coeffs_data);
for (int i = 1; true; i++) {
// 读取图片和对应四元数
auto img_path = fmt::format("{}/{}.jpg", input_folder, i);
auto q_path = fmt::format("{}/{}.txt", input_folder, i);
auto img = cv::imread(img_path);
Eigen::Quaterniond q = read_q(q_path);
if (img.empty()) break;
// 计算云台的欧拉角
Eigen::Matrix3d R_imubody2imuabs = q.toRotationMatrix();
Eigen::Matrix3d R_gimbal2world =
R_gimbal2imubody.transpose() * R_imubody2imuabs * R_gimbal2imubody;
Eigen::Vector3d ypr = tools::eulers(R_gimbal2world, 2, 1, 0) * 57.3; // degree
// 在图片上显示云台的欧拉角用来检验R_gimbal2imubody是否正确
auto drawing = img.clone();
tools::draw_text(drawing, fmt::format("yaw {:.2f}", ypr[0]), {40, 40}, {0, 0, 255});
tools::draw_text(drawing, fmt::format("pitch {:.2f}", ypr[1]), {40, 80}, {0, 0, 255});
tools::draw_text(drawing, fmt::format("roll {:.2f}", ypr[2]), {40, 120}, {0, 0, 255});
// 识别标定板
std::vector<cv::Point2f> centers_2d;
auto success = cv::findCirclesGrid(img, pattern_size, centers_2d); // 默认是对称圆点图案
// 显示识别结果
cv::drawChessboardCorners(drawing, pattern_size, centers_2d, success);
cv::resize(drawing, drawing, {}, 0.5, 0.5); // 显示时缩小图片尺寸
cv::imshow("Press any to continue", drawing);
cv::waitKey(0);
// 输出识别结果
fmt::print("[{}] {}\n", success ? "success" : "failure", img_path);
if (!success) continue;
// 计算所需的数据
cv::Mat t_gimbal2world = (cv::Mat_<double>(3, 1) << 0, 0, 0);
cv::Mat R_gimbal2world_cv;
cv::eigen2cv(R_gimbal2world, R_gimbal2world_cv);
cv::Mat rvec, tvec;
auto centers_3d_ = centers_3d(pattern_size, center_distance_mm);
cv::solvePnP(
centers_3d_, centers_2d, camera_matrix, distort_coeffs, rvec, tvec, false, cv::SOLVEPNP_IPPE);
// 记录所需的数据
R_gimbal2world_list.emplace_back(R_gimbal2world_cv);
t_gimbal2world_list.emplace_back(t_gimbal2world);
rvecs.emplace_back(rvec);
tvecs.emplace_back(tvec);
}
}
void print_yaml(
const std::vector<double> & R_gimbal2imubody_data, const cv::Mat & R_camera2gimbal,
const cv::Mat & t_camera2gimbal, const Eigen::Vector3d & ypr)
{
YAML::Emitter result;
std::vector<double> R_camera2gimbal_data(
R_camera2gimbal.begin<double>(), R_camera2gimbal.end<double>());
std::vector<double> t_camera2gimbal_data(
t_camera2gimbal.begin<double>(), t_camera2gimbal.end<double>());
result << YAML::BeginMap;
result << YAML::Key << "R_gimbal2imubody";
result << YAML::Value << YAML::Flow << R_gimbal2imubody_data;
result << YAML::Newline;
result << YAML::Newline;
result << YAML::Comment(fmt::format(
"相机同理想情况的偏角: yaw{:.2f} pitch{:.2f} roll{:.2f} degree", ypr[0], ypr[1], ypr[2]));
result << YAML::Key << "R_camera2gimbal";
result << YAML::Value << YAML::Flow << R_camera2gimbal_data;
result << YAML::Key << "t_camera2gimbal";
result << YAML::Value << YAML::Flow << t_camera2gimbal_data;
result << YAML::Newline;
result << YAML::EndMap;
fmt::print("\n{}\n", result.c_str());
}
int main(int argc, char * argv[])
{
// 读取命令行参数
cv::CommandLineParser cli(argc, argv, keys);
if (cli.has("help")) {
cli.printMessage();
return 0;
}
auto input_folder = cli.get<std::string>(0);
auto config_path = cli.get<std::string>("config-path");
// 从输入文件夹中加载标定所需的数据
std::vector<double> R_gimbal2imubody_data;
std::vector<cv::Mat> R_gimbal2world_list, t_gimbal2world_list;
std::vector<cv::Mat> rvecs, tvecs;
load(
input_folder, config_path, R_gimbal2imubody_data, R_gimbal2world_list, t_gimbal2world_list,
rvecs, tvecs);
// 手眼标定
cv::Mat R_camera2gimbal, t_camera2gimbal;
cv::calibrateHandEye(
R_gimbal2world_list, t_gimbal2world_list, rvecs, tvecs, R_camera2gimbal, t_camera2gimbal);
t_camera2gimbal /= 1e3; // mm to m
// 计算相机同理想情况的偏角
Eigen::Matrix3d R_camera2gimbal_eigen;
cv::cv2eigen(R_camera2gimbal, R_camera2gimbal_eigen);
Eigen::Matrix3d R_gimbal2ideal{{0, -1, 0}, {0, 0, -1}, {1, 0, 0}};
Eigen::Matrix3d R_camera2ideal = R_gimbal2ideal * R_camera2gimbal_eigen;
Eigen::Vector3d ypr = tools::eulers(R_camera2ideal, 1, 0, 2) * 57.3; // degree
// 输出yaml
print_yaml(R_gimbal2imubody_data, R_camera2gimbal, t_camera2gimbal, ypr);
}

View File

@ -0,0 +1,204 @@
#include <fmt/core.h>
#include <yaml-cpp/yaml.h>
#include <Eigen/Dense> // 必须在opencv2/core/eigen.hpp上面
#include <fstream>
#include <opencv2/core/eigen.hpp>
#include <opencv2/opencv.hpp>
#include "tools/img_tools.hpp"
#include "tools/math_tools.hpp"
const std::string keys =
"{help h usage ? | | 输出命令行参数说明}"
"{config-path c | configs/calibration.yaml | yaml配置文件路径 }"
"{@input-folder | assets/img_with_q | 输入文件夹路径 }";
std::vector<cv::Point3f> centers_3d(const cv::Size & pattern_size, const float center_distance)
{
std::vector<cv::Point3f> centers_3d;
for (int i = 0; i < pattern_size.height; i++) {
for (int j = 0; j < pattern_size.width; j++) {
float x = 0;
float y = (-j + 0.5 * pattern_size.width) * center_distance;
float z = (-i + 0.5 * pattern_size.height) * center_distance;
centers_3d.push_back({x, y, z});
}
}
return centers_3d;
}
Eigen::Quaterniond read_q(const std::string & q_path)
{
std::ifstream q_file(q_path);
double w, x, y, z;
q_file >> w >> x >> y >> z;
return {w, x, y, z};
}
void load(
const std::string & input_folder, const std::string & config_path,
std::vector<double> & R_gimbal2imubody_data, std::vector<cv::Mat> & R_world2gimbal_list,
std::vector<cv::Mat> & t_world2gimbal_list, std::vector<cv::Mat> & rvecs,
std::vector<cv::Mat> & tvecs)
{
// 读取yaml参数
auto yaml = YAML::LoadFile(config_path);
auto pattern_cols = yaml["pattern_cols"].as<int>();
auto pattern_rows = yaml["pattern_rows"].as<int>();
auto center_distance_mm = yaml["center_distance_mm"].as<double>();
R_gimbal2imubody_data = yaml["R_gimbal2imubody"].as<std::vector<double>>();
auto camera_matrix_data = yaml["camera_matrix"].as<std::vector<double>>();
auto distort_coeffs_data = yaml["distort_coeffs"].as<std::vector<double>>();
cv::Size pattern_size(pattern_cols, pattern_rows);
Eigen::Matrix<double, 3, 3, Eigen::RowMajor> R_gimbal2imubody(R_gimbal2imubody_data.data());
cv::Matx33d camera_matrix(camera_matrix_data.data());
cv::Mat distort_coeffs(distort_coeffs_data);
for (int i = 1; true; i++) {
// 读取图片和对应四元数
auto img_path = fmt::format("{}/{}.jpg", input_folder, i);
auto q_path = fmt::format("{}/{}.txt", input_folder, i);
auto img = cv::imread(img_path);
Eigen::Quaterniond q = read_q(q_path);
if (img.empty()) break;
// 计算云台的欧拉角
Eigen::Matrix3d R_imubody2imuabs = q.toRotationMatrix();
Eigen::Matrix3d R_gimbal2world =
R_gimbal2imubody.transpose() * R_imubody2imuabs * R_gimbal2imubody;
Eigen::Vector3d ypr = tools::eulers(R_gimbal2world, 2, 1, 0) * 57.3; // degree
// 在图片上显示云台的欧拉角用来检验R_gimbal2imubody是否正确
auto drawing = img.clone();
tools::draw_text(drawing, fmt::format("yaw {:.2f}", ypr[0]), {40, 40}, {0, 0, 255});
tools::draw_text(drawing, fmt::format("pitch {:.2f}", ypr[1]), {40, 80}, {0, 0, 255});
tools::draw_text(drawing, fmt::format("roll {:.2f}", ypr[2]), {40, 120}, {0, 0, 255});
// 识别标定板
std::vector<cv::Point2f> centers_2d;
auto success = cv::findCirclesGrid(img, pattern_size, centers_2d); // 默认是对称圆点图案
// 显示识别结果
cv::drawChessboardCorners(drawing, pattern_size, centers_2d, success);
cv::resize(drawing, drawing, {}, 0.5, 0.5); // 显示时缩小图片尺寸
cv::imshow("Press any to continue", drawing);
cv::waitKey(0);
// 输出识别结果
fmt::print("[{}] {}\n", success ? "success" : "failure", img_path);
if (!success) continue;
// 计算所需的数据
Eigen::Matrix3d R_world2gimbal = R_gimbal2world.transpose();
cv::Mat t_world2gimbal = (cv::Mat_<double>(3, 1) << 0, 0, 0);
cv::Mat R_world2gimbal_cv;
cv::eigen2cv(R_world2gimbal, R_world2gimbal_cv);
cv::Mat rvec, tvec;
auto centers_3d_ = centers_3d(pattern_size, center_distance_mm);
cv::solvePnP(
centers_3d_, centers_2d, camera_matrix, distort_coeffs, rvec, tvec, false, cv::SOLVEPNP_IPPE);
// 记录所需的数据
R_world2gimbal_list.emplace_back(R_world2gimbal_cv);
t_world2gimbal_list.emplace_back(t_world2gimbal);
rvecs.emplace_back(rvec);
tvecs.emplace_back(tvec);
}
}
void print_yaml(
const std::vector<double> & R_gimbal2imubody_data, const cv::Mat & R_camera2gimbal,
const cv::Mat & t_camera2gimbal, const Eigen::Vector3d & camera_ypr, double distance,
const Eigen::Vector3d & board_ypr)
{
YAML::Emitter result;
std::vector<double> R_camera2gimbal_data(
R_camera2gimbal.begin<double>(), R_camera2gimbal.end<double>());
std::vector<double> t_camera2gimbal_data(
t_camera2gimbal.begin<double>(), t_camera2gimbal.end<double>());
result << YAML::BeginMap;
result << YAML::Key << "R_gimbal2imubody";
result << YAML::Value << YAML::Flow << R_gimbal2imubody_data;
result << YAML::Newline;
result << YAML::Newline;
result << YAML::Comment(fmt::format(
"相机同理想情况的偏角: yaw{:.2f} pitch{:.2f} roll{:.2f} degree", camera_ypr[0], camera_ypr[1],
camera_ypr[2]));
result << YAML::Newline;
result << YAML::Comment(fmt::format("标定板到世界坐标系原点的水平距离: {:.2f} m", distance));
result << YAML::Newline;
result << YAML::Comment(fmt::format(
"标定板同竖直摆放时的偏角: yaw{:.2f} pitch{:.2f} roll{:.2f} degree", board_ypr[0], board_ypr[1],
board_ypr[2]));
result << YAML::Key << "R_camera2gimbal";
result << YAML::Value << YAML::Flow << R_camera2gimbal_data;
result << YAML::Key << "t_camera2gimbal";
result << YAML::Value << YAML::Flow << t_camera2gimbal_data;
result << YAML::Newline;
result << YAML::EndMap;
fmt::print("\n{}\n", result.c_str());
}
int main(int argc, char * argv[])
{
// 读取命令行参数
cv::CommandLineParser cli(argc, argv, keys);
if (cli.has("help")) {
cli.printMessage();
return 0;
}
auto input_folder = cli.get<std::string>(0);
auto config_path = cli.get<std::string>("config-path");
// 从输入文件夹中加载标定所需的数据
std::vector<double> R_gimbal2imubody_data;
std::vector<cv::Mat> R_world2gimbal_list, t_world2gimbal_list;
std::vector<cv::Mat> rvecs, tvecs;
load(
input_folder, config_path, R_gimbal2imubody_data, R_world2gimbal_list, t_world2gimbal_list,
rvecs, tvecs);
// 手眼标定
cv::Mat R_gimbal2camera, t_gimbal2camera;
cv::Mat R_world2board, t_world2board;
cv::calibrateRobotWorldHandEye(
rvecs, tvecs, R_world2gimbal_list, t_world2gimbal_list, R_world2board, t_world2board,
R_gimbal2camera, t_gimbal2camera);
t_gimbal2camera /= 1e3; // mm to m
t_world2board /= 1e3; // mm to m
// 计算所需的数据
cv::Mat R_camera2gimbal, t_camera2gimbal;
cv::Mat R_board2world, t_board2world;
cv::transpose(R_gimbal2camera, R_camera2gimbal);
cv::transpose(R_world2board, R_board2world);
t_camera2gimbal = -R_camera2gimbal * t_gimbal2camera;
t_board2world = -R_board2world * t_world2board;
// 计算相机同理想情况的偏角
Eigen::Matrix3d R_camera2gimbal_eigen;
cv::cv2eigen(R_camera2gimbal, R_camera2gimbal_eigen);
Eigen::Matrix3d R_gimbal2ideal{{0, -1, 0}, {0, 0, -1}, {1, 0, 0}};
Eigen::Matrix3d R_camera2ideal = R_gimbal2ideal * R_camera2gimbal_eigen;
Eigen::Vector3d camera_ypr = tools::eulers(R_camera2ideal, 1, 0, 2) * 57.3; // degree
// 计算标定板到世界坐标系原点的水平距离
auto x = t_board2world.at<double>(0);
auto y = t_board2world.at<double>(1);
auto distance = std::sqrt(x * x + y * y);
// 计算标定板同竖直摆放时的偏角
Eigen::Matrix3d R_board2world_eigen;
cv::cv2eigen(R_board2world, R_board2world_eigen);
Eigen::Vector3d board_ypr = tools::eulers(R_board2world_eigen, 2, 1, 0) * 57.3; // degree
// 输出yaml
print_yaml(
R_gimbal2imubody_data, R_camera2gimbal, t_camera2gimbal, camera_ypr, distance, board_ypr);
}

93
calibration/capture.cpp Normal file
View File

@ -0,0 +1,93 @@
#include <fmt/core.h>
#include <filesystem>
#include <fstream>
#include <opencv2/opencv.hpp>
#include "io/camera.hpp"
#include "io/cboard.hpp"
#include "tools/img_tools.hpp"
#include "tools/logger.hpp"
#include "tools/math_tools.hpp"
const std::string keys =
"{help h usage ? | | 输出命令行参数说明}"
"{@config-path c | configs/calibration.yaml | yaml配置文件路径 }"
"{output-folder o | assets/img_with_q | 输出文件夹路径 }";
void write_q(const std::string q_path, const Eigen::Quaterniond & q)
{
std::ofstream q_file(q_path);
Eigen::Vector4d xyzw = q.coeffs();
// 输出顺序为wxyz
q_file << fmt::format("{} {} {} {}", xyzw[3], xyzw[0], xyzw[1], xyzw[2]);
q_file.close();
}
void capture_loop(
const std::string & config_path, const std::string & can, const std::string & output_folder)
{
io::CBoard cboard(config_path);
io::Camera camera(config_path);
cv::Mat img;
std::chrono::steady_clock::time_point timestamp;
int count = 0;
while (true) {
camera.read(img, timestamp);
Eigen::Quaterniond q = cboard.imu_at(timestamp);
// 在图像上显示欧拉角用来判断imuabs系的xyz正方向同时判断imu是否存在零漂
auto img_with_ypr = img.clone();
Eigen::Vector3d zyx = tools::eulers(q, 2, 1, 0) * 57.3; // degree
tools::draw_text(img_with_ypr, fmt::format("Z {:.2f}", zyx[0]), {40, 40}, {0, 0, 255});
tools::draw_text(img_with_ypr, fmt::format("Y {:.2f}", zyx[1]), {40, 80}, {0, 0, 255});
tools::draw_text(img_with_ypr, fmt::format("X {:.2f}", zyx[2]), {40, 120}, {0, 0, 255});
std::vector<cv::Point2f> centers_2d;
auto success = cv::findCirclesGrid(img, cv::Size(10, 7), centers_2d); // 默认是对称圆点图案
cv::drawChessboardCorners(img_with_ypr, cv::Size(10, 7), centers_2d, success); // 显示识别结果
cv::resize(img_with_ypr, img_with_ypr, {}, 0.5, 0.5); // 显示时缩小图片尺寸
// 按“s”保存图片和对应四元数按“q”退出程序
cv::imshow("Press s to save, q to quit", img_with_ypr);
auto key = cv::waitKey(1);
if (key == 'q')
break;
else if (key != 's')
continue;
// 保存图片和四元数
count++;
auto img_path = fmt::format("{}/{}.jpg", output_folder, count);
auto q_path = fmt::format("{}/{}.txt", output_folder, count);
cv::imwrite(img_path, img);
write_q(q_path, q);
tools::logger()->info("[{}] Saved in {}", count, output_folder);
}
// 离开该作用域时camera和cboard会自动关闭
}
int main(int argc, char * argv[])
{
// 读取命令行参数
cv::CommandLineParser cli(argc, argv, keys);
if (cli.has("help")) {
cli.printMessage();
return 0;
}
auto config_path = cli.get<std::string>(0);
auto output_folder = cli.get<std::string>("output-folder");
// 新建输出文件夹
std::filesystem::create_directory(output_folder);
tools::logger()->info("默认标定板尺寸为10列7行");
// 主循环,保存图片和对应四元数
capture_loop(config_path, "can0", output_folder);
tools::logger()->warn("注意四元数输出顺序为wxyz");
return 0;
}

View File

@ -0,0 +1,89 @@
#include <fmt/format.h>
#include <chrono>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <string>
#include "tools/exiter.hpp"
#include "tools/img_tools.hpp"
#include "tools/logger.hpp"
#include "tools/math_tools.hpp"
// 定义命令行参数
const std::string keys =
"{help h usage ? | | 输出命令行参数说明 }"
"{start-index s | | 视频起始帧下标 }"
"{end-index e | | 视频结束帧下标 }"
"{output-path p | records/Big/2024-05-14_11-6-26 | avi和txt文件的路径}"
"{@input-path | | avi和txt文件的路径}";
int main(int argc, char * argv[])
{
// 读取命令行参数
cv::CommandLineParser cli(argc, argv, keys);
if (cli.has("help")) {
cli.printMessage();
return 0;
}
auto input_path = cli.get<std::string>(0);
auto output_path = cli.get<std::string>("output-path");
auto start_index = cli.get<int>("start-index");
std::cout << start_index << std::endl;
auto end_index = cli.get<int>("end-index");
// 初始化绘图器和退出器
tools::Exiter exiter;
// 构造视频和文本文件路径
auto video_path = fmt::format("{}.avi", input_path);
auto text_path = fmt::format("{}.txt", input_path);
cv::VideoCapture video(video_path);
std::ifstream text(text_path);
// 设置视频起始帧
video.set(cv::CAP_PROP_POS_FRAMES, start_index);
for (int i = 0; i < start_index; i++) {
double t, w, x, y, z;
text >> t >> w >> x >> y >> z;
}
// 获取原始视频的参数
int frameWidth = video.get(cv::CAP_PROP_FRAME_WIDTH);
int frameHeight = video.get(cv::CAP_PROP_FRAME_HEIGHT);
double fps = video.get(cv::CAP_PROP_FPS);
int fourcc = static_cast<int>(video.get(cv::CAP_PROP_FOURCC));
// 创建输出文件
auto outvideo_path = fmt::format("{}.avi", output_path);
auto outtext_path = fmt::format("{}.txt", output_path);
cv::VideoWriter outvideo(outvideo_path, fourcc, fps, cv::Size(frameWidth, frameHeight));
std::ofstream outtext(outtext_path);
std::string line;
cv::Mat img;
// 循环处理视频帧
for (int frame_count = start_index; !exiter.exit(); frame_count++) {
if (end_index > 0 && frame_count > end_index) break;
video.read(img);
if (img.empty()) break;
outvideo.write(img);
getline(text, line);
outtext << line << std::endl;
cv::resize(img, img, cv::Size(img.size().width * 0.8, img.size().height * 0.8));
cv::imshow("result", img);
int key = cv::waitKey(1);
if (key == 'q') break;
}
cv::destroyAllWindows();
text.close(); // 关闭文件
outtext.close();
return 0;
}

85
configs/ascento.yaml Normal file
View File

@ -0,0 +1,85 @@
# enemy_color: "red"
enemy_color: "blue"
#####-----神经网络参数-----#####
yolo_name: yolov5
classify_model: assets/tiny_resnet.onnx
yolo11_model_path: assets/yolo11.xml
yolov8_model_path: assets/yolov8.xml
yolov5_model_path: assets/yolov5.xml
device: GPU
min_confidence: 0.8
use_traditional: false
#####-----ROI-----#####
roi:
x: 500
y: 400
width: 500
height: 500
use_roi: false
#####-----传统方法参数-----#####
threshold: 150
max_angle_error: 45 # degree
min_lightbar_ratio: 1.5
max_lightbar_ratio: 20
min_lightbar_length: 8
min_armor_ratio: 1
max_armor_ratio: 5
max_side_ratio: 1.5
max_rectangular_error: 25 # degree
min_confidence: 0.8
#####-----tracker参数-----#####
min_detect_count: 5
max_temp_lost_count: 15
outpost_max_temp_lost_count: 75
#####-----aimer参数-----#####
yaw_offset: 1.5 # degree
pitch_offset: -0.5 # degree
comming_angle: 60 # degree
leaving_angle: 20 # degree
decision_speed: 7 # rad/s
high_speed_delay_time: 0.050 # s
low_speed_delay_time: 0.015 # s
#####-----shooter参数-----#####
first_tolerance: 100 # 近距离射击容差degree
second_tolerance: 100 # 远距离射击容差degree
judge_distance: 2 #距离判断阈值
auto_fire: true # 是否由自瞄控制射击
camera_name: "hikrobot"
exposure_ms: 2
gain: 16
vid_pid: "2bdf:0001"
R_gimbal2imubody: [1, 0, 0, 0, 1, 0, 0, 0, 1]
# 重投影误差: 0.1488px
camera_matrix: [1775.1300101814929, 0, 710.22041588791421, 0, 1777.9427175568535, 599.38373307949621, 0, 0, 1]
distort_coeffs: [-0.081907189655237952, 0.14019999270205855, -0.0012264127665053185, 0.0014292255962000792, 0]
# 相机同理想情况的偏角: yaw1.81 pitch0.16 roll-0.00 degree
R_camera2gimbal: [-0.03152275773856239, 0.0027095830669845509, 0.99949936163269204, -0.99950303430107212, -9.8404785402239625e-05, -0.031522606799691932, 1.2942398579498703e-05, -0.99999632423129503, 0.0027113384873522772]
t_camera2gimbal: [0.13895789074180098, 0.066620637390426771, 0.028079650211170731]
#####-----cboard参数-----#####
quaternion_canid: 0x100
bullet_speed_canid: 0x101
send_canid: 0xff
can_interface: "can0"
#####-----gimbal参数-----#####
com_port: "/dev/gimbal"
#####-----buff_detector参数-----#####
model: "assets/yolo11_buff_int8.xml"
#####-----buff_aimer参数-----#####
fire_gap_time: 0.520 # s
predict_time: 0.100 # s

16
configs/calibration.yaml Normal file
View File

@ -0,0 +1,16 @@
pattern_cols: 10
pattern_rows: 7
center_distance_mm: 40
R_gimbal2imubody: [1, 0, 0, 0, 1, 0, 0, 0, 1]
camera_name: "hikrobot"
exposure_ms: 3
gain: 10.0
vid_pid: "2bdf:0001"
#####-----cboard参数-----#####
quaternion_canid: 0x01
bullet_speed_canid: 0x110
send_canid: 0xff
can_interface: "can0"

9
configs/camera.yaml Normal file
View File

@ -0,0 +1,9 @@
camera_name: "mindvision"
exposure_ms: 2
gamma: 0.5
vid_pid: "f622:d13a"
# camera_name: "hikrobot"
# exposure_ms: 3
# gain: 10.0
# vid_pid: "2bdf:0001"

121
configs/demo.yaml Normal file
View File

@ -0,0 +1,121 @@
# enemy_color: "red"
enemy_color: "blue"
#####-----神经网络参数-----#####
yolo_name: yolov5
classify_model: assets/tiny_resnet.onnx
yolo11_model_path: assets/yolo11.xml
yolov8_model_path: assets/yolov8.xml
yolov5_model_path: assets/yolov5.xml
device: CPU
min_confidence: 0.8
use_traditional: true
#####-----ROI-----#####
roi:
x: 420
y: 50
width: 600
height: 600
use_roi: false
#####-----传统方法参数-----#####
threshold: 150
max_angle_error: 45 # degree
min_lightbar_ratio: 1.5
max_lightbar_ratio: 20
min_lightbar_length: 8
min_armor_ratio: 1
max_armor_ratio: 5
max_side_ratio: 1.5
max_rectangular_error: 25 # degree
min_confidence: 0.8
#####-----tracker参数-----#####
min_detect_count: 5
max_temp_lost_count: 15
outpost_max_temp_lost_count: 75
#####-----aimer参数-----#####
yaw_offset: -1 # degree -2.5
pitch_offset: -1.4 # degree 2
comming_angle: 60 # degree
leaving_angle: 20 # degree
decision_speed: 8 # rad/s
high_speed_delay_time: 0.030 # s
low_speed_delay_time: 0.015 # s
#####-----shooter参数-----#####
first_tolerance: 3 # 近距离射击容差degree
second_tolerance: 2 # 远距离射击容差degree
judge_distance: 2 #距离判断阈值
auto_fire: true # 是否由自瞄控制射击
camera_name: "hikrobot"
exposure_ms: 2
gain: 16
vid_pid: "2bdf:0001"
# -1 0 0
# 0 -1 0
# 0 0 1
R_gimbal2imubody: [-1, 0, 0, 0, -1, 0, 0, 0, 1]
# 重投影误差: 0.2697px
camera_matrix: [1818.3669452465165, 0, 751.06226574703498, 0, 1822.494494078506, 530.43671556112133, 0, 0, 1]
distort_coeffs: [-0.077944626599568856, 0.15447826031486889, -0.0025714394278524674, 0.00083016311301273629, 0]
# 相机同理想情况的偏角: yaw0.46 pitch0.61 roll-1.53 degree
R_camera2gimbal: [-0.0083195760046954614, 0.010498791137270739, 0.99991027599468041, -0.99960756138647755, -0.026835747568381807, -0.0080352891314148939, 0.026748978935305992, -0.99958472279097077, 0.010717933047771133]
t_camera2gimbal: [0.094969301833534511, 0.095006290298006682, 0.050987066291756609]
#####-----cboard参数-----#####
quaternion_canid: 0x100
bullet_speed_canid: 0x101
send_canid: 0xff
can_interface: "can0"
#####-----gimbal参数-----#####
com_port: "/dev/gimbal"
#####-----planner-----#####
fire_thresh: 0.003
max_yaw_acc: 50
Q_yaw: [9e6, 0]
R_yaw: [1]
max_pitch_acc: 100
Q_pitch: [9e6,0]
R_pitch: [1]
#####-----buff_detector参数-----#####
detect:
contrast: 1
brightness:
blue: -120
red: -100
brightness_threshold:
blue: 120
red: 40
morphology_size:
blue: 3
red: 3
dilate_size: 2
# canny_low_threshold: 100
# canny_high_threshold: 180
# approx_epsilon: 1.0
R_contours_min_area: 200
R_contours_max_area: 600
fanblades_head_contours_min_area: 3000
fanblades_head_contours_max_area: 8000
fanblades_body_contours_min_area: 1000
fanblades_body_contours_max_area: 4000
standard_fanblade_path: ./assets/standard_fanblade.jpg
#####-----buff_aimer参数-----#####
aim_time: 0.150 # s
wait_time: 0.300 # s
command_fire_gap: 0.080 # s
predict_time: 0.150 # s

83
configs/example.yaml Normal file
View File

@ -0,0 +1,83 @@
# enemy_color: "red"
enemy_color: "blue"
#####-----神经网络参数-----#####
yolo_name: yolov5
classify_model: assets/tiny_resnet.onnx
yolo11_model_path: assets/yolo11.xml
yolov8_model_path: assets/yolov8.xml
yolov5_model_path: assets/yolov5.xml
device: CPU
min_confidence: 0.8
use_traditional: true
#####-----ROI-----#####
roi:
x: 420
y: 50
width: 600
height: 600
#####-----USB相机参数-----#####
image_width: 1920
image_height: 1080
fov_h: 87.7
fov_v: 56.7
usb_frame_rate: 60
usb_exposure: 250 #1-80000______250
usb_gamma: 160
usb_gain: 10 #0-96
#####-----工业相机参数-----#####
camera_name: "mindvision"
exposure_ms: 2
gamma: 0.5
vid_pid: "f622:d13a"
#####-----传统方法参数-----#####
threshold: 150
max_angle_error: 45 # degree
min_lightbar_ratio: 1.5
max_lightbar_ratio: 20
min_lightbar_length: 8
min_armor_ratio: 1
max_armor_ratio: 5
max_side_ratio: 1.5
max_rectangular_error: 25 # degree
min_confidence: 0.8
#####-----cboard参数-----#####
quaternion_canid: 0x01
bullet_speed_canid: 0x101
send_canid: 0xff
can_interface: "can0"
#####-----tracker参数-----#####
min_detect_count: 5
max_temp_lost_count: 15
#####-----aimer参数-----#####
yaw_offset: -2.5 # degree -2.5
pitch_offset: 3 # degree 2
comming_angle: 60 # degree
leaving_angle: 20 # degree
#####-----shooter参数-----#####
first_tolerance: 3 # 近距离射击容差degree
second_tolerance: 2 # 远距离射击容差degree
judge_distance: 2 #距离判断阈值
auto_fire: true # 是否由自瞄控制射击
#####-----工业相机标定参数-----#####
R_gimbal2imubody: [1, 0, 0, 0, 1, 0, 0, 0, 1]
# 重投影误差: 0.1944px
camera_matrix: [1295.4665175006589, 0, 655.71498478800618, 0, 1297.2591156991834, 506.21320670125334, 0, 0, 1]
distort_coeffs: [-0.48599095566724387, 0.23999516531343185, -0.00029018466701866776, -0.00083639963030895752, 0]
# 相机同理想情况的偏角: yaw-2.64 pitch-3.20 roll-0.77 degree
# 标定板到世界坐标系原点的水平距离: 1.45 m
# 标定板同竖直摆放时的偏角: yaw90.85 pitch8.54 roll-0.32 degree
R_camera2gimbal: [0.046736929626455238, -0.055211941324114208, 0.99738021884550865, -0.99881598162461238, -0.016078770676278314, 0.0459141370909011, 0.013501639172863072, -0.99834518813322415, -0.055898041744621867]
t_camera2gimbal: [0.27420934670256336, 0.0098763306562371159, 0.043798385984197351]

124
configs/mvs.yaml Normal file
View File

@ -0,0 +1,124 @@
# enemy_color: "red"
enemy_color: "blue"
#####-----神经网络参数-----#####
yolo_name: yolov5
classify_model: assets/tiny_resnet.onnx
yolo11_model_path: assets/yolo11.xml
yolov8_model_path: assets/yolov8.xml
yolov5_model_path: assets/yolov5.xml
device: GPU
min_confidence: 0.8
use_traditional: true
#####-----ROI-----#####
roi:
x: 420
y: 50
width: 600
height: 600
use_roi: false
#####-----USB相机参数-----#####
image_width: 640
image_height: 360
new_image_width: 1280
new_image_height: 720
fov_h: 57.7 #87.7
fov_v: 56.7
new_fov_h: 37 #67
new_fov_v: 40.9
usb_frame_rate: 60
usb_exposure: 305 #1-80000______250
new_usb_exposure: 320
usb_gamma: 160
usb_gain: 10 #0-96
#####-----工业相机参数-----#####
camera_name: "hikrobot"
exposure_ms: 2
gain: 16
vid_pid: "2bdf:0001"
#####-----传统方法参数-----#####
threshold: 150
max_angle_error: 45 # degree
min_lightbar_ratio: 1.5
max_lightbar_ratio: 20
min_lightbar_length: 8
min_armor_ratio: 1
max_armor_ratio: 5
max_side_ratio: 1.5
max_rectangular_error: 25 # degree
min_confidence: 0.8
#####-----cboard参数-----#####
quaternion_canid: 0x01
bullet_speed_canid: 0x110
send_canid: 0xff
can_interface: "can0"
#####-----tracker参数-----#####
min_detect_count: 5
max_temp_lost_count: 15
outpost_max_temp_lost_count: 75
#####-----aimer参数-----#####
yaw_offset: -2.5 # degree -2.5
pitch_offset: 0 # degree 2
comming_angle: 70 # degree
leaving_angle: 30 # degree
decision_speed: 7 # rad/s
high_speed_delay_time: 0.066 # s
low_speed_delay_time: 0.015 # s
#####-----shooter参数-----#####
first_tolerance: 3 # 近距离射击容差degree
second_tolerance: 2 # 远距离射击容差degree
judge_distance: 2 #距离判断阈值
auto_fire: true # 是否由自瞄控制射击
#####-----decider参数-----#####
mode: 1
#####-----工业相机标定参数-----#####
R_gimbal2imubody: [1, 0, 0, 0, 1, 0, 0, 0, 1]
# 重投影误差: 0.1322px
camera_matrix: [1776.9477196851155, 0, 756.31235265560952, 0, 1776.0591253569607, 566.16539069551641, 0, 0, 1]
distort_coeffs: [-0.08382326954462313, 0.097449270330296239, -0.0012558283068959985, 0.0037372210254148081, 0]
R_camera2gimbal: [0, 0, 1, -1, 0, 0, 0, -1, 0]
t_camera2gimbal: [0.1, 0, 0.05]
#####-----buff_detector参数-----#####
detect:
contrast: 1
brightness:
blue: -120
red: -100
brightness_threshold:
blue: 120
red: 80
morphology_size:
blue: 3
red: 2
dilate_size: 1
# canny_low_threshold: 100
# canny_high_threshold: 180
# approx_epsilon: 1.0
R_contours_min_area: 1
R_contours_max_area: 600
fanblades_head_contours_min_area: 300
fanblades_head_contours_max_area: 8000
fanblades_body_contours_min_area: 1000
fanblades_body_contours_max_area: 4000
standard_fanblade_path: ./assets/standard_fanblade.jpg
#####-----buff_aimer参数-----#####
aim_time: 0.200 # s
wait_time: 0.050 # s
predict_time: 0.300 # s

96
configs/sentry.yaml Normal file
View File

@ -0,0 +1,96 @@
# enemy_color: "red"
enemy_color: "blue"
#####-----神经网络参数-----#####
yolo_name: yolov5
classify_model: assets/tiny_resnet.onnx
yolo11_model_path: assets/yolo11.xml
yolov8_model_path: assets/yolov8.xml
yolov5_model_path: assets/yolov5.xml
device: GPU
min_confidence: 0.8
use_traditional: true
#####-----ROI-----#####
roi:
x: 420
y: 50
width: 600
height: 600
use_roi: false
#####-----USB相机参数-----#####
image_width: 1280
image_height: 720
fov_h: 57.7 #87.7
fov_v: 56.7
new_fov_h: 27 #67
new_fov_v: 40.9
usb_frame_rate: 120
usb_exposure: 500 #1-80000______250
usb_gamma: 160
usb_gain: 10 #0-96
#####-----工业相机参数-----#####
camera_name: "hikrobot"
exposure_ms: 0.8
gain: 16.9
vid_pid: "2bdf:0001"
#####-----传统方法参数-----#####
threshold: 150
max_angle_error: 45 # degree
min_lightbar_ratio: 1.5
max_lightbar_ratio: 20
min_lightbar_length: 8
min_armor_ratio: 1
max_armor_ratio: 5
max_side_ratio: 1.5
max_rectangular_error: 25 # degree
min_confidence: 0.8
#####-----cboard参数-----#####
quaternion_canid: 0x01
bullet_speed_canid: 0x110
send_canid: 0xff
can_interface: "can0"
#####-----tracker参数-----#####
min_detect_count: 5
max_temp_lost_count: 25
outpost_max_temp_lost_count: 75
#####-----aimer参数-----#####
yaw_offset: -0.8 # degree -2.5
pitch_offset: -1 # degree 2
comming_angle: 60 # degree
leaving_angle: 20 # degree
left_yaw_offset: -1
right_yaw_offset: -0.6
decision_speed: 10 # rad/s
high_speed_delay_time: 0.026 # s
low_speed_delay_time: 0.010 # s
#####-----shooter参数-----#####
first_tolerance: 5 # 近距离射击容差degree
second_tolerance: 2 # 远距离射击容差degree
judge_distance: 3 #距离判断阈值
auto_fire: true # 是否由自瞄控制射击
#####-----decider参数-----#####
mode: 1
#####-----工业相机标定参数-----#####
R_gimbal2imubody: [1, 0, 0, 0, 1, 0, 0, 0, 1]
# 重投影误差: 0.1833px
camera_matrix: [2414.9359264386621, 0, 717.26243105567414, 0, 2418.0489262208148, 582.68540529942845, 0, 0, 1]
distort_coeffs: [-0.0209453389287673, 0.15028138841073832, -0.0006517722113234505, -0.0016861906197686788, 0]
# 相机同理想情况的偏角: yaw-1.11 pitch0.01 roll-0.06 degree
# 标定板到世界坐标系原点的水平距离: 1.20 m
# 标定板同竖直摆放时的偏角: yaw123.89 pitch14.05 roll-0.86 degree
R_camera2gimbal: [0.01928451708725664, 0.00012696140743255463, 0.99981402834802846, -0.99981344688553653, -0.0010834913551969569, 0.019284643459122196, 0.0010857382619952124, -0.99999940496346484, 0.00010604311483339372]
t_camera2gimbal: [0.13089617453251859, 0.0038468007459533785, 0.094139945222010288]

103
configs/standard3.yaml Normal file
View File

@ -0,0 +1,103 @@
enemy_color: "red"
# enemy_color: "blue"
#####-----神经网络参数-----#####
yolo_name: yolov5
classify_model: assets/tiny_resnet.onnx
yolo11_model_path: assets/yolo11.xml
yolov8_model_path: assets/yolov8.xml
yolov5_model_path: assets/yolov5.xml
device: GPU
min_confidence: 0.8
use_traditional: true
#####-----ROI-----#####
roi:
x: 420
y: 50
width: 600
height: 600
use_roi: false
#####-----传统方法参数-----#####
threshold: 150
max_angle_error: 45 # degree
min_lightbar_ratio: 1.5
max_lightbar_ratio: 20
min_lightbar_length: 8
min_armor_ratio: 1
max_armor_ratio: 5
max_side_ratio: 1.5
max_rectangular_error: 25 # degree
#####-----tracker参数-----#####
min_detect_count: 5
max_temp_lost_count: 15
outpost_max_temp_lost_count: 75
#####-----aimer参数-----#####
yaw_offset: 2 # degree -2.5
pitch_offset: 6.5 # degree 2
comming_angle: 55 # degree
leaving_angle: 20 # degree
decision_speed: 7 # rad/s
high_speed_delay_time: 0.0 # s
low_speed_delay_time: 0.0 # s planner use this value
#####-----shooter参数-----#####
first_tolerance: 3 # 近距离射击容差degree
second_tolerance: 2 # 远距离射击容差degree
judge_distance: 2 #距离判断阈值
auto_fire: true # 是否由自瞄控制射击
camera_name: "hikrobot"
exposure_ms: 2.5
gain: 16.9
vid_pid: "2bdf:0001"
# 1 0 0
# 0 1 0
# 0 0 1
R_gimbal2imubody: [1, 0, 0, 0, 1, 0, 0, 0, 1]
# 重投影误差: 0.1820px
camera_matrix: [1785.4881526822305, 0, 672.4806478241826, 0, 1785.026019470562, 559.89603224794314, 0, 0, 1]
distort_coeffs: [-0.076005079619881746, 0.11182817466388446, 0.0005362204787722057, -0.0027546300984895122, 0]
# 相机同理想情况的偏角: yaw1.44 pitch-7.28 roll0.96 degree
# 标定板到世界坐标系原点的水平距离: 1.13 m
# 标定板同竖直摆放时的偏角: yaw7.61 pitch13.92 roll-0.46 degree
R_camera2gimbal: [-0.027182119030230909, -0.12616154330853446, 0.99163723074269183, -0.99949106557517331, 0.019998323121329122, -0.024853106601381177, -0.016695575474690555, -0.99180811252093692, -0.12664093215554434]
t_camera2gimbal: [0.13160669975045827, 0.10377721766577375, 0.024908271912914642]
#####-----cboard参数-----#####
quaternion_canid: 0x100
bullet_speed_canid: 0x101
send_canid: 0xff
can_interface: "can0"
#####-----gimbal参数-----#####
com_port: "/dev/gimbal"
yaw_kp: 0
yaw_kd: 0
pitch_kp: 0
pitch_kd: 0
#####-----planner-----#####
fire_thresh: 0.0035
max_yaw_acc: 50
Q_yaw: [9e6, 0]
R_yaw: [1]
max_pitch_acc: 100
Q_pitch: [9e6, 0]
R_pitch: [1]
#####-----buff_detector参数-----#####
model: "assets/yolo11_buff_int8.xml"
#####-----buff_aimer参数-----#####
fire_gap_time: 0.700 # s
predict_time: 0.120 # s

99
configs/standard4.yaml Normal file
View File

@ -0,0 +1,99 @@
enemy_color: "red"
# enemy_color: "blue"
#####-----神经网络参数-----#####
yolo_name: yolov5
classify_model: assets/tiny_resnet.onnx
yolo11_model_path: assets/yolo11.xml
yolov8_model_path: assets/yolov8.xml
yolov5_model_path: assets/yolov5.xml
device: GPU
min_confidence: 0.8
use_traditional: true
#####-----ROI-----#####
roi:
x: 420
y: 50
width: 600
height: 600
use_roi: false
#####-----传统方法参数-----#####
threshold: 150
max_angle_error: 45 # degree
min_lightbar_ratio: 1.5
max_lightbar_ratio: 20
min_lightbar_length: 8
min_armor_ratio: 1
max_armor_ratio: 5
max_side_ratio: 1.5
max_rectangular_error: 25 # degree
min_confidence: 0.8
#####-----tracker参数-----#####
min_detect_count: 5
max_temp_lost_count: 15
outpost_max_temp_lost_count: 75
#####-----aimer参数-----#####
yaw_offset: -2 # degree -2.5
pitch_offset: 0 # degree 2
comming_angle: 60 # degree
leaving_angle: 20 # degree
decision_speed: 8 # rad/s
high_speed_delay_time: 0.015 # s
low_speed_delay_time: 0.015 # s
#####-----shooter参数-----#####
first_tolerance: 3 # 近距离射击容差degree
second_tolerance: 2 # 远距离射击容差degree
judge_distance: 2 #距离判断阈值
auto_fire: true # 是否由自瞄控制射击
camera_name: "hikrobot"
exposure_ms: 2
gain: 16
vid_pid: "2bdf:0001"
# 1 0 0
# 0 1 0
# 0 0 1
R_gimbal2imubody: [1, 0, 0, 0, 1, 0, 0, 0, 1]
# 重投影误差: 0.3145px
camera_matrix: [1851.7070167840545, 0, 721.12585328714192, 0, 1851.8175594364079, 571.69879709276688, 0, 0, 1]
distort_coeffs: [-0.093662536083526302, 0.18945726820633155, -0.00040424349861928674, -0.0040568403852123142, 0]
# 相机同理想情况的偏角: yaw-1.61 pitch-0.82 roll-0.61 degree
R_camera2gimbal: [0.02823004230930648, -0.014076983590428133, 0.99950232778328707, -0.99954530259354468, -0.010995644138609872, 0.028076393521179785, 0.010594940981141165, -0.99984045444409364, -0.014380990321749998]
t_camera2gimbal: [0.045517325957791413, 0.10544338092767802, 0.034649710880185793]
#####-----cboard参数-----#####
quaternion_canid: 0x100
bullet_speed_canid: 0x101
send_canid: 0xff
can_interface: "can0"
#####-----gimbal参数-----#####
com_port: "/dev/gimbal"
#####-----planner-----#####
fire_thresh: 0.003
max_yaw_acc: 50
Q_yaw: [9e6, 0]
R_yaw: [1]
max_pitch_acc: 100
Q_pitch: [9e6,0]
R_pitch: [1]
#####-----buff_detector参数-----#####
model: "assets/yolo11_buff_int8.xml"
#####-----buff_aimer参数-----#####
fire_gap_time: 0.520 # s
predict_time: 0.100 # s

105
configs/uav.yaml Normal file
View File

@ -0,0 +1,105 @@
enemy_color: "red"
# enemy_color: "blue"
#####-----神经网络参数-----#####
yolo_name: yolov5
classify_model: assets/tiny_resnet.onnx
yolo11_model_path: assets/yolo11.xml
yolov8_model_path: assets/yolov8.xml
yolov5_model_path: assets/yolov5.xml
device: CPU
min_confidence: 0.8
use_traditional: true
#####-----ROI-----#####
roi:
x: 420
y: 50
width: 600
height: 600
use_roi: false
#####-----工业相机参数-----#####
camera_name: "mindvision"
exposure_ms: 8
gamma: 0.6
vid_pid: "f622:d13a"
#####-----USB相机参数-----#####
image_width: 640
image_height: 360
new_image_width: 1280
new_image_height: 720
fov_h: 87.7
fov_v: 56.7
new_fov_h: 67
new_fov_v: 40.9
usb_frame_rate: 100
usb_exposure: 315 #1-80000______250
usb_gamma: 160
usb_gain: 10 #0-96
#####-----传统方法参数-----#####
threshold: 150
max_angle_error: 45 # degree
min_lightbar_ratio: 1.5
max_lightbar_ratio: 20
min_lightbar_length: 8
min_armor_ratio: 1
max_armor_ratio: 5
max_side_ratio: 1.5
max_rectangular_error: 25 # degree
min_confidence: 0.8
#####-----cboard参数-----#####
quaternion_canid: 0x001
bullet_speed_canid: 0x110
send_canid: 0xff
can_interface: "can0"
#####-----tracker参数-----#####
min_detect_count: 5
max_temp_lost_count: 15
outpost_max_temp_lost_count: 150
#####-----aimer参数-----#####
yaw_offset: 0 # degree -2.5
pitch_offset: 1.5 # degree 2
comming_angle: 70 # degree
leaving_angle: 30 # degree
min_spin_speed: 2 # rad/s
decision_speed: 12 # rad/s
high_speed_delay_time: 0.005 # s
low_speed_delay_time: 0.005 # s
#####-----decider参数-----#####
mode: 1
#####-----shooter参数-----#####
first_tolerance: 2 # 近距离射击容差degree
second_tolerance: 0.8 # 远距离射击容差degree
judge_distance: 0.5 #距离判断阈值
auto_fire: true # 是否由自瞄控制射击
#####-----工业相机标定参数-----#####
R_gimbal2imubody: [1, 0, 0, 0, 1, 0, 0, 0, 1]
# 重投影误差: 0.1032px
camera_matrix: [2924.6190997571712, 0, 647.0245571651617, 0, 2927.4258594148396, 388.18625585771758, 0, 0, 1]
distort_coeffs: [-0.58886594170687334, 0.32512251112647716, 0.012447953238733123, -0.0032411418907421475, 0]
# 相机同理想情况的偏角: yaw0.02 pitch1.94 roll1.40 degree
# 标定板到世界坐标系原点的水平距离: 4.12 m
# 标定板同竖直摆放时的偏角: yaw-87.29 pitch7.65 roll-0.51 degree
R_camera2gimbal: [0.00046423063676173171, 0.033770528223625203, 0.99942950522456209, -0.99970300483287733, 0.024367462669785803, -0.00035901413901253575, -0.02436568525675643, -0.99913251282626891, 0.03377181066266309]
t_camera2gimbal: [-0.034955523715399906, -0.000074403211899371, 0.001248173910106823]
#####-----buff_detector参数-----#####
model: "assets/yolo11_buff_int8.xml"
#####-----buff_aimer参数-----#####
fire_gap_time: 0.600 # s
predict_time: 0.090 # s

59
io/CMakeLists.txt Normal file
View File

@ -0,0 +1,59 @@
cmake_minimum_required(VERSION 3.16)
find_package(yaml-cpp REQUIRED)
add_subdirectory(serial)
# io
add_library(io STATIC
hikrobot/hikrobot.cpp
mindvision/mindvision.cpp
usbcamera/usbcamera.cpp
camera.cpp
cboard.cpp
dm_imu/dm_imu.cpp
gimbal/gimbal.cpp
)
# hikrobot
target_include_directories(io PUBLIC hikrobot/include)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
target_link_directories(io PUBLIC hikrobot/lib/amd64)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
target_link_directories(io PUBLIC hikrobot/lib/arm64)
else()
message(FATAL_ERROR "Unsupported architecture: ${CMAKE_HOST_SYSTEM_PROCESSOR}!")
endif()
# mindvision
target_include_directories(io PUBLIC mindvision/include)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
target_link_directories(io PUBLIC mindvision/lib/amd64)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
target_link_directories(io PUBLIC mindvision/lib/arm64)
else()
message(FATAL_ERROR "Unsupported architecture: ${CMAKE_HOST_SYSTEM_PROCESSOR}!")
endif()
target_link_libraries(io MvCameraControl MVSDK usb-1.0 yaml-cpp serial)
################## ROS ##################
find_package(ament_cmake QUIET)
find_package(rclcpp QUIET)
find_package(std_msgs QUIET)
find_package(rosidl_typesupport_cpp QUIET)
find_package(sp_msgs QUIET)
# ROS ROS
if(NOT ament_cmake_FOUND OR NOT rclcpp_FOUND OR NOT std_msgs_FOUND OR NOT rosidl_typesupport_cpp_FOUND OR NOT sp_msgs_FOUND)
message(WARNING "ROS2 not found, skipping ROS2 specific code.")
else()
message(STATUS "ROS2 environment found, compiling ROS2-related code.")
# ROS2
target_sources(io PRIVATE ros2/publish2nav.cpp ros2/ros2.cpp ros2/subscribe2nav.cpp)
# ROS2
include_directories(${std_msgs_INCLUDE_DIRS})
ament_target_dependencies(io rclcpp std_msgs sp_msgs)
endif()

39
io/camera.cpp Normal file
View File

@ -0,0 +1,39 @@
#include "camera.hpp"
#include <stdexcept>
#include "hikrobot/hikrobot.hpp"
#include "mindvision/mindvision.hpp"
#include "tools/yaml.hpp"
namespace io
{
Camera::Camera(const std::string & config_path)
{
auto yaml = tools::load(config_path);
auto camera_name = tools::read<std::string>(yaml, "camera_name");
auto exposure_ms = tools::read<double>(yaml, "exposure_ms");
if (camera_name == "mindvision") {
auto gamma = tools::read<double>(yaml, "gamma");
auto vid_pid = tools::read<std::string>(yaml, "vid_pid");
camera_ = std::make_unique<MindVision>(exposure_ms, gamma, vid_pid);
}
else if (camera_name == "hikrobot") {
auto gain = tools::read<double>(yaml, "gain");
auto vid_pid = tools::read<std::string>(yaml, "vid_pid");
camera_ = std::make_unique<HikRobot>(exposure_ms, gain, vid_pid);
}
else {
throw std::runtime_error("Unknow camera_name: " + camera_name + "!");
}
}
void Camera::read(cv::Mat & img, std::chrono::steady_clock::time_point & timestamp)
{
camera_->read(img, timestamp);
}
} // namespace io

30
io/camera.hpp Normal file
View File

@ -0,0 +1,30 @@
#ifndef IO__CAMERA_HPP
#define IO__CAMERA_HPP
#include <chrono>
#include <memory>
#include <opencv2/opencv.hpp>
#include <string>
namespace io
{
class CameraBase
{
public:
virtual ~CameraBase() = default;
virtual void read(cv::Mat & img, std::chrono::steady_clock::time_point & timestamp) = 0;
};
class Camera
{
public:
Camera(const std::string & config_path);
void read(cv::Mat & img, std::chrono::steady_clock::time_point & timestamp);
private:
std::unique_ptr<CameraBase> camera_;
};
} // namespace io
#endif // IO__CAMERA_HPP

121
io/cboard.cpp Normal file
View File

@ -0,0 +1,121 @@
#include "cboard.hpp"
#include "tools/math_tools.hpp"
#include "tools/yaml.hpp"
namespace io
{
CBoard::CBoard(const std::string & config_path)
: mode(Mode::idle),
shoot_mode(ShootMode::left_shoot),
bullet_speed(0),
queue_(5000),
can_(read_yaml(config_path), std::bind(&CBoard::callback, this, std::placeholders::_1))
// 注意: callback的运行会早于Cboard构造函数的完成
{
tools::logger()->info("[Cboard] Waiting for q...");
queue_.pop(data_ahead_);
queue_.pop(data_behind_);
tools::logger()->info("[Cboard] Opened.");
}
Eigen::Quaterniond CBoard::imu_at(std::chrono::steady_clock::time_point timestamp)
{
if (data_behind_.timestamp < timestamp) data_ahead_ = data_behind_;
while (true) {
queue_.pop(data_behind_);
if (data_behind_.timestamp > timestamp) break;
data_ahead_ = data_behind_;
}
Eigen::Quaterniond q_a = data_ahead_.q.normalized();
Eigen::Quaterniond q_b = data_behind_.q.normalized();
auto t_a = data_ahead_.timestamp;
auto t_b = data_behind_.timestamp;
auto t_c = timestamp;
std::chrono::duration<double> t_ab = t_b - t_a;
std::chrono::duration<double> t_ac = t_c - t_a;
// 四元数插值
auto k = t_ac / t_ab;
Eigen::Quaterniond q_c = q_a.slerp(k, q_b).normalized();
return q_c;
}
void CBoard::send(Command command) const
{
can_frame frame;
frame.can_id = send_canid_;
frame.can_dlc = 8;
frame.data[0] = (command.control) ? 1 : 0;
frame.data[1] = (command.shoot) ? 1 : 0;
frame.data[2] = (int16_t)(command.yaw * 1e4) >> 8;
frame.data[3] = (int16_t)(command.yaw * 1e4);
frame.data[4] = (int16_t)(command.pitch * 1e4) >> 8;
frame.data[5] = (int16_t)(command.pitch * 1e4);
frame.data[6] = (int16_t)(command.horizon_distance * 1e4) >> 8;
frame.data[7] = (int16_t)(command.horizon_distance * 1e4);
try {
can_.write(&frame);
} catch (const std::exception & e) {
tools::logger()->warn("{}", e.what());
}
}
void CBoard::callback(const can_frame & frame)
{
auto timestamp = std::chrono::steady_clock::now();
if (frame.can_id == quaternion_canid_) {
auto x = (int16_t)(frame.data[0] << 8 | frame.data[1]) / 1e4;
auto y = (int16_t)(frame.data[2] << 8 | frame.data[3]) / 1e4;
auto z = (int16_t)(frame.data[4] << 8 | frame.data[5]) / 1e4;
auto w = (int16_t)(frame.data[6] << 8 | frame.data[7]) / 1e4;
if (std::abs(x * x + y * y + z * z + w * w - 1) > 1e-2) {
tools::logger()->warn("Invalid q: {} {} {} {}", w, x, y, z);
return;
}
queue_.push({{w, x, y, z}, timestamp});
}
else if (frame.can_id == bullet_speed_canid_) {
bullet_speed = (int16_t)(frame.data[0] << 8 | frame.data[1]) / 1e2;
mode = Mode(frame.data[2]);
shoot_mode = ShootMode(frame.data[3]);
ft_angle = (int16_t)(frame.data[4] << 8 | frame.data[5]) / 1e4;
// 限制日志输出频率为1Hz
static auto last_log_time = std::chrono::steady_clock::time_point::min();
auto now = std::chrono::steady_clock::now();
if (bullet_speed > 0 && tools::delta_time(now, last_log_time) >= 1.0) {
tools::logger()->info(
"[CBoard] Bullet speed: {:.2f} m/s, Mode: {}, Shoot mode: {}, FT angle: {:.2f} rad",
bullet_speed, MODES[mode], SHOOT_MODES[shoot_mode], ft_angle);
last_log_time = now;
}
}
}
// 实现方式有待改进
std::string CBoard::read_yaml(const std::string & config_path)
{
auto yaml = tools::load(config_path);
quaternion_canid_ = tools::read<int>(yaml, "quaternion_canid");
bullet_speed_canid_ = tools::read<int>(yaml, "bullet_speed_canid");
send_canid_ = tools::read<int>(yaml, "send_canid");
if (!yaml["can_interface"]) {
throw std::runtime_error("Missing 'can_interface' in YAML configuration.");
}
return yaml["can_interface"].as<std::string>();
}
} // namespace io

72
io/cboard.hpp Normal file
View File

@ -0,0 +1,72 @@
#ifndef IO__CBOARD_HPP
#define IO__CBOARD_HPP
#include <Eigen/Geometry>
#include <chrono>
#include <cmath>
#include <functional>
#include <string>
#include <vector>
#include "io/command.hpp"
#include "io/socketcan.hpp"
#include "tools/logger.hpp"
#include "tools/thread_safe_queue.hpp"
namespace io
{
enum Mode
{
idle,
auto_aim,
small_buff,
big_buff,
outpost
};
const std::vector<std::string> MODES = {"idle", "auto_aim", "small_buff", "big_buff", "outpost"};
// 哨兵专有
enum ShootMode
{
left_shoot,
right_shoot,
both_shoot
};
const std::vector<std::string> SHOOT_MODES = {"left_shoot", "right_shoot", "both_shoot"};
class CBoard
{
public:
double bullet_speed;
Mode mode;
ShootMode shoot_mode;
double ft_angle; //无人机专有
CBoard(const std::string & config_path);
Eigen::Quaterniond imu_at(std::chrono::steady_clock::time_point timestamp);
void send(Command command) const;
private:
struct IMUData
{
Eigen::Quaterniond q;
std::chrono::steady_clock::time_point timestamp;
};
tools::ThreadSafeQueue<IMUData> queue_; // 必须在can_之前初始化否则存在死锁的可能
SocketCAN can_;
IMUData data_ahead_;
IMUData data_behind_;
int quaternion_canid_, bullet_speed_canid_, send_canid_;
void callback(const can_frame & frame);
std::string read_yaml(const std::string & config_path);
};
} // namespace io
#endif // IO__CBOARD_HPP

17
io/command.hpp Normal file
View File

@ -0,0 +1,17 @@
#ifndef IO__COMMAND_HPP
#define IO__COMMAND_HPP
namespace io
{
struct Command
{
bool control;
bool shoot;
double yaw;
double pitch;
double horizon_distance = 0; //无人机专有
};
} // namespace io
#endif // IO__COMMAND_HPP

131
io/dm_imu/dm_imu.cpp Normal file
View File

@ -0,0 +1,131 @@
#include "dm_imu.hpp"
#include <atomic>
#include <chrono>
#include <cstdint>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
#include "tools/crc.hpp"
#include "tools/logger.hpp"
#include "tools/math_tools.hpp"
namespace io
{
DM_IMU::DM_IMU() : queue_(5000)
{
init_serial();
rec_thread_ = std::thread(&DM_IMU::get_imu_data_thread, this);
queue_.pop(data_ahead_);
queue_.pop(data_behind_);
tools::logger()->info("[DM_IMU] initialized");
}
DM_IMU::~DM_IMU()
{
stop_thread_ = true;
if (rec_thread_.joinable()) {
rec_thread_.join();
}
if (serial_.isOpen()) {
serial_.close();
}
}
void DM_IMU::init_serial()
{
try {
serial_.setPort("/dev/ttyACM0");
serial_.setBaudrate(921600);
serial_.setFlowcontrol(serial::flowcontrol_none);
serial_.setParity(serial::parity_none); //default is parity_none
serial_.setStopbits(serial::stopbits_one);
serial_.setBytesize(serial::eightbits);
serial::Timeout time_out = serial::Timeout::simpleTimeout(20);
serial_.setTimeout(time_out);
serial_.open();
usleep(1000000); //1s
tools::logger()->info("[DM_IMU] serial port opened");
}
catch (serial::IOException & e) {
tools::logger()->warn("[DM_IMU] failed to open serial port ");
exit(0);
}
}
void DM_IMU::get_imu_data_thread()
{
while (!stop_thread_) {
if (!serial_.isOpen()) {
tools::logger()->warn("In get_imu_data_thread,imu serial port unopen");
}
serial_.read((uint8_t *)(&receive_data.FrameHeader1), 4);
if (
receive_data.FrameHeader1 == 0x55 && receive_data.flag1 == 0xAA &&
receive_data.slave_id1 == 0x01 && receive_data.reg_acc == 0x01)
{
serial_.read((uint8_t *)(&receive_data.accx_u32), 57 - 4);
if (tools::get_crc16((uint8_t *)(&receive_data.FrameHeader1), 16) == receive_data.crc1) {
data.accx = *((float *)(&receive_data.accx_u32));
data.accy = *((float *)(&receive_data.accy_u32));
data.accz = *((float *)(&receive_data.accz_u32));
}
if (tools::get_crc16((uint8_t *)(&receive_data.FrameHeader2), 16) == receive_data.crc2) {
data.gyrox = *((float *)(&receive_data.gyrox_u32));
data.gyroy = *((float *)(&receive_data.gyroy_u32));
data.gyroz = *((float *)(&receive_data.gyroz_u32));
}
if (tools::get_crc16((uint8_t *)(&receive_data.FrameHeader3), 16) == receive_data.crc3) {
data.roll = *((float *)(&receive_data.roll_u32));
data.pitch = *((float *)(&receive_data.pitch_u32));
data.yaw = *((float *)(&receive_data.yaw_u32));
// tools::logger()->debug(
// "yaw: {:.2f}, pitch: {:.2f}, roll: {:.2f}", static_cast<double>(data.yaw),
// static_cast<double>(data.pitch), static_cast<double>(data.roll));
}
auto timestamp = std::chrono::steady_clock::now();
Eigen::Quaterniond q = Eigen::AngleAxisd(data.yaw * M_PI / 180, Eigen::Vector3d::UnitZ()) *
Eigen::AngleAxisd(data.pitch * M_PI / 180, Eigen::Vector3d::UnitY()) *
Eigen::AngleAxisd(data.roll * M_PI / 180, Eigen::Vector3d::UnitX());
q.normalize();
queue_.push({q, timestamp});
} else {
tools::logger()->info("[DM_IMU] failed to get correct data");
}
}
}
Eigen::Quaterniond DM_IMU::imu_at(std::chrono::steady_clock::time_point timestamp)
{
if (data_behind_.timestamp < timestamp) data_ahead_ = data_behind_;
while (true) {
queue_.pop(data_behind_);
if (data_behind_.timestamp > timestamp) break;
data_ahead_ = data_behind_;
}
Eigen::Quaterniond q_a = data_ahead_.q.normalized();
Eigen::Quaterniond q_b = data_behind_.q.normalized();
auto t_a = data_ahead_.timestamp;
auto t_b = data_behind_.timestamp;
auto t_c = timestamp;
std::chrono::duration<double> t_ab = t_b - t_a;
std::chrono::duration<double> t_ac = t_c - t_a;
// 四元数插值
auto k = t_ac / t_ab;
Eigen::Quaterniond q_c = q_a.slerp(k, q_b).normalized();
return q_c;
}
} // namespace io

96
io/dm_imu/dm_imu.hpp Normal file
View File

@ -0,0 +1,96 @@
#ifndef IO__Dm_Imu_HPP
#define IO__Dm_Imu_HPP
#include <math.h>
#include <serial/serial.h>
#include <Eigen/Geometry>
#include <array>
#include <fstream>
#include <initializer_list>
#include <iostream>
#include <thread>
#include "tools/thread_safe_queue.hpp"
namespace io
{
struct __attribute__((packed)) IMU_Receive_Frame
{
uint8_t FrameHeader1;
uint8_t flag1;
uint8_t slave_id1;
uint8_t reg_acc;
uint32_t accx_u32;
uint32_t accy_u32;
uint32_t accz_u32;
uint16_t crc1;
uint8_t FrameEnd1;
uint8_t FrameHeader2;
uint8_t flag2;
uint8_t slave_id2;
uint8_t reg_gyro;
uint32_t gyrox_u32;
uint32_t gyroy_u32;
uint32_t gyroz_u32;
uint16_t crc2;
uint8_t FrameEnd2;
uint8_t FrameHeader3;
uint8_t flag3;
uint8_t slave_id3;
uint8_t reg_euler; //r-p-y
uint32_t roll_u32;
uint32_t pitch_u32;
uint32_t yaw_u32;
uint16_t crc3;
uint8_t FrameEnd3;
};
typedef struct
{
float accx;
float accy;
float accz;
float gyrox;
float gyroy;
float gyroz;
float roll;
float pitch;
float yaw;
} IMU_Data;
class DM_IMU
{
public:
DM_IMU();
~DM_IMU();
Eigen::Quaterniond imu_at(std::chrono::steady_clock::time_point timestamp);
private:
struct IMUData
{
Eigen::Quaterniond q;
std::chrono::steady_clock::time_point timestamp;
};
void init_serial();
void get_imu_data_thread();
serial::Serial serial_;
std::thread rec_thread_;
tools::ThreadSafeQueue<IMUData> queue_;
IMUData data_ahead_, data_behind_;
std::atomic<bool> stop_thread_{false};
IMU_Receive_Frame receive_data{}; //receive data frame
IMU_Data data{};
};
} // namespace io
#endif

223
io/gimbal/gimbal.cpp Normal file
View File

@ -0,0 +1,223 @@
#include "gimbal.hpp"
#include "tools/crc.hpp"
#include "tools/logger.hpp"
#include "tools/math_tools.hpp"
#include "tools/yaml.hpp"
namespace io
{
Gimbal::Gimbal(const std::string & config_path)
{
auto yaml = tools::load(config_path);
auto com_port = tools::read<std::string>(yaml, "com_port");
try {
serial_.setPort(com_port);
serial_.open();
} catch (const std::exception & e) {
tools::logger()->error("[Gimbal] Failed to open serial: {}", e.what());
exit(1);
}
thread_ = std::thread(&Gimbal::read_thread, this);
queue_.pop();
tools::logger()->info("[Gimbal] First q received.");
}
Gimbal::~Gimbal()
{
quit_ = true;
if (thread_.joinable()) thread_.join();
serial_.close();
}
GimbalMode Gimbal::mode() const
{
std::lock_guard<std::mutex> lock(mutex_);
return mode_;
}
GimbalState Gimbal::state() const
{
std::lock_guard<std::mutex> lock(mutex_);
return state_;
}
std::string Gimbal::str(GimbalMode mode) const
{
switch (mode) {
case GimbalMode::IDLE:
return "IDLE";
case GimbalMode::AUTO_AIM:
return "AUTO_AIM";
case GimbalMode::SMALL_BUFF:
return "SMALL_BUFF";
case GimbalMode::BIG_BUFF:
return "BIG_BUFF";
default:
return "INVALID";
}
}
Eigen::Quaterniond Gimbal::q(std::chrono::steady_clock::time_point t)
{
while (true) {
auto [q_a, t_a] = queue_.pop();
auto [q_b, t_b] = queue_.front();
auto t_ab = tools::delta_time(t_a, t_b);
auto t_ac = tools::delta_time(t_a, t);
auto k = t_ac / t_ab;
Eigen::Quaterniond q_c = q_a.slerp(k, q_b).normalized();
if (t < t_a) return q_c;
if (!(t_a < t && t <= t_b)) continue;
return q_c;
}
}
void Gimbal::send(io::VisionToGimbal VisionToGimbal)
{
tx_data_.mode = VisionToGimbal.mode;
tx_data_.yaw = VisionToGimbal.yaw;
tx_data_.yaw_vel = VisionToGimbal.yaw_vel;
tx_data_.yaw_acc = VisionToGimbal.yaw_acc;
tx_data_.pitch = VisionToGimbal.pitch;
tx_data_.pitch_vel = VisionToGimbal.pitch_vel;
tx_data_.pitch_acc = VisionToGimbal.pitch_acc;
tx_data_.crc16 = tools::get_crc16(
reinterpret_cast<uint8_t *>(&tx_data_), sizeof(tx_data_) - sizeof(tx_data_.crc16));
try {
serial_.write(reinterpret_cast<uint8_t *>(&tx_data_), sizeof(tx_data_));
} catch (const std::exception & e) {
tools::logger()->warn("[Gimbal] Failed to write serial: {}", e.what());
}
}
void Gimbal::send(
bool control, bool fire, float yaw, float yaw_vel, float yaw_acc, float pitch, float pitch_vel,
float pitch_acc)
{
tx_data_.mode = control ? (fire ? 2 : 1) : 0;
tx_data_.yaw = yaw;
tx_data_.yaw_vel = yaw_vel;
tx_data_.yaw_acc = yaw_acc;
tx_data_.pitch = pitch;
tx_data_.pitch_vel = pitch_vel;
tx_data_.pitch_acc = pitch_acc;
tx_data_.crc16 = tools::get_crc16(
reinterpret_cast<uint8_t *>(&tx_data_), sizeof(tx_data_) - sizeof(tx_data_.crc16));
try {
serial_.write(reinterpret_cast<uint8_t *>(&tx_data_), sizeof(tx_data_));
} catch (const std::exception & e) {
tools::logger()->warn("[Gimbal] Failed to write serial: {}", e.what());
}
}
bool Gimbal::read(uint8_t * buffer, size_t size)
{
try {
return serial_.read(buffer, size) == size;
} catch (const std::exception & e) {
// tools::logger()->warn("[Gimbal] Failed to read serial: {}", e.what());
return false;
}
}
void Gimbal::read_thread()
{
tools::logger()->info("[Gimbal] read_thread started.");
int error_count = 0;
while (!quit_) {
if (error_count > 5000) {
error_count = 0;
tools::logger()->warn("[Gimbal] Too many errors, attempting to reconnect...");
reconnect();
continue;
}
if (!read(reinterpret_cast<uint8_t *>(&rx_data_), sizeof(rx_data_.head))) {
error_count++;
continue;
}
if (rx_data_.head[0] != 'S' || rx_data_.head[1] != 'P') continue;
auto t = std::chrono::steady_clock::now();
if (!read(
reinterpret_cast<uint8_t *>(&rx_data_) + sizeof(rx_data_.head),
sizeof(rx_data_) - sizeof(rx_data_.head))) {
error_count++;
continue;
}
if (!tools::check_crc16(reinterpret_cast<uint8_t *>(&rx_data_), sizeof(rx_data_))) {
tools::logger()->debug("[Gimbal] CRC16 check failed.");
continue;
}
error_count = 0;
Eigen::Quaterniond q(rx_data_.q[0], rx_data_.q[1], rx_data_.q[2], rx_data_.q[3]);
queue_.push({q, t});
std::lock_guard<std::mutex> lock(mutex_);
state_.yaw = rx_data_.yaw;
state_.yaw_vel = rx_data_.yaw_vel;
state_.pitch = rx_data_.pitch;
state_.pitch_vel = rx_data_.pitch_vel;
state_.bullet_speed = rx_data_.bullet_speed;
state_.bullet_count = rx_data_.bullet_count;
switch (rx_data_.mode) {
case 0:
mode_ = GimbalMode::IDLE;
break;
case 1:
mode_ = GimbalMode::AUTO_AIM;
break;
case 2:
mode_ = GimbalMode::SMALL_BUFF;
break;
case 3:
mode_ = GimbalMode::BIG_BUFF;
break;
default:
mode_ = GimbalMode::IDLE;
tools::logger()->warn("[Gimbal] Invalid mode: {}", rx_data_.mode);
break;
}
}
tools::logger()->info("[Gimbal] read_thread stopped.");
}
void Gimbal::reconnect()
{
int max_retry_count = 10;
for (int i = 0; i < max_retry_count && !quit_; ++i) {
tools::logger()->warn("[Gimbal] Reconnecting serial, attempt {}/{}...", i + 1, max_retry_count);
try {
serial_.close();
std::this_thread::sleep_for(std::chrono::seconds(1));
} catch (...) {
}
try {
serial_.open(); // 尝试重新打开
queue_.clear();
tools::logger()->info("[Gimbal] Reconnected serial successfully.");
break;
} catch (const std::exception & e) {
tools::logger()->warn("[Gimbal] Reconnect failed: {}", e.what());
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
}
} // namespace io

106
io/gimbal/gimbal.hpp Normal file
View File

@ -0,0 +1,106 @@
#ifndef IO__GIMBAL_HPP
#define IO__GIMBAL_HPP
#include <Eigen/Geometry>
#include <atomic>
#include <chrono>
#include <mutex>
#include <string>
#include <thread>
#include <tuple>
#include "serial/serial.h"
#include "tools/thread_safe_queue.hpp"
namespace io
{
struct __attribute__((packed)) GimbalToVision
{
uint8_t head[2] = {'M', 'R'};
uint8_t mode; // 0: 空闲, 1: 自瞄, 2: 小符, 3: 大符
float q[4]; // wxyz顺序
float yaw;
float yaw_vel;
float pitch;
float pitch_vel;
float bullet_speed;
uint16_t bullet_count; // 子弹累计发送次数
uint16_t crc16;
};
static_assert(sizeof(GimbalToVision) <= 64);
struct __attribute__((packed)) VisionToGimbal
{
uint8_t head[2] = {'M', 'R'};
uint8_t mode; // 0: 不控制, 1: 控制云台但不开火2: 控制云台且开火
float yaw;
float yaw_vel;
float yaw_acc;
float pitch;
float pitch_vel;
float pitch_acc;
uint16_t crc16;
};
static_assert(sizeof(VisionToGimbal) <= 64);
enum class GimbalMode
{
IDLE, // 空闲
AUTO_AIM, // 自瞄
SMALL_BUFF, // 小符
BIG_BUFF // 大符
};
struct GimbalState
{
float yaw;
float yaw_vel;
float pitch;
float pitch_vel;
float bullet_speed;
uint16_t bullet_count;
};
class Gimbal
{
public:
Gimbal(const std::string & config_path);
~Gimbal();
GimbalMode mode() const;
GimbalState state() const;
std::string str(GimbalMode mode) const;
Eigen::Quaterniond q(std::chrono::steady_clock::time_point t);
void send(
bool control, bool fire, float yaw, float yaw_vel, float yaw_acc, float pitch, float pitch_vel,
float pitch_acc);
void send(io::VisionToGimbal VisionToGimbal);
private:
serial::Serial serial_;
std::thread thread_;
std::atomic<bool> quit_ = false;
mutable std::mutex mutex_;
GimbalToVision rx_data_;
VisionToGimbal tx_data_;
GimbalMode mode_ = GimbalMode::IDLE;
GimbalState state_;
tools::ThreadSafeQueue<std::tuple<Eigen::Quaterniond, std::chrono::steady_clock::time_point>>
queue_{1000};
bool read(uint8_t * buffer, size_t size);
void read_thread();
void reconnect();
};
} // namespace io
#endif // IO__GIMBAL_HPP

246
io/hikrobot/hikrobot.cpp Normal file
View File

@ -0,0 +1,246 @@
#include "hikrobot.hpp"
#include <libusb-1.0/libusb.h>
#include "tools/logger.hpp"
using namespace std::chrono_literals;
namespace io
{
HikRobot::HikRobot(double exposure_ms, double gain, const std::string & vid_pid)
: exposure_us_(exposure_ms * 1e3), gain_(gain), queue_(1), daemon_quit_(false), vid_(-1), pid_(-1)
{
set_vid_pid(vid_pid);
if (libusb_init(NULL)) tools::logger()->warn("Unable to init libusb!");
daemon_thread_ = std::thread{[this] {
tools::logger()->info("HikRobot's daemon thread started.");
capture_start();
while (!daemon_quit_) {
std::this_thread::sleep_for(100ms);
if (capturing_) continue;
capture_stop();
reset_usb();
capture_start();
}
capture_stop();
tools::logger()->info("HikRobot's daemon thread stopped.");
}};
}
HikRobot::~HikRobot()
{
daemon_quit_ = true;
if (daemon_thread_.joinable()) daemon_thread_.join();
tools::logger()->info("HikRobot destructed.");
}
void HikRobot::read(cv::Mat & img, std::chrono::steady_clock::time_point & timestamp)
{
CameraData data;
queue_.pop(data);
img = data.img;
timestamp = data.timestamp;
}
void HikRobot::capture_start()
{
capturing_ = false;
capture_quit_ = false;
unsigned int ret;
MV_CC_DEVICE_INFO_LIST device_list;
ret = MV_CC_EnumDevices(MV_USB_DEVICE, &device_list);
if (ret != MV_OK) {
tools::logger()->warn("MV_CC_EnumDevices failed: {:#x}", ret);
return;
}
if (device_list.nDeviceNum == 0) {
tools::logger()->warn("Not found camera!");
return;
}
ret = MV_CC_CreateHandle(&handle_, device_list.pDeviceInfo[0]);
if (ret != MV_OK) {
tools::logger()->warn("MV_CC_CreateHandle failed: {:#x}", ret);
return;
}
ret = MV_CC_OpenDevice(handle_);
if (ret != MV_OK) {
tools::logger()->warn("MV_CC_OpenDevice failed: {:#x}", ret);
return;
}
set_enum_value("BalanceWhiteAuto", MV_BALANCEWHITE_AUTO_CONTINUOUS);
set_enum_value("ExposureAuto", MV_EXPOSURE_AUTO_MODE_OFF);
set_enum_value("GainAuto", MV_GAIN_MODE_OFF);
set_float_value("ExposureTime", exposure_us_);
set_float_value("Gain", gain_);
MV_CC_SetFrameRate(handle_, 150);
ret = MV_CC_StartGrabbing(handle_);
if (ret != MV_OK) {
tools::logger()->warn("MV_CC_StartGrabbing failed: {:#x}", ret);
return;
}
capture_thread_ = std::thread{[this] {
tools::logger()->info("HikRobot's capture thread started.");
capturing_ = true;
MV_FRAME_OUT raw;
MV_CC_PIXEL_CONVERT_PARAM cvt_param;
while (!capture_quit_) {
std::this_thread::sleep_for(1ms);
unsigned int ret;
unsigned int nMsec = 100;
ret = MV_CC_GetImageBuffer(handle_, &raw, nMsec);
if (ret != MV_OK) {
tools::logger()->warn("MV_CC_GetImageBuffer failed: {:#x}", ret);
break;
}
auto timestamp = std::chrono::steady_clock::now();
cv::Mat img(cv::Size(raw.stFrameInfo.nWidth, raw.stFrameInfo.nHeight), CV_8U, raw.pBufAddr);
cvt_param.nWidth = raw.stFrameInfo.nWidth;
cvt_param.nHeight = raw.stFrameInfo.nHeight;
cvt_param.pSrcData = raw.pBufAddr;
cvt_param.nSrcDataLen = raw.stFrameInfo.nFrameLen;
cvt_param.enSrcPixelType = raw.stFrameInfo.enPixelType;
cvt_param.pDstBuffer = img.data;
cvt_param.nDstBufferSize = img.total() * img.elemSize();
cvt_param.enDstPixelType = PixelType_Gvsp_BGR8_Packed;
// ret = MV_CC_ConvertPixelType(handle_, &cvt_param);
const auto & frame_info = raw.stFrameInfo;
auto pixel_type = frame_info.enPixelType;
cv::Mat dst_image;
const static std::unordered_map<MvGvspPixelType, cv::ColorConversionCodes> type_map = {
{PixelType_Gvsp_BayerGR8, cv::COLOR_BayerGR2RGB},
{PixelType_Gvsp_BayerRG8, cv::COLOR_BayerRG2RGB},
{PixelType_Gvsp_BayerGB8, cv::COLOR_BayerGB2RGB},
{PixelType_Gvsp_BayerBG8, cv::COLOR_BayerBG2RGB}};
cv::cvtColor(img, dst_image, type_map.at(pixel_type));
img = dst_image;
queue_.push({img, timestamp});
ret = MV_CC_FreeImageBuffer(handle_, &raw);
if (ret != MV_OK) {
tools::logger()->warn("MV_CC_FreeImageBuffer failed: {:#x}", ret);
break;
}
}
capturing_ = false;
tools::logger()->info("HikRobot's capture thread stopped.");
}};
}
void HikRobot::capture_stop()
{
capture_quit_ = true;
if (capture_thread_.joinable()) capture_thread_.join();
unsigned int ret;
ret = MV_CC_StopGrabbing(handle_);
if (ret != MV_OK) {
tools::logger()->warn("MV_CC_StopGrabbing failed: {:#x}", ret);
return;
}
ret = MV_CC_CloseDevice(handle_);
if (ret != MV_OK) {
tools::logger()->warn("MV_CC_CloseDevice failed: {:#x}", ret);
return;
}
ret = MV_CC_DestroyHandle(handle_);
if (ret != MV_OK) {
tools::logger()->warn("MV_CC_DestroyHandle failed: {:#x}", ret);
return;
}
}
void HikRobot::set_float_value(const std::string & name, double value)
{
unsigned int ret;
ret = MV_CC_SetFloatValue(handle_, name.c_str(), value);
if (ret != MV_OK) {
tools::logger()->warn("MV_CC_SetFloatValue(\"{}\", {}) failed: {:#x}", name, value, ret);
return;
}
}
void HikRobot::set_enum_value(const std::string & name, unsigned int value)
{
unsigned int ret;
ret = MV_CC_SetEnumValue(handle_, name.c_str(), value);
if (ret != MV_OK) {
tools::logger()->warn("MV_CC_SetEnumValue(\"{}\", {}) failed: {:#x}", name, value, ret);
return;
}
}
void HikRobot::set_vid_pid(const std::string & vid_pid)
{
auto index = vid_pid.find(':');
if (index == std::string::npos) {
tools::logger()->warn("Invalid vid_pid: \"{}\"", vid_pid);
return;
}
auto vid_str = vid_pid.substr(0, index);
auto pid_str = vid_pid.substr(index + 1);
try {
vid_ = std::stoi(vid_str, 0, 16);
pid_ = std::stoi(pid_str, 0, 16);
} catch (const std::exception &) {
tools::logger()->warn("Invalid vid_pid: \"{}\"", vid_pid);
}
}
void HikRobot::reset_usb() const
{
if (vid_ == -1 || pid_ == -1) return;
// https://github.com/ralight/usb-reset/blob/master/usb-reset.c
auto handle = libusb_open_device_with_vid_pid(NULL, vid_, pid_);
if (!handle) {
tools::logger()->warn("Unable to open usb!");
return;
}
if (libusb_reset_device(handle))
tools::logger()->warn("Unable to reset usb!");
else
tools::logger()->info("Reset usb successfully :)");
libusb_close(handle);
}
} // namespace io

56
io/hikrobot/hikrobot.hpp Normal file
View File

@ -0,0 +1,56 @@
#ifndef IO__HIKROBOT_HPP
#define IO__HIKROBOT_HPP
#include <atomic>
#include <chrono>
#include <opencv2/opencv.hpp>
#include <string>
#include <thread>
#include "MvCameraControl.h"
#include "io/camera.hpp"
#include "tools/thread_safe_queue.hpp"
namespace io
{
class HikRobot : public CameraBase
{
public:
HikRobot(double exposure_ms, double gain, const std::string & vid_pid);
~HikRobot() override;
void read(cv::Mat & img, std::chrono::steady_clock::time_point & timestamp) override;
private:
struct CameraData
{
cv::Mat img;
std::chrono::steady_clock::time_point timestamp;
};
double exposure_us_;
double gain_;
std::thread daemon_thread_;
std::atomic<bool> daemon_quit_;
void * handle_;
std::thread capture_thread_;
std::atomic<bool> capturing_;
std::atomic<bool> capture_quit_;
tools::ThreadSafeQueue<CameraData> queue_;
int vid_, pid_;
void capture_start();
void capture_stop();
void set_float_value(const std::string & name, double value);
void set_enum_value(const std::string & name, unsigned int value);
void set_vid_pid(const std::string & vid_pid);
void reset_usb() const;
};
} // namespace io
#endif // IO__HIKROBOT_HPP

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,143 @@
#ifndef _MV_ERROR_DEFINE_H_
#define _MV_ERROR_DEFINE_H_
#include "MvISPErrorDefine.h"
/********************************************************************/
/// \~chinese
/// \name 正确码定义
/// @{
/// \~english
/// \name Definition of correct code
/// @{
#define MV_OK 0x00000000 ///< \~chinese 成功,无错误 \~english Successed, no error
/// @}
/********************************************************************/
/// \~chinese
/// \name 通用错误码定义:范围0x80000000-0x800000FF
/// @{
/// \~english
/// \name Definition of General error code
/// @{
#define MV_E_HANDLE \
0x80000000 ///< \~chinese 错误或无效的句柄 \~english Error or invalid handle
#define MV_E_SUPPORT \
0x80000001 ///< \~chinese 不支持的功能 \~english Not supported function
#define MV_E_BUFOVER 0x80000002 ///< \~chinese 缓存已满 \~english Buffer overflow
#define MV_E_CALLORDER \
0x80000003 ///< \~chinese 函数调用顺序错误 \~english Function calling order error
#define MV_E_PARAMETER \
0x80000004 ///< \~chinese 错误的参数 \~english Incorrect parameter
#define MV_E_RESOURCE \
0x80000006 ///< \~chinese 资源申请失败 \~english Applying resource failed
#define MV_E_NODATA 0x80000007 ///< \~chinese 无数据 \~english No data
#define MV_E_PRECONDITION \
0x80000008 ///< \~chinese 前置条件有误,或运行环境已发生变化 \~english Precondition error, or running environment changed
#define MV_E_VERSION \
0x80000009 ///< \~chinese 版本不匹配 \~english Version mismatches
#define MV_E_NOENOUGH_BUF \
0x8000000A ///< \~chinese 传入的内存空间不足 \~english Insufficient memory
#define MV_E_ABNORMAL_IMAGE \
0x8000000B ///< \~chinese 异常图像,可能是丢包导致图像不完整 \~english Abnormal image, maybe incomplete image because of lost packet
#define MV_E_LOAD_LIBRARY \
0x8000000C ///< \~chinese 动态导入DLL失败 \~english Load library failed
#define MV_E_NOOUTBUF \
0x8000000D ///< \~chinese 没有可输出的缓存 \~english No Avaliable Buffer
#define MV_E_ENCRYPT 0x8000000E ///< \~chinese 加密错误 \~english Encryption error
#define MV_E_OPENFILE 0x8000000F ///< \~chinese 打开文件出现错误 \~english open file error
#define MV_E_UNKNOW 0x800000FF ///< \~chinese 未知的错误 \~english Unknown error
/// @}
/********************************************************************/
/// \~chinese
/// \name GenICam系列错误:范围0x80000100-0x800001FF
/// @{
/// \~english
/// \name GenICam Series Error Codes: Range from 0x80000100 to 0x800001FF
/// @{
#define MV_E_GC_GENERIC 0x80000100 ///< \~chinese 通用错误 \~english General error
#define MV_E_GC_ARGUMENT \
0x80000101 ///< \~chinese 参数非法 \~english Illegal parameters
#define MV_E_GC_RANGE \
0x80000102 ///< \~chinese 值超出范围 \~english The value is out of range
#define MV_E_GC_PROPERTY 0x80000103 ///< \~chinese 属性 \~english Property
#define MV_E_GC_RUNTIME \
0x80000104 ///< \~chinese 运行环境有问题 \~english Running environment error
#define MV_E_GC_LOGICAL 0x80000105 ///< \~chinese 逻辑错误 \~english Logical error
#define MV_E_GC_ACCESS \
0x80000106 ///< \~chinese 节点访问条件有误 \~english Node accessing condition error
#define MV_E_GC_TIMEOUT 0x80000107 ///< \~chinese 超时 \~english Timeout
#define MV_E_GC_DYNAMICCAST \
0x80000108 ///< \~chinese 转换异常 \~english Transformation exception
#define MV_E_GC_UNKNOW \
0x800001FF ///< \~chinese GenICam未知错误 \~english GenICam unknown error
/// @}
/********************************************************************/
/// \~chinese
/// \name GigE_STATUS对应的错误码:范围0x80000200-0x800002FF
/// @{
/// \~english
/// \name GigE_STATUS Error Codes: Range from 0x80000200 to 0x800002FF
/// @{
#define MV_E_NOT_IMPLEMENTED \
0x80000200 ///< \~chinese 命令不被设备支持 \~english The command is not supported by device
#define MV_E_INVALID_ADDRESS \
0x80000201 ///< \~chinese 访问的目标地址不存在 \~english The target address being accessed does not exist
#define MV_E_WRITE_PROTECT \
0x80000202 ///< \~chinese 目标地址不可写 \~english The target address is not writable
#define MV_E_ACCESS_DENIED \
0x80000203 ///< \~chinese 设备无访问权限 \~english No permission
#define MV_E_BUSY \
0x80000204 ///< \~chinese 设备忙,或网络断开 \~english Device is busy, or network disconnected
#define MV_E_PACKET \
0x80000205 ///< \~chinese 网络包数据错误 \~english Network data packet error
#define MV_E_NETER 0x80000206 ///< \~chinese 网络相关错误 \~english Network error
#define MV_E_IP_CONFLICT \
0x80000221 ///< \~chinese 设备IP冲突 \~english Device IP conflict
/// @}
/********************************************************************/
/// \~chinese
/// \name USB_STATUS对应的错误码:范围0x80000300-0x800003FF
/// @{
/// \~english
/// \name USB_STATUS Error Codes: Range from 0x80000300 to 0x800003FF
/// @{
#define MV_E_USB_READ \
0x80000300 ///< \~chinese 读usb出错 \~english Reading USB error
#define MV_E_USB_WRITE \
0x80000301 ///< \~chinese 写usb出错 \~english Writing USB error
#define MV_E_USB_DEVICE \
0x80000302 ///< \~chinese 设备异常 \~english Device exception
#define MV_E_USB_GENICAM 0x80000303 ///< \~chinese GenICam相关错误 \~english GenICam error
#define MV_E_USB_BANDWIDTH \
0x80000304 ///< \~chinese 带宽不足 \~english Insufficient bandwidth
#define MV_E_USB_DRIVER \
0x80000305 ///< \~chinese 驱动不匹配或者未装驱动 \~english Driver mismatch or unmounted drive
#define MV_E_USB_UNKNOW \
0x800003FF ///< \~chinese USB未知的错误 \~english USB unknown error
/// @}
/********************************************************************/
/// \~chinese
/// \name 升级时对应的错误码:范围0x80000400-0x800004FF
/// @{
/// \~english
/// \name Upgrade Error Codes: Range from 0x80000400 to 0x800004FF
/// @{
#define MV_E_UPG_FILE_MISMATCH \
0x80000400 ///< \~chinese 升级固件不匹配 \~english Firmware mismatches
#define MV_E_UPG_LANGUSGE_MISMATCH \
0x80000401 ///< \~chinese 升级固件语言不匹配 \~english Firmware language mismatches
#define MV_E_UPG_CONFLICT \
0x80000402 ///< \~chinese 升级冲突(设备已经在升级了再次请求升级即返回此错误) \~english Upgrading conflicted (repeated upgrading requests during device upgrade)
#define MV_E_UPG_INNER_ERR \
0x80000403 ///< \~chinese 升级时设备内部出现错误 \~english Camera internal error during upgrade
#define MV_E_UPG_UNKNOW \
0x800004FF ///< \~chinese 升级时未知错误 \~english Unknown error during upgrade
/// @}
#endif //_MV_ERROR_DEFINE_H_

View File

@ -0,0 +1,93 @@
#ifndef _MV_ISP_ERROR_DEFINE_H_
#define _MV_ISP_ERROR_DEFINE_H_
/************************************************************************
* ISP算法库的错误码
************************************************************************/
// 通用类型
#define MV_ALG_OK 0x00000000 //处理正确
#define MV_ALG_ERR 0x10000000 //不确定类型错误
// 能力检查
#define MV_ALG_E_ABILITY_ARG 0x10000001 //能力集中存在无效参数
// 内存检查
#define MV_ALG_E_MEM_NULL 0x10000002 //内存地址为空
#define MV_ALG_E_MEM_ALIGN 0x10000003 //内存对齐不满足要求
#define MV_ALG_E_MEM_LACK 0x10000004 //内存空间大小不够
#define MV_ALG_E_MEM_SIZE_ALIGN 0x10000005 //内存空间大小不满足对齐要求
#define MV_ALG_E_MEM_ADDR_ALIGN 0x10000006 //内存地址不满足对齐要求
// 图像检查
#define MV_ALG_E_IMG_FORMAT 0x10000007 //图像格式不正确或者不支持
#define MV_ALG_E_IMG_SIZE 0x10000008 //图像宽高不正确或者超出范围
#define MV_ALG_E_IMG_STEP 0x10000009 //图像宽高与step参数不匹配
#define MV_ALG_E_IMG_DATA_NULL 0x1000000A //图像数据存储地址为空
// 输入输出参数检查
#define MV_ALG_E_CFG_TYPE 0x1000000B //设置或者获取参数类型不正确
#define MV_ALG_E_CFG_SIZE 0x1000000C //设置或者获取参数的输入、输出结构体大小不正确
#define MV_ALG_E_PRC_TYPE 0x1000000D //处理类型不正确
#define MV_ALG_E_PRC_SIZE 0x1000000E //处理时输入、输出参数大小不正确
#define MV_ALG_E_FUNC_TYPE 0x1000000F //子处理类型不正确
#define MV_ALG_E_FUNC_SIZE 0x10000010 //子处理时输入、输出参数大小不正确
// 运行参数检查
#define MV_ALG_E_PARAM_INDEX 0x10000011 //index参数不正确
#define MV_ALG_E_PARAM_VALUE 0x10000012 //value参数不正确或者超出范围
#define MV_ALG_E_PARAM_NUM 0x10000013 //param_num参数不正确
// 接口调用检查
#define MV_ALG_E_NULL_PTR 0x10000014 //函数参数指针为空
#define MV_ALG_E_OVER_MAX_MEM 0x10000015 //超过限定的最大内存
#define MV_ALG_E_CALL_BACK 0x10000016 //回调函数出错
// 算法库加密相关检查
#define MV_ALG_E_ENCRYPT 0x10000017 //加密错误
#define MV_ALG_E_EXPIRE 0x10000018 //算法库使用期限错误
// 内部模块返回的基本错误类型
#define MV_ALG_E_BAD_ARG 0x10000019 //参数范围不正确
#define MV_ALG_E_DATA_SIZE 0x1000001A //数据大小不正确
#define MV_ALG_E_STEP 0x1000001B //数据step不正确
// cpu指令集支持错误码
#define MV_ALG_E_CPUID 0x1000001C //cpu不支持优化代码中的指令集
#define MV_ALG_WARNING 0x1000001D //警告
#define MV_ALG_E_TIME_OUT 0x1000001E //算法库超时
#define MV_ALG_E_LIB_VERSION 0x1000001F //算法版本号出错
#define MV_ALG_E_MODEL_VERSION 0x10000020 //模型版本号出错
#define MV_ALG_E_GPU_MEM_ALLOC 0x10000021 //GPU内存分配错误
#define MV_ALG_E_FILE_NON_EXIST 0x10000022 //文件不存在
#define MV_ALG_E_NONE_STRING 0x10000023 //字符串为空
#define MV_ALG_E_IMAGE_CODEC 0x10000024 //图像解码器错误
#define MV_ALG_E_FILE_OPEN 0x10000025 //打开文件错误
#define MV_ALG_E_FILE_READ 0x10000026 //文件读取错误
#define MV_ALG_E_FILE_WRITE 0x10000027 //文件写错误
#define MV_ALG_E_FILE_READ_SIZE 0x10000028 //文件读取大小错误
#define MV_ALG_E_FILE_TYPE 0x10000029 //文件类型错误
#define MV_ALG_E_MODEL_TYPE 0x1000002A //模型类型错误
#define MV_ALG_E_MALLOC_MEM 0x1000002B //分配内存错误
#define MV_ALG_E_BIND_CORE_FAILED 0x1000002C //线程绑核失败
// 降噪特有错误码
#define MV_ALG_E_DENOISE_NE_IMG_FORMAT 0x10402001 //噪声特性图像格式错误
#define MV_ALG_E_DENOISE_NE_FEATURE_TYPE 0x10402002 //噪声特性类型错误
#define MV_ALG_E_DENOISE_NE_PROFILE_NUM 0x10402003 //噪声特性个数错误
#define MV_ALG_E_DENOISE_NE_GAIN_NUM 0x10402004 //噪声特性增益个数错误
#define MV_ALG_E_DENOISE_NE_GAIN_VAL 0x10402005 //噪声曲线增益值输入错误
#define MV_ALG_E_DENOISE_NE_BIN_NUM 0x10402006 //噪声曲线柱数错误
#define MV_ALG_E_DENOISE_NE_INIT_GAIN 0x10402007 //噪声估计初始化增益设置错误
#define MV_ALG_E_DENOISE_NE_NOT_INIT 0x10402008 //噪声估计未初始化
#define MV_ALG_E_DENOISE_COLOR_MODE 0x10402009 //颜色空间模式错误
#define MV_ALG_E_DENOISE_ROI_NUM 0x1040200a //图像ROI个数错误
#define MV_ALG_E_DENOISE_ROI_ORI_PT 0x1040200b //图像ROI原点错误
#define MV_ALG_E_DENOISE_ROI_SIZE 0x1040200c //图像ROI大小错误
#define MV_ALG_E_DENOISE_GAIN_NOT_EXIST 0x1040200d //输入的相机增益不存在(增益个数已达上限)
#define MV_ALG_E_DENOISE_GAIN_BEYOND_RANGE 0x1040200e //输入的相机增益不在范围内
#define MV_ALG_E_DENOISE_NP_BUF_SIZE 0x1040200f //输入的噪声特性内存大小错误
#endif //_MV_ISP_ERROR_DEFINE_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,714 @@
#ifndef _MV_OBSOLETE_CAM_PARAMS_H_
#define _MV_OBSOLETE_CAM_PARAMS_H_
#include "PixelType.h"
/// \~chinese 输出帧的信息 \~english Output Frame Information
typedef struct _MV_FRAME_OUT_INFO_
{
unsigned short nWidth; ///< [OUT] \~chinese 图像宽 \~english Image Width
unsigned short nHeight; ///< [OUT] \~chinese 图像高 \~english Image Height
enum MvGvspPixelType enPixelType; ///< [OUT] \~chinese 像素格式 \~english Pixel Type
unsigned int nFrameNum; ///< [OUT] \~chinese 帧号 \~english Frame Number
unsigned int
nDevTimeStampHigh; ///< [OUT] \~chinese 时间戳高32位 \~english Timestamp high 32 bits
unsigned int
nDevTimeStampLow; ///< [OUT] \~chinese 时间戳低32位 \~english Timestamp low 32 bits
unsigned int
nReserved0; ///< [OUT] \~chinese 保留8字节对齐 \~english Reserved, 8-byte aligned
int64_t
nHostTimeStamp; ///< [OUT] \~chinese 主机生成的时间戳 \~english Host-generated timestamp
unsigned int nFrameLen;
unsigned int nLostPacket; // 本帧丢包数
unsigned int nReserved[2];
} MV_FRAME_OUT_INFO;
/// \~chinese 保存图片参数 \~english Save image type
typedef struct _MV_SAVE_IMAGE_PARAM_T_
{
unsigned char * pData; ///< [IN] \~chinese 输入数据缓存 \~english Input Data Buffer
unsigned int nDataLen; ///< [IN] \~chinese 输入数据大小 \~english Input Data Size
enum MvGvspPixelType
enPixelType; ///< [IN] \~chinese 输入像素格式 \~english Input Data Pixel Format
unsigned short nWidth; ///< [IN] \~chinese 图像宽 \~english Image Width
unsigned short nHeight; ///< [IN] \~chinese 图像高 \~english Image Height
unsigned char *
pImageBuffer; ///< [OUT] \~chinese 输出图片缓存 \~english Output Image Buffer
unsigned int nImageLen; ///< [OUT] \~chinese 输出图片大小 \~english Output Image Size
unsigned int
nBufferSize; ///< [IN] \~chinese 提供的输出缓冲区大小 \~english Output buffer size provided
enum MV_SAVE_IAMGE_TYPE
enImageType; ///< [IN] \~chinese 输出图片格式 \~english Output Image Format
} MV_SAVE_IMAGE_PARAM;
typedef struct _MV_IMAGE_BASIC_INFO_
{
unsigned short nWidthValue;
unsigned short nWidthMin;
unsigned int nWidthMax;
unsigned int nWidthInc;
unsigned int nHeightValue;
unsigned int nHeightMin;
unsigned int nHeightMax;
unsigned int nHeightInc;
float fFrameRateValue;
float fFrameRateMin;
float fFrameRateMax;
unsigned int enPixelType; ///< [OUT] \~chinese 当前的像素格式 \~english Current pixel format
unsigned int
nSupportedPixelFmtNum; ///< [OUT] \~chinese 支持的像素格式种类 \~english Support pixel format
unsigned int enPixelList[MV_MAX_XML_SYMBOLIC_NUM];
unsigned int nReserved[8];
} MV_IMAGE_BASIC_INFO;
/// \~chinese 噪声特性类型 \~english Noise feature type
typedef enum _MV_CC_BAYER_NOISE_FEATURE_TYPE
{
MV_CC_BAYER_NOISE_FEATURE_TYPE_INVALID =
0, ///< \~chinese 无效值 \~english Invalid
MV_CC_BAYER_NOISE_FEATURE_TYPE_PROFILE =
1, ///< \~chinese 噪声曲线 \~english Noise curve
MV_CC_BAYER_NOISE_FEATURE_TYPE_LEVEL =
2, ///< \~chinese 噪声水平 \~english Noise level
MV_CC_BAYER_NOISE_FEATURE_TYPE_DEFAULT =
1, ///< \~chinese 默认值 \~english Default
} MV_CC_BAYER_NOISE_FEATURE_TYPE;
/// \~chinese Bayer格式降噪特性信息 \~english Denoise profile info
typedef struct _MV_CC_BAYER_NOISE_PROFILE_INFO_T_
{
unsigned int nVersion; ///< \~chinese 版本 \~english version
MV_CC_BAYER_NOISE_FEATURE_TYPE
enNoiseFeatureType; ///< \~chinese 噪声特性类型 \~english noise feature type
enum MvGvspPixelType
enPixelType; ///< \~chinese 图像格式 \~english image format
int nNoiseLevel; ///< \~chinese 平均噪声水平 \~english noise level
unsigned int
nCurvePointNum; ///< \~chinese 曲线点数 \~english curve point number
int * nNoiseCurve; ///< \~chinese 噪声曲线 \~english noise curve
int * nLumCurve; ///< \~chinese 亮度曲线 \~english luminance curve
unsigned int nRes[8]; ///< \~chinese 预留 \~english Reserved
} MV_CC_BAYER_NOISE_PROFILE_INFO;
/// \~chinese Bayer格式噪声估计参数 \~english Bayer noise estimate param
typedef struct _MV_CC_BAYER_NOISE_ESTIMATE_PARAM_T_
{
unsigned int nWidth; ///< [IN] \~chinese 图像宽(大于等于8) \~english Width
unsigned int nHeight; ///< [IN] \~chinese 图像高(大于等于8) \~english Height
enum MvGvspPixelType
enPixelType; ///< [IN] \~chinese 像素格式 \~english Pixel format
unsigned char *
pSrcData; ///< [IN] \~chinese 输入数据缓存 \~english Input data buffer
unsigned int
nSrcDataLen; ///< [IN] \~chinese 输入数据大小 \~english Input data size
unsigned int
nNoiseThreshold; ///< [IN] \~chinese 噪声阈值(0-4095) \~english Noise Threshold
unsigned char *
pCurveBuf; ///< [IN] \~chinese 用于存储噪声曲线和亮度曲线需要外部分配缓存大小4096 * sizeof(int) * 2 \~english Buffer used to store noise and brightness curves, size:4096 * sizeof(int) * 2)
MV_CC_BAYER_NOISE_PROFILE_INFO
stNoiseProfile; ///< [OUT] \~chinese 降噪特性信息 \~english Denoise profile
unsigned int
nThreadNum; ///< [IN] \~chinese 线程数量0表示算法库根据硬件自适应1表示单线程默认大于1表示线程数目 \~english Thread number, 0 means that the library is adaptive to the hardware, 1 means single thread(Default value), Greater than 1 indicates the number of threads
unsigned int nRes[8]; ///< \~chinese 预留 \~english Reserved
} MV_CC_BAYER_NOISE_ESTIMATE_PARAM;
/// \~chinese Bayer格式空域降噪参数 \~english Bayer spatial Denoise param
typedef struct _MV_CC_BAYER_SPATIAL_DENOISE_PARAM_T_
{
unsigned int nWidth; ///< [IN] \~chinese 图像宽(大于等于8) \~english Width
unsigned int nHeight; ///< [IN] \~chinese 图像高(大于等于8) \~english Height
enum MvGvspPixelType
enPixelType; ///< [IN] \~chinese 像素格式 \~english Pixel format
unsigned char *
pSrcData; ///< [IN] \~chinese 输入数据缓存 \~english Input data buffer
unsigned int
nSrcDataLen; ///< [IN] \~chinese 输入数据大小 \~english Input data size
unsigned char *
pDstBuf; ///< [OUT] \~chinese 输出降噪后的数据 \~english Output data buffer
unsigned int
nDstBufSize; ///< [IN] \~chinese 提供的输出缓冲区大小 \~english Provided output buffer size
unsigned int
nDstBufLen; ///< [OUT] \~chinese 输出降噪后的数据长度 \~english Output data length
MV_CC_BAYER_NOISE_PROFILE_INFO
stNoiseProfile; ///< [IN] \~chinese 降噪特性信息(来源于噪声估计) \~english Denoise profile
unsigned int
nDenoiseStrength; ///< [IN] \~chinese 降噪强度(0-100) \~english nDenoise Strength
unsigned int
nSharpenStrength; ///< [IN] \~chinese 锐化强度(0-32) \~english Sharpen Strength
unsigned int
nNoiseCorrect; ///< [IN] \~chinese 噪声校正系数(0-1280) \~english Noise Correct
unsigned int
nThreadNum; ///< [IN] \~chinese 线程数量0表示算法库根据硬件自适应1表示单线程默认大于1表示线程数目 \~english Thread number, 0 means that the library is adaptive to the hardware, 1 means single thread(Default value), Greater than 1 indicates the number of threads
unsigned int nRes[8]; ///< \~chinese 预留 \~english Reserved
} MV_CC_BAYER_SPATIAL_DENOISE_PARAM;
/// \~chinese CLUT参数 \~english CLUT param
typedef struct _MV_CC_CLUT_PARAM_T_
{
bool bCLUTEnable; ///< [IN] \~chinese 是否启用CLUT \~english CLUT enable
unsigned int
nCLUTScale; ///< [IN] \~chinese 量化系数(2的整数幂,最大65536) \~english Quantitative scale(Integer power of 2, <= 65536)
unsigned int
nCLUTSize; ///< [IN] \~chinese CLUT大小,[17,33]建议值17 \~english CLUT size[17,33](Recommended values of 17)
unsigned char * pCLUTBuf; ///< [IN] \~chinese 量化CLUT表 \~english CLUT buffer
unsigned int
nCLUTBufLen; ///< [IN] \~chinese 量化CLUT缓存大小(nCLUTSize*nCLUTSize*nCLUTSize*sizeof(int)*3) \~english CLUT buffer length(nCLUTSize*nCLUTSize*nCLUTSize*sizeof(int)*3)
unsigned int nRes[8]; ///< \~chinese 预留 \~english Reserved
} MV_CC_CLUT_PARAM;
/// \~chinese 锐化结构体 \~english Sharpen structure
typedef struct _MV_CC_SHARPEN_PARAM_T_
{
unsigned int nWidth; ///< [IN] \~chinese 图像宽度(最小8) \~english Image Width
unsigned int nHeight; ///< [IN] \~chinese 图像高度(最小8) \~english Image Height
unsigned char * pSrcBuf; ///< [IN] \~chinese 输入数据缓存 \~english Input data buffer
unsigned int nSrcBufLen; ///< [IN] \~chinese 输入数据大小 \~english Input data length
enum MvGvspPixelType
enPixelType; ///< [IN] \~chinese 像素格式 \~english Pixel format
unsigned char * pDstBuf; ///< [OUT] \~chinese 输出数据缓存 \~english Output data buffer
unsigned int
nDstBufSize; ///< [IN] \~chinese 提供的输出缓冲区大小 \~english Provided output buffer size
unsigned int nDstBufLen; ///< [OUT] \~chinese 输出数据长度 \~english Output data length
unsigned int
nSharpenAmount; ///< [IN] \~chinese 锐度调节强度,[0,500] \~english Sharpen amount,[0,500] // [nSharpenAmount 作废, 使用 nSharpenPosAmount & nSharpenNegAmount 替代 ]
unsigned int
nSharpenRadius; ///< [IN] \~chinese 锐度调节半径(半径越大,耗时越长)[1,21] \~english Sharpen radius(The larger the radius, the longer it takes),[1,21]
unsigned int
nSharpenThreshold; ///< [IN] \~chinese 锐度调节阈值,[0,255] \~english Sharpen threshold,[0,255]
unsigned int nSharpenPosAmount; // [IN] 锐度调节正向强度,范围:[0, 500]
unsigned int nSharpenNegAmount; // [IN] 锐度调节负向强度,范围:[0, 500]
unsigned int nRes[6]; ///< \~chinese 预留 \~english Reserved
} MV_CC_SHARPEN_PARAM;
/// \~chinese 色彩校正结构体 \~english Color correct structure
typedef struct _MV_CC_COLOR_CORRECT_PARAM_T_
{
unsigned int nWidth; ///< [IN] \~chinese 图像宽度 \~english Image Width
unsigned int nHeight; ///< [IN] \~chinese 图像高度 \~english Image Height
unsigned char * pSrcBuf; ///< [IN] \~chinese 输入数据缓存 \~english Input data buffer
unsigned int nSrcBufLen; ///< [IN] \~chinese 输入数据大小 \~english Input data length
enum MvGvspPixelType
enPixelType; ///< [IN] \~chinese 像素格式 \~english Pixel format
unsigned char * pDstBuf; ///< [OUT] \~chinese 输出数据缓存 \~english Output data buffer
unsigned int
nDstBufSize; ///< [IN] \~chinese 提供的输出缓冲区大小 \~english Provided output buffer size
unsigned int nDstBufLen; ///< [OUT] \~chinese 输出数据长度 \~english Output data length
unsigned int
nImageBit; ///< [IN] \~chinese 有效图像位数(8,10,12,16) \~english Image bit(8 or 10 or 12 or 16)
MV_CC_GAMMA_PARAM stGammaParam; ///< [IN] \~chinese Gamma信息 \~english Gamma info
MV_CC_CCM_PARAM_EX stCCMParam; ///< [IN] \~chinese CCM信息 \~english CCM info
MV_CC_CLUT_PARAM stCLUTParam; ///< [IN] \~chinese CLUT信息 \~english CLUT info
unsigned int nRes[8]; ///< \~chinese 预留 \~english Reserved
} MV_CC_COLOR_CORRECT_PARAM;
/// \~chinese 矩形ROI结构体 \~english Rect ROI structure
typedef struct _MV_CC_RECT_I_
{
unsigned int nX; ///< \~chinese 矩形左上角X轴坐标 \~english X Position
unsigned int nY; ///< \~chinese 矩形左上角Y轴坐标 \~english Y Position
unsigned int nWidth; ///< \~chinese 矩形宽度 \~english Rect Width
unsigned int nHeight; ///< \~chinese 矩形高度 \~english Rect Height
} MV_CC_RECT_I;
/// \~chinese 噪声估计结构体 \~english Noise estimate structure
typedef struct _MV_CC_NOISE_ESTIMATE_PARAM_T_
{
unsigned int nWidth; ///< [IN] \~chinese 图像宽度(最小8) \~english Image Width
unsigned int nHeight; ///< [IN] \~chinese 图像高度(最小8) \~english Image Height
enum MvGvspPixelType
enPixelType; ///< [IN] \~chinese 像素格式 \~english Pixel format
unsigned char * pSrcBuf; ///< [IN] \~chinese 输入数据缓存 \~english Input data buffer
unsigned int nSrcBufLen; ///< [IN] \~chinese 输入数据大小 \~english Input data length
MV_CC_RECT_I * pstROIRect; ///< [IN] \~chinese 图像ROI \~english Image ROI
unsigned int nROINum; ///< [IN] \~chinese ROI个数 \~english ROI number
///< \~chinese Bayer域噪声估计参数Mono8/RGB域无效 \~english Bayer Noise estimate param,Mono8/RGB formats are invalid
unsigned int
nNoiseThreshold; ///< [IN] \~chinese 噪声阈值[0,4095] \~english Noise threshold[0,4095]
///< \~chinese 建议值:8bit,0xE0;10bit,0x380;12bit,0xE00 \~english Suggestive value:8bit,0xE0;10bit,0x380;12bit,0xE00
unsigned char *
pNoiseProfile; ///< [OUT] \~chinese 输出噪声特性 \~english Output Noise Profile
unsigned int
nNoiseProfileSize; ///< [IN] \~chinese 提供的输出缓冲区大小 \~english Provided output buffer size
unsigned int
nNoiseProfileLen; ///< [OUT] \~chinese 输出噪声特性长度 \~english Output Noise Profile length
unsigned int nRes[8]; ///< \~chinese 预留 \~english Reserved
} MV_CC_NOISE_ESTIMATE_PARAM;
/// \~chinese 空域降噪结构体 \~english Spatial denoise structure
typedef struct _MV_CC_SPATIAL_DENOISE_PARAM_T_
{
unsigned int nWidth; ///< [IN] \~chinese 图像宽度(最小8) \~english Image Width
unsigned int nHeight; ///< [IN] \~chinese 图像高度(最小8) \~english Image Height
enum MvGvspPixelType
enPixelType; ///< [IN] \~chinese 像素格式 \~english Pixel format
unsigned char * pSrcBuf; ///< [IN] \~chinese 输入数据缓存 \~english Input data buffer
unsigned int nSrcBufLen; ///< [IN] \~chinese 输入数据大小 \~english Input data length
unsigned char * pDstBuf; ///< [OUT] \~chinese 输出降噪后的数据 \~english Output data buffer
unsigned int
nDstBufSize; ///< [IN] \~chinese 提供的输出缓冲区大小 \~english Provided output buffer size
unsigned int nDstBufLen; ///< [OUT] \~chinese 输出降噪后的数据长度 \~english Output data length
unsigned char *
pNoiseProfile; ///< [IN] \~chinese 输入噪声特性 \~english Input Noise Profile
unsigned int
nNoiseProfileLen; ///< [IN] \~chinese 输入噪声特性长度 \~english Input Noise Profile length
///< \~chinese Bayer域空域降噪参数Mono8/RGB域无效 \~english Bayer Spatial denoise param,Mono8/RGB formats are invalid
unsigned int
nBayerDenoiseStrength; ///< [IN] \~chinese 降噪强度[0,100] \~english Denoise Strength[0,100]
unsigned int
nBayerSharpenStrength; ///< [IN] \~chinese 锐化强度[0,32] \~english Sharpen Strength[0,32]
unsigned int
nBayerNoiseCorrect; ///< [IN] \~chinese 噪声校正系数[0,1280] \~english Noise Correct[0,1280]
///< \~chinese Mono8/RGB域空域降噪参数Bayer域无效 \~english Mono8/RGB Spatial denoise param,Bayer formats are invalid
unsigned int
nNoiseCorrectLum; ///< [IN] \~chinese 亮度校正系数[1,2000] \~english Noise Correct Lum[1,2000]
unsigned int
nNoiseCorrectChrom; ///< [IN] \~chinese 色调校正系数[1,2000] \~english Noise Correct Chrom[1,2000]
unsigned int
nStrengthLum; ///< [IN] \~chinese 亮度降噪强度[0,100] \~english Strength Lum[0,100]
unsigned int
nStrengthChrom; ///< [IN] \~chinese 色调降噪强度[0,100] \~english Strength Chrom[0,100]
unsigned int
nStrengthSharpen; ///< [IN] \~chinese 锐化强度[1,1000] \~english Strength Sharpen[1,1000]
unsigned int nRes[8]; ///< \~chinese 预留 \~english Reserved
} MV_CC_SPATIAL_DENOISE_PARAM;
/// \~chinese LSC标定结构体 \~english LSC calib structure
typedef struct _MV_CC_LSC_CALIB_PARAM_T_
{
unsigned int nWidth; ///< [IN] \~chinese 图像宽度[16,65535] \~english Image Width
unsigned int nHeight; ///< [IN] \~chinese 图像高度[16-65535] \~english Image Height
enum MvGvspPixelType
enPixelType; ///< [IN] \~chinese 像素格式 \~english Pixel format
unsigned char * pSrcBuf; ///< [IN] \~chinese 输入数据缓存 \~english Input data buffer
unsigned int nSrcBufLen; ///< [IN] \~chinese 输入数据长度 \~english Input data length
unsigned char *
pCalibBuf; ///< [OUT] \~chinese 输出标定表缓存 \~english Output calib buffer
unsigned int
nCalibBufSize; ///< [IN] \~chinese 提供的标定表缓冲大小(nWidth*nHeight*sizeof(unsigned short)) \~english Provided output buffer size
unsigned int
nCalibBufLen; ///< [OUT] \~chinese 输出标定表缓存长度 \~english Output calib buffer length
unsigned int nSecNumW; ///< [IN] \~chinese 宽度分块数 \~english Width Sec num
unsigned int nSecNumH; ///< [IN] \~chinese 高度分块数 \~english Height Sec num
unsigned int nPadCoef; ///< [IN] \~chinese 边缘填充系数[1,5] \~english Pad Coef[1,5]
unsigned int
nCalibMethod; ///< [IN] \~chinese 标定方式(0-中心为基准;1-最亮区域为基准;2-目标亮度为基准) \~english Calib method
unsigned int
nTargetGray; ///< [IN] \~chinese 目标亮度(标定方式为2时有效) \~english Target Gray
///< \~chinese 8位,范围:[0,255] \~english 8bit,range:[0,255]
///< \~chinese 10位,范围:[0,1023] \~english 10bit,range:[0,1023]
///< \~chinese 12位,范围:[0,4095] \~english 12bit,range:[0,4095]
unsigned int nRes[8]; ///< \~chinese 预留 \~english Reserved
} MV_CC_LSC_CALIB_PARAM;
/// \~chinese LSC校正结构体 \~english LSC correct structure
typedef struct _MV_CC_LSC_CORRECT_PARAM_T_
{
unsigned int nWidth; ///< [IN] \~chinese 图像宽度[16,65535] \~english Image Width
unsigned int nHeight; ///< [IN] \~chinese 图像高度[16,65535] \~english Image Height
enum MvGvspPixelType
enPixelType; ///< [IN] \~chinese 像素格式 \~english Pixel format
unsigned char * pSrcBuf; ///< [IN] \~chinese 输入数据缓存 \~english Input data buffer
unsigned int nSrcBufLen; ///< [IN] \~chinese 输入数据长度 \~english Input data length
unsigned char * pDstBuf; ///< [OUT] \~chinese 输出数据缓存 \~english Output data buffer
unsigned int
nDstBufSize; ///< [IN] \~chinese 提供的输出缓冲区大小 \~english Provided output buffer size
unsigned int nDstBufLen; ///< [OUT] \~chinese 输出数据长度 \~english Output data length
unsigned char *
pCalibBuf; ///< [IN] \~chinese 输入标定表缓存 \~english Input calib buffer
unsigned int
nCalibBufLen; ///< [IN] \~chinese 输入标定表缓存长度 \~english Input calib buffer length
unsigned int nRes[8]; ///< \~chinese 预留 \~english Reserved
} MV_CC_LSC_CORRECT_PARAM;
/// \~chinese 某个节点对应的子节点个数最大值 \~english The maximum number of child nodes corresponding to a node
#define MV_MAX_XML_NODE_NUM_C 128
/// \~chinese 节点名称字符串最大长度 \~english The maximum length of node name string
#define MV_MAX_XML_NODE_STRLEN_C 64
/// \~chinese 节点String值最大长度 \~english The maximum length of Node String
#define MV_MAX_XML_STRVALUE_STRLEN_C 64
/// \~chinese 节点描述字段最大长度 \~english The maximum length of the node description field
#define MV_MAX_XML_DISC_STRLEN_C 512
/// \~chinese 最多的单元数 \~english The maximum number of units
#define MV_MAX_XML_ENTRY_NUM 10
/// \~chinese 父节点个数上限 \~english The maximum number of parent nodes
#define MV_MAX_XML_PARENTS_NUM 8
/// \~chinese 每个已经实现单元的名称长度 \~english The length of the name of each unit that has been implemented
#define MV_MAX_XML_SYMBOLIC_STRLEN_C 64
enum MV_XML_Visibility
{
V_Beginner = 0, ///< Always visible
V_Expert = 1, ///< Visible for experts or Gurus
V_Guru = 2, ///< Visible for Gurus
V_Invisible = 3, ///< Not Visible
V_Undefined = 99 ///< Object is not yet initialized
};
/// \~chinese 单个节点基本属性 | en:Single Node Basic Attributes
typedef struct _MV_XML_NODE_FEATURE_
{
enum MV_XML_InterfaceType enType; ///< \~chinese 节点类型 \~english Node Type
enum MV_XML_Visibility enVisivility; ///< \~chinese 是否可见 \~english Is visibility
char strDescription
[MV_MAX_XML_DISC_STRLEN_C]; ///< \~chinese 节点描述,目前暂不支持 \~english Node Description, NOT SUPPORT NOW
char strDisplayName
[MV_MAX_XML_NODE_STRLEN_C]; ///< \~chinese 显示名称 \~english Display Name
char strName[MV_MAX_XML_NODE_STRLEN_C]; ///< \~chinese 节点名 \~english Node Name
char strToolTip[MV_MAX_XML_DISC_STRLEN_C]; ///< \~chinese 提示 \~english Notice
unsigned int nReserved[4];
} MV_XML_NODE_FEATURE;
/// \~chinese 节点列表 | en:Node List
typedef struct _MV_XML_NODES_LIST_
{
unsigned int nNodeNum; ///< \~chinese 节点个数 \~english Node Number
MV_XML_NODE_FEATURE stNodes[MV_MAX_XML_NODE_NUM_C];
} MV_XML_NODES_LIST;
typedef struct _MV_XML_FEATURE_Value_
{
enum MV_XML_InterfaceType enType; ///< \~chinese 节点类型 \~english Node Type
char strDescription
[MV_MAX_XML_DISC_STRLEN_C]; ///< \~chinese 节点描述,目前暂不支持 \~english Node Description, NOT SUPPORT NOW
char strDisplayName
[MV_MAX_XML_NODE_STRLEN_C]; ///< \~chinese 显示名称 \~english Display Name
char strName[MV_MAX_XML_NODE_STRLEN_C]; ///< \~chinese 节点名 \~english Node Name
char strToolTip[MV_MAX_XML_DISC_STRLEN_C]; ///< \~chinese 提示 \~english Notice
unsigned int nReserved[4];
} MV_XML_FEATURE_Value;
typedef struct _MV_XML_FEATURE_Base_
{
enum MV_XML_AccessMode enAccessMode; ///< \~chinese 访问模式 \~english Access Mode
} MV_XML_FEATURE_Base;
typedef struct _MV_XML_FEATURE_Integer_
{
char strName[MV_MAX_XML_NODE_STRLEN_C];
char strDisplayName[MV_MAX_XML_NODE_STRLEN_C];
char strDescription
[MV_MAX_XML_DISC_STRLEN_C]; ///< \~chinese 目前暂不支持 \~english NOT SUPPORT NOW
char strToolTip[MV_MAX_XML_DISC_STRLEN_C];
enum MV_XML_Visibility enVisivility; ///< \~chinese 是否可见 \~english Visible
enum MV_XML_AccessMode enAccessMode; ///< \~chinese 访问模式 \~english Access Mode
int
bIsLocked; ///< \~chinese 是否锁定。0-否1-是,目前暂不支持 \~english Locked. 0-NO; 1-YES, NOT SUPPORT NOW
int64_t nValue; ///< \~chinese 当前值 \~english Current Value
int64_t nMinValue; ///< \~chinese 最小值 \~english Min Value
int64_t nMaxValue; ///< \~chinese 最大值 \~english Max Value
int64_t nIncrement; ///< \~chinese 增量 \~english Increment
unsigned int nReserved[4];
} MV_XML_FEATURE_Integer;
typedef struct _MV_XML_FEATURE_Boolean_
{
char strName[MV_MAX_XML_NODE_STRLEN_C];
char strDisplayName[MV_MAX_XML_NODE_STRLEN_C];
char strDescription
[MV_MAX_XML_DISC_STRLEN_C]; ///< \~chinese 目前暂不支持 \~english NOT SUPPORT NOW
char strToolTip[MV_MAX_XML_DISC_STRLEN_C];
enum MV_XML_Visibility enVisivility; ///< \~chinese 是否可见 \~english Visible
enum MV_XML_AccessMode enAccessMode; ///< \~chinese 访问模式 \~english Access Mode
int
bIsLocked; ///< \~chinese 是否锁定。0-否1-是,目前暂不支持 \~english Locked. 0-NO; 1-YES, NOT SUPPORT NOW
bool bValue; ///< \~chinese 当前值 \~english Current Value
unsigned int nReserved[4];
} MV_XML_FEATURE_Boolean;
typedef struct _MV_XML_FEATURE_Command_
{
char strName[MV_MAX_XML_NODE_STRLEN_C];
char strDisplayName[MV_MAX_XML_NODE_STRLEN_C];
char strDescription
[MV_MAX_XML_DISC_STRLEN_C]; ///< \~chinese 目前暂不支持 \~english NOT SUPPORT NOW
char strToolTip[MV_MAX_XML_DISC_STRLEN_C];
enum MV_XML_Visibility enVisivility; ///< \~chinese 是否可见 \~english Visible
enum MV_XML_AccessMode enAccessMode; ///< \~chinese 访问模式 \~english Access Mode
int
bIsLocked; ///< \~chinese 是否锁定。0-否1-是,目前暂不支持 \~english Locked. 0-NO; 1-YES, NOT SUPPORT NOW
unsigned int nReserved[4];
} MV_XML_FEATURE_Command;
typedef struct _MV_XML_FEATURE_Float_
{
char strName[MV_MAX_XML_NODE_STRLEN_C];
char strDisplayName[MV_MAX_XML_NODE_STRLEN_C];
char strDescription
[MV_MAX_XML_DISC_STRLEN_C]; ///< \~chinese 目前暂不支持 \~english NOT SUPPORT NOW
char strToolTip[MV_MAX_XML_DISC_STRLEN_C];
enum MV_XML_Visibility enVisivility; ///< \~chinese 是否可见 \~english Visible
enum MV_XML_AccessMode enAccessMode; ///< \~chinese 访问模式 \~english Access Mode
int
bIsLocked; ///< \~chinese 是否锁定。0-否1-是,目前暂不支持 \~english Locked. 0-NO; 1-YES, NOT SUPPORT NOW
double dfValue; ///< \~chinese 当前值 \~english Current Value
double dfMinValue; ///< \~chinese 最小值 \~english Min Value
double dfMaxValue; ///< \~chinese 最大值 \~english Max Value
double dfIncrement; ///< \~chinese 增量 \~english Increment
unsigned int nReserved[4];
} MV_XML_FEATURE_Float;
typedef struct _MV_XML_FEATURE_String_
{
char strName[MV_MAX_XML_NODE_STRLEN_C];
char strDisplayName[MV_MAX_XML_NODE_STRLEN_C];
char strDescription
[MV_MAX_XML_DISC_STRLEN_C]; ///< \~chinese 目前暂不支持 \~english NOT SUPPORT NOW
char strToolTip[MV_MAX_XML_DISC_STRLEN_C];
enum MV_XML_Visibility enVisivility; ///< \~chinese 是否可见 \~english Visible
enum MV_XML_AccessMode enAccessMode; ///< \~chinese 访问模式 \~english Access Mode
int
bIsLocked; ///< \~chinese 是否锁定。0-否1-是,目前暂不支持 \~english Locked. 0-NO; 1-YES, NOT SUPPORT NOW
char
strValue[MV_MAX_XML_STRVALUE_STRLEN_C]; ///< \~chinese 当前值 \~english Current Value
unsigned int nReserved[4];
} MV_XML_FEATURE_String;
typedef struct _MV_XML_FEATURE_Register_
{
char strName[MV_MAX_XML_NODE_STRLEN_C];
char strDisplayName[MV_MAX_XML_NODE_STRLEN_C];
char strDescription
[MV_MAX_XML_DISC_STRLEN_C]; ///< \~chinese 目前暂不支持 \~english NOT SUPPORT NOW
char strToolTip[MV_MAX_XML_DISC_STRLEN_C];
enum MV_XML_Visibility enVisivility; ///< \~chinese 是否可见 \~english Visible
enum MV_XML_AccessMode enAccessMode; ///< \~chinese 访问模式 \~english Access Mode
int
bIsLocked; ///< \~chinese 是否锁定。0-否1-是,目前暂不支持 \~english Locked. 0-NO; 1-YES, NOT SUPPORT NOW
int64_t nAddrValue; ///< \~chinese 当前值 \~english Current Value
unsigned int nReserved[4];
} MV_XML_FEATURE_Register;
typedef struct _MV_XML_FEATURE_Category_
{
char strDescription
[MV_MAX_XML_DISC_STRLEN_C]; ///< \~chinese 节点描述 目前暂不支持 \~english Node Description, NOT SUPPORT NOW
char strDisplayName
[MV_MAX_XML_NODE_STRLEN_C]; ///< \~chinese 显示名称 \~english Display Name
char strName[MV_MAX_XML_NODE_STRLEN_C]; ///< \~chinese 节点名 \~english Node Name
char strToolTip[MV_MAX_XML_DISC_STRLEN_C]; ///< \~chinese 提示 \~english Notice
enum MV_XML_Visibility enVisivility; ///< \~chinese 是否可见 \~english Visible
unsigned int nReserved[4];
} MV_XML_FEATURE_Category;
typedef struct _MV_XML_FEATURE_EnumEntry_
{
char strName[MV_MAX_XML_NODE_STRLEN_C];
char strDisplayName[MV_MAX_XML_NODE_STRLEN_C];
char strDescription
[MV_MAX_XML_DISC_STRLEN_C]; ///< \~chinese 目前暂不支持 \~english NOT SUPPORT NOW
char strToolTip[MV_MAX_XML_DISC_STRLEN_C];
int bIsImplemented;
int nParentsNum;
MV_XML_NODE_FEATURE stParentsList[MV_MAX_XML_PARENTS_NUM];
enum MV_XML_Visibility enVisivility; ///< \~chinese 是否可见 \~english Visible
int64_t nValue; ///< \~chinese 当前值 \~english Current Value
enum MV_XML_AccessMode enAccessMode; ///< \~chinese 访问模式 \~english Access Mode
int
bIsLocked; ///< \~chinese 是否锁定。0-否1-是,目前暂不支持 \~english Locked. 0-NO; 1-YES, NOT SUPPORT NOW
int nReserved[8];
} MV_XML_FEATURE_EnumEntry;
typedef struct _MV_XML_FEATURE_Enumeration_
{
enum MV_XML_Visibility enVisivility; ///< \~chinese 是否可见 \~english Visible
char strDescription
[MV_MAX_XML_DISC_STRLEN_C]; ///< \~chinese 节点描述 目前暂不支持 \~english Node Description, NOT SUPPORT NOW
char strDisplayName
[MV_MAX_XML_NODE_STRLEN_C]; ///< \~chinese 显示名称 \~english Display Name
char strName[MV_MAX_XML_NODE_STRLEN_C]; ///< \~chinese 节点名 \~english Node Name
char strToolTip[MV_MAX_XML_DISC_STRLEN_C]; ///< \~chinese 提示 \~english Notice
int nSymbolicNum; ///< \~chinese ymbolic数 \~english Symbolic Number
char strCurrentSymbolic
[MV_MAX_XML_SYMBOLIC_STRLEN_C]; ///< \~chinese 当前Symbolic索引 \~english Current Symbolic Index
char strSymbolic[MV_MAX_XML_SYMBOLIC_NUM][MV_MAX_XML_SYMBOLIC_STRLEN_C];
enum MV_XML_AccessMode enAccessMode; ////< \~chinese 访问模式 \~english Access Mode
int
bIsLocked; ///< \~chinese 是否锁定。0-否1-是,目前暂不支持 \~english Locked. 0-NO; 1-YES, NOT SUPPORT NOW
int64_t nValue; ///< \~chinese 当前值 \~english Current Value
unsigned int nReserved[4];
} MV_XML_FEATURE_Enumeration;
typedef struct _MV_XML_FEATURE_Port_
{
enum MV_XML_Visibility enVisivility; ///< \~chinese 是否可见 \~english Visible
char strDescription
[MV_MAX_XML_DISC_STRLEN_C]; ///< \~chinese 节点描述,目前暂不支持 \~english Node Description, NOT SUPPORT NOW
char strDisplayName
[MV_MAX_XML_NODE_STRLEN_C]; ///< \~chinese 显示名称 \~english Display Name
char strName[MV_MAX_XML_NODE_STRLEN_C]; ///< \~chinese 节点名 \~english Node Name
char strToolTip[MV_MAX_XML_DISC_STRLEN_C]; ///< \~chinese 提示 \~english Notice
enum MV_XML_AccessMode enAccessMode; ///< \~chinese 访问模式 \~english Access Mode
int
bIsLocked; ///< \~chinese 是否锁定。0-否1-是,目前暂不支持 \~english Locked. 0-NO; 1-YES, NOT SUPPORT NOW
unsigned int nReserved[4];
} MV_XML_FEATURE_Port;
typedef struct _MV_XML_CAMERA_FEATURE_
{
enum MV_XML_InterfaceType enType;
union {
MV_XML_FEATURE_Integer stIntegerFeature;
MV_XML_FEATURE_Float stFloatFeature;
MV_XML_FEATURE_Enumeration stEnumerationFeature;
MV_XML_FEATURE_String stStringFeature;
} SpecialFeature;
} MV_XML_CAMERA_FEATURE;
/// \~chinese 图片保存参数 \~english Save Image Parameters
typedef struct _MV_SAVE_IMAGE_PARAM_T_EX_
{
unsigned char * pData; ///< [IN] \~chinese 输入数据缓存 \~english Input Data Buffer
unsigned int nDataLen; ///< [IN] \~chinese 输入数据长度 \~english Input Data length
enum MvGvspPixelType
enPixelType; ///< [IN] \~chinese 输入数据的像素格式 \~english Input Data Pixel Format
unsigned short nWidth; ///< [IN] \~chinese 图像宽 \~english Image Width
unsigned short nHeight; ///< [IN] \~chinese 图像高 \~english Image Height
unsigned char *
pImageBuffer; ///< [OUT] \~chinese 输出图片缓存 \~english Output Image Buffer
unsigned int nImageLen; ///< [OUT] \~chinese 输出图片长度 \~english Output Image length
unsigned int
nBufferSize; ///< [IN] \~chinese 提供的输出缓冲区大小 \~english Output buffer size provided
enum MV_SAVE_IAMGE_TYPE
enImageType; ///< [IN] \~chinese 输出图片格式 \~english Output Image Format
unsigned int
nJpgQuality; ///< [IN] \~chinese JPG编码质量(50-99],其它格式无效 \~english Encoding quality(50-99]Other formats are invalid
unsigned int
iMethodValue; ///< [IN] \~chinese 插值方法 0-快速 1-均衡 2-最优(其它值默认为最优) \~english Bayer interpolation method 0-Fast 1-Equilibrium 2-Optimal
unsigned int nReserved[3]; ///< \~chinese 预留 \~english Reserved
} MV_SAVE_IMAGE_PARAM_EX;
/// \~chinese 图片保存参数 \~english Save Image Parameters
typedef struct _MV_SAVE_IMG_TO_FILE_PARAM_
{
enum MvGvspPixelType
enPixelType; ///< [IN] \~chinese输入数据的像素格式 \~english The pixel format of the input data
unsigned char * pData; ///< [IN] \~chinese 输入数据缓存 \~english Input Data Buffer
unsigned int nDataLen; ///< [IN] \~chinese 输入数据长度 \~english Input Data length
unsigned short nWidth; ///< [IN] \~chinese 图像宽 \~english Image Width
unsigned short nHeight; ///< [IN] \~chinese 图像高 \~english Image Height
enum MV_SAVE_IAMGE_TYPE
enImageType; ///< [IN] \~chinese 输入图片格式 \~english Input Image Format
unsigned int
nQuality; ///< [IN] \~chinese JPG编码质量(50-99]PNG编码质量[0-9],其它格式无效 \~english JPG Encoding quality(50-99],PNG Encoding quality[0-9]Other formats are invalid
char pImagePath[256]; ///< [IN] \~chinese 输入文件路径 \~english Input file path
int
iMethodValue; ///< [IN] \~chinese 插值方法 0-快速 1-均衡 2-最优(其它值默认为最优) \~english Bayer interpolation method 0-Fast 1-Equilibrium 2-Optimal
unsigned int nReserved[8]; ///< \~chinese 预留 \~english Reserved
} MV_SAVE_IMG_TO_FILE_PARAM;
// \~chinese 像素转换结构体 \~english Pixel convert structure
typedef struct _MV_CC_PIXEL_CONVERT_PARAM_
{
unsigned short nWidth; ///< [IN] \~chinese 图像宽 \~english Width
unsigned short nHeight; ///< [IN] \~chinese 图像高 \~english Height
enum MvGvspPixelType
enSrcPixelType; ///< [IN] \~chinese 源像素格式 \~english Source pixel format
unsigned char * pSrcData; ///< [IN] \~chinese 输入数据缓存 \~english Input data buffer
unsigned int nSrcDataLen; ///< [IN] \~chinese 输入数据长度 \~english Input data length
enum MvGvspPixelType
enDstPixelType; ///< [IN] \~chinese 目标像素格式 \~english Destination pixel format
unsigned char *
pDstBuffer; ///< [OUT] \~chinese 输出数据缓存 \~english Output data buffer
unsigned int nDstLen; ///< [OUT] \~chinese 输出数据长度 \~english Output data length
unsigned int
nDstBufferSize; ///< [IN] \~chinese 提供的输出缓冲区大小 \~english Provided output buffer size
unsigned int nRes[4]; ///< \~chinese 预留 \~english Reserved
} MV_CC_PIXEL_CONVERT_PARAM;
#endif /* _MV_OBSOLETE_CAM_PARAMS_H_ */

View File

@ -0,0 +1,248 @@
#ifndef _MV_PIXEL_TYPE_H_
#define _MV_PIXEL_TYPE_H_
/************************************************************************/
/* GigE Vision (2.0.03) PIXEL FORMATS */
/************************************************************************/
// Indicate if pixel is monochrome or RGB
#define MV_GVSP_PIX_MONO 0x01000000
#define MV_GVSP_PIX_RGB 0x02000000 // deprecated in version 1.1
#define MV_GVSP_PIX_COLOR 0x02000000
#define MV_GVSP_PIX_CUSTOM 0x80000000
#define MV_GVSP_PIX_COLOR_MASK 0xFF000000
// Indicate effective number of bits occupied by the pixel (including padding).
// This can be used to compute amount of memory required to store an image.
#define MV_PIXEL_BIT_COUNT(n) ((n) << 16)
#define MV_GVSP_PIX_EFFECTIVE_PIXEL_SIZE_MASK 0x00FF0000
#define MV_GVSP_PIX_EFFECTIVE_PIXEL_SIZE_SHIFT 16
// Pixel ID: lower 16-bit of the pixel formats
#define MV_GVSP_PIX_ID_MASK 0x0000FFFF
#define MV_GVSP_PIX_COUNT 0x46 // next Pixel ID available
enum MvGvspPixelType
{
// Undefined pixel type
#ifdef WIN32
PixelType_Gvsp_Undefined = 0xFFFFFFFF,
#else
PixelType_Gvsp_Undefined = -1,
#endif
// Mono buffer format defines
PixelType_Gvsp_Mono1p = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(1) | 0x0037),
PixelType_Gvsp_Mono2p = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(2) | 0x0038),
PixelType_Gvsp_Mono4p = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(4) | 0x0039),
PixelType_Gvsp_Mono8 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x0001),
PixelType_Gvsp_Mono8_Signed = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x0002),
PixelType_Gvsp_Mono10 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0003),
PixelType_Gvsp_Mono10_Packed = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0004),
PixelType_Gvsp_Mono12 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0005),
PixelType_Gvsp_Mono12_Packed = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0006),
PixelType_Gvsp_Mono14 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0025),
PixelType_Gvsp_Mono16 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0007),
// Bayer buffer format defines
PixelType_Gvsp_BayerGR8 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x0008),
PixelType_Gvsp_BayerRG8 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x0009),
PixelType_Gvsp_BayerGB8 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x000A),
PixelType_Gvsp_BayerBG8 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x000B),
PixelType_Gvsp_BayerRBGG8 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x0046),
PixelType_Gvsp_BayerGR10 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x000C),
PixelType_Gvsp_BayerRG10 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x000D),
PixelType_Gvsp_BayerGB10 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x000E),
PixelType_Gvsp_BayerBG10 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x000F),
PixelType_Gvsp_BayerGR12 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0010),
PixelType_Gvsp_BayerRG12 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0011),
PixelType_Gvsp_BayerGB12 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0012),
PixelType_Gvsp_BayerBG12 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0013),
PixelType_Gvsp_BayerGR10_Packed = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0026),
PixelType_Gvsp_BayerRG10_Packed = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0027),
PixelType_Gvsp_BayerGB10_Packed = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0028),
PixelType_Gvsp_BayerBG10_Packed = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0029),
PixelType_Gvsp_BayerGR12_Packed = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x002A),
PixelType_Gvsp_BayerRG12_Packed = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x002B),
PixelType_Gvsp_BayerGB12_Packed = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x002C),
PixelType_Gvsp_BayerBG12_Packed = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x002D),
PixelType_Gvsp_BayerGR16 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x002E),
PixelType_Gvsp_BayerRG16 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x002F),
PixelType_Gvsp_BayerGB16 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0030),
PixelType_Gvsp_BayerBG16 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0031),
// RGB Packed buffer format defines
PixelType_Gvsp_RGB8_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(24) | 0x0014),
PixelType_Gvsp_BGR8_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(24) | 0x0015),
PixelType_Gvsp_RGBA8_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(32) | 0x0016),
PixelType_Gvsp_BGRA8_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(32) | 0x0017),
PixelType_Gvsp_RGB10_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x0018),
PixelType_Gvsp_BGR10_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x0019),
PixelType_Gvsp_RGB12_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x001A),
PixelType_Gvsp_BGR12_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x001B),
PixelType_Gvsp_RGB16_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x0033),
PixelType_Gvsp_BGR16_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x004B),
PixelType_Gvsp_RGBA16_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(64) | 0x0064),
PixelType_Gvsp_BGRA16_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(64) | 0x0051),
PixelType_Gvsp_RGB10V1_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(32) | 0x001C),
PixelType_Gvsp_RGB10V2_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(32) | 0x001D),
PixelType_Gvsp_RGB12V1_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(36) | 0X0034),
PixelType_Gvsp_RGB565_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x0035),
PixelType_Gvsp_BGR565_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0X0036),
// YUV Packed buffer format defines
PixelType_Gvsp_YUV411_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(12) | 0x001E),
PixelType_Gvsp_YUV422_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x001F),
PixelType_Gvsp_YUV422_YUYV_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x0032),
PixelType_Gvsp_YUV444_Packed = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(24) | 0x0020),
PixelType_Gvsp_YCBCR8_CBYCR = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(24) | 0x003A),
PixelType_Gvsp_YCBCR422_8 = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x003B),
PixelType_Gvsp_YCBCR422_8_CBYCRY = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x0043),
PixelType_Gvsp_YCBCR411_8_CBYYCRYY = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(12) | 0x003C),
PixelType_Gvsp_YCBCR601_8_CBYCR = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(24) | 0x003D),
PixelType_Gvsp_YCBCR601_422_8 = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x003E),
PixelType_Gvsp_YCBCR601_422_8_CBYCRY = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x0044),
PixelType_Gvsp_YCBCR601_411_8_CBYYCRYY = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(12) | 0x003F),
PixelType_Gvsp_YCBCR709_8_CBYCR = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(24) | 0x0040),
PixelType_Gvsp_YCBCR709_422_8 = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x0041),
PixelType_Gvsp_YCBCR709_422_8_CBYCRY = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x0045),
PixelType_Gvsp_YCBCR709_411_8_CBYYCRYY = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(12) | 0x0042),
// YUV420
PixelType_Gvsp_YUV420SP_NV12 = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(12) | 0x8001),
PixelType_Gvsp_YUV420SP_NV21 = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(12) | 0x8002),
// RGB Planar buffer format defines
PixelType_Gvsp_RGB8_Planar = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(24) | 0x0021),
PixelType_Gvsp_RGB10_Planar = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x0022),
PixelType_Gvsp_RGB12_Planar = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x0023),
PixelType_Gvsp_RGB16_Planar = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x0024),
// 自定义的图片格式
PixelType_Gvsp_Jpeg = (MV_GVSP_PIX_CUSTOM | MV_PIXEL_BIT_COUNT(24) | 0x0001),
PixelType_Gvsp_Coord3D_ABC32f =
(MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(96) | 0x00C0), //0x026000C0
PixelType_Gvsp_Coord3D_ABC32f_Planar =
(MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(96) | 0x00C1), //0x026000C1
// 该值被废弃请参考PixelType_Gvsp_Coord3D_AC32f_64; the value is discarded
PixelType_Gvsp_Coord3D_AC32f = (MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(40) | 0x00C2),
// 该值被废弃; the value is discarded (已放入Chunkdata)
PixelType_Gvsp_COORD3D_DEPTH_PLUS_MASK =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(28) | 0x0001),
PixelType_Gvsp_Coord3D_ABC32 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(96) | 0x3001), //0x82603001
PixelType_Gvsp_Coord3D_AB32f =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(64) | 0x3002), //0x82403002
PixelType_Gvsp_Coord3D_AB32 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(64) | 0x3003), //0x82403003
PixelType_Gvsp_Coord3D_AC32f_64 =
(MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(64) | 0x00C2), //0x024000C2
PixelType_Gvsp_Coord3D_AC32f_Planar =
(MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(64) | 0x00C3), //0x024000C3
PixelType_Gvsp_Coord3D_AC32 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(64) | 0x3004), //0x82403004
PixelType_Gvsp_Coord3D_A32f = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(32) | 0x00BD), //0x012000BD
PixelType_Gvsp_Coord3D_A32 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(32) | 0x3005), //0x81203005
PixelType_Gvsp_Coord3D_C32f = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(32) | 0x00BF), //0x012000BF
PixelType_Gvsp_Coord3D_C32 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(32) | 0x3006), //0x81203006
PixelType_Gvsp_Coord3D_ABC16 =
(MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x00B9), //0x023000B9
PixelType_Gvsp_Coord3D_C16 = (MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x00B8), //0x011000B8
PixelType_Gvsp_Float32 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(32) | 0x0001), //0x81200001
//无损压缩像素格式定义
PixelType_Gvsp_HB_Mono8 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x0001),
PixelType_Gvsp_HB_Mono10 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0003),
PixelType_Gvsp_HB_Mono10_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0004),
PixelType_Gvsp_HB_Mono12 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0005),
PixelType_Gvsp_HB_Mono12_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0006),
PixelType_Gvsp_HB_Mono16 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0007),
PixelType_Gvsp_HB_BayerGR8 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x0008),
PixelType_Gvsp_HB_BayerRG8 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x0009),
PixelType_Gvsp_HB_BayerGB8 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x000A),
PixelType_Gvsp_HB_BayerBG8 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x000B),
PixelType_Gvsp_HB_BayerRBGG8 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(8) | 0x0046),
PixelType_Gvsp_HB_BayerGR10 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x000C),
PixelType_Gvsp_HB_BayerRG10 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x000D),
PixelType_Gvsp_HB_BayerGB10 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x000E),
PixelType_Gvsp_HB_BayerBG10 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x000F),
PixelType_Gvsp_HB_BayerGR12 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0010),
PixelType_Gvsp_HB_BayerRG12 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0011),
PixelType_Gvsp_HB_BayerGB12 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0012),
PixelType_Gvsp_HB_BayerBG12 =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(16) | 0x0013),
PixelType_Gvsp_HB_BayerGR10_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0026),
PixelType_Gvsp_HB_BayerRG10_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0027),
PixelType_Gvsp_HB_BayerGB10_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0028),
PixelType_Gvsp_HB_BayerBG10_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x0029),
PixelType_Gvsp_HB_BayerGR12_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x002A),
PixelType_Gvsp_HB_BayerRG12_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x002B),
PixelType_Gvsp_HB_BayerGB12_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x002C),
PixelType_Gvsp_HB_BayerBG12_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_MONO | MV_PIXEL_BIT_COUNT(12) | 0x002D),
PixelType_Gvsp_HB_YUV422_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x001F),
PixelType_Gvsp_HB_YUV422_YUYV_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(16) | 0x0032),
PixelType_Gvsp_HB_RGB8_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(24) | 0x0014),
PixelType_Gvsp_HB_BGR8_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(24) | 0x0015),
PixelType_Gvsp_HB_RGBA8_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(32) | 0x0016),
PixelType_Gvsp_HB_BGRA8_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(32) | 0x0017),
PixelType_Gvsp_HB_RGB16_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x0033),
PixelType_Gvsp_HB_BGR16_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(48) | 0x004B),
PixelType_Gvsp_HB_RGBA16_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(64) | 0x0064),
PixelType_Gvsp_HB_BGRA16_Packed =
(MV_GVSP_PIX_CUSTOM | MV_GVSP_PIX_COLOR | MV_PIXEL_BIT_COUNT(64) | 0x0051),
};
#ifdef WIN32
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
#endif /* _MV_PIXEL_TYPE_H_ */

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,842 @@
#pragma once
#ifndef _CAMERA_DEFINE_H_
#define _CAMERA_DEFINE_H_
#include "CameraStatus.h"
#define MAX_CROSS_LINE 9
//相机的句柄类型定义
typedef int CameraHandle;
typedef int INT;
typedef int LONG;
typedef unsigned int UINT;
typedef unsigned long long UINT64;
typedef int BOOL;
typedef unsigned char BYTE;
typedef unsigned int DWORD;
typedef void* PVOID;
typedef void* HWND;
typedef char* LPCTSTR;
typedef unsigned short USHORT;
typedef short SHORT;
typedef unsigned char* LPBYTE;
typedef char CHAR;
typedef char TCHAR;
typedef unsigned short WORD;
typedef INT HANDLE;
typedef void VOID;
typedef unsigned int ULONG;
typedef void* LPVOID;
typedef unsigned char UCHAR;
typedef void* HMODULE;
#define TRUE 1
#define FALSE 0
//图像查表变换的方式
typedef enum
{
LUTMODE_PARAM_GEN=0,//通过调节参数动态生成LUT表
LUTMODE_PRESET, //使用预设的LUT表
LUTMODE_USER_DEF //使用用户自定义的LUT表
}emSdkLutMode;
//相机的视频流控制
typedef enum
{
RUNMODE_PLAY=0, //正常预览,捕获到图像就显示。(如果相机处于触发模式,则会等待触发帧的到来)
RUNMODE_PAUSE, //暂停,会暂停相机的图像输出,同时也不会去捕获图像
RUNMODE_STOP //停止相机工作。反初始化后,相机就处于停止模式
}emSdkRunMode;
//SDK内部显示接口的显示方式
typedef enum
{
DISPLAYMODE_SCALE=0, //缩放显示模式,缩放到显示控件的尺寸
DISPLAYMODE_REAL //1:1显示模式当图像尺寸大于显示控件的尺寸时只显示局部
}emSdkDisplayMode;
//录像状态
typedef enum
{
RECORD_STOP = 0, //停止
RECORD_START, //录像中
RECORD_PAUSE //暂停
}emSdkRecordMode;
//图像的镜像操作
typedef enum
{
MIRROR_DIRECTION_HORIZONTAL = 0,//水平镜像
MIRROR_DIRECTION_VERTICAL //垂直镜像
}emSdkMirrorDirection;
/// @ingroup MV_ENUM_TYPE
/// \~chinese 图像的旋转操作
/// \~english Rotation of the image
typedef enum
{
ROTATE_DIRECTION_0=0, ///< \~chinese 不旋转 \~english Do not rotate
ROTATE_DIRECTION_90=1, ///< \~chinese 逆时针90度 \~english Counterclockwise 90 degrees
ROTATE_DIRECTION_180=2, ///< \~chinese 逆时针180度 \~english Counterclockwise 180 degrees
ROTATE_DIRECTION_270=3, ///< \~chinese 逆时针270度 \~english Counterclockwise 270 degrees
}emSdkRotateDirection;
//相机视频的帧率
typedef enum
{
FRAME_SPEED_LOW = 0, //低速模式
FRAME_SPEED_NORMAL, //普通模式
FRAME_SPEED_HIGH, //高速模式(需要较高的传输带宽,多设备共享传输带宽时会对帧率的稳定性有影响)
FRAME_SPEED_SUPER //超高速模式(需要较高的传输带宽,多设备共享传输带宽时会对帧率的稳定性有影响)
}emSdkFrameSpeed;
//保存文件的格式类型
typedef enum
{
FILE_JPG = 1,//JPG
FILE_BMP = 2,//BMP
FILE_RAW = 4,//相机输出的bayer格式文件,对于不支持bayer格式输出相机无法保存为该格式
FILE_PNG = 8, //PNG
FILE_BMP_8BIT = 16, ///< \~chinese BMP 8bit \~english BMP 8bit
FILE_PNG_8BIT = 32, ///< \~chinese PNG 8bit \~english PNG 8bit
FILE_RAW_16BIT = 64, ///< \~chinese RAW 16bit \~english RAW 16bit
}emSdkFileType;
/// @ingroup MV_ENUM_TYPE
/// \~chinese 相机中的图像传感器的工作模式
/// \~english Image Sensor Operation Mode in Camera
typedef enum
{
/// \~chinese 连续采集模式
/// \~english Continuous acquisition mode
CONTINUATION=0,
/// \~chinese 软件触发模式,由软件发送指令后,传感器开始采集指定帧数的图像,采集完成后,停止输出
/// \~english Software trigger mode. After the software sends the instruction, the sensor starts to capture the image of the specified frame number. After the acquisition is completed, the output is stopped.
SOFT_TRIGGER=1,
/// \~chinese 硬件触发模式,当接收到外部信号,传感器开始采集指定帧数的图像,采集完成后,停止输出
/// \~english In the hardware trigger mode, when receiving an external signal, the sensor starts to capture the image of the specified frame number. After the acquisition is completed, the output is stopped.
EXTERNAL_TRIGGER=2,
/// \~chinese 编码器触发模式(仅用于线阵相机)
/// \~english Encoder trigger mode (only for line scan cameras)
ROTARYENC_TRIGGER=3,
/// \~chinese 编码器条件触发模式(仅用于线阵相机)
/// \~english Encoder condition trigger mode (only for line scan cameras)
ROTARYENC_COND_TRIGGER=4,
} emSdkSnapMode;
//自动曝光时抗频闪的频闪
typedef enum
{
LIGHT_FREQUENCY_50HZ = 0,//50HZ,一般的灯光都是50HZ
LIGHT_FREQUENCY_60HZ //60HZ,主要是指显示器的
}emSdkLightFrequency;
//相机的配置参数分为A,B,C,D 4组进行保存。
typedef enum
{
PARAMETER_TEAM_DEFAULT = 0xff,
PARAMETER_TEAM_A = 0,
PARAMETER_TEAM_B = 1,
PARAMETER_TEAM_C = 2,
PARAMETER_TEAM_D = 3
}emSdkParameterTeam;
/*emSdkParameterMode 相机参数加载模式,参数加载分为从文件和从设备加载两种方式
PARAM_MODE_BY_MODEL:ABCD四组参数文件
PARAM_MODE_BY_NAME:ABCD四组参数文件
PARAM_MODE_BY_SN:ABCD四组参数文件
使使
MV-U300为例 4
使PARAM_MODE_BY_MODEL方式;MV-U300能
使MV-U300又要使用相同的参数文件使
PARAM_MODE_BY_NAME方式;MV-U300都使用不同的参数文件
使PARAM_MODE_BY_SN方式
\Camera\Configs config为后缀名的文件
*/
typedef enum
{
PARAM_MODE_BY_MODEL = 0, //根据相机型号名从文件中加载参数例如MV-U300
PARAM_MODE_BY_NAME, //根据设备昵称(tSdkCameraDevInfo.acFriendlyName)从文件中加载参数例如MV-U300,该昵称可自定义
PARAM_MODE_BY_SN, //根据设备的唯一序列号从文件中加载参数,序列号在出厂时已经写入设备,每台相机拥有不同的序列号。
PARAM_MODE_IN_DEVICE //从设备的固态存储器中加载参数。不是所有的型号都支持从相机中读写参数组由tSdkCameraCapbility.bParamInDevice决定
}emSdkParameterMode;
//SDK生成的相机配置页面掩码值
typedef enum
{
PROP_SHEET_INDEX_EXPOSURE=0, ///< \~chinese 曝光设置 \~english Exposure Settings
PROP_SHEET_INDEX_ISP_COLOR=1, ///< \~chinese 颜色矩阵设置 \~english Color Matrix Settings
PROP_SHEET_INDEX_ISP_LUT=2, ///< \~chinese LUT设置 \~english LUT setting
PROP_SHEET_INDEX_ISP_SHAPE=3, ///< \~chinese 变换设置 \~english transform settings
PROP_SHEET_INDEX_VIDEO_FORMAT=4, ///< \~chinese 格式设置 \~english Formatting
PROP_SHEET_INDEX_RESOLUTION=5, ///< \~chinese 分辨率设置 \~english resolution setting
PROP_SHEET_INDEX_IO_CTRL=6, ///< \~chinese IO控制 \~english IO control
PROP_SHEET_INDEX_TRIGGER_SET=7, ///< \~chinese 触发模式 \~english trigger setting
PROP_SHEET_INDEX_OVERLAY=8, ///< \~chinese 十字线 \~english Crosshair
PROP_SHEET_INDEX_DEVICE_INFO=9, ///< \~chinese 设备信息 \~english Device Information
PROP_SHEET_INDEX_WDR=10, ///< \~chinese 宽动态 \~english Wide Dynamic
PROP_SHEET_INDEX_MULTI_EXPOSURE=11, ///< \~chinese 多重曝光 \~english Multi exposure
PROP_SHEET_INDEX_SPECIAL=12, ///< \~chinese 特殊设置 \~english Special settings
PROP_SHEET_INDEX_GIGE=13, ///< \~chinese GIGE设置 \~english GIGE settings
PROP_SHEET_INDEX_GF_SETTING_I = 14, ///< \~chinese GF系列红外相机设置I \~english GF Settings I
PROP_SHEET_INDEX_GF_SETTING_II = 15, ///< \~chinese GF系列红外相机设置II \~english GF Settings II
PROP_SHEET_INDEX_NEW_ISP_COLOR = 16, ///< \~chinese 白平衡设置 \~english WB Settings
}emSdkPropSheetMask;
//SDK生成的相机配置页面的回调消息类型
typedef enum
{
SHEET_MSG_LOAD_PARAM_DEFAULT = 0, //参数被恢复成默认后,触发该消息
SHEET_MSG_LOAD_PARAM_GROUP, //加载指定参数组,触发该消息
SHEET_MSG_LOAD_PARAM_FROMFILE, //从指定文件加载参数后,触发该消息
SHEET_MSG_SAVE_PARAM_GROUP //当前参数组被保存时,触发该消息
}emSdkPropSheetMsg;
//可视化选择参考窗口的类型
typedef enum
{
REF_WIN_AUTO_EXPOSURE = 0,
REF_WIN_WHITE_BALANCE,
}emSdkRefWinType;
//可视化选择参考窗口的类型
typedef enum
{
RES_MODE_PREVIEW = 0,
RES_MODE_SNAPSHOT,
}emSdkResolutionMode;
//白平衡时色温模式
typedef enum
{
CT_MODE_AUTO = 0, //自动识别色温
CT_MODE_PRESET, //使用指定的预设色温
CT_MODE_USER_DEF //自定义色温(增益和矩阵)
}emSdkClrTmpMode;
//LUT的颜色通道
typedef enum
{
LUT_CHANNEL_ALL = 0,//R,B,G三通道同时调节
LUT_CHANNEL_RED, //红色通道
LUT_CHANNEL_GREEN, //绿色通道
LUT_CHANNEL_BLUE, //蓝色通道
}emSdkLutChannel;
//ISP处理单元
typedef enum
{
ISP_PROCESSSOR_PC = 0,//使用PC的软件ISP模块
ISP_PROCESSSOR_DEVICE //使用相机自带的硬件ISP模块
}emSdkIspProcessor;
//闪光灯信号控制方式
typedef enum
{
STROBE_SYNC_WITH_TRIG_AUTO = 0, //和触发信号同步触发后相机进行曝光时自动生成STROBE信号。此时有效极性可设置(CameraSetStrobePolarity)。
STROBE_SYNC_WITH_TRIG_MANUAL, //和触发信号同步触发后STROBE延时指定的时间后(CameraSetStrobeDelayTime),再持续指定时间的脉冲(CameraSetStrobePulseWidth),有效极性可设置(CameraSetStrobePolarity)。
STROBE_ALWAYS_HIGH, //始终为高忽略STROBE信号的其他设置
STROBE_ALWAYS_LOW //始终为低忽略STROBE信号的其他设置
}emStrobeControl;
//硬件外触发的信号种类
typedef enum
{
EXT_TRIG_LEADING_EDGE = 0, //上升沿触发,默认为该方式
EXT_TRIG_TRAILING_EDGE, //下降沿触发
EXT_TRIG_HIGH_LEVEL, //高电平触发,电平宽度决定曝光时间,仅部分型号的相机支持电平触发方式。
EXT_TRIG_LOW_LEVEL //低电平触发,
}emExtTrigSignal;
//硬件外触发时的快门方式
typedef enum
{
EXT_TRIG_EXP_STANDARD = 0, //标准方式,默认为该方式。
EXT_TRIG_EXP_GRR, //全局复位方式部分滚动快门的CMOS型号的相机支持该方式配合外部机械快门可以达到全局快门的效果适合拍高速运动的物体
}emExtTrigShutterMode;
/// @ingroup MV_ENUM_TYPE
/// \~chinese 清晰度评估算法
/// \~english Sharpness assessment algorithm
typedef enum
{
EVALUATE_DEFINITION_DEVIATION=0, ///< \~chinese 方差法 \~english Variance method
EVALUATE_DEFINITION_SMD=1, ///< \~chinese 相邻像素灰度方差法 \~english Adjacent Pixel Gray Difference Method
EVALUATE_DEFINITION_GRADIENT=2, ///< \~chinese 梯度统计 \~english Gradient statistics
EVALUATE_DEFINITION_SOBEL=3, ///< \~chinese Sobel \~english Sobel
EVALUATE_DEFINITION_ROBERT=4, ///< \~chinese Robert \~english Robert
EVALUATE_DEFINITION_LAPLACE=5, ///< \~chinese Laplace \~english Laplace
EVALUATE_DEFINITION_ALG_MAX=6, ///< \~chinese 算法个数 \~english The number of algorithms
}emEvaluateDefinitionAlgorith;
// GPIO模式
typedef enum
{
IOMODE_TRIG_INPUT=0, ///< \~chinese 触发输入 \~english Trigger input
IOMODE_STROBE_OUTPUT=1, ///< \~chinese 闪光灯输出 \~english Strobe output
IOMODE_GP_INPUT=2, ///< \~chinese 通用型输入 \~english Universal input
IOMODE_GP_OUTPUT=3, ///< \~chinese 通用型输出 \~english Universal output
IOMODE_PWM_OUTPUT=4, ///< \~chinese PWM型输出 \~english PWM output
IOMODE_ROTARYENC_INPUT=5, ///< \~chinese 编码器输入 \~english rotary input
}emCameraGPIOMode;
/// @ingroup MV_ENUM_TYPE
/// \~chinese GPIO 格式
/// \~english GPIO Format
typedef enum
{
IOFORMAT_SINGLE=0, ///< \~chinese 单端 \~english single ended
IOFORMAT_RS422=1, ///< \~chinese 差分RS422 \~english Differential RS422
IOFORMAT_RS422_TERM=2, ///< \~chinese 差分RS422带终端电阻 \~english Differential RS422 and Termination Enable
IOFORMAT_OCEP=3, ///< \~chinese 光耦 \~english opticalcoupler equipment
}emCameraGPIOFormat;
/// @ingroup MV_ENUM_TYPE
/// \~chinese 取图优先级
/// \~english Get Image priority
typedef enum
{
CAMERA_GET_IMAGE_PRIORITY_OLDEST=0, ///< \~chinese 获取缓存中最旧的一帧 \~english Get the oldest frame in the cache
CAMERA_GET_IMAGE_PRIORITY_NEWEST=1, ///< \~chinese 获取缓存中最新的一帧(比此帧旧的将全部丢弃) \~english Get the latest frame in the cache (older than this frame will be discarded)
/// \~chinese 丢弃缓存中的所有帧,并且如果此刻相机正在曝光或传输将会被立即打断,等待接收下一帧
/// \note 某些型号的相机不支持此功能,对于不支持此功能的相机这个标志相当于@link #CAMERA_GET_IMAGE_PRIORITY_OLDEST @endlink
/// \~english All frames in the cache are discarded, and if the camera is now being exposed or transmitted it will be immediately interrupted, waiting to receive the next frame
/// \note Some models do not support this feature. For cameras that do not support this feature this flag is equivalent to @link #CAMERA_GET_IMAGE_PRIORITY_OLDEST @endlink
CAMERA_GET_IMAGE_PRIORITY_NEXT=2,
}emCameraGetImagePriority;
/// @ingroup MV_ENUM_TYPE
/// \~chinese 软触发功能标志
/// \~english Soft trigger function flag
typedef enum
{
CAMERA_ST_CLEAR_BUFFER_BEFORE = 0x1, ///< \~chinese 在软触发之前先清空相机已缓存的帧 \~english Empty camera-cached frames before soft triggering
}emCameraSoftTriggerExFlags;
//相机的设备信息
typedef struct
{
char acProductSeries[32]; // 产品系列
char acProductName[32]; // 产品名称
char acFriendlyName[32]; // 产品昵称,用户可自定义改昵称,保存在相机内,用于区分多个相机同时使用,可以用CameraSetFriendlyName接口改变该昵称设备重启后生效。
char acLinkName[32]; // 内核符号连接名,内部使用
char acDriverVersion[32]; // 驱动版本
char acSensorType[32]; // sensor类型
char acPortType[32]; // 接口类型
char acSn[32]; // 产品唯一序列号
UINT uInstance; // 该型号相机在该电脑上的实例索引号,用于区分同型号多相机
} tSdkCameraDevInfo;
#define EXT_TRIG_MASK_GRR_SHUTTER 1 ///< \~chinese 快门支持GRR模式 \~english Shutter supports GRR mode
#define EXT_TRIG_MASK_LEVEL_MODE 2 ///< \~chinese 支持电平触发 \~english Support level trigger
#define EXT_TRIG_MASK_DOUBLE_EDGE 4 ///< \~chinese 支持双边沿触发 \~english Supports bilateral triggering
#define EXT_TRIG_MASK_BUFFERED_DELAY 8 ///< \~chinese 支持信号后延 \~english Supports signal delayed activation
//tSdkResolutionRange结构体中SKIP、 BIN、RESAMPLE模式的掩码值
#define MASK_2X2_HD (1<<0) //硬件SKIP、BIN、重采样 2X2
#define MASK_3X3_HD (1<<1)
#define MASK_4X4_HD (1<<2)
#define MASK_5X5_HD (1<<3)
#define MASK_6X6_HD (1<<4)
#define MASK_7X7_HD (1<<5)
#define MASK_8X8_HD (1<<6)
#define MASK_9X9_HD (1<<7)
#define MASK_10X10_HD (1<<8)
#define MASK_11X11_HD (1<<9)
#define MASK_12X12_HD (1<<10)
#define MASK_13X13_HD (1<<11)
#define MASK_14X14_HD (1<<12)
#define MASK_15X15_HD (1<<13)
#define MASK_16X16_HD (1<<14)
#define MASK_17X17_HD (1<<15)
#define MASK_2X2_SW (1<<16) //硬件SKIP、BIN、重采样 2X2
#define MASK_3X3_SW (1<<17)
#define MASK_4X4_SW (1<<18)
#define MASK_5X5_SW (1<<19)
#define MASK_6X6_SW (1<<20)
#define MASK_7X7_SW (1<<21)
#define MASK_8X8_SW (1<<22)
#define MASK_9X9_SW (1<<23)
#define MASK_10X10_SW (1<<24)
#define MASK_11X11_SW (1<<25)
#define MASK_12X12_SW (1<<26)
#define MASK_13X13_SW (1<<27)
#define MASK_14X14_SW (1<<28)
#define MASK_15X15_SW (1<<29)
#define MASK_16X16_SW (1<<30)
#define MASK_17X17_SW (1<<31)
//相机的分辨率设定范围用于构件UI
typedef struct
{
INT iHeightMax; //图像最大高度
INT iHeightMin; //图像最小高度
INT iWidthMax; //图像最大宽度
INT iWidthMin; //图像最小宽度
UINT uSkipModeMask; //SKIP模式掩码为0表示不支持SKIP 。bit0为1,表示支持SKIP 2x2 ;bit1为1表示支持SKIP 3x3....
UINT uBinSumModeMask; //BIN(求和)模式掩码为0表示不支持BIN 。bit0为1,表示支持BIN 2x2 ;bit1为1表示支持BIN 3x3....
UINT uBinAverageModeMask; //BIN(求均值)模式掩码为0表示不支持BIN 。bit0为1,表示支持BIN 2x2 ;bit1为1表示支持BIN 3x3....
UINT uResampleMask; //硬件重采样的掩码
} tSdkResolutionRange;
//相机的分辨率描述
typedef struct
{
INT iIndex; // 索引号,[0,N]表示预设的分辨率(N 为预设分辨率的最大个数一般不超过20),OXFF 表示自定义分辨率(ROI)
char acDescription[32]; // 该分辨率的描述信息。仅预设分辨率时该信息有效。自定义分辨率可忽略该信息
UINT uBinSumMode; // BIN(求和)的模式,范围不能超过tSdkResolutionRange中uBinSumModeMask
UINT uBinAverageMode; // BIN(求均值)的模式,范围不能超过tSdkResolutionRange中uBinAverageModeMask
UINT uSkipMode; // 是否SKIP的尺寸为0表示禁止SKIP模式范围不能超过tSdkResolutionRange中uSkipModeMask
UINT uResampleMask; // 硬件重采样的掩码
INT iHOffsetFOV; // 采集视场相对于Sensor最大视场左上角的垂直偏移
INT iVOffsetFOV; // 采集视场相对于Sensor最大视场左上角的水平偏移
INT iWidthFOV; // 采集视场的宽度
INT iHeightFOV; // 采集视场的高度
INT iWidth; // 相机最终输出的图像的宽度
INT iHeight; // 相机最终输出的图像的高度
INT iWidthZoomHd; // 硬件缩放的宽度,不需要进行此操作的分辨率此变量设置为0.
INT iHeightZoomHd; // 硬件缩放的高度,不需要进行此操作的分辨率此变量设置为0.
INT iWidthZoomSw; // 软件缩放的宽度,不需要进行此操作的分辨率此变量设置为0.
INT iHeightZoomSw; // 软件缩放的高度,不需要进行此操作的分辨率此变量设置为0.
} tSdkImageResolution;
//相机白平衡色温模式描述信息
typedef struct
{
INT iIndex; // 模式索引号
char acDescription[32]; // 描述信息
} tSdkColorTemperatureDes;
//相机帧率描述信息
typedef struct
{
INT iIndex; // 帧率索引号一般0对应于低速模式1对应于普通模式2对应于高速模式
char acDescription[32]; // 描述信息
} tSdkFrameSpeed;
//相机曝光功能范围定义
typedef struct
{
UINT uiTargetMin; //自动曝光亮度目标最小值
UINT uiTargetMax; //自动曝光亮度目标最大值
UINT uiAnalogGainMin; //模拟增益的最小值单位为fAnalogGainStep中定义
UINT uiAnalogGainMax; //模拟增益的最大值单位为fAnalogGainStep中定义
float fAnalogGainStep; //模拟增益每增加1对应的增加的放大倍数。例如uiAnalogGainMin一般为16fAnalogGainStep一般为0.125那么最小放大倍数就是16*0.125 = 2倍
UINT uiExposeTimeMin; //手动模式下,曝光时间的最小值,单位:行。根据CameraGetExposureLineTime可以获得一行对应的时间(微秒),从而得到整帧的曝光时间
UINT uiExposeTimeMax; //手动模式下,曝光时间的最大值,单位:行
} tSdkExpose;
//触发模式描述
typedef struct
{
INT iIndex; //模式索引号
char acDescription[32]; //该模式的描述信息
} tSdkTrigger;
//传输分包大小描述(主要是针对网络相机有效)
typedef struct
{
INT iIndex; //分包大小索引号
char acDescription[32]; //对应的描述信息
UINT iPackSize;
} tSdkPackLength;
//预设的LUT表描述
typedef struct
{
INT iIndex; //编号
char acDescription[32]; //描述信息
} tSdkPresetLut;
//AE算法描述
typedef struct
{
INT iIndex; //编号
char acDescription[32]; //描述信息
} tSdkAeAlgorithm;
//RAW转RGB算法描述
typedef struct
{
INT iIndex; //编号
char acDescription[32]; //描述信息
} tSdkBayerDecodeAlgorithm;
//帧率统计信息
typedef struct
{
INT iTotal; //当前采集的总帧数(包括错误帧)
INT iCapture; //当前采集的有效帧的数量
INT iLost; //当前丢帧的数量
} tSdkFrameStatistic;
//相机输出的图像数据格式
typedef struct
{
INT iIndex; //格式种类编号
char acDescription[32]; //描述信息
UINT iMediaType; //对应的图像格式编码如CAMERA_MEDIA_TYPE_BAYGR8在本文件中有定义。
} tSdkMediaType;
//伽马的设定范围
typedef struct
{
INT iMin; //最小值
INT iMax; //最大值
} tGammaRange;
//对比度的设定范围
typedef struct
{
INT iMin; //最小值
INT iMax; //最大值
} tContrastRange;
//RGB三通道数字增益的设定范围
typedef struct
{
INT iRGainMin; //红色增益的最小值
INT iRGainMax; //红色增益的最大值
INT iGGainMin; //绿色增益的最小值
INT iGGainMax; //绿色增益的最大值
INT iBGainMin; //蓝色增益的最小值
INT iBGainMax; //蓝色增益的最大值
} tRgbGainRange;
//饱和度设定的范围
typedef struct
{
INT iMin; //最小值
INT iMax; //最大值
} tSaturationRange;
//锐化的设定范围
typedef struct
{
INT iMin; //最小值
INT iMax; //最大值
} tSharpnessRange;
//ISP模块的使能信息
typedef struct
{
BOOL bMonoSensor; //表示该型号相机是否为黑白相机,如果是黑白相机,则颜色相关的功能都无法调节
BOOL bWbOnce; //表示该型号相机是否支持手动白平衡功能
BOOL bAutoWb; //表示该型号相机是否支持自动白平衡功能
BOOL bAutoExposure; //表示该型号相机是否支持自动曝光功能
BOOL bManualExposure; //表示该型号相机是否支持手动曝光功能
BOOL bAntiFlick; //表示该型号相机是否支持抗频闪功能
BOOL bDeviceIsp; //表示该型号相机是否支持硬件ISP功能
BOOL bForceUseDeviceIsp;//bDeviceIsp和bForceUseDeviceIsp同时为TRUE时表示强制只用硬件ISP不可取消。
BOOL bZoomHD; //相机硬件是否支持图像缩放输出(只能是缩小)。
} tSdkIspCapacity;
/* 定义整合的设备描述信息这些信息可以用于动态构建UI */
typedef struct
{
tSdkTrigger *pTriggerDesc; // 触发模式
INT iTriggerDesc; // 触发模式的个数即pTriggerDesc数组的大小
tSdkImageResolution *pImageSizeDesc;// 预设分辨率选择
INT iImageSizeDesc; // 预设分辨率的个数即pImageSizeDesc数组的大小
tSdkColorTemperatureDes *pClrTempDesc;// 预设色温模式,用于白平衡
INT iClrTempDesc;
tSdkMediaType *pMediaTypeDesc; // 相机输出图像格式
INT iMediaTypdeDesc; // 相机输出图像格式的种类个数即pMediaTypeDesc数组的大小。
tSdkFrameSpeed *pFrameSpeedDesc; // 可调节帧速类型,对应界面上普通 高速 和超级三种速度设置
INT iFrameSpeedDesc; // 可调节帧速类型的个数即pFrameSpeedDesc数组的大小。
tSdkPackLength *pPackLenDesc; // 传输包长度,一般用于网络设备
INT iPackLenDesc; // 可供选择的传输分包长度的个数即pPackLenDesc数组的大小。
INT iOutputIoCounts; // 可编程输出IO的个数
INT iInputIoCounts; // 可编程输入IO的个数
tSdkPresetLut *pPresetLutDesc; // 相机预设的LUT表
INT iPresetLut; // 相机预设的LUT表的个数即pPresetLutDesc数组的大小
INT iUserDataMaxLen; // 指示该相机中用于保存用户数据区的最大长度。为0表示无。
BOOL bParamInDevice; // 指示该设备是否支持从设备中读写参数组。1为支持0不支持。
tSdkAeAlgorithm *pAeAlmSwDesc; // 软件自动曝光算法描述
int iAeAlmSwDesc; // 软件自动曝光算法个数
tSdkAeAlgorithm *pAeAlmHdDesc; // 硬件自动曝光算法描述为NULL表示不支持硬件自动曝光
int iAeAlmHdDesc; // 硬件自动曝光算法个数为0表示不支持硬件自动曝光
tSdkBayerDecodeAlgorithm *pBayerDecAlmSwDesc; // 软件Bayer转换为RGB数据的算法描述
int iBayerDecAlmSwDesc; // 软件Bayer转换为RGB数据的算法个数
tSdkBayerDecodeAlgorithm *pBayerDecAlmHdDesc; // 硬件Bayer转换为RGB数据的算法描述为NULL表示不支持
int iBayerDecAlmHdDesc; // 硬件Bayer转换为RGB数据的算法个数为0表示不支持
/* 图像参数的调节范围定义,用于动态构建UI*/
tSdkExpose sExposeDesc; // 曝光的范围值
tSdkResolutionRange sResolutionRange; // 分辨率范围描述
tRgbGainRange sRgbGainRange; // 图像数字增益范围描述
tSaturationRange sSaturationRange; // 饱和度范围描述
tGammaRange sGammaRange; // 伽马范围描述
tContrastRange sContrastRange; // 对比度范围描述
tSharpnessRange sSharpnessRange; // 锐化范围描述
tSdkIspCapacity sIspCapacity; // ISP能力描述
} tSdkCameraCapbility;
//图像帧头信息
typedef struct
{
UINT uiMediaType; // 图像格式,Image Format
UINT uBytes; // 图像数据字节数,Total bytes
INT iWidth; // 图像的宽度,调用图像处理函数后,该变量可能被动态修改,来指示处理后的图像尺寸
INT iHeight; // 图像的高度,调用图像处理函数后,该变量可能被动态修改,来指示处理后的图像尺寸
INT iWidthZoomSw; // 软件缩放的宽度,不需要进行软件裁剪的图像此变量设置为0.
INT iHeightZoomSw; // 软件缩放的高度,不需要进行软件裁剪的图像此变量设置为0.
BOOL bIsTrigger; // 指示是否为触发帧 is trigger
UINT uiTimeStamp; // 该帧的采集时间单位0.1毫秒
UINT uiExpTime; // 当前图像的曝光值单位为微秒us
float fAnalogGain; // 当前图像的模拟增益倍数
INT iGamma; // 该帧图像的伽马设定值仅当LUT模式为动态参数生成时有效其余模式下为-1
INT iContrast; // 该帧图像的对比度设定值仅当LUT模式为动态参数生成时有效其余模式下为-1
INT iSaturation; // 该帧图像的饱和度设定值对于黑白相机无意义为0
float fRgain; // 该帧图像处理的红色数字增益倍数对于黑白相机无意义为1
float fGgain; // 该帧图像处理的绿色数字增益倍数对于黑白相机无意义为1
float fBgain; // 该帧图像处理的蓝色数字增益倍数对于黑白相机无意义为1
}tSdkFrameHead;
//图像帧描述
typedef struct sCameraFrame
{
tSdkFrameHead head; //帧头
BYTE * pBuffer; //数据区
}tSdkFrame;
/// \~chinese 帧事件
/// \~english Frame Event
typedef struct tSdkFrameEvent_
{
UINT uType; ///< \~chinese 事件类型(1:帧开始 2:帧结束) \~english Event type (1:frame start 2:frame end)
UINT uStatus; ///< \~chinese 状态(0:成功 非0:错误) \~english Status (0:success, non-zero:error)
UINT uFrameID; ///< \~chinese 帧ID \~english Frame ID
UINT uWidth; ///< \~chinese 宽度 \~english Width
UINT uHeight; ///< \~chinese 高度 \~english Height
UINT uPixelFormat; ///< \~chinese 图像格式 \~english Image Format
UINT TimeStampL; ///< \~chinese 时间戳低32位 \~english Lower 32 bits of timestamp
UINT TimeStampH; ///< \~chinese 时间戳高32位 \~english High 32 bits of timestamp
}tSdkFrameEvent;
//图像捕获的回调函数定义
typedef void (*CAMERA_SNAP_PROC)(CameraHandle hCamera, BYTE *pFrameBuffer, tSdkFrameHead* pFrameHead,PVOID pContext);
//SDK生成的相机配置页面的消息回调函数定义
typedef void (*CAMERA_PAGE_MSG_PROC)(CameraHandle hCamera,UINT MSG,UINT uParam,PVOID pContext);
/// @ingroup API_RECONNECT
/// \~chinese 相机连接状态回调
/// \param [in] hCamera 相机句柄
/// \param [in] MSG 消息0: 相机连接断开 1: 相机连接恢复
/// \param [in] uParam 附加信息
/// \param [in] pContext 用户数据
/// \return 无
/// \note USB相机uParam取值
/// \note 未定义
/// \note 网口相机uParam取值
/// \note 当MSG=0时未定义
/// \note 当MSG=1时
/// \note 0上次掉线原因网络通讯失败
/// \note 1上次掉线原因相机掉电
/// \~english Camera connection status callback
/// \param [in] hCamera Camera handle
/// \param [in] MSG message, 0: Camera disconnected 1: Camera connection restored
/// \param [in] uParam Additional Information
/// \param [in] pContext user data
/// \return None
/// \note USB camera uParam value:
/// \note Undefined
/// \note network camera uParam value:
/// \note When MSG=0: Undefined
/// \note When MSG=1:
/// \note 0: The last dropped reason, network communication failed
/// \note 1: The last dropped reason, the camera lost power
typedef void (*CAMERA_CONNECTION_STATUS_CALLBACK)(CameraHandle hCamera,UINT MSG,UINT uParam,PVOID pContext);
/// @ingroup API_ADVANCE
/// \~chinese 帧事件回调函数定义
/// \~english Callback function definition for frame event
typedef void (*CAMERA_FRAME_EVENT_CALLBACK)(CameraHandle hCamera, tSdkFrameEvent* pEvent, PVOID pContext);
//----------------------------IMAGE FORMAT DEFINE------------------------------------
//----------------------------图像格式定义-------------------------------------------
#define CAMERA_MEDIA_TYPE_MONO 0x01000000
#define CAMERA_MEDIA_TYPE_RGB 0x02000000
#define CAMERA_MEDIA_TYPE_COLOR 0x02000000
#define CAMERA_MEDIA_TYPE_CUSTOM 0x80000000
#define CAMERA_MEDIA_TYPE_COLOR_MASK 0xFF000000
#define CAMERA_MEDIA_TYPE_OCCUPY1BIT 0x00010000
#define CAMERA_MEDIA_TYPE_OCCUPY2BIT 0x00020000
#define CAMERA_MEDIA_TYPE_OCCUPY4BIT 0x00040000
#define CAMERA_MEDIA_TYPE_OCCUPY8BIT 0x00080000
#define CAMERA_MEDIA_TYPE_OCCUPY10BIT 0x000A0000
#define CAMERA_MEDIA_TYPE_OCCUPY12BIT 0x000C0000
#define CAMERA_MEDIA_TYPE_OCCUPY16BIT 0x00100000
#define CAMERA_MEDIA_TYPE_OCCUPY24BIT 0x00180000
#define CAMERA_MEDIA_TYPE_OCCUPY32BIT 0x00200000
#define CAMERA_MEDIA_TYPE_OCCUPY36BIT 0x00240000
#define CAMERA_MEDIA_TYPE_OCCUPY48BIT 0x00300000
#define CAMERA_MEDIA_TYPE_OCCUPY64BIT 0x00400000
#define CAMERA_MEDIA_TYPE_EFFECTIVE_PIXEL_SIZE_MASK 0x00FF0000
#define CAMERA_MEDIA_TYPE_EFFECTIVE_PIXEL_SIZE_SHIFT 16
#define CAMERA_MEDIA_TYPE_PIXEL_SIZE(type) (((type) & CAMERA_MEDIA_TYPE_EFFECTIVE_PIXEL_SIZE_MASK)>>CAMERA_MEDIA_TYPE_EFFECTIVE_PIXEL_SIZE_SHIFT)
#define CAMERA_MEDIA_TYPE_ID_MASK 0x0000FFFF
#define CAMERA_MEDIA_TYPE_COUNT 0x46
/*mono*/
#define CAMERA_MEDIA_TYPE_MONO1P (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY1BIT | 0x0037)
#define CAMERA_MEDIA_TYPE_MONO2P (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY2BIT | 0x0038)
#define CAMERA_MEDIA_TYPE_MONO4P (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY4BIT | 0x0039)
#define CAMERA_MEDIA_TYPE_MONO8 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY8BIT | 0x0001)
#define CAMERA_MEDIA_TYPE_MONO8S (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY8BIT | 0x0002)
#define CAMERA_MEDIA_TYPE_MONO10 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0003)
#define CAMERA_MEDIA_TYPE_MONO10_PACKED (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0004)
#define CAMERA_MEDIA_TYPE_MONO12 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0005)
#define CAMERA_MEDIA_TYPE_MONO12_PACKED (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0006)
#define CAMERA_MEDIA_TYPE_MONO14 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0025)
#define CAMERA_MEDIA_TYPE_MONO16 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0007)
/*Bayer */
#define CAMERA_MEDIA_TYPE_BAYGR8 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY8BIT | 0x0008)
#define CAMERA_MEDIA_TYPE_BAYRG8 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY8BIT | 0x0009)
#define CAMERA_MEDIA_TYPE_BAYGB8 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY8BIT | 0x000A)
#define CAMERA_MEDIA_TYPE_BAYBG8 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY8BIT | 0x000B)
#define CAMERA_MEDIA_TYPE_BAYGR10_MIPI (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY10BIT | 0x0026)
#define CAMERA_MEDIA_TYPE_BAYRG10_MIPI (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY10BIT | 0x0027)
#define CAMERA_MEDIA_TYPE_BAYGB10_MIPI (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY10BIT | 0x0028)
#define CAMERA_MEDIA_TYPE_BAYBG10_MIPI (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY10BIT | 0x0029)
#define CAMERA_MEDIA_TYPE_BAYGR10 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x000C)
#define CAMERA_MEDIA_TYPE_BAYRG10 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x000D)
#define CAMERA_MEDIA_TYPE_BAYGB10 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x000E)
#define CAMERA_MEDIA_TYPE_BAYBG10 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x000F)
#define CAMERA_MEDIA_TYPE_BAYGR12 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0010)
#define CAMERA_MEDIA_TYPE_BAYRG12 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0011)
#define CAMERA_MEDIA_TYPE_BAYGB12 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0012)
#define CAMERA_MEDIA_TYPE_BAYBG12 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0013)
#define CAMERA_MEDIA_TYPE_BAYGR10_PACKED (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0026)
#define CAMERA_MEDIA_TYPE_BAYRG10_PACKED (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0027)
#define CAMERA_MEDIA_TYPE_BAYGB10_PACKED (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0028)
#define CAMERA_MEDIA_TYPE_BAYBG10_PACKED (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0029)
#define CAMERA_MEDIA_TYPE_BAYGR12_PACKED (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x002A)
#define CAMERA_MEDIA_TYPE_BAYRG12_PACKED (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x002B)
#define CAMERA_MEDIA_TYPE_BAYGB12_PACKED (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x002C)
#define CAMERA_MEDIA_TYPE_BAYBG12_PACKED (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x002D)
#define CAMERA_MEDIA_TYPE_BAYGR16 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x002E)
#define CAMERA_MEDIA_TYPE_BAYRG16 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x002F)
#define CAMERA_MEDIA_TYPE_BAYGB16 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0030)
#define CAMERA_MEDIA_TYPE_BAYBG16 (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0031)
/*RGB */
#define CAMERA_MEDIA_TYPE_RGB8 (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY24BIT | 0x0014)
#define CAMERA_MEDIA_TYPE_BGR8 (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY24BIT | 0x0015)
#define CAMERA_MEDIA_TYPE_RGBA8 (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY32BIT | 0x0016)
#define CAMERA_MEDIA_TYPE_BGRA8 (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY32BIT | 0x0017)
#define CAMERA_MEDIA_TYPE_RGB10 (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY48BIT | 0x0018)
#define CAMERA_MEDIA_TYPE_BGR10 (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY48BIT | 0x0019)
#define CAMERA_MEDIA_TYPE_RGB12 (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY48BIT | 0x001A)
#define CAMERA_MEDIA_TYPE_BGR12 (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY48BIT | 0x001B)
#define CAMERA_MEDIA_TYPE_RGB16 (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY48BIT | 0x0033)
#define CAMERA_MEDIA_TYPE_BGR16 (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY48BIT | 0x004B)
#define CAMERA_MEDIA_TYPE_RGBA16 (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY64BIT | 0x0064)
#define CAMERA_MEDIA_TYPE_BGRA16 (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY64BIT | 0x0051)
#define CAMERA_MEDIA_TYPE_RGB10V1_PACKED (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY32BIT | 0x001C)
#define CAMERA_MEDIA_TYPE_RGB10P32 (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY32BIT | 0x001D)
#define CAMERA_MEDIA_TYPE_RGB12V1_PACKED (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY36BIT | 0X0034)
#define CAMERA_MEDIA_TYPE_RGB565P (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0035)
#define CAMERA_MEDIA_TYPE_BGR565P (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0X0036)
/*YUV and YCbCr*/
#define CAMERA_MEDIA_TYPE_YUV411_8_UYYVYY (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x001E)
#define CAMERA_MEDIA_TYPE_YUV422_8_UYVY (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x001F)
#define CAMERA_MEDIA_TYPE_YUV422_8 (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0032)
#define CAMERA_MEDIA_TYPE_YUV8_UYV (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY24BIT | 0x0020)
#define CAMERA_MEDIA_TYPE_YCBCR8_CBYCR (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY24BIT | 0x003A)
//CAMERA_MEDIA_TYPE_YCBCR422_8 : YYYYCbCrCbCr
#define CAMERA_MEDIA_TYPE_YCBCR422_8 (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x003B)
#define CAMERA_MEDIA_TYPE_YCBCR422_8_CBYCRY (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0043)
#define CAMERA_MEDIA_TYPE_YCBCR411_8_CBYYCRYY (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x003C)
#define CAMERA_MEDIA_TYPE_YCBCR601_8_CBYCR (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY24BIT | 0x003D)
#define CAMERA_MEDIA_TYPE_YCBCR601_422_8 (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x003E)
#define CAMERA_MEDIA_TYPE_YCBCR601_422_8_CBYCRY (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0044)
#define CAMERA_MEDIA_TYPE_YCBCR601_411_8_CBYYCRYY (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x003F)
#define CAMERA_MEDIA_TYPE_YCBCR709_8_CBYCR (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY24BIT | 0x0040)
#define CAMERA_MEDIA_TYPE_YCBCR709_422_8 (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0041)
#define CAMERA_MEDIA_TYPE_YCBCR709_422_8_CBYCRY (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY16BIT | 0x0045)
#define CAMERA_MEDIA_TYPE_YCBCR709_411_8_CBYYCRYY (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0042)
/*RGB Planar */
#define CAMERA_MEDIA_TYPE_RGB8_PLANAR (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY24BIT | 0x0021)
#define CAMERA_MEDIA_TYPE_RGB10_PLANAR (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY48BIT | 0x0022)
#define CAMERA_MEDIA_TYPE_RGB12_PLANAR (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY48BIT | 0x0023)
#define CAMERA_MEDIA_TYPE_RGB16_PLANAR (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY48BIT | 0x0024)
/*MindVision 12bit packed bayer*/
#define CAMERA_MEDIA_TYPE_BAYGR12_PACKED_MV (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0060)
#define CAMERA_MEDIA_TYPE_BAYRG12_PACKED_MV (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0061)
#define CAMERA_MEDIA_TYPE_BAYGB12_PACKED_MV (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0062)
#define CAMERA_MEDIA_TYPE_BAYBG12_PACKED_MV (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0063)
/*MindVision 12bit packed monochome*/
#define CAMERA_MEDIA_TYPE_MONO12_PACKED_MV (CAMERA_MEDIA_TYPE_MONO | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0064)
#define CAMERA_MEDIA_TYPE_YUV420P_MV (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0065)
/*planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte V and the following byte U)*/
#define CAMERA_MEDIA_TYPE_YUV_NV21_MV (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY12BIT | 0x0066)
/* H264 H265 */
#define CAMERA_MEDIA_TYPE_H264_MV (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY8BIT | 0x0067)
#define CAMERA_MEDIA_TYPE_H265_MV (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY8BIT | 0x0068)
/* JPEG */
#define CAMERA_MEDIA_TYPE_JPEG_MV (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY8BIT | 0x0069)
#endif

View File

@ -0,0 +1,118 @@
#ifndef __CAMERA_STATUS_DEF__
#define __CAMERA_STATUS_DEF__
typedef int CameraSdkStatus;
/*常用的宏*/
#define SDK_SUCCESS(_FUC_) ((_FUC_) == CAMERA_STATUS_SUCCESS)
#define SDK_UNSUCCESS(_FUC_) ((_FUC_) != CAMERA_STATUS_SUCCESS)
#define SDK_UNSUCCESS_RETURN(_FUC_, RET) \
if ((RET = (_FUC_)) != CAMERA_STATUS_SUCCESS) { \
return RET; \
}
#define SDK_UNSUCCESS_BREAK(_FUC_) \
if ((_FUC_) != CAMERA_STATUS_SUCCESS) { \
break; \
}
/* 常用错误 */
#define CAMERA_STATUS_SUCCESS 0 // 操作成功
#define CAMERA_STATUS_FAILED -1 // 操作失败
#define CAMERA_STATUS_INTERNAL_ERROR -2 // 内部错误
#define CAMERA_STATUS_UNKNOW -3 // 未知错误
#define CAMERA_STATUS_NOT_SUPPORTED -4 // 不支持该功能
#define CAMERA_STATUS_NOT_INITIALIZED -5 // 初始化未完成
#define CAMERA_STATUS_PARAMETER_INVALID -6 // 参数无效
#define CAMERA_STATUS_PARAMETER_OUT_OF_BOUND -7 // 参数越界
#define CAMERA_STATUS_UNENABLED -8 // 未使能
#define CAMERA_STATUS_USER_CANCEL -9 // 用户手动取消了比如roi面板点击取消返回
#define CAMERA_STATUS_PATH_NOT_FOUND -10 // 注册表中没有找到对应的路径
#define CAMERA_STATUS_SIZE_DISMATCH -11 // 获得图像数据长度和定义的尺寸不匹配
#define CAMERA_STATUS_TIME_OUT -12 // 超时错误
#define CAMERA_STATUS_IO_ERROR -13 // 硬件IO错误
#define CAMERA_STATUS_COMM_ERROR -14 // 通讯错误
#define CAMERA_STATUS_BUS_ERROR -15 // 总线错误
#define CAMERA_STATUS_NO_DEVICE_FOUND -16 // 没有发现设备
#define CAMERA_STATUS_NO_LOGIC_DEVICE_FOUND -17 // 未找到逻辑设备
#define CAMERA_STATUS_DEVICE_IS_OPENED -18 // 设备已经打开
#define CAMERA_STATUS_DEVICE_IS_CLOSED -19 // 设备已经关闭
#define CAMERA_STATUS_DEVICE_VEDIO_CLOSED \
-20 // 没有打开设备视频,调用录像相关的函数时,如果相机视频没有打开,则回返回该错误。
#define CAMERA_STATUS_NO_MEMORY -21 // 没有足够系统内存
#define CAMERA_STATUS_FILE_CREATE_FAILED -22 // 创建文件失败
#define CAMERA_STATUS_FILE_INVALID -23 // 文件格式无效
#define CAMERA_STATUS_WRITE_PROTECTED -24 // 写保护,不可写
#define CAMERA_STATUS_GRAB_FAILED -25 // 数据采集失败
#define CAMERA_STATUS_LOST_DATA -26 // 数据丢失,不完整
#define CAMERA_STATUS_EOF_ERROR -27 // 未接收到帧结束符
#define CAMERA_STATUS_BUSY -28 // 正忙(上一次操作还在进行中),此次操作不能进行
#define CAMERA_STATUS_WAIT -29 // 需要等待(进行操作的条件不成立)可以再次尝试trf
#define CAMERA_STATUS_IN_PROCESS -30 // 正在进行,已经被操作过
#define CAMERA_STATUS_IIC_ERROR -31 // IIC传输错误
#define CAMERA_STATUS_SPI_ERROR -32 // SPI传输错误
#define CAMERA_STATUS_USB_CONTROL_ERROR -33 // USB控制传输错误
#define CAMERA_STATUS_USB_BULK_ERROR -34 // USB BULK传输错误
#define CAMERA_STATUS_SOCKET_INIT_ERROR -35 // 网络传输套件初始化失败
#define CAMERA_STATUS_GIGE_FILTER_INIT_ERROR \
-36 // 网络相机内核过滤驱动初始化失败,请检查是否正确安装了驱动,或者重新安装。
#define CAMERA_STATUS_NET_SEND_ERROR -37 // 网络数据发送错误
#define CAMERA_STATUS_DEVICE_LOST -38 // 与网络相机失去连接,心跳检测超时
#define CAMERA_STATUS_DATA_RECV_LESS -39 // 接收到的字节数比请求的少
#define CAMERA_STATUS_FUNCTION_LOAD_FAILED -40 // 从文件中加载程序失败
#define CAMERA_STATUS_CRITICAL_FILE_LOST -41 // 程序运行所必须的文件丢失。
#define CAMERA_STATUS_SENSOR_ID_DISMATCH -42 // 固件和程序不匹配,原因是下载了错误的固件。
#define CAMERA_STATUS_OUT_OF_RANGE -43 // 参数超出有效范围。
#define CAMERA_STATUS_REGISTRY_ERROR \
-44 // 安装程序注册错误。请重新安装程序或者运行安装目录Setup/Installer.exe
#define CAMERA_STATUS_ACCESS_DENY \
-45 // 禁止访问。指定相机已经被其他程序占用时,再申请访问该相机,会返回该状态。(一个相机不能被多个程序同时访问)
#define CAMERA_STATUS_CAMERA_NEED_RESET \
-46 // 表示相机需要复位后才能正常使用,此时请让相机断电重启,或者重启操作系统后,便可正常使用。
#define CAMERA_STATUS_ISP_MOUDLE_NOT_INITIALIZED -47 // ISP模块未初始化
#define CAMERA_STATUS_ISP_DATA_CRC_ERROR -48 // 数据校验错误
#define CAMERA_STATUS_MV_TEST_FAILED -49 // 数据测试失败
#define CAMERA_STATUS_INTERNAL_ERR1 -50 // 内部错误1
#define CAMERA_STATUS_U3V_NO_CONTROL_EP -51 // U3V控制端点未找到
#define CAMERA_STATUS_U3V_CONTROL_ERROR -52 // U3V控制通讯错误
#define CAMERA_STATUS_INVALID_FRIENDLY_NAME \
-53 ///< \~chinese 无效的设备名,名字里不能包含以下字符(\/:*?"<>|") \~english Invalid device name, the name cannot contain the following characters (\/:*?"<>|")
#define CAMERA_STATUS_FORMAT_ERROR -54 ///< \~chinese 格式错误 \~english Format error
#define CAMERA_STATUS_PCIE_OPEN_ERROR \
-55 ///< \~chinese PCIE设备打开失败 \~english PCIE device open failed
#define CAMERA_STATUS_PCIE_COMM_ERROR \
-56 ///< \~chinese PCIE设备通讯失败 \~english PCIE device communication failed
#define CAMERA_STATUS_PCIE_DDR_ERROR -57 ///< \~chinese PCIE DDR错误 \~english PCIE DDR error
//和AIA制定的标准相同
/*#define CAMERA_AIA_SUCCESS 0x0000 */
#define CAMERA_AIA_PACKET_RESEND 0x0100 //该帧需要重传
#define CAMERA_AIA_NOT_IMPLEMENTED 0x8001 //设备不支持的命令
#define CAMERA_AIA_INVALID_PARAMETER 0x8002 //命令参数非法
#define CAMERA_AIA_INVALID_ADDRESS 0x8003 //不可访问的地址
#define CAMERA_AIA_WRITE_PROTECT 0x8004 //访问的对象不可写
#define CAMERA_AIA_BAD_ALIGNMENT 0x8005 //访问的地址没有按照要求对齐
#define CAMERA_AIA_ACCESS_DENIED 0x8006 //没有访问权限
#define CAMERA_AIA_BUSY 0x8007 //命令正在处理中
#define CAMERA_AIA_DEPRECATED 0x8008 //0x8008-0x0800B 0x800F 该指令已经废弃
#define CAMERA_AIA_PACKET_UNAVAILABLE 0x800C //包无效
#define CAMERA_AIA_DATA_OVERRUN 0x800D //数据溢出,通常是收到的数据比需要的多
#define CAMERA_AIA_INVALID_HEADER 0x800E //数据包头部中某些区域与协议不匹配
#define CAMERA_AIA_PACKET_NOT_YET_AVAILABLE \
0x8010 //图像分包数据还未准备好,多用于触发模式,应用程序访问超时
#define CAMERA_AIA_PACKET_AND_PREV_REMOVED_FROM_MEMORY \
0x8011 //需要访问的分包已经不存在。多用于重传时数据已经不在缓冲区中
#define CAMERA_AIA_PACKET_REMOVED_FROM_MEMORY \
0x8012 //CAMERA_AIA_PACKET_AND_PREV_REMOVED_FROM_MEMORY
#define CAMERA_AIA_NO_REF_TIME 0x0813 //没有参考时钟源。多用于时间同步的命令执行时
#define CAMERA_AIA_PACKET_TEMPORARILY_UNAVAILABLE \
0x0814 //由于信道带宽问题,当前分包暂时不可用,需稍后进行访问
#define CAMERA_AIA_OVERFLOW 0x0815 //设备端数据溢出,通常是队列已满
#define CAMERA_AIA_ACTION_LATE 0x0816 //命令执行已经超过有效的指定时间
#define CAMERA_AIA_ERROR 0x8FFF //错误
#endif

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,171 @@
#include "mindvision.hpp"
#include <libusb-1.0/libusb.h>
#include <stdexcept>
#include "tools/logger.hpp"
using namespace std::chrono_literals;
namespace io
{
MindVision::MindVision(double exposure_ms, double gamma, const std::string & vid_pid)
: exposure_ms_(exposure_ms),
gamma_(gamma),
handle_(-1),
quit_(false),
ok_(false),
queue_(1),
vid_(-1),
pid_(-1)
{
set_vid_pid(vid_pid);
if (libusb_init(NULL)) tools::logger()->warn("Unable to init libusb!");
try_open();
// 守护线程
daemon_thread_ = std::thread{[this] {
while (!quit_) {
std::this_thread::sleep_for(100ms);
if (ok_) continue;
if (capture_thread_.joinable()) capture_thread_.join();
close();
reset_usb();
try_open();
}
}};
}
MindVision::~MindVision()
{
quit_ = true;
if (daemon_thread_.joinable()) daemon_thread_.join();
if (capture_thread_.joinable()) capture_thread_.join();
close();
tools::logger()->info("Mindvision destructed.");
}
void MindVision::read(cv::Mat & img, std::chrono::steady_clock::time_point & timestamp)
{
CameraData data;
queue_.pop(data);
img = data.img;
timestamp = data.timestamp;
}
void MindVision::open()
{
int camera_num = 1;
tSdkCameraDevInfo camera_info_list;
tSdkCameraCapbility camera_capbility;
CameraSdkInit(1);
CameraEnumerateDevice(&camera_info_list, &camera_num);
if (camera_num == 0) throw std::runtime_error("Not found camera!");
if (CameraInit(&camera_info_list, -1, -1, &handle_) != CAMERA_STATUS_SUCCESS)
throw std::runtime_error("Failed to init camera!");
CameraGetCapability(handle_, &camera_capbility);
width_ = camera_capbility.sResolutionRange.iWidthMax;
height_ = camera_capbility.sResolutionRange.iHeightMax;
CameraSetAeState(handle_, FALSE); // 关闭自动曝光
CameraSetExposureTime(handle_, exposure_ms_ * 1e3); // 设置曝光
CameraSetGamma(handle_, gamma_ * 1e2); // 设置伽马
CameraSetIspOutFormat(handle_, CAMERA_MEDIA_TYPE_BGR8); // 设置输出格式为BGR
CameraSetTriggerMode(handle_, 0); // 设置为连续采集模式
CameraSetFrameSpeed(handle_, 1); // 设置为低帧率模式
CameraPlay(handle_);
// 取图线程
capture_thread_ = std::thread{[this] {
tSdkFrameHead head;
BYTE * raw;
ok_ = true;
while (!quit_) {
std::this_thread::sleep_for(1ms);
auto img = cv::Mat(height_, width_, CV_8UC3);
auto status = CameraGetImageBuffer(handle_, &head, &raw, 100);
auto timestamp = std::chrono::steady_clock::now();
if (status != CAMERA_STATUS_SUCCESS) {
tools::logger()->warn("Camera dropped!");
ok_ = false;
break;
}
CameraImageProcess(handle_, raw, img.data, &head);
CameraReleaseImageBuffer(handle_, raw);
queue_.push({img, timestamp});
}
}};
tools::logger()->info("Mindvision opened.");
}
void MindVision::try_open()
{
try {
open();
} catch (const std::exception & e) {
tools::logger()->warn("{}", e.what());
}
}
void MindVision::close()
{
if (handle_ == -1) return;
CameraUnInit(handle_);
}
void MindVision::set_vid_pid(const std::string & vid_pid)
{
auto index = vid_pid.find(':');
if (index == std::string::npos) {
tools::logger()->warn("Invalid vid_pid: \"{}\"", vid_pid);
return;
}
auto vid_str = vid_pid.substr(0, index);
auto pid_str = vid_pid.substr(index + 1);
try {
vid_ = std::stoi(vid_str, 0, 16);
pid_ = std::stoi(pid_str, 0, 16);
} catch (const std::exception &) {
tools::logger()->warn("Invalid vid_pid: \"{}\"", vid_pid);
}
}
void MindVision::reset_usb() const
{
if (vid_ == -1 || pid_ == -1) return;
// https://github.com/ralight/usb-reset/blob/master/usb-reset.c
auto handle = libusb_open_device_with_vid_pid(NULL, vid_, pid_);
if (!handle) {
tools::logger()->warn("Unable to open usb!");
return;
}
if (libusb_reset_device(handle))
tools::logger()->warn("Unable to reset usb!");
else
tools::logger()->info("Reset usb successfully :)");
libusb_close(handle);
}
} // namespace io

View File

@ -0,0 +1,46 @@
#ifndef IO__MINDVISION_HPP
#define IO__MINDVISION_HPP
#include <chrono>
#include <opencv2/opencv.hpp>
#include <thread>
#include "CameraApi.h"
#include "io/camera.hpp"
#include "tools/thread_safe_queue.hpp"
namespace io
{
class MindVision : public CameraBase
{
public:
MindVision(double exposure_ms, double gamma, const std::string & vid_pid);
~MindVision() override;
void read(cv::Mat & img, std::chrono::steady_clock::time_point & timestamp) override;
private:
struct CameraData
{
cv::Mat img;
std::chrono::steady_clock::time_point timestamp;
};
double exposure_ms_, gamma_;
CameraHandle handle_;
int height_, width_;
bool quit_, ok_;
std::thread capture_thread_;
std::thread daemon_thread_;
tools::ThreadSafeQueue<CameraData> queue_;
int vid_, pid_;
void open();
void try_open();
void close();
void set_vid_pid(const std::string & vid_pid);
void reset_usb() const;
};
} // namespace io
#endif // IO__MINDVISION_HPP

48
io/ros2/publish2nav.cpp Normal file
View File

@ -0,0 +1,48 @@
#include "publish2nav.hpp"
#include <Eigen/Dense>
#include <chrono>
#include <memory>
#include <thread>
#include "tools/logger.hpp"
namespace io
{
Publish2Nav::Publish2Nav() : Node("auto_aim_target_pos_publisher")
{
publisher_ = this->create_publisher<std_msgs::msg::String>("auto_aim_target_pos", 10);
RCLCPP_INFO(this->get_logger(), "auto_aim_target_pos_publisher node initialized.");
}
Publish2Nav::~Publish2Nav()
{
RCLCPP_INFO(this->get_logger(), "auto_aim_target_pos_publisher node shutting down.");
}
void Publish2Nav::send_data(const Eigen::Vector4d & target_pos)
{
// 创建消息
auto message = std::make_shared<std_msgs::msg::String>();
// 将 Eigen::Vector3d 数据转换为字符串并存储在消息中
message->data = std::to_string(target_pos[0]) + "," + std::to_string(target_pos[1]) + "," +
std::to_string(target_pos[2]) + "," + std::to_string(target_pos[3]);
// 发布消息
publisher_->publish(*message);
// RCLCPP_INFO(
// this->get_logger(), "auto_aim_target_pos_publisher node sent message: '%s'",
// message->data.c_str());
}
void Publish2Nav::start()
{
RCLCPP_INFO(this->get_logger(), "auto_aim_target_pos_publisher node starting to spin...");
rclcpp::spin(this->shared_from_this());
}
} // namespace io

35
io/ros2/publish2nav.hpp Normal file
View File

@ -0,0 +1,35 @@
#ifndef IO__PBLISH2NAV_HPP
#define IO__PBLISH2NAV_HPP
#include <Eigen/Dense> // For Eigen::Vector3d
#include <chrono>
#include <deque>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
namespace io
{
class Publish2Nav : public rclcpp::Node
{
public:
Publish2Nav();
~Publish2Nav();
void start();
void send_data(const Eigen::Vector4d & data);
private:
// ROS2 发布者
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
};
} // namespace io
#endif // Publish2Nav_HPP_

36
io/ros2/ros2.cpp Normal file
View File

@ -0,0 +1,36 @@
#include "ros2.hpp"
namespace io
{
ROS2::ROS2()
{
rclcpp::init(0, nullptr);
publish2nav_ = std::make_shared<Publish2Nav>();
subscribe2nav_ = std::make_shared<Subscribe2Nav>();
publish_spin_thread_ = std::make_unique<std::thread>([this]() { publish2nav_->start(); });
subscribe_spin_thread_ = std::make_unique<std::thread>([this]() { subscribe2nav_->start(); });
}
ROS2::~ROS2()
{
rclcpp::shutdown();
publish_spin_thread_->join();
subscribe_spin_thread_->join();
}
void ROS2::publish(const Eigen::Vector4d & target_pos) { publish2nav_->send_data(target_pos); }
std::vector<int8_t> ROS2::subscribe_enemy_status()
{
return subscribe2nav_->subscribe_enemy_status();
}
std::vector<int8_t> ROS2::subscribe_autoaim_target()
{
return subscribe2nav_->subscribe_autoaim_target();
}
} // namespace io

45
io/ros2/ros2.hpp Normal file
View File

@ -0,0 +1,45 @@
#ifndef IO__ROS2_HPP
#define IO__ROS2_HPP
#include "publish2nav.hpp"
#include "subscribe2nav.hpp"
namespace io
{
class ROS2
{
public:
ROS2();
~ROS2();
void publish(const Eigen::Vector4d & target_pos);
std::vector<int8_t> subscribe_enemy_status();
std::vector<int8_t> subscribe_autoaim_target();
template <typename T>
std::shared_ptr<rclcpp::Publisher<T>> create_publisher(
const std::string & node_name, const std::string & topic_name, size_t queue_size)
{
auto node = std::make_shared<rclcpp::Node>(node_name);
auto publisher = node->create_publisher<T>(topic_name, queue_size);
// 运行一个单独的线程来 spin 这个节点,确保消息可以被正确发布
std::thread([node]() { rclcpp::spin(node); }).detach();
return publisher;
}
private:
std::shared_ptr<Publish2Nav> publish2nav_;
std::shared_ptr<Subscribe2Nav> subscribe2nav_;
std::unique_ptr<std::thread> publish_spin_thread_;
std::unique_ptr<std::thread> subscribe_spin_thread_;
};
} // namespace io
#endif

108
io/ros2/subscribe2nav.cpp Normal file
View File

@ -0,0 +1,108 @@
#include "subscribe2nav.hpp"
#include <sstream>
#include <vector>
namespace io
{
Subscribe2Nav::Subscribe2Nav()
: Node("nav_subscriber"),
enemy_statue_queue_(1),
autoaim_target_queue_(1),
enemy_status_counter_(0),
autoaim_target_counter_(0)
{
enemy_status_subscription_ = this->create_subscription<sp_msgs::msg::EnemyStatusMsg>(
"enemy_status", 10,
std::bind(&Subscribe2Nav::enemy_status_callback, this, std::placeholders::_1));
autoaim_target_subscription_ = this->create_subscription<sp_msgs::msg::AutoaimTargetMsg>(
"autoaim_target", 10,
std::bind(&Subscribe2Nav::autoaim_target_callback, this, std::placeholders::_1));
RCLCPP_INFO(this->get_logger(), "nav_subscriber node initialized.");
}
Subscribe2Nav::~Subscribe2Nav()
{
RCLCPP_INFO(this->get_logger(), "nav_subscriber node shutting down.");
}
void Subscribe2Nav::enemy_status_callback(const sp_msgs::msg::EnemyStatusMsg::SharedPtr msg)
{
enemy_statue_queue_.clear();
enemy_statue_queue_.push(*msg);
enemy_status_counter_++;
if (enemy_status_counter_ >= 2) {
if (enemy_status_timer_) {
enemy_status_timer_->cancel();
}
enemy_status_timer_ = this->create_wall_timer(std::chrono::milliseconds(1500), [this]() {
enemy_statue_queue_.clear();
enemy_status_counter_ = 0;
RCLCPP_INFO(
this->get_logger(), "Enemy status queue cleared due to inactivity after two messages.");
});
}
}
void Subscribe2Nav::autoaim_target_callback(const sp_msgs::msg::AutoaimTargetMsg::SharedPtr msg)
{
autoaim_target_queue_.clear();
autoaim_target_queue_.push(*msg);
autoaim_target_counter_++;
if (autoaim_target_counter_ >= 2) {
if (autoaim_target_timer_) {
autoaim_target_timer_->cancel();
}
autoaim_target_timer_ = this->create_wall_timer(std::chrono::milliseconds(1500), [this]() {
autoaim_target_queue_.clear();
autoaim_target_counter_ = 0;
RCLCPP_INFO(
this->get_logger(), "Autoaim target queue cleared due to inactivity after two messages.");
});
}
}
void Subscribe2Nav::start()
{
RCLCPP_INFO(this->get_logger(), "nav_subscriber node Starting to spin...");
rclcpp::spin(this->shared_from_this());
}
std::vector<int8_t> Subscribe2Nav::subscribe_enemy_status()
{
if (enemy_statue_queue_.empty()) {
return std::vector<int8_t>();
}
sp_msgs::msg::EnemyStatusMsg msg;
enemy_statue_queue_.back(msg);
RCLCPP_INFO(
this->get_logger(), "Subscribe enemy_status at: %d.%09u", msg.timestamp.sec,
msg.timestamp.nanosec);
return msg.invincible_enemy_ids;
}
std::vector<int8_t> Subscribe2Nav::subscribe_autoaim_target()
{
if (autoaim_target_queue_.empty()) {
return std::vector<int8_t>();
}
sp_msgs::msg::AutoaimTargetMsg msg;
autoaim_target_queue_.back(msg);
RCLCPP_INFO(
this->get_logger(), "Subscribe autoaim_target at: %d.%09u", msg.timestamp.sec,
msg.timestamp.nanosec);
return msg.target_ids;
}
} // namespace io

45
io/ros2/subscribe2nav.hpp Normal file
View File

@ -0,0 +1,45 @@
#ifndef IO__SUBSCRIBE2NAV_HPP
#define IO__SUBSCRIBE2NAV_HPP
#include <rclcpp/rclcpp.hpp>
#include <rclcpp/timer.hpp>
#include <sp_msgs/msg/detail/autoaim_target_msg__struct.hpp>
#include <vector>
#include "sp_msgs/msg/autoaim_target_msg.hpp"
#include "sp_msgs/msg/enemy_status_msg.hpp"
#include "tools/thread_safe_queue.hpp"
namespace io
{
class Subscribe2Nav : public rclcpp::Node
{
public:
Subscribe2Nav();
~Subscribe2Nav();
void start();
std::vector<int8_t> subscribe_enemy_status();
std::vector<int8_t> subscribe_autoaim_target();
private:
void enemy_status_callback(const sp_msgs::msg::EnemyStatusMsg::SharedPtr msg);
void autoaim_target_callback(const sp_msgs::msg::AutoaimTargetMsg::SharedPtr msg);
int enemy_status_counter_;
int autoaim_target_counter_;
rclcpp::TimerBase::SharedPtr enemy_status_timer_;
rclcpp::TimerBase::SharedPtr autoaim_target_timer_;
rclcpp::Subscription<sp_msgs::msg::EnemyStatusMsg>::SharedPtr enemy_status_subscription_;
rclcpp::Subscription<sp_msgs::msg::AutoaimTargetMsg>::SharedPtr autoaim_target_subscription_;
tools::ThreadSafeQueue<sp_msgs::msg::EnemyStatusMsg> enemy_statue_queue_;
tools::ThreadSafeQueue<sp_msgs::msg::AutoaimTargetMsg> autoaim_target_queue_;
};
} // namespace io
#endif // IO__SUBSCRIBE2NAV_HPP

46
io/serial/CMakeLists.txt Normal file
View File

@ -0,0 +1,46 @@
cmake_minimum_required(VERSION 3.16)
project(serial)
if(APPLE)
find_library(IOKIT_LIBRARY IOKit)
find_library(FOUNDATION_LIBRARY Foundation)
endif()
if(UNIX AND NOT APPLE)
# If Linux, add rt and pthread
set(rt_LIBRARIES rt)
set(pthread_LIBRARIES pthread)
endif()
## Sources
set(serial_SRCS
src/serial.cc
include/serial/serial.h
include/serial/v8stdint.h
)
if(APPLE)
# If OSX
list(APPEND serial_SRCS src/impl/unix.cc)
list(APPEND serial_SRCS src/impl/list_ports/list_ports_osx.cc)
elseif(UNIX)
# If unix
list(APPEND serial_SRCS src/impl/unix.cc)
list(APPEND serial_SRCS src/impl/list_ports/list_ports_linux.cc)
else()
# If windows
list(APPEND serial_SRCS src/impl/win.cc)
list(APPEND serial_SRCS src/impl/list_ports/list_ports_win.cc)
endif()
## Add serial library
add_library(${PROJECT_NAME} ${serial_SRCS})
if(APPLE)
target_link_libraries(${PROJECT_NAME} ${FOUNDATION_LIBRARY} ${IOKIT_LIBRARY})
elseif(UNIX)
target_link_libraries(${PROJECT_NAME} rt pthread)
else()
target_link_libraries(${PROJECT_NAME} setupapi)
endif()
## Include headers
target_include_directories(${PROJECT_NAME} PUBLIC include)

View File

@ -0,0 +1,183 @@
/*!
* \file serial/impl/unix.h
* \author William Woodall <wjwwood@gmail.com>
* \author John Harrison <ash@greaterthaninfinity.com>
* \version 0.1
*
* \section LICENSE
*
* The MIT License
*
* Copyright (c) 2012 William Woodall, John Harrison
*
* 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.
*
* \section DESCRIPTION
*
* This provides a unix based pimpl for the Serial class. This implementation is
* based off termios.h and uses select for multiplexing the IO ports.
*
*/
#if !defined(_WIN32)
#ifndef SERIAL_IMPL_UNIX_H
#define SERIAL_IMPL_UNIX_H
#include <pthread.h>
#include "serial/serial.h"
namespace serial
{
using std::invalid_argument;
using std::size_t;
using std::string;
using serial::IOException;
using serial::SerialException;
class MillisecondTimer
{
public:
MillisecondTimer(const uint32_t millis);
int64_t remaining();
private:
static timespec timespec_now();
timespec expiry;
};
class serial::Serial::SerialImpl
{
public:
SerialImpl(
const string & port, unsigned long baudrate, bytesize_t bytesize, parity_t parity,
stopbits_t stopbits, flowcontrol_t flowcontrol);
virtual ~SerialImpl();
void open();
void close();
bool isOpen() const;
size_t available();
bool waitReadable(uint32_t timeout);
void waitByteTimes(size_t count);
size_t read(uint8_t * buf, size_t size = 1);
size_t write(const uint8_t * data, size_t length);
void flush();
void flushInput();
void flushOutput();
void sendBreak(int duration);
void setBreak(bool level);
void setRTS(bool level);
void setDTR(bool level);
bool waitForChange();
bool getCTS();
bool getDSR();
bool getRI();
bool getCD();
void setPort(const string & port);
string getPort() const;
void setTimeout(Timeout & timeout);
Timeout getTimeout() const;
void setBaudrate(unsigned long baudrate);
unsigned long getBaudrate() const;
void setBytesize(bytesize_t bytesize);
bytesize_t getBytesize() const;
void setParity(parity_t parity);
parity_t getParity() const;
void setStopbits(stopbits_t stopbits);
stopbits_t getStopbits() const;
void setFlowcontrol(flowcontrol_t flowcontrol);
flowcontrol_t getFlowcontrol() const;
void readLock();
void readUnlock();
void writeLock();
void writeUnlock();
protected:
void reconfigurePort();
private:
string port_; // Path to the file descriptor
int fd_; // The current file descriptor
bool is_open_;
bool xonxoff_;
bool rtscts_;
Timeout timeout_; // Timeout for read operations
unsigned long baudrate_; // Baudrate
uint32_t byte_time_ns_; // Nanoseconds to transmit/receive a single byte
parity_t parity_; // Parity
bytesize_t bytesize_; // Size of the bytes
stopbits_t stopbits_; // Stop Bits
flowcontrol_t flowcontrol_; // Flow Control
// Mutex used to lock the read functions
pthread_mutex_t read_mutex;
// Mutex used to lock the write functions
pthread_mutex_t write_mutex;
};
} // namespace serial
#endif // SERIAL_IMPL_UNIX_H
#endif // !defined(_WIN32)

View File

@ -0,0 +1,167 @@
/*!
* \file serial/impl/windows.h
* \author William Woodall <wjwwood@gmail.com>
* \author John Harrison <ash@greaterthaninfinity.com>
* \version 0.1
*
* \section LICENSE
*
* The MIT License
*
* Copyright (c) 2012 William Woodall, John Harrison
*
* 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.
*
* \section DESCRIPTION
*
* This provides a windows implementation of the Serial class interface.
*
*/
#if defined(_WIN32)
#ifndef SERIAL_IMPL_WINDOWS_H
#define SERIAL_IMPL_WINDOWS_H
#include "serial/serial.h"
#include "windows.h"
namespace serial
{
using std::invalid_argument;
using std::string;
using std::wstring;
using serial::IOException;
using serial::SerialException;
class serial::Serial::SerialImpl
{
public:
SerialImpl(
const string & port, unsigned long baudrate, bytesize_t bytesize, parity_t parity,
stopbits_t stopbits, flowcontrol_t flowcontrol);
virtual ~SerialImpl();
void open();
void close();
bool isOpen() const;
size_t available();
bool waitReadable(uint32_t timeout);
void waitByteTimes(size_t count);
size_t read(uint8_t * buf, size_t size = 1);
size_t write(const uint8_t * data, size_t length);
void flush();
void flushInput();
void flushOutput();
void sendBreak(int duration);
void setBreak(bool level);
void setRTS(bool level);
void setDTR(bool level);
bool waitForChange();
bool getCTS();
bool getDSR();
bool getRI();
bool getCD();
void setPort(const string & port);
string getPort() const;
void setTimeout(Timeout & timeout);
Timeout getTimeout() const;
void setBaudrate(unsigned long baudrate);
unsigned long getBaudrate() const;
void setBytesize(bytesize_t bytesize);
bytesize_t getBytesize() const;
void setParity(parity_t parity);
parity_t getParity() const;
void setStopbits(stopbits_t stopbits);
stopbits_t getStopbits() const;
void setFlowcontrol(flowcontrol_t flowcontrol);
flowcontrol_t getFlowcontrol() const;
void readLock();
void readUnlock();
void writeLock();
void writeUnlock();
protected:
void reconfigurePort();
private:
wstring port_; // Path to the file descriptor
HANDLE fd_;
bool is_open_;
Timeout timeout_; // Timeout for read operations
unsigned long baudrate_; // Baudrate
parity_t parity_; // Parity
bytesize_t bytesize_; // Size of the bytes
stopbits_t stopbits_; // Stop Bits
flowcontrol_t flowcontrol_; // Flow Control
// Mutex used to lock the read functions
HANDLE read_mutex;
// Mutex used to lock the write functions
HANDLE write_mutex;
};
} // namespace serial
#endif // SERIAL_IMPL_WINDOWS_H
#endif // if defined(_WIN32)

View File

@ -0,0 +1,733 @@
/*!
* \file serial/serial.h
* \author William Woodall <wjwwood@gmail.com>
* \author John Harrison <ash.gti@gmail.com>
* \version 0.1
*
* \section LICENSE
*
* The MIT License
*
* Copyright (c) 2012 William Woodall
*
* 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.
*
* \section DESCRIPTION
*
* This provides a cross platform interface for interacting with Serial Ports.
*/
#ifndef SERIAL_H
#define SERIAL_H
#include <serial/v8stdint.h>
#include <cstring>
#include <exception>
#include <limits>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
#define THROW(exceptionClass, message) throw exceptionClass(__FILE__, __LINE__, (message))
namespace serial
{
/*!
* Enumeration defines the possible bytesizes for the serial port.
*/
typedef enum
{
fivebits = 5,
sixbits = 6,
sevenbits = 7,
eightbits = 8
} bytesize_t;
/*!
* Enumeration defines the possible parity types for the serial port.
*/
typedef enum
{
parity_none = 0,
parity_odd = 1,
parity_even = 2,
parity_mark = 3,
parity_space = 4
} parity_t;
/*!
* Enumeration defines the possible stopbit types for the serial port.
*/
typedef enum
{
stopbits_one = 1,
stopbits_two = 2,
stopbits_one_point_five
} stopbits_t;
/*!
* Enumeration defines the possible flowcontrol types for the serial port.
*/
typedef enum
{
flowcontrol_none = 0,
flowcontrol_software,
flowcontrol_hardware
} flowcontrol_t;
/*!
* Structure for setting the timeout of the serial port, times are
* in milliseconds.
*
* In order to disable the interbyte timeout, set it to Timeout::max().
*/
struct Timeout
{
#ifdef max
#undef max
#endif
static uint32_t max() { return std::numeric_limits<uint32_t>::max(); }
/*!
* Convenience function to generate Timeout structs using a
* single absolute timeout.
*
* \param timeout A long that defines the time in milliseconds until a
* timeout occurs after a call to read or write is made.
*
* \return Timeout struct that represents this simple timeout provided.
*/
static Timeout simpleTimeout(uint32_t timeout) { return Timeout(max(), timeout, 0, timeout, 0); }
/*! Number of milliseconds between bytes received to timeout on. */
uint32_t inter_byte_timeout;
/*! A constant number of milliseconds to wait after calling read. */
uint32_t read_timeout_constant;
/*! A multiplier against the number of requested bytes to wait after
* calling read.
*/
uint32_t read_timeout_multiplier;
/*! A constant number of milliseconds to wait after calling write. */
uint32_t write_timeout_constant;
/*! A multiplier against the number of requested bytes to wait after
* calling write.
*/
uint32_t write_timeout_multiplier;
explicit Timeout(
uint32_t inter_byte_timeout_ = 0, uint32_t read_timeout_constant_ = 0,
uint32_t read_timeout_multiplier_ = 0, uint32_t write_timeout_constant_ = 0,
uint32_t write_timeout_multiplier_ = 0)
: inter_byte_timeout(inter_byte_timeout_),
read_timeout_constant(read_timeout_constant_),
read_timeout_multiplier(read_timeout_multiplier_),
write_timeout_constant(write_timeout_constant_),
write_timeout_multiplier(write_timeout_multiplier_)
{
}
};
/*!
* Class that provides a portable serial port interface.
*/
class Serial
{
public:
/*!
* Creates a Serial object and opens the port if a port is specified,
* otherwise it remains closed until serial::Serial::open is called.
*
* \param port A std::string containing the address of the serial port,
* which would be something like 'COM1' on Windows and '/dev/ttyS0'
* on Linux.
*
* \param baudrate An unsigned 32-bit integer that represents the baudrate
*
* \param timeout A serial::Timeout struct that defines the timeout
* conditions for the serial port. \see serial::Timeout
*
* \param bytesize Size of each byte in the serial transmission of data,
* default is eightbits, possible values are: fivebits, sixbits, sevenbits,
* eightbits
*
* \param parity Method of parity, default is parity_none, possible values
* are: parity_none, parity_odd, parity_even
*
* \param stopbits Number of stop bits used, default is stopbits_one,
* possible values are: stopbits_one, stopbits_one_point_five, stopbits_two
*
* \param flowcontrol Type of flowcontrol used, default is
* flowcontrol_none, possible values are: flowcontrol_none,
* flowcontrol_software, flowcontrol_hardware
*
* \throw serial::PortNotOpenedException
* \throw serial::IOException
* \throw std::invalid_argument
*/
Serial(
const std::string & port = "", uint32_t baudrate = 9600, Timeout timeout = Timeout(),
bytesize_t bytesize = eightbits, parity_t parity = parity_none,
stopbits_t stopbits = stopbits_one, flowcontrol_t flowcontrol = flowcontrol_none);
/*! Destructor */
virtual ~Serial();
/*!
* Opens the serial port as long as the port is set and the port isn't
* already open.
*
* If the port is provided to the constructor then an explicit call to open
* is not needed.
*
* \see Serial::Serial
*
* \throw std::invalid_argument
* \throw serial::SerialException
* \throw serial::IOException
*/
void open();
/*! Gets the open status of the serial port.
*
* \return Returns true if the port is open, false otherwise.
*/
bool isOpen() const;
/*! Closes the serial port. */
void close();
/*! Return the number of characters in the buffer. */
size_t available();
/*! Block until there is serial data to read or read_timeout_constant
* number of milliseconds have elapsed. The return value is true when
* the function exits with the port in a readable state, false otherwise
* (due to timeout or select interruption). */
bool waitReadable();
/*! Block for a period of time corresponding to the transmission time of
* count characters at present serial settings. This may be used in con-
* junction with waitReadable to read larger blocks of data from the
* port. */
void waitByteTimes(size_t count);
/*! Read a given amount of bytes from the serial port into a given buffer.
*
* The read function will return in one of three cases:
* * The number of requested bytes was read.
* * In this case the number of bytes requested will match the size_t
* returned by read.
* * A timeout occurred, in this case the number of bytes read will not
* match the amount requested, but no exception will be thrown. One of
* two possible timeouts occurred:
* * The inter byte timeout expired, this means that number of
* milliseconds elapsed between receiving bytes from the serial port
* exceeded the inter byte timeout.
* * The total timeout expired, which is calculated by multiplying the
* read timeout multiplier by the number of requested bytes and then
* added to the read timeout constant. If that total number of
* milliseconds elapses after the initial call to read a timeout will
* occur.
* * An exception occurred, in this case an actual exception will be thrown.
*
* \param buffer An uint8_t array of at least the requested size.
* \param size A size_t defining how many bytes to be read.
*
* \return A size_t representing the number of bytes read as a result of the
* call to read.
*
* \throw serial::PortNotOpenedException
* \throw serial::SerialException
*/
size_t read(uint8_t * buffer, size_t size);
/*! Read a given amount of bytes from the serial port into a give buffer.
*
* \param buffer A reference to a std::vector of uint8_t.
* \param size A size_t defining how many bytes to be read.
*
* \return A size_t representing the number of bytes read as a result of the
* call to read.
*
* \throw serial::PortNotOpenedException
* \throw serial::SerialException
*/
size_t read(std::vector<uint8_t> & buffer, size_t size = 1);
/*! Read a given amount of bytes from the serial port into a give buffer.
*
* \param buffer A reference to a std::string.
* \param size A size_t defining how many bytes to be read.
*
* \return A size_t representing the number of bytes read as a result of the
* call to read.
*
* \throw serial::PortNotOpenedException
* \throw serial::SerialException
*/
size_t read(std::string & buffer, size_t size = 1);
/*! Read a given amount of bytes from the serial port and return a string
* containing the data.
*
* \param size A size_t defining how many bytes to be read.
*
* \return A std::string containing the data read from the port.
*
* \throw serial::PortNotOpenedException
* \throw serial::SerialException
*/
std::string read(size_t size = 1);
/*! Reads in a line or until a given delimiter has been processed.
*
* Reads from the serial port until a single line has been read.
*
* \param buffer A std::string reference used to store the data.
* \param size A maximum length of a line, defaults to 65536 (2^16)
* \param eol A string to match against for the EOL.
*
* \return A size_t representing the number of bytes read.
*
* \throw serial::PortNotOpenedException
* \throw serial::SerialException
*/
size_t readline(std::string & buffer, size_t size = 65536, std::string eol = "\n");
/*! Reads in a line or until a given delimiter has been processed.
*
* Reads from the serial port until a single line has been read.
*
* \param size A maximum length of a line, defaults to 65536 (2^16)
* \param eol A string to match against for the EOL.
*
* \return A std::string containing the line.
*
* \throw serial::PortNotOpenedException
* \throw serial::SerialException
*/
std::string readline(size_t size = 65536, std::string eol = "\n");
/*! Reads in multiple lines until the serial port times out.
*
* This requires a timeout > 0 before it can be run. It will read until a
* timeout occurs and return a list of strings.
*
* \param size A maximum length of combined lines, defaults to 65536 (2^16)
*
* \param eol A string to match against for the EOL.
*
* \return A vector<string> containing the lines.
*
* \throw serial::PortNotOpenedException
* \throw serial::SerialException
*/
std::vector<std::string> readlines(size_t size = 65536, std::string eol = "\n");
/*! Write a string to the serial port.
*
* \param data A const reference containing the data to be written
* to the serial port.
*
* \param size A size_t that indicates how many bytes should be written from
* the given data buffer.
*
* \return A size_t representing the number of bytes actually written to
* the serial port.
*
* \throw serial::PortNotOpenedException
* \throw serial::SerialException
* \throw serial::IOException
*/
size_t write(const uint8_t * data, size_t size);
/*! Write a string to the serial port.
*
* \param data A const reference containing the data to be written
* to the serial port.
*
* \return A size_t representing the number of bytes actually written to
* the serial port.
*
* \throw serial::PortNotOpenedException
* \throw serial::SerialException
* \throw serial::IOException
*/
size_t write(const std::vector<uint8_t> & data);
/*! Write a string to the serial port.
*
* \param data A const reference containing the data to be written
* to the serial port.
*
* \return A size_t representing the number of bytes actually written to
* the serial port.
*
* \throw serial::PortNotOpenedException
* \throw serial::SerialException
* \throw serial::IOException
*/
size_t write(const std::string & data);
/*! Sets the serial port identifier.
*
* \param port A const std::string reference containing the address of the
* serial port, which would be something like 'COM1' on Windows and
* '/dev/ttyS0' on Linux.
*
* \throw std::invalid_argument
*/
void setPort(const std::string & port);
/*! Gets the serial port identifier.
*
* \see Serial::setPort
*
* \throw std::invalid_argument
*/
std::string getPort() const;
/*! Sets the timeout for reads and writes using the Timeout struct.
*
* There are two timeout conditions described here:
* * The inter byte timeout:
* * The inter_byte_timeout component of serial::Timeout defines the
* maximum amount of time, in milliseconds, between receiving bytes on
* the serial port that can pass before a timeout occurs. Setting this
* to zero will prevent inter byte timeouts from occurring.
* * Total time timeout:
* * The constant and multiplier component of this timeout condition,
* for both read and write, are defined in serial::Timeout. This
* timeout occurs if the total time since the read or write call was
* made exceeds the specified time in milliseconds.
* * The limit is defined by multiplying the multiplier component by the
* number of requested bytes and adding that product to the constant
* component. In this way if you want a read call, for example, to
* timeout after exactly one second regardless of the number of bytes
* you asked for then set the read_timeout_constant component of
* serial::Timeout to 1000 and the read_timeout_multiplier to zero.
* This timeout condition can be used in conjunction with the inter
* byte timeout condition with out any problems, timeout will simply
* occur when one of the two timeout conditions is met. This allows
* users to have maximum control over the trade-off between
* responsiveness and efficiency.
*
* Read and write functions will return in one of three cases. When the
* reading or writing is complete, when a timeout occurs, or when an
* exception occurs.
*
* A timeout of 0 enables non-blocking mode.
*
* \param timeout A serial::Timeout struct containing the inter byte
* timeout, and the read and write timeout constants and multipliers.
*
* \see serial::Timeout
*/
void setTimeout(Timeout & timeout);
/*! Sets the timeout for reads and writes. */
void setTimeout(
uint32_t inter_byte_timeout, uint32_t read_timeout_constant, uint32_t read_timeout_multiplier,
uint32_t write_timeout_constant, uint32_t write_timeout_multiplier)
{
Timeout timeout(
inter_byte_timeout, read_timeout_constant, read_timeout_multiplier, write_timeout_constant,
write_timeout_multiplier);
return setTimeout(timeout);
}
/*! Gets the timeout for reads in seconds.
*
* \return A Timeout struct containing the inter_byte_timeout, and read
* and write timeout constants and multipliers.
*
* \see Serial::setTimeout
*/
Timeout getTimeout() const;
/*! Sets the baudrate for the serial port.
*
* Possible baudrates depends on the system but some safe baudrates include:
* 110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 56000,
* 57600, 115200
* Some other baudrates that are supported by some comports:
* 128000, 153600, 230400, 256000, 460800, 500000, 921600
*
* \param baudrate An integer that sets the baud rate for the serial port.
*
* \throw std::invalid_argument
*/
void setBaudrate(uint32_t baudrate);
/*! Gets the baudrate for the serial port.
*
* \return An integer that sets the baud rate for the serial port.
*
* \see Serial::setBaudrate
*
* \throw std::invalid_argument
*/
uint32_t getBaudrate() const;
/*! Sets the bytesize for the serial port.
*
* \param bytesize Size of each byte in the serial transmission of data,
* default is eightbits, possible values are: fivebits, sixbits, sevenbits,
* eightbits
*
* \throw std::invalid_argument
*/
void setBytesize(bytesize_t bytesize);
/*! Gets the bytesize for the serial port.
*
* \see Serial::setBytesize
*
* \throw std::invalid_argument
*/
bytesize_t getBytesize() const;
/*! Sets the parity for the serial port.
*
* \param parity Method of parity, default is parity_none, possible values
* are: parity_none, parity_odd, parity_even
*
* \throw std::invalid_argument
*/
void setParity(parity_t parity);
/*! Gets the parity for the serial port.
*
* \see Serial::setParity
*
* \throw std::invalid_argument
*/
parity_t getParity() const;
/*! Sets the stopbits for the serial port.
*
* \param stopbits Number of stop bits used, default is stopbits_one,
* possible values are: stopbits_one, stopbits_one_point_five, stopbits_two
*
* \throw std::invalid_argument
*/
void setStopbits(stopbits_t stopbits);
/*! Gets the stopbits for the serial port.
*
* \see Serial::setStopbits
*
* \throw std::invalid_argument
*/
stopbits_t getStopbits() const;
/*! Sets the flow control for the serial port.
*
* \param flowcontrol Type of flowcontrol used, default is flowcontrol_none,
* possible values are: flowcontrol_none, flowcontrol_software,
* flowcontrol_hardware
*
* \throw std::invalid_argument
*/
void setFlowcontrol(flowcontrol_t flowcontrol);
/*! Gets the flow control for the serial port.
*
* \see Serial::setFlowcontrol
*
* \throw std::invalid_argument
*/
flowcontrol_t getFlowcontrol() const;
/*! Flush the input and output buffers */
void flush();
/*! Flush only the input buffer */
void flushInput();
/*! Flush only the output buffer */
void flushOutput();
/*! Sends the RS-232 break signal. See tcsendbreak(3). */
void sendBreak(int duration);
/*! Set the break condition to a given level. Defaults to true. */
void setBreak(bool level = true);
/*! Set the RTS handshaking line to the given level. Defaults to true. */
void setRTS(bool level = true);
/*! Set the DTR handshaking line to the given level. Defaults to true. */
void setDTR(bool level = true);
/*!
* Blocks until CTS, DSR, RI, CD changes or something interrupts it.
*
* Can throw an exception if an error occurs while waiting.
* You can check the status of CTS, DSR, RI, and CD once this returns.
* Uses TIOCMIWAIT via ioctl if available (mostly only on Linux) with a
* resolution of less than +-1ms and as good as +-0.2ms. Otherwise a
* polling method is used which can give +-2ms.
*
* \return Returns true if one of the lines changed, false if something else
* occurred.
*
* \throw SerialException
*/
bool waitForChange();
/*! Returns the current status of the CTS line. */
bool getCTS();
/*! Returns the current status of the DSR line. */
bool getDSR();
/*! Returns the current status of the RI line. */
bool getRI();
/*! Returns the current status of the CD line. */
bool getCD();
private:
// Disable copy constructors
Serial(const Serial &);
Serial & operator=(const Serial &);
// Pimpl idiom, d_pointer
class SerialImpl;
SerialImpl * pimpl_;
// Scoped Lock Classes
class ScopedReadLock;
class ScopedWriteLock;
// Read common function
size_t read_(uint8_t * buffer, size_t size);
// Write common function
size_t write_(const uint8_t * data, size_t length);
};
class SerialException : public std::exception
{
// Disable copy constructors
SerialException & operator=(const SerialException &);
std::string e_what_;
public:
SerialException(const char * description)
{
std::stringstream ss;
ss << "SerialException " << description << " failed.";
e_what_ = ss.str();
}
SerialException(const SerialException & other) : e_what_(other.e_what_) {}
virtual ~SerialException() throw() {}
virtual const char * what() const throw() { return e_what_.c_str(); }
};
class IOException : public std::exception
{
// Disable copy constructors
IOException & operator=(const IOException &);
std::string file_;
int line_;
std::string e_what_;
int errno_;
public:
explicit IOException(std::string file, int line, int errnum)
: file_(file), line_(line), errno_(errnum)
{
std::stringstream ss;
#if defined(_WIN32) && !defined(__MINGW32__)
char error_str[1024];
strerror_s(error_str, 1024, errnum);
#else
char * error_str = strerror(errnum);
#endif
ss << "IO Exception (" << errno_ << "): " << error_str;
ss << ", file " << file_ << ", line " << line_ << ".";
e_what_ = ss.str();
}
explicit IOException(std::string file, int line, const char * description)
: file_(file), line_(line), errno_(0)
{
std::stringstream ss;
ss << "IO Exception: " << description;
ss << ", file " << file_ << ", line " << line_ << ".";
e_what_ = ss.str();
}
virtual ~IOException() throw() {}
IOException(const IOException & other)
: line_(other.line_), e_what_(other.e_what_), errno_(other.errno_)
{
}
int getErrorNumber() const { return errno_; }
virtual const char * what() const throw() { return e_what_.c_str(); }
};
class PortNotOpenedException : public std::exception
{
// Disable copy constructors
const PortNotOpenedException & operator=(PortNotOpenedException);
std::string e_what_;
public:
PortNotOpenedException(const char * description)
{
std::stringstream ss;
ss << "PortNotOpenedException " << description << " failed.";
e_what_ = ss.str();
}
PortNotOpenedException(const PortNotOpenedException & other) : e_what_(other.e_what_) {}
virtual ~PortNotOpenedException() throw() {}
virtual const char * what() const throw() { return e_what_.c_str(); }
};
/*!
* Structure that describes a serial device.
*/
struct PortInfo
{
/*! Address of the serial port (this can be passed to the constructor of Serial). */
std::string port;
/*! Human readable description of serial device if available. */
std::string description;
/*! Hardware ID (e.g. VID:PID of USB serial devices) or "n/a" if not available. */
std::string hardware_id;
};
/* Lists the serial ports available on the system
*
* Returns a vector of available serial ports, each represented
* by a serial::PortInfo data structure:
*
* \return vector of serial::PortInfo.
*/
std::vector<PortInfo> list_ports();
} // namespace serial
#endif

View File

@ -0,0 +1,57 @@
// This header is from the v8 google project:
// http://code.google.com/p/v8/source/browse/trunk/include/v8stdint.h
// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Load definitions of standard types.
#ifndef V8STDINT_H_
#define V8STDINT_H_
#include <stddef.h>
#include <stdio.h>
#if defined(_WIN32) && !defined(__MINGW32__)
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef short int16_t; // NOLINT
typedef unsigned short uint16_t; // NOLINT
typedef int int32_t;
typedef unsigned int uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
// intptr_t and friends are defined in crtdefs.h through stdio.h.
#else
#include <stdint.h>
#endif
#endif // V8STDINT_H_

View File

@ -0,0 +1,292 @@
#if defined(__linux__)
/*
* Copyright (c) 2014 Craig Lilley <cralilley@gmail.com>
* This software is made available under the terms of the MIT licence.
* A copy of the licence can be obtained from:
* http://opensource.org/licenses/MIT
*/
#include <glob.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
#include "serial/serial.h"
using serial::PortInfo;
using std::cout;
using std::endl;
using std::getline;
using std::ifstream;
using std::istringstream;
using std::string;
using std::vector;
static vector<string> glob(const vector<string> & patterns);
static string basename(const string & path);
static string dirname(const string & path);
static bool path_exists(const string & path);
static string realpath(const string & path);
static string usb_sysfs_friendly_name(const string & sys_usb_path);
static vector<string> get_sysfs_info(const string & device_path);
static string read_line(const string & file);
static string usb_sysfs_hw_string(const string & sysfs_path);
static string format(const char * format, ...);
vector<string> glob(const vector<string> & patterns)
{
vector<string> paths_found;
if (patterns.size() == 0) return paths_found;
glob_t glob_results;
int glob_retval = glob(patterns[0].c_str(), 0, NULL, &glob_results);
vector<string>::const_iterator iter = patterns.begin();
while (++iter != patterns.end()) {
glob_retval = glob(iter->c_str(), GLOB_APPEND, NULL, &glob_results);
}
for (int path_index = 0; path_index < glob_results.gl_pathc; path_index++) {
paths_found.push_back(glob_results.gl_pathv[path_index]);
}
globfree(&glob_results);
return paths_found;
}
string basename(const string & path)
{
size_t pos = path.rfind("/");
if (pos == std::string::npos) return path;
return string(path, pos + 1, string::npos);
}
string dirname(const string & path)
{
size_t pos = path.rfind("/");
if (pos == std::string::npos)
return path;
else if (pos == 0)
return "/";
return string(path, 0, pos);
}
bool path_exists(const string & path)
{
struct stat sb;
if (stat(path.c_str(), &sb) == 0) return true;
return false;
}
string realpath(const string & path)
{
char * real_path = realpath(path.c_str(), NULL);
string result;
if (real_path != NULL) {
result = real_path;
free(real_path);
}
return result;
}
string usb_sysfs_friendly_name(const string & sys_usb_path)
{
unsigned int device_number = 0;
istringstream(read_line(sys_usb_path + "/devnum")) >> device_number;
string manufacturer = read_line(sys_usb_path + "/manufacturer");
string product = read_line(sys_usb_path + "/product");
string serial = read_line(sys_usb_path + "/serial");
if (manufacturer.empty() && product.empty() && serial.empty()) return "";
return format("%s %s %s", manufacturer.c_str(), product.c_str(), serial.c_str());
}
vector<string> get_sysfs_info(const string & device_path)
{
string device_name = basename(device_path);
string friendly_name;
string hardware_id;
string sys_device_path = format("/sys/class/tty/%s/device", device_name.c_str());
if (device_name.compare(0, 6, "ttyUSB") == 0) {
sys_device_path = dirname(dirname(realpath(sys_device_path)));
if (path_exists(sys_device_path)) {
friendly_name = usb_sysfs_friendly_name(sys_device_path);
hardware_id = usb_sysfs_hw_string(sys_device_path);
}
} else if (device_name.compare(0, 6, "ttyACM") == 0) {
sys_device_path = dirname(realpath(sys_device_path));
if (path_exists(sys_device_path)) {
friendly_name = usb_sysfs_friendly_name(sys_device_path);
hardware_id = usb_sysfs_hw_string(sys_device_path);
}
} else {
// Try to read ID string of PCI device
string sys_id_path = sys_device_path + "/id";
if (path_exists(sys_id_path)) hardware_id = read_line(sys_id_path);
}
if (friendly_name.empty()) friendly_name = device_name;
if (hardware_id.empty()) hardware_id = "n/a";
vector<string> result;
result.push_back(friendly_name);
result.push_back(hardware_id);
return result;
}
string read_line(const string & file)
{
ifstream ifs(file.c_str(), ifstream::in);
string line;
if (ifs) {
getline(ifs, line);
}
return line;
}
string format(const char * format, ...)
{
va_list ap;
size_t buffer_size_bytes = 256;
string result;
char * buffer = (char *)malloc(buffer_size_bytes);
if (buffer == NULL) return result;
bool done = false;
unsigned int loop_count = 0;
while (!done) {
va_start(ap, format);
int return_value = vsnprintf(buffer, buffer_size_bytes, format, ap);
if (return_value < 0) {
done = true;
} else if (return_value >= buffer_size_bytes) {
// Realloc and try again.
buffer_size_bytes = return_value + 1;
char * new_buffer_ptr = (char *)realloc(buffer, buffer_size_bytes);
if (new_buffer_ptr == NULL) {
done = true;
} else {
buffer = new_buffer_ptr;
}
} else {
result = buffer;
done = true;
}
va_end(ap);
if (++loop_count > 5) done = true;
}
free(buffer);
return result;
}
string usb_sysfs_hw_string(const string & sysfs_path)
{
string serial_number = read_line(sysfs_path + "/serial");
if (serial_number.length() > 0) {
serial_number = format("SNR=%s", serial_number.c_str());
}
string vid = read_line(sysfs_path + "/idVendor");
string pid = read_line(sysfs_path + "/idProduct");
return format("USB VID:PID=%s:%s %s", vid.c_str(), pid.c_str(), serial_number.c_str());
}
vector<PortInfo> serial::list_ports()
{
vector<PortInfo> results;
vector<string> search_globs;
search_globs.push_back("/dev/ttyACM*");
search_globs.push_back("/dev/ttyS*");
search_globs.push_back("/dev/ttyUSB*");
search_globs.push_back("/dev/tty.*");
search_globs.push_back("/dev/cu.*");
vector<string> devices_found = glob(search_globs);
vector<string>::iterator iter = devices_found.begin();
while (iter != devices_found.end()) {
string device = *iter++;
vector<string> sysfs_info = get_sysfs_info(device);
string friendly_name = sysfs_info[0];
string hardware_id = sysfs_info[1];
PortInfo device_entry;
device_entry.port = device;
device_entry.description = friendly_name;
device_entry.hardware_id = hardware_id;
results.push_back(device_entry);
}
return results;
}
#endif // defined(__linux__)

View File

@ -0,0 +1,234 @@
#if defined(__APPLE__)
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOBSD.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/serial/IOSerialKeys.h>
#include <stdint.h>
#include <sys/param.h>
#include <iostream>
#include <string>
#include <vector>
#include "serial/serial.h"
using serial::PortInfo;
using std::string;
using std::vector;
#define HARDWARE_ID_STRING_LENGTH 128
string cfstring_to_string(CFStringRef cfstring);
string get_device_path(io_object_t & serial_port);
string get_class_name(io_object_t & obj);
io_registry_entry_t get_parent_iousb_device(io_object_t & serial_port);
string get_string_property(io_object_t & device, const char * property);
uint16_t get_int_property(io_object_t & device, const char * property);
string rtrim(const string & str);
string cfstring_to_string(CFStringRef cfstring)
{
char cstring[MAXPATHLEN];
string result;
if (cfstring) {
Boolean success =
CFStringGetCString(cfstring, cstring, sizeof(cstring), kCFStringEncodingASCII);
if (success) result = cstring;
}
return result;
}
string get_device_path(io_object_t & serial_port)
{
CFTypeRef callout_path;
string device_path;
callout_path = IORegistryEntryCreateCFProperty(
serial_port, CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
if (callout_path) {
if (CFGetTypeID(callout_path) == CFStringGetTypeID())
device_path = cfstring_to_string(static_cast<CFStringRef>(callout_path));
CFRelease(callout_path);
}
return device_path;
}
string get_class_name(io_object_t & obj)
{
string result;
io_name_t class_name;
kern_return_t kern_result;
kern_result = IOObjectGetClass(obj, class_name);
if (kern_result == KERN_SUCCESS) result = class_name;
return result;
}
io_registry_entry_t get_parent_iousb_device(io_object_t & serial_port)
{
io_object_t device = serial_port;
io_registry_entry_t parent = 0;
io_registry_entry_t result = 0;
kern_return_t kern_result = KERN_FAILURE;
string name = get_class_name(device);
// Walk the IO Registry tree looking for this devices parent IOUSBDevice.
while (name != "IOUSBDevice") {
kern_result = IORegistryEntryGetParentEntry(device, kIOServicePlane, &parent);
if (kern_result != KERN_SUCCESS) {
result = 0;
break;
}
device = parent;
name = get_class_name(device);
}
if (kern_result == KERN_SUCCESS) result = device;
return result;
}
string get_string_property(io_object_t & device, const char * property)
{
string property_name;
if (device) {
CFStringRef property_as_cfstring =
CFStringCreateWithCString(kCFAllocatorDefault, property, kCFStringEncodingASCII);
CFTypeRef name_as_cfstring =
IORegistryEntryCreateCFProperty(device, property_as_cfstring, kCFAllocatorDefault, 0);
if (name_as_cfstring) {
if (CFGetTypeID(name_as_cfstring) == CFStringGetTypeID())
property_name = cfstring_to_string(static_cast<CFStringRef>(name_as_cfstring));
CFRelease(name_as_cfstring);
}
if (property_as_cfstring) CFRelease(property_as_cfstring);
}
return property_name;
}
uint16_t get_int_property(io_object_t & device, const char * property)
{
uint16_t result = 0;
if (device) {
CFStringRef property_as_cfstring =
CFStringCreateWithCString(kCFAllocatorDefault, property, kCFStringEncodingASCII);
CFTypeRef number =
IORegistryEntryCreateCFProperty(device, property_as_cfstring, kCFAllocatorDefault, 0);
if (property_as_cfstring) CFRelease(property_as_cfstring);
if (number) {
if (CFGetTypeID(number) == CFNumberGetTypeID()) {
bool success =
CFNumberGetValue(static_cast<CFNumberRef>(number), kCFNumberSInt16Type, &result);
if (!success) result = 0;
}
CFRelease(number);
}
}
return result;
}
string rtrim(const string & str)
{
string result = str;
string whitespace = " \t\f\v\n\r";
std::size_t found = result.find_last_not_of(whitespace);
if (found != std::string::npos)
result.erase(found + 1);
else
result.clear();
return result;
}
vector<PortInfo> serial::list_ports(void)
{
vector<PortInfo> devices_found;
CFMutableDictionaryRef classes_to_match;
io_iterator_t serial_port_iterator;
io_object_t serial_port;
mach_port_t master_port;
kern_return_t kern_result;
kern_result = IOMasterPort(MACH_PORT_NULL, &master_port);
if (kern_result != KERN_SUCCESS) return devices_found;
classes_to_match = IOServiceMatching(kIOSerialBSDServiceValue);
if (classes_to_match == NULL) return devices_found;
CFDictionarySetValue(classes_to_match, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes));
kern_result = IOServiceGetMatchingServices(master_port, classes_to_match, &serial_port_iterator);
if (KERN_SUCCESS != kern_result) return devices_found;
while ((serial_port = IOIteratorNext(serial_port_iterator))) {
string device_path = get_device_path(serial_port);
io_registry_entry_t parent = get_parent_iousb_device(serial_port);
IOObjectRelease(serial_port);
if (device_path.empty()) continue;
PortInfo port_info;
port_info.port = device_path;
port_info.description = "n/a";
port_info.hardware_id = "n/a";
string device_name = rtrim(get_string_property(parent, "USB Product Name"));
string vendor_name = rtrim(get_string_property(parent, "USB Vendor Name"));
string description = rtrim(vendor_name + " " + device_name);
if (!description.empty()) port_info.description = description;
string serial_number = rtrim(get_string_property(parent, "USB Serial Number"));
uint16_t vendor_id = get_int_property(parent, "idVendor");
uint16_t product_id = get_int_property(parent, "idProduct");
if (vendor_id && product_id) {
char cstring[HARDWARE_ID_STRING_LENGTH];
if (serial_number.empty()) serial_number = "None";
int ret = snprintf(
cstring, HARDWARE_ID_STRING_LENGTH, "USB VID:PID=%04x:%04x SNR=%s", vendor_id, product_id,
serial_number.c_str());
if ((ret >= 0) && (ret < HARDWARE_ID_STRING_LENGTH)) port_info.hardware_id = cstring;
}
devices_found.push_back(port_info);
}
IOObjectRelease(serial_port_iterator);
return devices_found;
}
#endif // defined(__APPLE__)

View File

@ -0,0 +1,128 @@
#if defined(_WIN32)
/*
* Copyright (c) 2014 Craig Lilley <cralilley@gmail.com>
* This software is made available under the terms of the MIT licence.
* A copy of the licence can be obtained from:
* http://opensource.org/licenses/MIT
*/
#include <devguid.h>
#include <initguid.h>
#include <setupapi.h>
#include <tchar.h>
#include <windows.h>
#include <cstring>
#include "serial/serial.h"
using serial::PortInfo;
using std::string;
using std::vector;
static const DWORD port_name_max_length = 256;
static const DWORD friendly_name_max_length = 256;
static const DWORD hardware_id_max_length = 256;
// Convert a wide Unicode string to an UTF8 string
std::string utf8_encode(const std::wstring & wstr)
{
int size_needed =
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
std::string strTo(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
return strTo;
}
vector<PortInfo> serial::list_ports()
{
vector<PortInfo> devices_found;
HDEVINFO device_info_set =
SetupDiGetClassDevs((const GUID *)&GUID_DEVCLASS_PORTS, NULL, NULL, DIGCF_PRESENT);
unsigned int device_info_set_index = 0;
SP_DEVINFO_DATA device_info_data;
device_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
while (SetupDiEnumDeviceInfo(device_info_set, device_info_set_index, &device_info_data)) {
device_info_set_index++;
// Get port name
HKEY hkey = SetupDiOpenDevRegKey(
device_info_set, &device_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
TCHAR port_name[port_name_max_length];
DWORD port_name_length = port_name_max_length;
LONG return_code =
RegQueryValueEx(hkey, _T("PortName"), NULL, NULL, (LPBYTE)port_name, &port_name_length);
RegCloseKey(hkey);
if (return_code != EXIT_SUCCESS) continue;
if (port_name_length > 0 && port_name_length <= port_name_max_length)
port_name[port_name_length - 1] = '\0';
else
port_name[0] = '\0';
// Ignore parallel ports
if (_tcsstr(port_name, _T("LPT")) != NULL) continue;
// Get port friendly name
TCHAR friendly_name[friendly_name_max_length];
DWORD friendly_name_actual_length = 0;
BOOL got_friendly_name = SetupDiGetDeviceRegistryProperty(
device_info_set, &device_info_data, SPDRP_FRIENDLYNAME, NULL, (PBYTE)friendly_name,
friendly_name_max_length, &friendly_name_actual_length);
if (got_friendly_name == TRUE && friendly_name_actual_length > 0)
friendly_name[friendly_name_actual_length - 1] = '\0';
else
friendly_name[0] = '\0';
// Get hardware ID
TCHAR hardware_id[hardware_id_max_length];
DWORD hardware_id_actual_length = 0;
BOOL got_hardware_id = SetupDiGetDeviceRegistryProperty(
device_info_set, &device_info_data, SPDRP_HARDWAREID, NULL, (PBYTE)hardware_id,
hardware_id_max_length, &hardware_id_actual_length);
if (got_hardware_id == TRUE && hardware_id_actual_length > 0)
hardware_id[hardware_id_actual_length - 1] = '\0';
else
hardware_id[0] = '\0';
#ifdef UNICODE
std::string portName = utf8_encode(port_name);
std::string friendlyName = utf8_encode(friendly_name);
std::string hardwareId = utf8_encode(hardware_id);
#else
std::string portName = port_name;
std::string friendlyName = friendly_name;
std::string hardwareId = hardware_id;
#endif
PortInfo port_entry;
port_entry.port = portName;
port_entry.description = friendlyName;
port_entry.hardware_id = hardwareId;
devices_found.push_back(port_entry);
}
SetupDiDestroyDeviceInfoList(device_info_set);
return devices_found;
}
#endif // #if defined(_WIN32)

1050
io/serial/src/impl/unix.cc Normal file

File diff suppressed because it is too large Load Diff

631
io/serial/src/impl/win.cc Normal file
View File

@ -0,0 +1,631 @@
#if defined(_WIN32)
/* Copyright 2012 William Woodall and John Harrison */
#include "serial/impl/win.h"
#include <sstream>
using serial::bytesize_t;
using serial::flowcontrol_t;
using serial::IOException;
using serial::parity_t;
using serial::PortNotOpenedException;
using serial::Serial;
using serial::SerialException;
using serial::stopbits_t;
using serial::Timeout;
using std::invalid_argument;
using std::string;
using std::stringstream;
using std::wstring;
inline wstring _prefix_port_if_needed(const wstring & input)
{
static wstring windows_com_port_prefix = L"\\\\.\\";
if (input.compare(windows_com_port_prefix) != 0) {
return windows_com_port_prefix + input;
}
return input;
}
Serial::SerialImpl::SerialImpl(
const string & port, unsigned long baudrate, bytesize_t bytesize, parity_t parity,
stopbits_t stopbits, flowcontrol_t flowcontrol)
: port_(port.begin(), port.end()),
fd_(INVALID_HANDLE_VALUE),
is_open_(false),
baudrate_(baudrate),
parity_(parity),
bytesize_(bytesize),
stopbits_(stopbits),
flowcontrol_(flowcontrol)
{
if (port_.empty() == false) open();
read_mutex = CreateMutex(NULL, false, NULL);
write_mutex = CreateMutex(NULL, false, NULL);
}
Serial::SerialImpl::~SerialImpl()
{
this->close();
CloseHandle(read_mutex);
CloseHandle(write_mutex);
}
void Serial::SerialImpl::open()
{
if (port_.empty()) {
throw invalid_argument("Empty port is invalid.");
}
if (is_open_ == true) {
throw SerialException("Serial port already open.");
}
// See: https://github.com/wjwwood/serial/issues/84
wstring port_with_prefix = _prefix_port_if_needed(port_);
LPCWSTR lp_port = port_with_prefix.c_str();
fd_ = CreateFileW(
lp_port, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (fd_ == INVALID_HANDLE_VALUE) {
DWORD create_file_err = GetLastError();
stringstream ss;
switch (create_file_err) {
case ERROR_FILE_NOT_FOUND:
// Use this->getPort to convert to a std::string
ss << "Specified port, " << this->getPort() << ", does not exist.";
THROW(IOException, ss.str().c_str());
default:
ss << "Unknown error opening the serial port: " << create_file_err;
THROW(IOException, ss.str().c_str());
}
}
reconfigurePort();
is_open_ = true;
}
void Serial::SerialImpl::reconfigurePort()
{
if (fd_ == INVALID_HANDLE_VALUE) {
// Can only operate on a valid file descriptor
THROW(IOException, "Invalid file descriptor, is the serial port open?");
}
DCB dcbSerialParams = {0};
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (!GetCommState(fd_, &dcbSerialParams)) {
//error getting state
THROW(IOException, "Error getting the serial port state.");
}
// setup baud rate
switch (baudrate_) {
#ifdef CBR_0
case 0:
dcbSerialParams.BaudRate = CBR_0;
break;
#endif
#ifdef CBR_50
case 50:
dcbSerialParams.BaudRate = CBR_50;
break;
#endif
#ifdef CBR_75
case 75:
dcbSerialParams.BaudRate = CBR_75;
break;
#endif
#ifdef CBR_110
case 110:
dcbSerialParams.BaudRate = CBR_110;
break;
#endif
#ifdef CBR_134
case 134:
dcbSerialParams.BaudRate = CBR_134;
break;
#endif
#ifdef CBR_150
case 150:
dcbSerialParams.BaudRate = CBR_150;
break;
#endif
#ifdef CBR_200
case 200:
dcbSerialParams.BaudRate = CBR_200;
break;
#endif
#ifdef CBR_300
case 300:
dcbSerialParams.BaudRate = CBR_300;
break;
#endif
#ifdef CBR_600
case 600:
dcbSerialParams.BaudRate = CBR_600;
break;
#endif
#ifdef CBR_1200
case 1200:
dcbSerialParams.BaudRate = CBR_1200;
break;
#endif
#ifdef CBR_1800
case 1800:
dcbSerialParams.BaudRate = CBR_1800;
break;
#endif
#ifdef CBR_2400
case 2400:
dcbSerialParams.BaudRate = CBR_2400;
break;
#endif
#ifdef CBR_4800
case 4800:
dcbSerialParams.BaudRate = CBR_4800;
break;
#endif
#ifdef CBR_7200
case 7200:
dcbSerialParams.BaudRate = CBR_7200;
break;
#endif
#ifdef CBR_9600
case 9600:
dcbSerialParams.BaudRate = CBR_9600;
break;
#endif
#ifdef CBR_14400
case 14400:
dcbSerialParams.BaudRate = CBR_14400;
break;
#endif
#ifdef CBR_19200
case 19200:
dcbSerialParams.BaudRate = CBR_19200;
break;
#endif
#ifdef CBR_28800
case 28800:
dcbSerialParams.BaudRate = CBR_28800;
break;
#endif
#ifdef CBR_57600
case 57600:
dcbSerialParams.BaudRate = CBR_57600;
break;
#endif
#ifdef CBR_76800
case 76800:
dcbSerialParams.BaudRate = CBR_76800;
break;
#endif
#ifdef CBR_38400
case 38400:
dcbSerialParams.BaudRate = CBR_38400;
break;
#endif
#ifdef CBR_115200
case 115200:
dcbSerialParams.BaudRate = CBR_115200;
break;
#endif
#ifdef CBR_128000
case 128000:
dcbSerialParams.BaudRate = CBR_128000;
break;
#endif
#ifdef CBR_153600
case 153600:
dcbSerialParams.BaudRate = CBR_153600;
break;
#endif
#ifdef CBR_230400
case 230400:
dcbSerialParams.BaudRate = CBR_230400;
break;
#endif
#ifdef CBR_256000
case 256000:
dcbSerialParams.BaudRate = CBR_256000;
break;
#endif
#ifdef CBR_460800
case 460800:
dcbSerialParams.BaudRate = CBR_460800;
break;
#endif
#ifdef CBR_921600
case 921600:
dcbSerialParams.BaudRate = CBR_921600;
break;
#endif
default:
// Try to blindly assign it
dcbSerialParams.BaudRate = baudrate_;
}
// setup char len
if (bytesize_ == eightbits)
dcbSerialParams.ByteSize = 8;
else if (bytesize_ == sevenbits)
dcbSerialParams.ByteSize = 7;
else if (bytesize_ == sixbits)
dcbSerialParams.ByteSize = 6;
else if (bytesize_ == fivebits)
dcbSerialParams.ByteSize = 5;
else
throw invalid_argument("invalid char len");
// setup stopbits
if (stopbits_ == stopbits_one)
dcbSerialParams.StopBits = ONESTOPBIT;
else if (stopbits_ == stopbits_one_point_five)
dcbSerialParams.StopBits = ONE5STOPBITS;
else if (stopbits_ == stopbits_two)
dcbSerialParams.StopBits = TWOSTOPBITS;
else
throw invalid_argument("invalid stop bit");
// setup parity
if (parity_ == parity_none) {
dcbSerialParams.Parity = NOPARITY;
} else if (parity_ == parity_even) {
dcbSerialParams.Parity = EVENPARITY;
} else if (parity_ == parity_odd) {
dcbSerialParams.Parity = ODDPARITY;
} else if (parity_ == parity_mark) {
dcbSerialParams.Parity = MARKPARITY;
} else if (parity_ == parity_space) {
dcbSerialParams.Parity = SPACEPARITY;
} else {
throw invalid_argument("invalid parity");
}
// setup flowcontrol
if (flowcontrol_ == flowcontrol_none) {
dcbSerialParams.fOutxCtsFlow = false;
dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
dcbSerialParams.fOutX = false;
dcbSerialParams.fInX = false;
}
if (flowcontrol_ == flowcontrol_software) {
dcbSerialParams.fOutxCtsFlow = false;
dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
dcbSerialParams.fOutX = true;
dcbSerialParams.fInX = true;
}
if (flowcontrol_ == flowcontrol_hardware) {
dcbSerialParams.fOutxCtsFlow = true;
dcbSerialParams.fRtsControl = RTS_CONTROL_HANDSHAKE;
dcbSerialParams.fOutX = false;
dcbSerialParams.fInX = false;
}
// activate settings
if (!SetCommState(fd_, &dcbSerialParams)) {
CloseHandle(fd_);
THROW(IOException, "Error setting serial port settings.");
}
// Setup timeouts
COMMTIMEOUTS timeouts = {0};
timeouts.ReadIntervalTimeout = timeout_.inter_byte_timeout;
timeouts.ReadTotalTimeoutConstant = timeout_.read_timeout_constant;
timeouts.ReadTotalTimeoutMultiplier = timeout_.read_timeout_multiplier;
timeouts.WriteTotalTimeoutConstant = timeout_.write_timeout_constant;
timeouts.WriteTotalTimeoutMultiplier = timeout_.write_timeout_multiplier;
if (!SetCommTimeouts(fd_, &timeouts)) {
THROW(IOException, "Error setting timeouts.");
}
}
void Serial::SerialImpl::close()
{
if (is_open_ == true) {
if (fd_ != INVALID_HANDLE_VALUE) {
int ret;
ret = CloseHandle(fd_);
if (ret == 0) {
stringstream ss;
ss << "Error while closing serial port: " << GetLastError();
THROW(IOException, ss.str().c_str());
} else {
fd_ = INVALID_HANDLE_VALUE;
}
}
is_open_ = false;
}
}
bool Serial::SerialImpl::isOpen() const { return is_open_; }
size_t Serial::SerialImpl::available()
{
if (!is_open_) {
return 0;
}
COMSTAT cs;
if (!ClearCommError(fd_, NULL, &cs)) {
stringstream ss;
ss << "Error while checking status of the serial port: " << GetLastError();
THROW(IOException, ss.str().c_str());
}
return static_cast<size_t>(cs.cbInQue);
}
bool Serial::SerialImpl::waitReadable(uint32_t /*timeout*/)
{
THROW(IOException, "waitReadable is not implemented on Windows.");
return false;
}
void Serial::SerialImpl::waitByteTimes(size_t /*count*/)
{
THROW(IOException, "waitByteTimes is not implemented on Windows.");
}
size_t Serial::SerialImpl::read(uint8_t * buf, size_t size)
{
if (!is_open_) {
throw PortNotOpenedException("Serial::read");
}
DWORD bytes_read;
if (!ReadFile(fd_, buf, static_cast<DWORD>(size), &bytes_read, NULL)) {
stringstream ss;
ss << "Error while reading from the serial port: " << GetLastError();
THROW(IOException, ss.str().c_str());
}
return (size_t)(bytes_read);
}
size_t Serial::SerialImpl::write(const uint8_t * data, size_t length)
{
if (is_open_ == false) {
throw PortNotOpenedException("Serial::write");
}
DWORD bytes_written;
if (!WriteFile(fd_, data, static_cast<DWORD>(length), &bytes_written, NULL)) {
stringstream ss;
ss << "Error while writing to the serial port: " << GetLastError();
THROW(IOException, ss.str().c_str());
}
return (size_t)(bytes_written);
}
void Serial::SerialImpl::setPort(const string & port) { port_ = wstring(port.begin(), port.end()); }
string Serial::SerialImpl::getPort() const { return string(port_.begin(), port_.end()); }
void Serial::SerialImpl::setTimeout(serial::Timeout & timeout)
{
timeout_ = timeout;
if (is_open_) {
reconfigurePort();
}
}
serial::Timeout Serial::SerialImpl::getTimeout() const { return timeout_; }
void Serial::SerialImpl::setBaudrate(unsigned long baudrate)
{
baudrate_ = baudrate;
if (is_open_) {
reconfigurePort();
}
}
unsigned long Serial::SerialImpl::getBaudrate() const { return baudrate_; }
void Serial::SerialImpl::setBytesize(serial::bytesize_t bytesize)
{
bytesize_ = bytesize;
if (is_open_) {
reconfigurePort();
}
}
serial::bytesize_t Serial::SerialImpl::getBytesize() const { return bytesize_; }
void Serial::SerialImpl::setParity(serial::parity_t parity)
{
parity_ = parity;
if (is_open_) {
reconfigurePort();
}
}
serial::parity_t Serial::SerialImpl::getParity() const { return parity_; }
void Serial::SerialImpl::setStopbits(serial::stopbits_t stopbits)
{
stopbits_ = stopbits;
if (is_open_) {
reconfigurePort();
}
}
serial::stopbits_t Serial::SerialImpl::getStopbits() const { return stopbits_; }
void Serial::SerialImpl::setFlowcontrol(serial::flowcontrol_t flowcontrol)
{
flowcontrol_ = flowcontrol;
if (is_open_) {
reconfigurePort();
}
}
serial::flowcontrol_t Serial::SerialImpl::getFlowcontrol() const { return flowcontrol_; }
void Serial::SerialImpl::flush()
{
if (is_open_ == false) {
throw PortNotOpenedException("Serial::flush");
}
FlushFileBuffers(fd_);
}
void Serial::SerialImpl::flushInput()
{
if (is_open_ == false) {
throw PortNotOpenedException("Serial::flushInput");
}
PurgeComm(fd_, PURGE_RXCLEAR);
}
void Serial::SerialImpl::flushOutput()
{
if (is_open_ == false) {
throw PortNotOpenedException("Serial::flushOutput");
}
PurgeComm(fd_, PURGE_TXCLEAR);
}
void Serial::SerialImpl::sendBreak(int /*duration*/)
{
THROW(IOException, "sendBreak is not supported on Windows.");
}
void Serial::SerialImpl::setBreak(bool level)
{
if (is_open_ == false) {
throw PortNotOpenedException("Serial::setBreak");
}
if (level) {
EscapeCommFunction(fd_, SETBREAK);
} else {
EscapeCommFunction(fd_, CLRBREAK);
}
}
void Serial::SerialImpl::setRTS(bool level)
{
if (is_open_ == false) {
throw PortNotOpenedException("Serial::setRTS");
}
if (level) {
EscapeCommFunction(fd_, SETRTS);
} else {
EscapeCommFunction(fd_, CLRRTS);
}
}
void Serial::SerialImpl::setDTR(bool level)
{
if (is_open_ == false) {
throw PortNotOpenedException("Serial::setDTR");
}
if (level) {
EscapeCommFunction(fd_, SETDTR);
} else {
EscapeCommFunction(fd_, CLRDTR);
}
}
bool Serial::SerialImpl::waitForChange()
{
if (is_open_ == false) {
throw PortNotOpenedException("Serial::waitForChange");
}
DWORD dwCommEvent;
if (!SetCommMask(fd_, EV_CTS | EV_DSR | EV_RING | EV_RLSD)) {
// Error setting communications mask
return false;
}
if (!WaitCommEvent(fd_, &dwCommEvent, NULL)) {
// An error occurred waiting for the event.
return false;
} else {
// Event has occurred.
return true;
}
}
bool Serial::SerialImpl::getCTS()
{
if (is_open_ == false) {
throw PortNotOpenedException("Serial::getCTS");
}
DWORD dwModemStatus;
if (!GetCommModemStatus(fd_, &dwModemStatus)) {
THROW(IOException, "Error getting the status of the CTS line.");
}
return (MS_CTS_ON & dwModemStatus) != 0;
}
bool Serial::SerialImpl::getDSR()
{
if (is_open_ == false) {
throw PortNotOpenedException("Serial::getDSR");
}
DWORD dwModemStatus;
if (!GetCommModemStatus(fd_, &dwModemStatus)) {
THROW(IOException, "Error getting the status of the DSR line.");
}
return (MS_DSR_ON & dwModemStatus) != 0;
}
bool Serial::SerialImpl::getRI()
{
if (is_open_ == false) {
throw PortNotOpenedException("Serial::getRI");
}
DWORD dwModemStatus;
if (!GetCommModemStatus(fd_, &dwModemStatus)) {
THROW(IOException, "Error getting the status of the RI line.");
}
return (MS_RING_ON & dwModemStatus) != 0;
}
bool Serial::SerialImpl::getCD()
{
if (is_open_ == false) {
throw PortNotOpenedException("Serial::getCD");
}
DWORD dwModemStatus;
if (!GetCommModemStatus(fd_, &dwModemStatus)) {
// Error in GetCommModemStatus;
THROW(IOException, "Error getting the status of the CD line.");
}
return (MS_RLSD_ON & dwModemStatus) != 0;
}
void Serial::SerialImpl::readLock()
{
if (WaitForSingleObject(read_mutex, INFINITE) != WAIT_OBJECT_0) {
THROW(IOException, "Error claiming read mutex.");
}
}
void Serial::SerialImpl::readUnlock()
{
if (!ReleaseMutex(read_mutex)) {
THROW(IOException, "Error releasing read mutex.");
}
}
void Serial::SerialImpl::writeLock()
{
if (WaitForSingleObject(write_mutex, INFINITE) != WAIT_OBJECT_0) {
THROW(IOException, "Error claiming write mutex.");
}
}
void Serial::SerialImpl::writeUnlock()
{
if (!ReleaseMutex(write_mutex)) {
THROW(IOException, "Error releasing write mutex.");
}
}
#endif // #if defined(_WIN32)

293
io/serial/src/serial.cc Normal file
View File

@ -0,0 +1,293 @@
/* Copyright 2012 William Woodall and John Harrison */
#include <algorithm>
#if !defined(_WIN32) && !defined(__OpenBSD__) && !defined(__FreeBSD__)
#include <alloca.h>
#endif
#if defined(__MINGW32__)
#define alloca __builtin_alloca
#endif
#include "serial/serial.h"
#ifdef _WIN32
#include "serial/impl/win.h"
#else
#include "serial/impl/unix.h"
#endif
using std::invalid_argument;
using std::min;
using std::numeric_limits;
using std::size_t;
using std::string;
using std::vector;
using serial::bytesize_t;
using serial::flowcontrol_t;
using serial::IOException;
using serial::parity_t;
using serial::Serial;
using serial::SerialException;
using serial::stopbits_t;
class Serial::ScopedReadLock
{
public:
ScopedReadLock(SerialImpl * pimpl) : pimpl_(pimpl) { this->pimpl_->readLock(); }
~ScopedReadLock() { this->pimpl_->readUnlock(); }
private:
// Disable copy constructors
ScopedReadLock(const ScopedReadLock &);
const ScopedReadLock & operator=(ScopedReadLock);
SerialImpl * pimpl_;
};
class Serial::ScopedWriteLock
{
public:
ScopedWriteLock(SerialImpl * pimpl) : pimpl_(pimpl) { this->pimpl_->writeLock(); }
~ScopedWriteLock() { this->pimpl_->writeUnlock(); }
private:
// Disable copy constructors
ScopedWriteLock(const ScopedWriteLock &);
const ScopedWriteLock & operator=(ScopedWriteLock);
SerialImpl * pimpl_;
};
Serial::Serial(
const string & port, uint32_t baudrate, serial::Timeout timeout, bytesize_t bytesize,
parity_t parity, stopbits_t stopbits, flowcontrol_t flowcontrol)
: pimpl_(new SerialImpl(port, baudrate, bytesize, parity, stopbits, flowcontrol))
{
pimpl_->setTimeout(timeout);
}
Serial::~Serial() { delete pimpl_; }
void Serial::open() { pimpl_->open(); }
void Serial::close() { pimpl_->close(); }
bool Serial::isOpen() const { return pimpl_->isOpen(); }
size_t Serial::available() { return pimpl_->available(); }
bool Serial::waitReadable()
{
serial::Timeout timeout(pimpl_->getTimeout());
return pimpl_->waitReadable(timeout.read_timeout_constant);
}
void Serial::waitByteTimes(size_t count) { pimpl_->waitByteTimes(count); }
size_t Serial::read_(uint8_t * buffer, size_t size) { return this->pimpl_->read(buffer, size); }
size_t Serial::read(uint8_t * buffer, size_t size)
{
ScopedReadLock lock(this->pimpl_);
return this->pimpl_->read(buffer, size);
}
size_t Serial::read(std::vector<uint8_t> & buffer, size_t size)
{
ScopedReadLock lock(this->pimpl_);
uint8_t * buffer_ = new uint8_t[size];
size_t bytes_read = 0;
try {
bytes_read = this->pimpl_->read(buffer_, size);
} catch (const std::exception & e) {
delete[] buffer_;
throw;
}
buffer.insert(buffer.end(), buffer_, buffer_ + bytes_read);
delete[] buffer_;
return bytes_read;
}
size_t Serial::read(std::string & buffer, size_t size)
{
ScopedReadLock lock(this->pimpl_);
uint8_t * buffer_ = new uint8_t[size];
size_t bytes_read = 0;
try {
bytes_read = this->pimpl_->read(buffer_, size);
} catch (const std::exception & e) {
delete[] buffer_;
throw;
}
buffer.append(reinterpret_cast<const char *>(buffer_), bytes_read);
delete[] buffer_;
return bytes_read;
}
string Serial::read(size_t size)
{
std::string buffer;
this->read(buffer, size);
return buffer;
}
size_t Serial::readline(string & buffer, size_t size, string eol)
{
ScopedReadLock lock(this->pimpl_);
size_t eol_len = eol.length();
uint8_t * buffer_ = static_cast<uint8_t *>(alloca(size * sizeof(uint8_t)));
size_t read_so_far = 0;
while (true) {
size_t bytes_read = this->read_(buffer_ + read_so_far, 1);
read_so_far += bytes_read;
if (bytes_read == 0) {
break; // Timeout occured on reading 1 byte
}
if (string(reinterpret_cast<const char *>(buffer_ + read_so_far - eol_len), eol_len) == eol) {
break; // EOL found
}
if (read_so_far == size) {
break; // Reached the maximum read length
}
}
buffer.append(reinterpret_cast<const char *>(buffer_), read_so_far);
return read_so_far;
}
string Serial::readline(size_t size, string eol)
{
std::string buffer;
this->readline(buffer, size, eol);
return buffer;
}
vector<string> Serial::readlines(size_t size, string eol)
{
ScopedReadLock lock(this->pimpl_);
std::vector<std::string> lines;
size_t eol_len = eol.length();
uint8_t * buffer_ = static_cast<uint8_t *>(alloca(size * sizeof(uint8_t)));
size_t read_so_far = 0;
size_t start_of_line = 0;
while (read_so_far < size) {
size_t bytes_read = this->read_(buffer_ + read_so_far, 1);
read_so_far += bytes_read;
if (bytes_read == 0) {
if (start_of_line != read_so_far) {
lines.push_back(string(
reinterpret_cast<const char *>(buffer_ + start_of_line), read_so_far - start_of_line));
}
break; // Timeout occured on reading 1 byte
}
if (string(reinterpret_cast<const char *>(buffer_ + read_so_far - eol_len), eol_len) == eol) {
// EOL found
lines.push_back(string(
reinterpret_cast<const char *>(buffer_ + start_of_line), read_so_far - start_of_line));
start_of_line = read_so_far;
}
if (read_so_far == size) {
if (start_of_line != read_so_far) {
lines.push_back(string(
reinterpret_cast<const char *>(buffer_ + start_of_line), read_so_far - start_of_line));
}
break; // Reached the maximum read length
}
}
return lines;
}
size_t Serial::write(const string & data)
{
ScopedWriteLock lock(this->pimpl_);
return this->write_(reinterpret_cast<const uint8_t *>(data.c_str()), data.length());
}
size_t Serial::write(const std::vector<uint8_t> & data)
{
ScopedWriteLock lock(this->pimpl_);
return this->write_(&data[0], data.size());
}
size_t Serial::write(const uint8_t * data, size_t size)
{
ScopedWriteLock lock(this->pimpl_);
return this->write_(data, size);
}
size_t Serial::write_(const uint8_t * data, size_t length) { return pimpl_->write(data, length); }
void Serial::setPort(const string & port)
{
ScopedReadLock rlock(this->pimpl_);
ScopedWriteLock wlock(this->pimpl_);
bool was_open = pimpl_->isOpen();
if (was_open) close();
pimpl_->setPort(port);
if (was_open) open();
}
string Serial::getPort() const { return pimpl_->getPort(); }
void Serial::setTimeout(serial::Timeout & timeout) { pimpl_->setTimeout(timeout); }
serial::Timeout Serial::getTimeout() const { return pimpl_->getTimeout(); }
void Serial::setBaudrate(uint32_t baudrate) { pimpl_->setBaudrate(baudrate); }
uint32_t Serial::getBaudrate() const { return uint32_t(pimpl_->getBaudrate()); }
void Serial::setBytesize(bytesize_t bytesize) { pimpl_->setBytesize(bytesize); }
bytesize_t Serial::getBytesize() const { return pimpl_->getBytesize(); }
void Serial::setParity(parity_t parity) { pimpl_->setParity(parity); }
parity_t Serial::getParity() const { return pimpl_->getParity(); }
void Serial::setStopbits(stopbits_t stopbits) { pimpl_->setStopbits(stopbits); }
stopbits_t Serial::getStopbits() const { return pimpl_->getStopbits(); }
void Serial::setFlowcontrol(flowcontrol_t flowcontrol) { pimpl_->setFlowcontrol(flowcontrol); }
flowcontrol_t Serial::getFlowcontrol() const { return pimpl_->getFlowcontrol(); }
void Serial::flush()
{
ScopedReadLock rlock(this->pimpl_);
ScopedWriteLock wlock(this->pimpl_);
pimpl_->flush();
}
void Serial::flushInput()
{
ScopedReadLock lock(this->pimpl_);
pimpl_->flushInput();
}
void Serial::flushOutput()
{
ScopedWriteLock lock(this->pimpl_);
pimpl_->flushOutput();
}
void Serial::sendBreak(int duration) { pimpl_->sendBreak(duration); }
void Serial::setBreak(bool level) { pimpl_->setBreak(level); }
void Serial::setRTS(bool level) { pimpl_->setRTS(level); }
void Serial::setDTR(bool level) { pimpl_->setDTR(level); }
bool Serial::waitForChange() { return pimpl_->waitForChange(); }
bool Serial::getCTS() { return pimpl_->getCTS(); }
bool Serial::getDSR() { return pimpl_->getDSR(); }
bool Serial::getRI() { return pimpl_->getRI(); }
bool Serial::getCD() { return pimpl_->getCD(); }

159
io/socketcan.hpp Normal file
View File

@ -0,0 +1,159 @@
#ifndef IO__SOCKETCAN_HPP
#define IO__SOCKETCAN_HPP
#include <linux/can.h>
#include <net/if.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <chrono>
#include <cstring>
#include <functional>
#include <stdexcept>
#include <thread>
#include "tools/logger.hpp"
using namespace std::chrono_literals;
constexpr int MAX_EVENTS = 10;
namespace io
{
class SocketCAN
{
public:
SocketCAN(const std::string & interface, std::function<void(const can_frame & frame)> rx_handler)
: interface_(interface),
socket_fd_(-1),
epoll_fd_(-1),
rx_handler_(rx_handler),
quit_(false),
ok_(false)
{
try_open();
// 守护线程
daemon_thread_ = std::thread{[this] {
while (!quit_) {
std::this_thread::sleep_for(100ms);
if (ok_) continue;
if (read_thread_.joinable()) read_thread_.join();
close();
try_open();
}
}};
}
~SocketCAN()
{
quit_ = true;
if (daemon_thread_.joinable()) daemon_thread_.join();
if (read_thread_.joinable()) read_thread_.join();
close();
tools::logger()->info("SocketCAN destructed.");
}
void write(can_frame * frame) const
{
if (::write(socket_fd_, frame, sizeof(can_frame)) == -1)
throw std::runtime_error("Unable to write!");
}
private:
std::string interface_;
int socket_fd_;
int epoll_fd_;
bool quit_;
bool ok_;
std::thread read_thread_;
std::thread daemon_thread_;
can_frame frame_;
epoll_event events_[MAX_EVENTS];
std::function<void(const can_frame & frame)> rx_handler_;
void open()
{
socket_fd_ = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (socket_fd_ < 0) throw std::runtime_error("Error opening socket!");
ifreq ifr;
std::strncpy(ifr.ifr_name, interface_.c_str(), IFNAMSIZ - 1);
if (ioctl(socket_fd_, SIOCGIFINDEX, &ifr) < 0)
throw std::runtime_error("Error getting interface index!");
sockaddr_can addr;
std::memset(&addr, 0, sizeof(sockaddr_can));
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(socket_fd_, (sockaddr *)&addr, sizeof(sockaddr_can)) < 0) {
::close(socket_fd_);
throw std::runtime_error("Error binding socket to interface!");
}
epoll_event ev;
epoll_fd_ = epoll_create1(0);
if (epoll_fd_ == -1) throw std::runtime_error("Error creating epoll file descriptor!");
ev.events = EPOLLIN;
ev.data.fd = socket_fd_;
if (epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, ev.data.fd, &ev))
throw std::runtime_error("Error adding socket to epoll file descriptor!");
// 接收线程
read_thread_ = std::thread([this]() {
ok_ = true;
while (!quit_) {
std::this_thread::sleep_for(10us);
try {
read();
} catch (const std::exception & e) {
tools::logger()->warn("SocketCAN::read() failed: {}", e.what());
ok_ = false;
break;
}
}
});
tools::logger()->info("SocketCAN opened.");
}
void try_open()
{
try {
open();
} catch (const std::exception & e) {
tools::logger()->warn("SocketCAN::open() failed: {}", e.what());
}
}
void read()
{
int num_events = epoll_wait(epoll_fd_, events_, MAX_EVENTS, 2);
if (num_events == -1) throw std::runtime_error("Error wating for events!");
for (int i = 0; i < num_events; i++) {
ssize_t num_bytes = recv(socket_fd_, &frame_, sizeof(can_frame), MSG_DONTWAIT);
if (num_bytes == -1) throw std::runtime_error("Error reading from SocketCAN!");
rx_handler_(frame_);
}
}
void close()
{
if (socket_fd_ == -1) return;
epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, socket_fd_, NULL);
::close(epoll_fd_);
::close(socket_fd_);
}
};
} // namespace io
#endif // IO__SOCKETCAN_HPP

174
io/usbcamera/usbcamera.cpp Normal file
View File

@ -0,0 +1,174 @@
#include "usbcamera.hpp"
#include <stdexcept>
#include "tools/logger.hpp"
#include "tools/yaml.hpp"
using namespace std::chrono_literals;
namespace io
{
USBCamera::USBCamera(const std::string & open_name, const std::string & config_path)
: open_name_(open_name), quit_(false), ok_(false), queue_(1), open_count_(0)
{
auto yaml = tools::load(config_path);
image_width_ = tools::read<double>(yaml, "image_width");
image_height_ = tools::read<double>(yaml, "image_height");
usb_exposure_ = tools::read<double>(yaml, "usb_exposure");
usb_frame_rate_ = tools::read<double>(yaml, "usb_frame_rate");
usb_gamma_ = tools::read<double>(yaml, "usb_gamma");
usb_gain_ = tools::read<double>(yaml, "usb_gain");
try_open();
// 守护线程
daemon_thread_ = std::thread{[this] {
// tools::logger()->info("daemon thread start");
while (!quit_) {
std::this_thread::sleep_for(100ms);
if (ok_) continue;
if (open_count_ > 20) {
tools::logger()->warn("Give up to open {} USB camera", this->device_name);
quit_ = true;
{
std::lock_guard<std::mutex> lock(cap_mutex_);
close(); // 先关闭摄像头
}
if (capture_thread_.joinable()) {
tools::logger()->warn("Stopping capture thread");
capture_thread_.join();
}
break;
}
if (capture_thread_.joinable()) capture_thread_.join();
{
std::lock_guard<std::mutex> lock(cap_mutex_);
close();
}
try_open();
}
// tools::logger()->info("daemon thread exit");
}};
}
USBCamera::~USBCamera()
{
quit_ = true;
{
std::lock_guard<std::mutex> lock(cap_mutex_);
close();
}
if (daemon_thread_.joinable()) daemon_thread_.join();
if (capture_thread_.joinable()) capture_thread_.join();
tools::logger()->info("USBCamera destructed.");
}
cv::Mat USBCamera::read()
{
std::lock_guard<std::mutex> lock(cap_mutex_);
if (!cap_.isOpened()) {
tools::logger()->warn("Failed to read {} USB camera", this->device_name);
return cv::Mat();
}
cap_ >> img_;
return img_;
}
void USBCamera::read(cv::Mat & img, std::chrono::steady_clock::time_point & timestamp)
{
CameraData data;
queue_.pop(data);
img = data.img;
timestamp = data.timestamp;
}
void USBCamera::open()
{
std::lock_guard<std::mutex> lock(cap_mutex_);
std::string true_device_name = "/dev/" + open_name_;
cap_.open(true_device_name, cv::CAP_V4L);
if (!cap_.isOpened()) {
tools::logger()->warn("Failed to open USB camera");
return;
}
sharpness_ = cap_.get(cv::CAP_PROP_SHARPNESS);
cap_.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G'));
cap_.set(cv::CAP_PROP_FPS, usb_frame_rate_);
cap_.set(cv::CAP_PROP_AUTO_EXPOSURE, 1);
cap_.set(cv::CAP_PROP_GAMMA, usb_gamma_);
cap_.set(cv::CAP_PROP_GAIN, usb_gain_);
if (sharpness_ == 2) {
device_name = "left";
cap_.set(cv::CAP_PROP_FRAME_WIDTH, image_width_);
cap_.set(cv::CAP_PROP_FRAME_HEIGHT, image_height_);
cap_.set(cv::CAP_PROP_EXPOSURE, usb_exposure_);
} else if (sharpness_ == 3) {
device_name = "right";
cap_.set(cv::CAP_PROP_FRAME_WIDTH, image_width_);
cap_.set(cv::CAP_PROP_FRAME_HEIGHT, image_height_);
cap_.set(cv::CAP_PROP_EXPOSURE, usb_exposure_);
}
tools::logger()->info("{} USBCamera opened", device_name);
// tools::logger()->info("USBCamera exposure time:{}", cap_.get(cv::CAP_PROP_EXPOSURE));
tools::logger()->info("USBCamera fps:{}", cap_.get(cv::CAP_PROP_FPS));
// tools::logger()->info("USBCamera gamma:{}", cap_.get(cv::CAP_PROP_GAMMA));
// 取图线程
capture_thread_ = std::thread{[this] {
ok_ = true;
std::this_thread::sleep_for(50ms);
tools::logger()->info("[{} USB camera] capture thread started ", this->device_name);
while (!quit_) {
std::this_thread::sleep_for(1ms);
cv::Mat img;
bool success;
{
std::lock_guard<std::mutex> lock(cap_mutex_);
if (!cap_.isOpened()) {
break;
}
success = cap_.read(img);
}
if (!success) {
tools::logger()->warn("Failed to read frame, exiting capture thread");
break;
}
auto timestamp = std::chrono::steady_clock::now();
queue_.push({img, timestamp});
}
ok_ = false;
}};
}
void USBCamera::try_open()
{
try {
open();
open_count_++;
} catch (const std::exception & e) {
tools::logger()->warn("{}", e.what());
}
}
void USBCamera::close()
{
if (cap_.isOpened()) {
cap_.release();
tools::logger()->info("USB camera released.");
}
}
} // namespace io

View File

@ -0,0 +1,49 @@
#ifndef IO__USBCamera_HPP
#define IO__USBCamera_HPP
#include <chrono>
#include <iostream>
#include <opencv2/opencv.hpp>
#include <thread>
#include "tools/thread_safe_queue.hpp"
namespace io
{
class USBCamera
{
public:
USBCamera(const std::string & open_name, const std::string & config_path);
~USBCamera();
cv::Mat read();
void read(cv::Mat & img, std::chrono::steady_clock::time_point & timestamp);
std::string device_name;
private:
struct CameraData
{
cv::Mat img;
std::chrono::steady_clock::time_point timestamp;
};
std::mutex cap_mutex_;
cv::VideoCapture cap_;
cv::Mat img_;
std::string open_name_;
int usb_exposure_, usb_frame_rate_, sharpness_;
int open_count_;
double image_width_, image_height_;
int usb_gamma_, usb_gain_;
bool quit_, ok_;
std::thread capture_thread_;
std::thread daemon_thread_;
tools::ThreadSafeQueue<CameraData> queue_;
void try_open();
void open();
void close();
};
} // namespace io
#endif

111
mpc_layout.xml Normal file
View File

@ -0,0 +1,111 @@
<?xml version='1.0' encoding='UTF-8'?>
<root>
<tabbed_widget parent="main_window" name="Main Window">
<Tab tab_name="tab2" containers="1">
<Container>
<DockSplitter sizes="0.333712;0.332577;0.333712" count="3" orientation="-">
<DockArea name="...">
<plot flip_y="false" mode="TimeSeries" flip_x="false" style="Lines">
<range left="2.850229" right="7.848447" bottom="-0.085876" top="0.079715"/>
<limitY/>
<curve color="#17becf" name="/ref_yaw"/>
<curve color="#d62728" name="/gimbal_yaw"/>
</plot>
</DockArea>
<DockArea name="...">
<plot flip_y="false" mode="TimeSeries" flip_x="false" style="Lines">
<range left="2.850229" right="7.848447" bottom="-7.433146" top="0.951805"/>
<limitY/>
<curve color="#bcbd22" name="/ref_vyaw"/>
<curve color="#1f77b4" name="/gimbal_vyaw"/>
</plot>
</DockArea>
<DockArea name="...">
<plot flip_y="false" mode="TimeSeries" flip_x="false" style="Lines">
<range left="2.850229" right="7.848447" bottom="-11.155253" top="9.237359"/>
<limitY/>
<curve color="#1ac938" name="/torque_yaw"/>
<curve color="#ff7f0e" name="/control"/>
</plot>
</DockArea>
</DockSplitter>
</Container>
</Tab>
<Tab tab_name="tab3" containers="1">
<Container>
<DockSplitter sizes="0.333712;0.332577;0.333712" count="3" orientation="-">
<DockArea name="...">
<plot flip_y="false" mode="TimeSeries" flip_x="false" style="Lines">
<range left="2.850229" right="7.848447" bottom="-0.080032" top="-0.014399"/>
<limitY/>
<curve color="#f14cc1" name="/ref_pitch"/>
<curve color="#1f77b4" name="/gimbal_pitch"/>
</plot>
</DockArea>
<DockArea name="...">
<plot flip_y="false" mode="TimeSeries" flip_x="false" style="Lines">
<range left="2.850229" right="7.848447" bottom="-2.829070" top="2.829055"/>
<limitY/>
<curve color="#9467bd" name="/ref_vpitch"/>
<curve color="#bcbd22" name="/gimbal_vpitch"/>
</plot>
</DockArea>
<DockArea name="...">
<plot flip_y="false" mode="TimeSeries" flip_x="false" style="Lines">
<range left="2.850229" right="7.848447" bottom="-2.517863" top="2.508088"/>
<limitY/>
<curve color="#17becf" name="/torque_pitch"/>
</plot>
</DockArea>
</DockSplitter>
</Container>
</Tab>
<currentTabIndex index="0"/>
</tabbed_widget>
<use_relative_time_offset enabled="1"/>
<!-- - - - - - - - - - - - - - - -->
<!-- - - - - - - - - - - - - - - -->
<Plugins>
<plugin ID="DataLoad CSV">
<parameters delimiter="0" time_axis=""/>
</plugin>
<plugin ID="DataLoad MCAP"/>
<plugin ID="DataLoad ROS2 bags">
<use_header_stamp value="false"/>
<discard_large_arrays value="true"/>
<max_array_size value="100"/>
<boolean_strings_to_number value="true"/>
<remove_suffix_from_strings value="true"/>
<selected_topics value=""/>
</plugin>
<plugin ID="DataLoad ULog"/>
<plugin ID="MQTT Subscriber (Mosquitto)"/>
<plugin ID="ROS2 Topic Subscriber">
<use_header_stamp value="false"/>
<discard_large_arrays value="true"/>
<max_array_size value="100"/>
<boolean_strings_to_number value="true"/>
<remove_suffix_from_strings value="true"/>
<selected_topics value=""/>
</plugin>
<plugin ID="UDP Server"/>
<plugin ID="WebSocket Server"/>
<plugin ID="ZMQ Subscriber"/>
<plugin ID="Fast Fourier Transform"/>
<plugin ID="Quaternion to RPY"/>
<plugin ID="Reactive Script Editor">
<library code="--[[ Helper function to create a series from arrays&#xa;&#xa; new_series: a series previously created with ScatterXY.new(name)&#xa; prefix: prefix of the timeseries, before the index of the array&#xa; suffix_X: suffix to complete the name of the series containing the X value. If [nil], use the index of the array.&#xa; suffix_Y: suffix to complete the name of the series containing the Y value&#xa; timestamp: usually the tracker_time variable&#xa; &#xa; Example:&#xa; &#xa; Assuming we have multiple series in the form:&#xa; &#xa; /trajectory/node.{X}/position/x&#xa; /trajectory/node.{X}/position/y&#xa; &#xa; where {N} is the index of the array (integer). We can create a reactive series from the array with:&#xa; &#xa; new_series = ScatterXY.new(&quot;my_trajectory&quot;) &#xa; CreateSeriesFromArray( new_series, &quot;/trajectory/node&quot;, &quot;position/x&quot;, &quot;position/y&quot;, tracker_time );&#xa;--]]&#xa;&#xa;function CreateSeriesFromArray( new_series, prefix, suffix_X, suffix_Y, timestamp )&#xa; &#xa; --- clear previous values&#xa; new_series:clear()&#xa; &#xa; --- Append points to new_series&#xa; index = 0&#xa; while(true) do&#xa;&#xa; x = index;&#xa; -- if not nil, get the X coordinate from a series&#xa; if suffix_X ~= nil then &#xa; series_x = TimeseriesView.find( string.format( &quot;%s.%d/%s&quot;, prefix, index, suffix_X) )&#xa; if series_x == nil then break end&#xa; x = series_x:atTime(timestamp)&#x9; &#xa; end&#xa; &#xa; series_y = TimeseriesView.find( string.format( &quot;%s.%d/%s&quot;, prefix, index, suffix_Y) )&#xa; if series_y == nil then break end &#xa; y = series_y:atTime(timestamp)&#xa; &#xa; new_series:push_back(x,y)&#xa; index = index+1&#xa; end&#xa;end&#xa;&#xa;--[[ Similar to the built-in function GetSeriesNames(), but select only the names with a give prefix. --]]&#xa;&#xa;function GetSeriesNamesByPrefix(prefix)&#xa; -- GetSeriesNames(9 is a built-in function&#xa; all_names = GetSeriesNames()&#xa; filtered_names = {}&#xa; for i, name in ipairs(all_names) do&#xa; -- check the prefix&#xa; if name:find(prefix, 1, #prefix) then&#xa; table.insert(filtered_names, name);&#xa; end&#xa; end&#xa; return filtered_names&#xa;end&#xa;&#xa;--[[ Modify an existing series, applying offsets to all their X and Y values&#xa;&#xa; series: an existing timeseries, obtained with TimeseriesView.find(name)&#xa; delta_x: offset to apply to each x value&#xa; delta_y: offset to apply to each y value &#xa; &#xa;--]]&#xa;&#xa;function ApplyOffsetInPlace(series, delta_x, delta_y)&#xa; -- use C++ indeces, not Lua indeces&#xa; for index=0, series:size()-1 do&#xa; x,y = series:at(index)&#xa; series:set(index, x + delta_x, y + delta_y)&#xa; end&#xa;end&#xa;"/>
<scripts/>
</plugin>
<plugin ID="CSV Exporter"/>
<plugin ID="ROS2 Topic Re-Publisher"/>
</Plugins>
<!-- - - - - - - - - - - - - - - -->
<previouslyLoaded_Datafiles/>
<previouslyLoaded_Streamer name="UDP Server"/>
<!-- - - - - - - - - - - - - - - -->
<customMathEquations/>
<snippets/>
<!-- - - - - - - - - - - - - - - -->
</root>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

7
neo/ww09.sum Normal file
View File

@ -0,0 +1,7 @@
4612de24099fd2f7d5e045a836efb4dbabba1166bb27d68dd8f5b48ec93e410c intel-igc-core_1.0.13463.18_amd64.deb
bfde6a612a260b158210b99ff1fcb7870e4304620c0a997bc40aef6c54f4fdec intel-igc-opencl_1.0.13463.18_amd64.deb
020b604f7768a7b9af3d97001d237ba56b5db5cc281a017a2f6d5c56e34fca60 intel-level-zero-gpu-dbgsym_1.3.25812.14_amd64.ddeb
1a7b533a11fe21146964bfaba99276dc35a387897619c26a750cb8d735043b38 intel-level-zero-gpu_1.3.25812.14_amd64.deb
65bd286bcf379eaaf4e375007713129c46d3ce393048d79f87671416f07b36c8 intel-opencl-icd-dbgsym_23.09.25812.14_amd64.ddeb
a1c23ceabe4db028ba2f1ae1a5dfc79b0a52a2e29215b6098e9d998664944f47 intel-opencl-icd_23.09.25812.14_amd64.deb
de6ed9333a74506de43993eb14c8e0e0eb23314c42b03af66fe9c3df24a8973d libigdgmm12_22.3.0_amd64.deb

351
readme.md Normal file
View File

@ -0,0 +1,351 @@
# 同济大学SuperPower战队25赛季自瞄算法开源
## 本项目亮点
- 无ROS依赖*新同学无需学习ROS相关知识就能上手自瞄。
- 完整工作流,包含开发、编译、调试、部署全流程。
- 模块化架构,包含各模块的功能说明、代码实现、以及独立的测试程序。
- 我们提出了“轨迹视角下的自瞄理论”并据此设计了“自瞄轨迹规划算法”。相比传统自瞄决策算法该算法实现更简洁、调试更方便、效果更好击杀时间仅需10s300HP14rad/s2m。该理论也为后续自瞄技术的改进提供了方向。
*为实现哨兵“追击”功能本项目预留了与导航通信的ROS接口。
## 1 功能介绍
自瞄的定义和意义。我们对自瞄的定义为“针对移动装甲板目标的自动瞄准和自动火控软件”。当操作手切换成自瞄模式后,自瞄会接管云台的控制权,通过对敌方运动轨迹的预测和弹道解算,控制云台进行追踪;同时,自瞄还会接管发射机构的控制权,判断开火时机。自瞄的意义在于提高我方作战能力,实现短击杀时间、高命中率的作战效果。
自瞄的模块组成。经过多年的发展大部份参赛队伍都具备了自瞄的能力。通过和一些队伍的交流目前各队的自瞄类似于如图1.1所示的模块划分。装甲板识别器和目标状态估计器作为“感知模块”,提供敌方运动信息。决策器根据上述信息,进行瞄准位置的计算和开火判断,并最终交由控制器进行执行。
![自瞄模块划分](https://github.com/user-attachments/assets/0e3e960e-0bf0-430a-95f5-d0803d1a6ade)
图1.1 自瞄模块划分
自瞄是分布式软件。识别器、估计器、决策器由于算法较为复杂,一般运行在算力较高的小电脑上;出于对实时性和稳定性的考量,控制器一般运行在嵌入式单片机上。模块划分解耦了视觉组和电控组的职责,明确了分工,提高了开发效率。
本项目包含了本队自瞄相关的视觉组部分的全部代码,包括但不限于:多线程相机驱动程序、电控通信协议和具体实现、图像-四元数对齐算法、相机内参标定和手眼标定程序、装甲板识别算法含传统、神经网络多种实现、装甲板位姿解算、坐标变换和yaw优化算法、基于拓展卡尔曼的整车估计器、瞄准位置和开火决策逻辑、以及各模块独立测试程序等。
本项目建立在往年[sp_vision_23](https://github.com/TongjiSuperPower/sp_vision_23)、[sp_vision_24](https://github.com/TongjiSuperPower/sp_vision_24)项目的基础之上。其中sp_vision_23完全基于Python开发跑通了自瞄从识别到射击的完整流程因其运行效率不佳在导航运行时帧率仅60FPSsp_vision_24采用C++重写帧率约100FPS并且具备参数文件加载、日志记录、离线检测与重启、类似rosbag时间戳+视频+四元数)录制等辅助功能,以及各个模块的独立测试程序,实现“赛前问题排查、赛后问题重现”的能力,保证了自瞄的可靠性和稳定性。
本项目在上述基础上改进了识别器和决策器。其中,识别器由传统的图像处理方案更换为其它战队开源的基于神经网络的四点检测模型[1,2],以期提高识别器的召回能力。而决策器则由基于经验主义的分段决策逻辑改为基于轨迹优化的规划器,简化代码的同时,实现了更优的云台控制效果和开火决策逻辑,其思路会在后文详细介绍。
## 2 效果展示
轨迹跟随效果。本项目创新性采用“自瞄轨迹规划算法”降低控制难度的同时提升轨迹跟随效果。如图2.1所示跟随单块装甲板时稳态误差小于0.01rad,装甲板切换时,具备提前减速的能力。
![轨迹跟随效果](https://github.com/user-attachments/assets/ac65ab13-bc2c-45c0-9c06-613442fc104d)
图2.1 轨迹跟随效果5rad/s3m
调试场景演示。本项目容易上手对新人友好。如视频2.1所示我们通过无线局域网或插网线方式使用NoMachine远程桌面软件连接机器人搭载的小电脑配合PlotJuggler曲线图绘制软件显示调试时常用的数据信息如云台yaw关节执行情况、开火决策、击打目标的角速度等。
https://github.com/user-attachments/assets/606c2907-2f11-4392-b3fe-7ee4b7b6fd29
视频2.1 调试场景演示
量化指标统计。如图2.2所示在25赛季国赛赛场上搭载本算法的3、4号步兵的最高命中率为39.6%发挥正常时命中率不低于30%。除了命中率我们还统计了击杀时间面对2m处300血的敌方步兵7rad/s转速下耗时约8s14rad/s转速下耗时约10s。
![国赛MVP结算数据](https://github.com/user-attachments/assets/4e17085d-3bc8-422e-b0df-b0fbe6e4c934)
图2.2 国赛MVP结算数据
## 3 详细信息
### 3.1 项目环境
操作系统Ubuntu 22.04\
运算平台NUC12WSKI7i7-1260P16GB\
相机型号海康MV-CS016-10UC\
镜头型号海康官方6mm镜头\
下位机型号RoboMaster开发板C型STM32F407\
IMU型号使用C板内置BMI088作为IMU\
通信方式USB2CAN、MicroUSB虚拟串口\
辅助工具NoMachine远程桌面、PlotJuggler绘制曲线图
### 3.2 编译方式
1. 安装依赖项:
- [MindVision SDK](https://mindvision.com.cn/category/software/sdk-installation-package/)或[HikRobot SDK](https://www.hikrobotics.com/cn2/source/support/software/MVS_STD_GML_V2.1.2_231116.zip)
- [OpenVINO](https://docs.openvino.ai/2024/get-started/install-openvino/install-openvino-archive-linux.html)
- [Ceres](http://ceres-solver.org/installation.html)
- 其余:
```bash
sudo apt install -y \
git \
g++ \
cmake \
can-utils \
libopencv-dev \
libfmt-dev \
libeigen3-dev \
libspdlog-dev \
libyaml-cpp-dev \
libusb-1.0-0-dev \
nlohmann-json3-dev \
openssh-server \
screen
```
2. 编译:
```bash
cmake -B build
make -C build/ -j`nproc`
```
3. 运行demo:
```bash
./build/auto_aim_test
```
4. 注册自启:
1. 确保已安装`screen`:
```
sudo apt install screen
```
2. 创建`.desktop`文件:
```
mkdir ~/.config/autostart/
touch ~/.config/autostart/sp_vision.desktop
```
3. 在该文件中写入:
```
[Desktop Entry]
Type=Application
Exec=/home/rm/Desktop/sp_vision_25/autostart.sh
Name=sp_vision
```
注: [Exec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html)必须为绝对路径.
4. 确保`autostart.sh`有可执行权限:
```
chmod +x autostart.sh
```
5. USB2CAN设置可选
1. 创建`.rules`文件:
```
sudo touch /etc/udev/rules.d/99-can-up.rules
```
2. 在该文件中写入:
```
ACTION=="add", KERNEL=="can0", RUN+="/sbin/ip link set can0 up type can bitrate 1000000"
ACTION=="add", KERNEL=="can1", RUN+="/sbin/ip link set can1 up type can bitrate 1000000"
6. 使用GPU推理可选
```
mkdir neo
cd neo
wget https://github.com/intel/intel-graphics-compiler/releases/download/igc-1.0.13463.18/intel-igc-core_1.0.13463.18_amd64.deb
wget https://github.com/intel/intel-graphics-compiler/releases/download/igc-1.0.13463.18/intel-igc-opencl_1.0.13463.18_amd64.deb
wget https://github.com/intel/compute-runtime/releases/download/23.09.25812.14/intel-level-zero-gpu-dbgsym_1.3.25812.14_amd64.ddeb
wget https://github.com/intel/compute-runtime/releases/download/23.09.25812.14/intel-level-zero-gpu_1.3.25812.14_amd64.deb
wget https://github.com/intel/compute-runtime/releases/download/23.09.25812.14/intel-opencl-icd-dbgsym_23.09.25812.14_amd64.ddeb
wget https://github.com/intel/compute-runtime/releases/download/23.09.25812.14/intel-opencl-icd_23.09.25812.14_amd64.deb
wget https://github.com/intel/compute-runtime/releases/download/23.09.25812.14/libigdgmm12_22.3.0_amd64.deb
wget https://github.com/intel/compute-runtime/releases/download/23.09.25812.14/ww09.sum
sha256sum -c ww09.sum
sudo dpkg -i *.deb
```
注:如果使用 GPU 异步推理async-infer最高显示分辨率限制为 1920×1080 (24Hz)
7. 串口设置
1. 授予权限
```
sudo usermod -a -G dialout $USER
```
2. 获取端口 IDserial, idVendor, idProduct
```
udevadm info -a -n /dev/ttyACM0 | grep -E '({serial}|{idVendor}|{idProduct})'
```
将 /dev/ttyACM0 替换为实际设备名。
3. 创建 udev 规则文件
```
sudo touch /etc/udev/rules.d/99-usb-serial.rules
```
然后在文件中写入如下内容(用真实 ID 替换示例SYMLINK 是规则应用后固定的串口名):
```
SUBSYSTEM=="tty", ATTRS{idVendor}=="1234", ATTRS{idProduct}=="1234", ATTRS{serial}=="A1234567", SYMLINK+="gimbal"
```
4. 重新加载 udev 规则
```
sudo udevadm control --reload-rules
sudo udevadm trigger
```
5. 检查结果
```
ls -l /dev/gimbal
# Expected output (example):
# lrwxrwxrwx 1 root root 7 Jul 21 10:00 /dev/gimbal -> ttyACM0
```
### 3.3 数据流图
视觉相关模块如图3.1所示。其中,相机线程产生图像、时间戳,通过下位机线程获取对应的云台姿态四元数;图像经过识别器,获得装甲板的四个顶点像素坐标,以及其图案类别;估计器根据装甲板信息,获得目标单位的运动状态;决策器则根据当前的目标运动状态信息,预测目标的运动轨迹,从而判断最佳瞄准位置和最佳开火时机,形成指令发送给下位机;最后控制器和执行机构则根据该指令进行执行,从而完成一个完整的自瞄流程。
![数据流图](https://github.com/user-attachments/assets/b89ce42f-a769-49c5-b82a-d69aeac02925)
图3.1 数据流图
### 3.4 软件架构
各兵种需要实现的功能往往有多个,但是每个功能不能作为独立的程序。例如步兵需要自瞄和打符,显然,这两个功能都需要从相机获取图像,但是相机只能被一个程序打开,这会导致另一个程序无法正常工作(相机被占用)。
为了解决这个问题我们提出了视觉框架sp_vision自瞄、打符等功能被拆解为该框架下的一个个功能组每个功能组包含多个类或函数如识别器、解算器、预测器等等而运行的程序main函数只有一个它负责从相机获取图像再根据电控发来的信号自瞄档or打符档选择对应的功能组执行不同兵种的执行逻辑各不相同即不同的main函数。此外为了方便大家合作开发视觉框架还提供了许多常用的工具函数减少因重复造轮子所导致的出错概率和时间成本。本框架的组成如图3.2所示。
![软件架构](https://github.com/user-attachments/assets/2603a3b3-ae1d-4fa8-afbb-490efde30d77)
图3.2 软件架构
### 3.5 文件结构
```
sp_vision_25
├── assets // 包含demo素材、网络权重等
│   └── ...
├── calibration // 标定相关程序
│   ├── calibrate_camera.cpp // 相机内参标定程序
│   ├── calibrate_handeye.cpp // 手眼标定程序
│   ├── calibrate_robotworld_handeye.cpp // 手眼标定程序(同时计算标定板位置)
│   └── capture.cpp // 相机标定数据采集程序
├── CMakeLists.txt // CMake配置文件
├── configs // 每台机器人的YAML配置文件
│   └── ...
├── io // 硬件抽象层见3.4软件架构
│   └── ...
├── src // 应用层见3.4软件架构
│   └── ...
├── tasks // 功能层见3.4软件架构
│   ├── auto_aim // 自瞄相关算法实现
│   │   └── ...
│   ├── auto_buff // 打符相关算法实现
│   │   └── ...
│   └── omniperception // 全向感知相关算法实现
│   │   └── ...
├── tests
│   ├── auto_aim_test.cpp // 自瞄录制视频测试程序
│   ├── auto_buff_test.cpp // 打符录制视频测试程序
│   ├── camera_detect_test.cpp // 识别器测试程序(工业相机)
│   ├── camera_test.cpp // 相机测试程序
│   ├── camera_thread_test.cpp // 相机线程测试程序
│   ├── cboard_test.cpp // C板测试程序
│   ├── detector_video_test.cpp // 识别器测试程序(视频)
│   ├── dm_test.cpp // 达妙IMU测试程序
│   ├── fire_test.cpp // 开火测试程序
│   ├── gimbal_response_test.cpp // 云台响应测试程序
│   ├── gimbal_test.cpp // 云台通信测试程序
│   ├── handeye_test.cpp // 手眼标定测试程序
│   ├── minimum_vision_system.cpp // 最小视觉系统测试程序
│   ├── multi_usbcamera_test.cpp // 多USB摄像头测试程序
│   ├── planner_test_offline.cpp // 规划器测试程序(离线)
│   ├── planner_test.cpp // 规划器测试程序(实车)
│   ├── publish_test.cpp // ROS发送测试程序
│   ├── subscribe_test.cpp // ROS接收测试程序
│   ├── topic_loop_test.cpp // ROS话题循环测试程序
│   ├── usbcamera_detect_test.cpp // 识别器测试程序USB相机
│   ├── usbcamera_test.cpp // USB相机测试程序
│   └── ...
└── tools // 工具层见3.4软件架构
├── crc.hpp // CRC校验
├── exiter.hpp // 退出检测
├── extended_kalman_filter.hpp // 扩展卡尔曼滤波器
├── img_tools.hpp // 图像处理工具
├── logger.hpp // 日志记录器
├── math_tools.hpp // 数学工具
├── plotter.hpp // 曲线图绘制工具
├── recorder.hpp // 视频录制器
├── thread_safe_queue.hpp // 线程安全队列
├── trajectory.hpp // 弹道解算
├── yaml.hpp // YAML配置文件解析器
└── ...
```
## 4 轨迹视角下的自瞄理论
### 4.1 引言
在自瞄的研发和测试过程中,我们发现决策器和控制器是目前的短板。
决策器实现繁琐。不同兵种、不同敌方移动状态(平移、低速小陀螺、高速小陀螺)需要不同的“自瞄行为”,例如:英雄只瞄准旋转中心位置,根据时间误差判断是否开火;平移和低速时,步兵的瞄准位置则持续跟随敌方装甲板移动,同时依据位置误差判断是否开火,而高速时则退化为类似英雄的情况。不同的自瞄行为需要不同的代码实现,而且需要设计不同的判断条件,这一方面提高了代码维护的成本,另一方面也引入额外参数,增大了调试的负担。
控制调参困难。传统控制指标的输入一般为阶跃或斜坡函数,而自瞄控制器的输入更类似于三角波,且周期和幅值随敌方运动状态变化而变化,我们无法找到合适的理论将二者联系起来,因此调参过程中更依赖于经验猜测而不是理论指导。此外,我们无法判断云台的控制效果上限在哪里,甚至对于其影响因素都缺乏充分的认识。这导致电控调参十分“坐牢”,调试一台机器人需要消耗大量时间和资源,并且调试后的机器人表现效果参差不齐。
因此,我们希望能够找到一个“理论”,统一不同决策逻辑、精简代码,同时提高我们对于自瞄以及控制的认识,指导我们更加高效、可靠地调试自瞄,最终提高整体的自瞄效果。
### 4.2 前置概念
命中率。命中率越高,意味着所发射的子弹中命中装甲板的数量越多,造成的伤害越高,是用来衡量自瞄效果最常见的指标。然而,“不谈射频的命中率是没有意义的”[3],因为如果自瞄只在最有把握的时候射击,只要时间足够长,早晚能打死对面,所以除了命中率还需要考虑击杀时间。
击杀时间。击杀时间衡量了打死敌方单位所需的时间,是衡量自瞄好坏的“金标准”:一方面,装甲板击打检测和发射机构射频均存在上限,杜绝了依靠超高射频刷击杀时间的可行性;另一方面,该指标便于测量,仅需要秒表和靶机即可,比赛时也可以通过回放视频来快速估算。在测量该指标时,需要控制敌方血量、距离和运动状态等变量,这样才能保证时间的可比较性。
目标运动状态。目标运动状态由估计器计算得出,用于决策器预测目标在一段时间后的位置。目前主流的估计算法为基于扩展卡尔曼滤波的整车估计器[3,4]其定义的目标运动状态包括目标旋转中心位置、速度、yaw旋转角度、yaw旋转角速度、各装甲板半径和高度差根据这些信息决策器可以计算出每个装甲板的位置并在其中选择击打目标。为了方便后续的论述这里有两点假设假设一估计器是完美的无需考虑估计导致的误差假设二目标处于匀速运动状态从而无需考虑预测时因目标变速导致的误差。上述两点假设简化了自瞄使用场景的复杂性帮助我们专注于决策器的改进。
目标轨迹和云台轨迹。已知目标运动状态根据匀速运动公式可以计算任意时刻t下目标各装甲板位置选择距离云台最近的装甲板计算其相对于云台的方位角yaw得到函数yaw_target(t)记为目标轨迹。由于pitch计算方式类似这里的“轨迹”只讨论yaw。云台轨迹同理代表对应时刻云台相对于初始位置所呈的夹角yaw记为yaw_gimbal(t)。
射击轨迹。子弹出膛后需经过子弹飞行时间t_fly后到达装甲板将目标轨迹提前t_fly可获得射击轨迹
```math
yaw_{shoot}(t) = yaw_{target}(t + t_{fly})
```
如果t时刻云台角度yaw_gimbal和对应的射击角度yaw_shoot满足一定的误差范围半个装甲板则此时从枪管射出的子弹会命中装甲板。更进一步如果云台轨迹和射击轨迹重合则任意时刻从枪管射出的子弹均会命中装甲板“子弹发射如水流一样”[3]。如图4.1所示射击轨迹的瞄准位置是14ms后目标轨迹的位置。
![轨迹示意图](https://github.com/user-attachments/assets/80019e43-8cdc-47d1-98cd-dd8ae3d5e20b)
图4.1 轨迹示意图
### 4.3 什么是好自瞄
在轨迹视角下“云台轨迹”和“射击轨迹”重合度越高击杀时间越短。击杀时间反映了DPSDamage Per Second公式如下
```math
击杀时间 = \frac{血量}{DPS}
```
```math
DPS = 单位时间射击窗口占比 \times 射频 \times 单发子弹伤害
```
不难看出重合度越高单位时间射击窗口占比越高DPS越高击杀时间越短自瞄效果越好。
轨迹重合度和云台控制能力息息相关。云台最大加速度的高低决定了云台控制能力的好坏,云台能产生的瞬时加速度越大,跟随轨迹变化的能力越强,轨迹重合度越高。云台最大加速度计算公式如下:
```math
云台最大加速度 = \frac{云台电机最大扭矩}{云台惯量}
```
其中,云台电机最大扭矩一般由电机厂家给出,云台惯量通过系统辨识[5]得出。除了云台最大加速度,控制算法的设计也会影响最终的云台控制效果,为了尽可能降低控制难度,我们采取了多种措施:
1. 我们提出了“自瞄轨迹规划器”,根据云台最大加速度优化射击轨迹,使其更容易被云台跟随。
2. 我们计算了轨迹对应的速度和加速度,作为前馈量一并发送给电控,提高云台的响应。
3. 我们采用了计算力矩控制算法[6]其结合PID控制和动力学模型相比双环PID调参更加简便。
除了击杀时间,命中率也可以在轨迹视角下进行分析。我们可以将云台轨迹划分为“重合射击轨迹段”和“偏离射击轨迹段”,二者的比例决定了理论命中率上限:
```math
命中率 \le 重合度 = \frac{重合射击轨迹段}{(重合射击轨迹段 + 偏离射击轨迹段)}
```
云台在移动过程中,不可避免地会出现偏离射击轨迹的情况,当该情况发生时,应停止开火,减少弹丸的浪费,保证命中率。在自瞄轨迹规划器中,我们将上述情况作为开火决策的依据,在保证击杀时间的同时提高命中率。
击杀时间越短、命中率越高,自瞄效果越好。前者依赖良好的瞄准位置决策,后者则依赖良好的开火决策。我们从轨迹视角出发,用自瞄轨迹规划器替代传统自瞄决策器:通过考虑云台控制的能力,使得决策后的瞄准位置的更具可行性;通过考虑射击轨迹和规划后轨迹的偏差,结合开火延迟时间,使得开火决策更加简洁清晰,无需额外的分段参数,调试时更加方便。
### 4.4 轨迹规划器
轨迹突变问题和提前减速策略。小陀螺时装甲板会发生切换导致目标轨迹和射击轨迹突变不连续点处的瞬时速度和加速度未定义强行让控制算法跟随这样的轨迹会有明显的超调或滞后现象。针对轨迹突变问题轨迹规划器采取“提前减速策略”若未来一段时间后装甲板会发生切换则提前减速向下一个装甲板过渡使规划后轨迹的加速度小于云台最大加速度如图4.2所示。
![提前减速策略](https://github.com/user-attachments/assets/f3c60424-5ece-4eff-a14e-f30fd9ddd584)
图4.2 提前减速策略示意图
该策略的实现方式不止一种,我们尝试了两种方案:
1. 隐式搜索以规划后轨迹加速度序列为变量构造代价函数重合度尽可能高和约束条件不超过云台最大加速度将该问题转换为二次规划问题调用第三方库TinyMPC[7]求解。该库针对MPC问题的求解进行了加速优化实测求解耗时小于1ms。这里MPC并非闭环控制器而是作为求解器寻找可行轨迹解其输入不包含云台的实际状态。我们也尝试过使用MPC直接作为闭环控制器通过下位机转发MPC求解后的力矩指令给电机当自身小陀螺时控制效果不如下位机方案。
2. 显式搜索以过渡时间为变量确定切换点前后的起点和终点使用五次多项式生成过渡段轨迹调整时间长度直到满足加速度限制。该方案确定性高“跟随段”不会参与优化和射击轨迹重合在高转速下更加稳定。同时实现更加轻量无需依赖第三方库和QR矩阵等额外参数。
由于时间有限,方案二仅进行了仿真验证,未上车测试,国赛上场采用了方案一。
开火延迟问题和提前开火决策。从开火命令发送到子弹出膛摩擦轮掉速存在时间延迟t_fire仅考虑当前位置误差进行开火判断并不严谨。轨迹规划器会生成一段时间内的轨迹序列通过查询t_fire时刻射击轨迹和对应规划后轨迹的误差判断经过t_fire时间后子弹是否应该出膛从而实现更加精细的开火决策。该方案的前提是开火延迟无波动对机械和电控的要求较高。
预测时间偏移量。射击轨迹提前于目标轨迹的时间称为预测时间,预测时间除了子弹飞行时间外,还需考虑各个环节引入的时间延迟,包括:
- 图像传输延迟:图像时间戳对应接收完成的时刻,需要图像传输至小电脑的时间。
- 图像处理延迟:神经网络推理耗时无法忽略,需要考虑图像开始处理到形成决策命令的时间。
- 下位机通信延迟:向下位机传输决策命令所需的时间。
- 下位机控制延迟:控制云台到目标位置所需的时间。
这里不需要考虑开火延迟,因为在射击轨迹上任意时间发射均会命中[3]。在实际代码实现中,除了图像处理延迟可以直接计算外,我们把其余延迟时间的总和作为一个调试参数[8]通过拍摄慢动作视频、比较击杀时间等方式进行调整约15ms。
## 5 未来优化方向
将轨迹规划器部署到更多兵种上。由于时间有限,国赛中仅步兵使用了轨迹规划器。我们非常期待其在英雄(射频低)、哨兵(惯量大)、无人机(射频高)上的表现。
边跑边打。目前的自瞄并没有考虑自身的移动,无法边跑边打。在本赛季,步兵经常需要从狗洞冲下去杀对面静止的英雄,而此时自瞄会认为对面在移动,导致前几发打不准,限制了操作手的发挥。我们计划引入轮式里程计信息,改善在该场景下的表现。
## 参考文献
[1] Alan Day.【RM2024赛季-识别模型】深圳大学-RobotPilots[EB/OL]. RoboMaster论坛. https://bbs.robomaster.com/article/54091, 2025.
[2] gaoxin.【RM2024-识别训练网络及推理代码开源】北京科技大学Reborn[EB/OL]. RoboMaster论坛. https://bbs.robomaster.com/article/9655, 2024.
[3] 方俊杰. Linear Modelled Top Detector[EB/OL]. GitHub. https://github.com/julyfun/rm.cv.fans, 2023.
[4] 陈君. rm_vision[EB/OL]. GitHub. https://github.com/chenjunnn/rm_vision, 2023.
[5] 桂凯. 系统辨识心得分享[EB/OL]. 知乎. https://www.zhihu.com/question/57405191/answer/153098166, 2017.
[6] Lynch K M, Park F C. Modern Robotics: Mechanics, Planning, and Control[M]. Cambridge: Cambridge University Press, 2017.
[7] Nguyen K, Schoedel S, Alavilli A, et al. TinyMPC: Model-predictive control on resource-constrained microcontrollers[C]//2024 IEEE International Conference on Robotics and Automation (ICRA). IEEE, 2024: 1-7.
[8] 王洪玺, 计泽贤, 张兰勇. 基于卡尔曼滤波的目标识别跟踪与射击系统设计[J]. Journal of Ordnance Equipment Engineering, 2022, 43(11).
## 项目成员
王骁扬、杨佳轩、奚睿豪、俞选涛、吴圳楠、杨瑞灵、程翔宇
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=TongjiSuperPower/sp_vision_25&type=Date)](https://www.star-history.com/#TongjiSuperPower/sp_vision_25&Date)

0
src/.gitkeep Normal file
View File

150
src/auto_aim_debug_mpc.cpp Normal file
View File

@ -0,0 +1,150 @@
#include <fmt/core.h>
#include <atomic>
#include <chrono>
#include <nlohmann/json.hpp>
#include <opencv2/opencv.hpp>
#include <thread>
#include "io/camera.hpp"
#include "io/gimbal/gimbal.hpp"
#include "tasks/auto_aim/planner/planner.hpp"
#include "tasks/auto_aim/solver.hpp"
#include "tasks/auto_aim/tracker.hpp"
#include "tasks/auto_aim/yolo.hpp"
#include "tools/exiter.hpp"
#include "tools/img_tools.hpp"
#include "tools/logger.hpp"
#include "tools/math_tools.hpp"
#include "tools/plotter.hpp"
#include "tools/thread_safe_queue.hpp"
using namespace std::chrono_literals;
const std::string keys =
"{help h usage ? | | 输出命令行参数说明}"
"{@config-path | configs/sentry.yaml | 位置参数yaml配置文件路径 }";
int main(int argc, char * argv[])
{
tools::Exiter exiter;
tools::Plotter plotter;
cv::CommandLineParser cli(argc, argv, keys);
auto config_path = cli.get<std::string>(0);
if (cli.has("help") || config_path.empty()) {
cli.printMessage();
return 0;
}
io::Gimbal gimbal(config_path);
io::Camera camera(config_path);
auto_aim::YOLO yolo(config_path, true);
auto_aim::Solver solver(config_path);
auto_aim::Tracker tracker(config_path, solver);
auto_aim::Planner planner(config_path);
tools::ThreadSafeQueue<std::optional<auto_aim::Target>, true> target_queue(1);
target_queue.push(std::nullopt);
std::atomic<bool> quit = false;
auto plan_thread = std::thread([&]() {
auto t0 = std::chrono::steady_clock::now();
uint16_t last_bullet_count = 0;
while (!quit) {
auto target = target_queue.front();
auto gs = gimbal.state();
auto plan = planner.plan(target, gs.bullet_speed);
gimbal.send(
plan.control, plan.fire, plan.yaw, plan.yaw_vel, plan.yaw_acc, plan.pitch, plan.pitch_vel,
plan.pitch_acc);
auto fired = gs.bullet_count > last_bullet_count;
last_bullet_count = gs.bullet_count;
nlohmann::json data;
data["t"] = tools::delta_time(std::chrono::steady_clock::now(), t0);
data["gimbal_yaw"] = gs.yaw;
data["gimbal_yaw_vel"] = gs.yaw_vel;
data["gimbal_pitch"] = gs.pitch;
data["gimbal_pitch_vel"] = gs.pitch_vel;
data["target_yaw"] = plan.target_yaw;
data["target_pitch"] = plan.target_pitch;
data["plan_yaw"] = plan.yaw;
data["plan_yaw_vel"] = plan.yaw_vel;
data["plan_yaw_acc"] = plan.yaw_acc;
data["plan_pitch"] = plan.pitch;
data["plan_pitch_vel"] = plan.pitch_vel;
data["plan_pitch_acc"] = plan.pitch_acc;
data["fire"] = plan.fire ? 1 : 0;
data["fired"] = fired ? 1 : 0;
if (target.has_value()) {
data["target_z"] = target->ekf_x()[4]; //z
data["target_vz"] = target->ekf_x()[5]; //vz
}
if (target.has_value()) {
data["w"] = target->ekf_x()[7];
} else {
data["w"] = 0.0;
}
plotter.plot(data);
std::this_thread::sleep_for(10ms);
}
});
cv::Mat img;
std::chrono::steady_clock::time_point t;
while (!exiter.exit()) {
camera.read(img, t);
auto q = gimbal.q(t);
solver.set_R_gimbal2world(q);
auto armors = yolo.detect(img);
auto targets = tracker.track(armors, t);
if (!targets.empty())
target_queue.push(targets.front());
else
target_queue.push(std::nullopt);
if (!targets.empty()) {
auto target = targets.front();
// 当前帧target更新后
std::vector<Eigen::Vector4d> armor_xyza_list = target.armor_xyza_list();
for (const Eigen::Vector4d & xyza : armor_xyza_list) {
auto image_points =
solver.reproject_armor(xyza.head(3), xyza[3], target.armor_type, target.name);
tools::draw_points(img, image_points, {0, 255, 0});
}
Eigen::Vector4d aim_xyza = planner.debug_xyza;
auto image_points =
solver.reproject_armor(aim_xyza.head(3), aim_xyza[3], target.armor_type, target.name);
tools::draw_points(img, image_points, {0, 0, 255});
}
cv::resize(img, img, {}, 0.5, 0.5); // 显示时缩小图片尺寸
cv::imshow("reprojection", img);
auto key = cv::waitKey(1);
if (key == 'q') break;
}
quit = true;
if (plan_thread.joinable()) plan_thread.join();
gimbal.send(false, false, 0, 0, 0, 0, 0, 0);
return 0;
}

158
src/auto_buff_debug.cpp Executable file
View File

@ -0,0 +1,158 @@
#include <fmt/format.h>
#include <string>
#include "io/camera.hpp"
#include "io/cboard.hpp"
#include "tasks/auto_buff/buff_aimer.hpp"
#include "tasks/auto_buff/buff_detector.hpp"
#include "tasks/auto_buff/buff_solver.hpp"
#include "tasks/auto_buff/buff_target.hpp"
#include "tasks/auto_buff/buff_type.hpp"
#include "tools/exiter.hpp"
#include "tools/img_tools.hpp"
#include "tools/logger.hpp"
#include "tools/math_tools.hpp"
#include "tools/plotter.hpp"
#include "tools/recorder.hpp"
#include "tools/trajectory.hpp"
// 定义命令行参数
const std::string keys =
"{help h usage ? | | 输出命令行参数说明}"
"{@config-path | | yaml配置文件路径 }";
int main(int argc, char * argv[])
{
// 读取命令行参数
cv::CommandLineParser cli(argc, argv, keys);
auto config_path = cli.get<std::string>(0);
if (cli.has("help") || config_path.empty()) {
cli.printMessage();
return 0;
}
// 初始化绘图器、录制器、退出器
tools::Plotter plotter;
tools::Recorder recorder;
tools::Exiter exiter;
// 初始化C板、相机
io::CBoard cboard(config_path);
io::Camera camera(config_path);
// 初始化识别器、解算器、追踪器、瞄准器
auto_buff::Buff_Detector detector(config_path);
auto_buff::Solver solver(config_path);
auto_buff::SmallTarget target;
// auto_buff::BigTarget target;
auto_buff::Aimer aimer(config_path);
cv::Mat img;
Eigen::Quaterniond q;
std::chrono::steady_clock::time_point t;
while (!exiter.exit()) {
camera.read(img, t);
q = cboard.imu_at(t);
// recorder.record(img, q, t);
// -------------- 打符核心逻辑 --------------
solver.set_R_gimbal2world(q);
auto power_runes = detector.detect(img);
solver.solve(power_runes);
target.get_target(power_runes, t);
auto target_copy = target;
auto command = aimer.aim(target_copy, t, cboard.bullet_speed, true);
cboard.send(command);
// -------------- 调试输出 --------------
nlohmann::json data;
// buff原始观测数据
if (power_runes.has_value()) {
const auto & p = power_runes.value();
data["buff_R_yaw"] = p.ypd_in_world[0];
data["buff_R_pitch"] = p.ypd_in_world[1];
data["buff_R_dis"] = p.ypd_in_world[2];
data["buff_yaw"] = p.ypr_in_world[0] * 57.3;
data["buff_pitch"] = p.ypr_in_world[1] * 57.3;
data["buff_roll"] = p.ypr_in_world[2] * 57.3;
}
if (!target.is_unsolve()) {
auto & p = power_runes.value();
// 显示
for (int i = 0; i < 4; i++) tools::draw_point(img, p.target().points[i]);
tools::draw_point(img, p.target().center, {0, 0, 255}, 3);
tools::draw_point(img, p.r_center, {0, 0, 255}, 3);
// 当前帧target更新后buff
auto Rxyz_in_world_now = target.point_buff2world(Eigen::Vector3d(0.0, 0.0, 0.0));
auto image_points =
solver.reproject_buff(Rxyz_in_world_now, target.ekf_x()[4], target.ekf_x()[5]);
tools::draw_points(
img, std::vector<cv::Point2f>(image_points.begin(), image_points.begin() + 4), {0, 255, 0});
tools::draw_points(
img, std::vector<cv::Point2f>(image_points.begin() + 4, image_points.end()), {0, 255, 0});
// buff瞄准位置(预测)
double dangle = target.ekf_x()[5] - target_copy.ekf_x()[5];
auto Rxyz_in_world_pre = target.point_buff2world(Eigen::Vector3d(0.0, 0.0, 0.0));
image_points =
solver.reproject_buff(Rxyz_in_world_pre, target_copy.ekf_x()[4], target_copy.ekf_x()[5]);
tools::draw_points(
img, std::vector<cv::Point2f>(image_points.begin(), image_points.begin() + 4), {255, 0, 0});
tools::draw_points(
img, std::vector<cv::Point2f>(image_points.begin() + 4, image_points.end()), {255, 0, 0});
// 观测器内部数据
Eigen::VectorXd x = target.ekf_x();
data["R_yaw"] = x[0];
data["R_V_yaw"] = x[1];
data["R_pitch"] = x[2];
data["R_dis"] = x[3];
data["yaw"] = x[4] * 57.3;
data["angle"] = x[5] * 57.3;
data["spd"] = x[6] * 57.3;
if (x.size() >= 10) {
data["spd"] = x[6];
data["a"] = x[7];
data["w"] = x[8];
data["fi"] = x[9];
data["spd0"] = target.spd;
}
}
// 云台响应情况
Eigen::Vector3d ypr = tools::eulers(solver.R_gimbal2world(), 2, 1, 0);
data["gimbal_yaw"] = ypr[0] * 57.3;
data["gimbal_pitch"] = ypr[1] * 57.3;
if (command.control) {
data["cmd_yaw"] = command.yaw * 57.3;
data["cmd_pitch"] = command.pitch * 57.3;
data["shoot"] = command.shoot ? 1 : 0;
}
plotter.plot(data);
cv::resize(img, img, {}, 0.5, 0.5);
cv::imshow("result", img);
auto key = cv::waitKey(1);
if (key == 'q') break;
}
return 0;
}

165
src/auto_buff_debug_mpc.cpp Executable file
View File

@ -0,0 +1,165 @@
#include <fmt/format.h>
#include <string>
#include "io/camera.hpp"
#include "io/gimbal/gimbal.hpp"
#include "tasks/auto_buff/buff_aimer.hpp"
#include "tasks/auto_buff/buff_detector.hpp"
#include "tasks/auto_buff/buff_solver.hpp"
#include "tasks/auto_buff/buff_target.hpp"
#include "tasks/auto_buff/buff_type.hpp"
#include "tools/exiter.hpp"
#include "tools/img_tools.hpp"
#include "tools/logger.hpp"
#include "tools/math_tools.hpp"
#include "tools/plotter.hpp"
#include "tools/recorder.hpp"
#include "tools/trajectory.hpp"
// 定义命令行参数
const std::string keys =
"{help h usage ? | | 输出命令行参数说明}"
"{@config-path | | yaml配置文件路径 }";
int main(int argc, char * argv[])
{
// 读取命令行参数
cv::CommandLineParser cli(argc, argv, keys);
auto config_path = cli.get<std::string>(0);
if (cli.has("help") || config_path.empty()) {
cli.printMessage();
return 0;
}
// 初始化绘图器、录制器、退出器
tools::Plotter plotter;
tools::Recorder recorder;
tools::Exiter exiter;
// 初始化云台、相机
io::Gimbal gimbal(config_path);
io::Camera camera(config_path);
// 初始化识别器、解算器、追踪器、瞄准器
auto_buff::Buff_Detector detector(config_path);
auto_buff::Solver solver(config_path);
auto_buff::SmallTarget target;
// auto_buff::BigTarget target;
auto_buff::Aimer aimer(config_path);
cv::Mat img;
Eigen::Quaterniond q;
std::chrono::steady_clock::time_point t;
while (!exiter.exit()) {
camera.read(img, t);
q = gimbal.q(t);
auto gs = gimbal.state();
// recorder.record(img, q, t);
// -------------- 打符核心逻辑 --------------
solver.set_R_gimbal2world(q);
auto power_runes = detector.detect(img);
solver.solve(power_runes);
target.get_target(power_runes, t);
auto target_copy = target;
auto plan = aimer.mpc_aim(target_copy, t, gs, true);
gimbal.send(
plan.control, plan.fire, plan.yaw, plan.yaw_vel, plan.yaw_acc, plan.pitch, plan.pitch_vel,
plan.pitch_acc);
// -------------- 调试输出 --------------
nlohmann::json data;
// buff原始观测数据
if (power_runes.has_value()) {
const auto & p = power_runes.value();
data["buff_R_yaw"] = p.ypd_in_world[0];
data["buff_R_pitch"] = p.ypd_in_world[1];
data["buff_R_dis"] = p.ypd_in_world[2];
data["buff_yaw"] = p.ypr_in_world[0] * 57.3;
data["buff_pitch"] = p.ypr_in_world[1] * 57.3;
data["buff_roll"] = p.ypr_in_world[2] * 57.3;
}
if (!target.is_unsolve()) {
auto & p = power_runes.value();
// 显示
for (int i = 0; i < 4; i++) tools::draw_point(img, p.target().points[i]);
tools::draw_point(img, p.target().center, {0, 0, 255}, 3);
tools::draw_point(img, p.r_center, {0, 0, 255}, 3);
// 当前帧target更新后buff
auto Rxyz_in_world_now = target.point_buff2world(Eigen::Vector3d(0.0, 0.0, 0.0));
auto image_points =
solver.reproject_buff(Rxyz_in_world_now, target.ekf_x()[4], target.ekf_x()[5]);
tools::draw_points(
img, std::vector<cv::Point2f>(image_points.begin(), image_points.begin() + 4), {0, 255, 0});
tools::draw_points(
img, std::vector<cv::Point2f>(image_points.begin() + 4, image_points.end()), {0, 255, 0});
// buff瞄准位置(预测)
double dangle = target.ekf_x()[5] - target_copy.ekf_x()[5];
auto Rxyz_in_world_pre = target.point_buff2world(Eigen::Vector3d(0.0, 0.0, 0.0));
image_points =
solver.reproject_buff(Rxyz_in_world_pre, target_copy.ekf_x()[4], target_copy.ekf_x()[5]);
tools::draw_points(
img, std::vector<cv::Point2f>(image_points.begin(), image_points.begin() + 4), {255, 0, 0});
tools::draw_points(
img, std::vector<cv::Point2f>(image_points.begin() + 4, image_points.end()), {255, 0, 0});
// 观测器内部数据
Eigen::VectorXd x = target.ekf_x();
data["R_yaw"] = x[0];
data["R_V_yaw"] = x[1];
data["R_pitch"] = x[2];
data["R_dis"] = x[3];
data["yaw"] = x[4] * 57.3;
data["angle"] = x[5] * 57.3;
data["spd"] = x[6] * 57.3;
if (x.size() >= 10) {
data["spd"] = x[6];
data["a"] = x[7];
data["w"] = x[8];
data["fi"] = x[9];
data["spd0"] = target.spd;
}
}
// 云台响应情况
data["gimbal_yaw"] = gs.yaw * 57.3;
data["gimbal_pitch"] = gs.pitch * 57.3;
data["gimbal_yaw_vel"] = gs.yaw_vel * 57.3;
data["gimbal_pitch_vel"] = gs.pitch_vel * 57.3;
if (plan.control) {
data["plan_yaw"] = plan.yaw * 57.3;
data["plan_pitch"] = plan.pitch * 57.3;
data["plan_yaw_vel"] = plan.yaw_vel * 57.3;
data["plan_pitch_vel"] = plan.pitch_vel * 57.3;
data["plan_yaw_acc"] = plan.yaw_acc * 57.3;
data["plan_pitch_acc"] = plan.pitch_acc * 57.3;
data["shoot"] = plan.fire ? 1 : 0;
}
plotter.plot(data);
cv::resize(img, img, {}, 0.5, 0.5);
cv::imshow("result", img);
auto key = cv::waitKey(1);
if (key == 'q') break;
}
return 0;
}

173
src/mt_auto_aim_debug.cpp Normal file
View File

@ -0,0 +1,173 @@
#include <fmt/core.h>
#include <chrono>
#include <nlohmann/json.hpp>
#include <opencv2/opencv.hpp>
#include "io/camera.hpp"
#include "io/cboard.hpp"
#include "tasks/auto_aim/aimer.hpp"
#include "tasks/auto_aim/multithread/commandgener.hpp"
#include "tasks/auto_aim/multithread/mt_detector.hpp"
#include "tasks/auto_aim/shooter.hpp"
#include "tasks/auto_aim/solver.hpp"
#include "tasks/auto_aim/tracker.hpp"
#include "tasks/auto_aim/yolo.hpp"
#include "tools/exiter.hpp"
#include "tools/img_tools.hpp"
#include "tools/logger.hpp"
#include "tools/math_tools.hpp"
#include "tools/plotter.hpp"
#include "tools/recorder.hpp"
const std::string keys =
"{help h usage ? | | 输出命令行参数说明}"
"{@config-path | configs/sentry.yaml | 位置参数yaml配置文件路径 }";
using namespace std::chrono;
int main(int argc, char * argv[])
{
cv::CommandLineParser cli(argc, argv, keys);
auto config_path = cli.get<std::string>(0);
if (cli.has("help") || config_path.empty()) {
cli.printMessage();
return 0;
}
tools::Exiter exiter;
tools::Plotter plotter;
tools::Recorder recorder(100); //根据实际帧率调整
io::CBoard cboard(config_path);
io::Camera camera(config_path);
auto_aim::multithread::MultiThreadDetector detector(config_path, true);
auto_aim::Solver solver(config_path);
auto_aim::Tracker tracker(config_path, solver);
auto_aim::Aimer aimer(config_path);
auto_aim::Shooter shooter(config_path);
auto_aim::multithread::CommandGener commandgener(shooter, aimer, cboard, plotter, true);
auto detect_thread = std::thread([&]() {
cv::Mat img;
std::chrono::steady_clock::time_point t;
while (!exiter.exit()) {
camera.read(img, t);
detector.push(img, t);
}
});
auto mode = io::Mode::idle;
auto last_mode = io::Mode::idle;
while (!exiter.exit()) {
auto t0 = std::chrono::steady_clock::now();
/// 自瞄核心逻辑
auto [img, armors, t] = detector.debug_pop();
Eigen::Quaterniond q = cboard.imu_at(t - 1ms);
mode = cboard.mode;
if (last_mode != mode) {
tools::logger()->info("Switch to {}", io::MODES[mode]);
last_mode = mode;
}
solver.set_R_gimbal2world(q);
Eigen::Vector3d ypr = tools::eulers(solver.R_gimbal2world(), 2, 1, 0);
auto targets = tracker.track(armors, t);
commandgener.push(targets, t, cboard.bullet_speed, ypr); // 发送给决策线程
/// debug
tools::draw_text(img, fmt::format("[{}]", tracker.state()), {10, 30}, {255, 255, 255});
nlohmann::json data;
data["t"] = tools::delta_time(std::chrono::steady_clock::now(), t0);
// 装甲板原始观测数据
data["armor_num"] = armors.size();
if (!armors.empty()) {
auto min_x = 1e10;
auto & armor = armors.front();
for (auto & a : armors) {
if (a.center.x < min_x) {
min_x = a.center.x;
armor = a;
}
} //always left
solver.solve(armor);
data["armor_x"] = armor.xyz_in_world[0];
data["armor_y"] = armor.xyz_in_world[1];
data["armor_yaw"] = armor.ypr_in_world[0] * 57.3;
data["armor_yaw_raw"] = armor.yaw_raw * 57.3;
}
if (!targets.empty()) {
auto target = targets.front();
// 当前帧target更新后
std::vector<Eigen::Vector4d> armor_xyza_list = target.armor_xyza_list();
for (const Eigen::Vector4d & xyza : armor_xyza_list) {
auto image_points =
solver.reproject_armor(xyza.head(3), xyza[3], target.armor_type, target.name);
tools::draw_points(img, image_points, {0, 255, 0});
}
// aimer瞄准位置
auto aim_point = aimer.debug_aim_point;
Eigen::Vector4d aim_xyza = aim_point.xyza;
auto image_points =
solver.reproject_armor(aim_xyza.head(3), aim_xyza[3], target.armor_type, target.name);
if (aim_point.valid)
tools::draw_points(img, image_points, {0, 0, 255});
else
tools::draw_points(img, image_points, {255, 0, 0});
// 观测器内部数据
Eigen::VectorXd x = target.ekf_x();
data["x"] = x[0];
data["vx"] = x[1];
data["y"] = x[2];
data["vy"] = x[3];
data["z"] = x[4];
data["vz"] = x[5];
data["a"] = x[6] * 57.3;
data["w"] = x[7];
data["r"] = x[8];
data["l"] = x[9];
data["h"] = x[10];
data["last_id"] = target.last_id;
// 卡方检验数据
data["residual_yaw"] = target.ekf().data.at("residual_yaw");
data["residual_pitch"] = target.ekf().data.at("residual_pitch");
data["residual_distance"] = target.ekf().data.at("residual_distance");
data["residual_angle"] = target.ekf().data.at("residual_angle");
data["nis"] = target.ekf().data.at("nis");
data["nees"] = target.ekf().data.at("nees");
data["nis_fail"] = target.ekf().data.at("nis_fail");
data["nees_fail"] = target.ekf().data.at("nees_fail");
data["recent_nis_failures"] = target.ekf().data.at("recent_nis_failures");
}
// 云台响应情况
data["gimbal_yaw"] = ypr[0] * 57.3;
data["gimbal_pitch"] = ypr[1] * 57.3;
data["bullet_speed"] = cboard.bullet_speed;
plotter.plot(data);
cv::resize(img, img, {}, 0.5, 0.5); // 显示时缩小图片尺寸
cv::imshow("reprojection", img);
auto key = cv::waitKey(1);
if (key == 'q') break;
}
detect_thread.join();
return 0;
}

138
src/mt_standard.cpp Normal file
View File

@ -0,0 +1,138 @@
#include <chrono>
#include <opencv2/opencv.hpp>
#include <thread>
#include "io/camera.hpp"
#include "io/dm_imu/dm_imu.hpp"
#include "tasks/auto_aim/aimer.hpp"
#include "tasks/auto_aim/multithread/commandgener.hpp"
#include "tasks/auto_aim/multithread/mt_detector.hpp"
#include "tasks/auto_aim/shooter.hpp"
#include "tasks/auto_aim/solver.hpp"
#include "tasks/auto_aim/tracker.hpp"
#include "tasks/auto_buff/buff_aimer.hpp"
#include "tasks/auto_buff/buff_detector.hpp"
#include "tasks/auto_buff/buff_solver.hpp"
#include "tasks/auto_buff/buff_target.hpp"
#include "tasks/auto_buff/buff_type.hpp"
#include "tools/exiter.hpp"
#include "tools/img_tools.hpp"
#include "tools/logger.hpp"
#include "tools/math_tools.hpp"
#include "tools/plotter.hpp"
#include "tools/recorder.hpp"
const std::string keys =
"{help h usage ? | | 输出命令行参数说明}"
"{@config-path | | yaml配置文件路径 }";
using namespace std::chrono_literals;
int main(int argc, char * argv[])
{
cv::CommandLineParser cli(argc, argv, keys);
auto config_path = cli.get<std::string>("@config-path");
if (cli.has("help") || !cli.has("@config-path")) {
cli.printMessage();
return 0;
}
tools::Exiter exiter;
tools::Plotter plotter;
tools::Recorder recorder;
io::Camera camera(config_path);
io::CBoard cboard(config_path);
auto_aim::multithread::MultiThreadDetector detector(config_path);
auto_aim::Solver solver(config_path);
auto_aim::Tracker tracker(config_path, solver);
auto_aim::Aimer aimer(config_path);
auto_aim::Shooter shooter(config_path);
auto_buff::Buff_Detector buff_detector(config_path);
auto_buff::Solver buff_solver(config_path);
auto_buff::SmallTarget buff_small_target;
auto_buff::BigTarget buff_big_target;
auto_buff::Aimer buff_aimer(config_path);
auto_aim::multithread::CommandGener commandgener(shooter, aimer, cboard, plotter);
std::atomic<io::Mode> mode{io::Mode::idle};
auto last_mode{io::Mode::idle};
auto detect_thread = std::thread([&]() {
cv::Mat img;
std::chrono::steady_clock::time_point t;
while (!exiter.exit()) {
if (mode.load() == io::Mode::auto_aim) {
camera.read(img, t);
detector.push(img, t);
} else
continue;
}
});
while (!exiter.exit()) {
mode = cboard.mode;
if (last_mode != mode) {
tools::logger()->info("Switch to {}", io::MODES[mode]);
last_mode = mode.load();
}
/// 自瞄
if (mode.load() == io::Mode::auto_aim) {
auto [img, armors, t] = detector.debug_pop();
Eigen::Quaterniond q = cboard.imu_at(t - 1ms);
// recorder.record(img, q, t);
solver.set_R_gimbal2world(q);
Eigen::Vector3d ypr = tools::eulers(solver.R_gimbal2world(), 2, 1, 0);
auto targets = tracker.track(armors, t);
commandgener.push(targets, t, cboard.bullet_speed, ypr); // 发送给决策线程
}
/// 打符
else if (mode.load() == io::Mode::small_buff || mode.load() == io::Mode::big_buff) {
cv::Mat img;
Eigen::Quaterniond q;
std::chrono::steady_clock::time_point t;
camera.read(img, t);
q = cboard.imu_at(t - 1ms);
// recorder.record(img, q, t);
buff_solver.set_R_gimbal2world(q);
auto power_runes = buff_detector.detect(img);
buff_solver.solve(power_runes);
io::Command buff_command;
if (mode.load() == io::Mode::small_buff) {
buff_small_target.get_target(power_runes, t);
auto target_copy = buff_small_target;
buff_command = buff_aimer.aim(target_copy, t, cboard.bullet_speed, true);
} else if (mode.load() == io::Mode::big_buff) {
buff_big_target.get_target(power_runes, t);
auto target_copy = buff_big_target;
buff_command = buff_aimer.aim(target_copy, t, cboard.bullet_speed, true);
}
cboard.send(buff_command);
} else
continue;
}
detect_thread.join();
return 0;
}

106
src/sentry.cpp Normal file
View File

@ -0,0 +1,106 @@
#include <fmt/core.h>
#include <chrono>
#include <nlohmann/json.hpp>
#include <opencv2/opencv.hpp>
#include <thread>
#include "io/camera.hpp"
#include "io/cboard.hpp"
#include "io/ros2/publish2nav.hpp"
#include "io/ros2/ros2.hpp"
#include "io/usbcamera/usbcamera.hpp"
#include "tasks/auto_aim/aimer.hpp"
#include "tasks/auto_aim/shooter.hpp"
#include "tasks/auto_aim/solver.hpp"
#include "tasks/auto_aim/tracker.hpp"
#include "tasks/auto_aim/yolo.hpp"
#include "tasks/omniperception/decider.hpp"
#include "tools/exiter.hpp"
#include "tools/img_tools.hpp"
#include "tools/logger.hpp"
#include "tools/math_tools.hpp"
#include "tools/plotter.hpp"
#include "tools/recorder.hpp"
using namespace std::chrono;
const std::string keys =
"{help h usage ? | | 输出命令行参数说明}"
"{@config-path | configs/sentry.yaml | 位置参数yaml配置文件路径 }";
int main(int argc, char * argv[])
{
tools::Exiter exiter;
tools::Plotter plotter;
tools::Recorder recorder;
cv::CommandLineParser cli(argc, argv, keys);
if (cli.has("help")) {
cli.printMessage();
return 0;
}
auto config_path = cli.get<std::string>(0);
io::ROS2 ros2;
io::CBoard cboard(config_path);
io::Camera camera(config_path);
io::Camera back_camera("configs/camera.yaml");
io::USBCamera usbcam1("video0", config_path);
io::USBCamera usbcam2("video2", config_path);
auto_aim::YOLO yolo(config_path, false);
auto_aim::Solver solver(config_path);
auto_aim::Tracker tracker(config_path, solver);
auto_aim::Aimer aimer(config_path);
auto_aim::Shooter shooter(config_path);
omniperception::Decider decider(config_path);
cv::Mat img;
std::chrono::steady_clock::time_point timestamp;
io::Command last_command;
while (!exiter.exit()) {
camera.read(img, timestamp);
Eigen::Quaterniond q = cboard.imu_at(timestamp - 1ms);
// recorder.record(img, q, timestamp);
/// 自瞄核心逻辑
solver.set_R_gimbal2world(q);
Eigen::Vector3d gimbal_pos = tools::eulers(solver.R_gimbal2world(), 2, 1, 0);
auto armors = yolo.detect(img);
decider.get_invincible_armor(ros2.subscribe_enemy_status());
decider.armor_filter(armors);
// decider.get_auto_aim_target(armors, ros2.subscribe_autoaim_target());
decider.set_priority(armors);
auto targets = tracker.track(armors, timestamp);
io::Command command{false, false, 0, 0};
/// 全向感知逻辑
if (tracker.state() == "lost")
command = decider.decide(yolo, gimbal_pos, usbcam1, usbcam2, back_camera);
else
command = aimer.aim(targets, timestamp, cboard.bullet_speed, cboard.shoot_mode);
/// 发射逻辑
command.shoot = shooter.shoot(command, aimer, targets, gimbal_pos);
cboard.send(command);
/// ROS2通信
Eigen::Vector4d target_info = decider.get_target_info(armors, targets);
ros2.publish(target_info);
}
return 0;
}

Some files were not shown because too many files have changed in this diff Show More