Compare commits

..

36 Commits

Author SHA1 Message Date
lgv
d22fe1053e feat:finsh joint space planner 2025-11-11 11:33:55 +08:00
lgv
61b0161218 feat:add data_center 2025-11-10 16:54:06 +08:00
lgv
9aa74f39ad feat: add best psi select 2025-11-07 14:28:41 +08:00
lgv
bad9b6cc10 feat: add ik joint limit 2025-11-06 16:27:54 +08:00
lgv
5afd63eabe feat:add ik closed-from solution 2025-11-05 17:41:17 +08:00
lgv
7d03c0eeaf feat:add get pose rpc service 2025-11-03 11:44:52 +08:00
lgv
057984f440 feat:add head control API 2025-10-11 14:51:47 +08:00
lgv
3aa3f86027 refactor: move robot gRPC commands and services to separate files 2025-10-10 11:51:00 +08:00
lgv
a1d5a6efa0 Merge branch 'lgv_dev_touch' into dev 2025-10-10 11:39:39 +08:00
4c852f5260 update ffmpeg_speaker 2025-10-10 10:27:45 +08:00
lgv
8afee807f7 feat:add touch api 2025-10-09 16:31:21 +08:00
11f0097521 update 2025-09-25 16:01:01 +08:00
83c52ac19b update 2025-09-19 15:23:14 +08:00
ee9a8022d0 update 2025-09-19 15:16:07 +08:00
9a4f2ee6d4 update 2025-09-19 15:06:32 +08:00
823e235ee0 update 2025-09-11 16:36:14 +08:00
25ec465e0b update moveL 2025-09-09 17:03:52 +08:00
fb3d6622f4 update readme 2025-09-04 10:36:34 +08:00
lgv
4765a69c49 test:test hlc touch grpc service 2025-09-01 16:30:07 +08:00
lgv
11b0609a35 Merge branch 'lgv_dev_robot' into dev 2025-09-01 16:25:12 +08:00
lgv
9bf547c2f7 feat:add touch grpc service API 2025-09-01 16:24:08 +08:00
8c40281ef9 update abstract_interpolation 2025-08-28 11:18:17 +08:00
de82c76f94 add abstract_interpolation.h 2025-08-28 10:50:22 +08:00
lgv
f0b5dfc72d Merge branch 'lgv_dev_robot' into dev 2025-08-28 09:46:20 +08:00
lgv
b2a6be4d34 feat:add move delta J and touch control api 2025-08-28 09:39:59 +08:00
2f96bf9c50 update camera intrinsics 2025-08-27 16:41:48 +08:00
ab5aadd82e update camera intrinsics 2025-08-27 15:30:51 +08:00
d466303937 update camera intrinsics 2025-08-25 14:05:02 +08:00
3582d84176 update camera intrinsics 2025-08-25 14:03:11 +08:00
5b2de6be0e update urdf 2025-08-25 10:29:39 +08:00
97d0c59fae update vision servo 2025-08-23 15:51:07 +08:00
lgv
e8cb8bb2b2 Merge branch 'dev' of http://192.168.1.100:18088/smart_bench/cmvr-es 2025-08-22 17:51:04 +08:00
lgv
77bd97afb2 feat:add eye hand calibration and pose follow 2025-08-22 16:57:29 +08:00
9bc8d3e7db change robot urdf 2025-08-22 10:40:49 +08:00
c307ba0bb7 update depends 2025-08-21 14:52:01 +08:00
cd6ad32bce copy code file 2025-08-21 13:56:39 +08:00
1771 changed files with 621682 additions and 80 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
/.idea
/cmake-build-debug
/cmake-build-sigma-debuggit
/build
/log
/third_party/osqp/
/third_party/OsqpEigen/

9
.gitmodules vendored Normal file
View File

@ -0,0 +1,9 @@
[submodule "third_party/grpc"]
path = third_party/grpc
url = https://github.com/grpc/grpc.git
[submodule "third_party/osqp"]
path = third_party/osqp
url = https://github.com/osqp/osqp.git
[submodule "third_party/OsqpEigen"]
path = third_party/osqp-eigen
url = https://github.com/robotology/osqp-eigen.git

105
CMakeLists.txt Normal file
View File

@ -0,0 +1,105 @@
cmake_minimum_required(VERSION 3.22.0)
project(cmvr_es)
# C++
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS -pthread)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
#
list(APPEND CMAKE_PREFIX_PATH "$ENV{HOME}./local")
###########################################################
## DEPENDENCIES
#############################################################
find_package(jsoncpp REQUIRED)
find_package(protobuf REQUIRED)
find_package(gRPC REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GLOG REQUIRED libglog)
############################################################
# PROTO
############################################################
set(PROTO_IMPORT_DIR ${PROJECT_SOURCE_DIR}/protos)
set(PROTO_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/_protobuf)
file(MAKE_DIRECTORY ${PROTO_BINARY_DIR})
file(GLOB_RECURSE PROTO_FILES ${PROTO_IMPORT_DIR}/*.proto)
add_library(proto-objects OBJECT ${PROTO_FILES})
message(STATUS "proto files will be loaded in ${PROTO_IMPORT_DIR}")
message(STATUS "proto files will be generated in ${PROTO_BINARY_DIR}")
protobuf_generate(
TARGET proto-objects
IMPORT_DIRS ${PROTO_IMPORT_DIR}
PROTOC_OUT_DIR ${PROTO_BINARY_DIR}
USAGE_REQUIREMENT INTERFACE
)
protobuf_generate(
TARGET proto-objects
LANGUAGE grpc
GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc
PLUGIN "protoc-gen-grpc=$ENV{HOME}/.local/bin/grpc_cpp_plugin"
USAGE_REQUIREMENT INTERFACE
IMPORT_DIRS ${PROTO_IMPORT_DIR}
PROTOC_OUT_DIR ${PROTO_BINARY_DIR}
)
target_include_directories(proto-objects PUBLIC ${PROTO_BINARY_DIR} ${PROTO_IMPORT_DIR})
target_link_libraries(proto-objects PUBLIC protobuf::libprotobuf gRPC::grpc++)
############################################################
# include
############################################################
include_directories(
/usr/include/opencv4
/usr/include/eigen3
/usr/local/include/osqp
/usr/local/share/osqp/codegen_files/inc/private/
$ENV{HOME}/.local/include
/usr/local/include/
${PROTO_BINARY_DIR}
${PROJECT_SOURCE_DIR}/include
${PROJECT_SOURCE_DIR}/src/devices
${PROJECT_SOURCE_DIR}/src/utils
${PROJECT_SOURCE_DIR}/third_party
${PROJECT_SOURCE_DIR}/src
${PROJECT_SOURCE_DIR}/third_party/toppra/0.6.2/include
)
############################################################
# subdirectory
############################################################
add_subdirectory(src)
#add_subdirectory(example)
#add_subdirectory(test)
############################################################
# executables
############################################################
add_executable(cmvr_es src/main.cpp)
target_include_directories(cmvr_es PRIVATE ${GLOG_INCLUDE_DIRS})
target_link_libraries(cmvr_es PRIVATE
proto-objects
service
${GLOG_LIBRARIES}
gflags
jsoncpp_lib
cmvr_es::utils
cmvr_es::service
cmvr_es::monitor
cmvr_es::hardware
cmvr_es::httpclient
cmvr_es::device::canbus
cmvr_es::device::ti5motor
cmvr_es::ctrl::controller
cmvr_es::data_center
cmvr_es::ik_solver
cmvr_es::planner
)

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2017 FullStory, Inc
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.

215
README.md
View File

@ -1,92 +1,147 @@
# cmvr-es # CMVR-ES
## Overview
## Getting started
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
## Add your files
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
```
cd existing_repo
git remote add origin http://192.168.1.100:18088/smart_bench/cmvr-es.git
git branch -M main
git push -uf origin main
```
## Integrate with your tools
- [ ] [Set up project integrations](http://192.168.1.100:18088/smart_bench/cmvr-es/-/settings/integrations)
## Collaborate with your team
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
## Test and Deploy
Use the built-in continuous integration in GitLab.
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
***
# Editing this README
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template.
## Suggestions for a good README
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
## Name
Choose a self-explaining name for your project.
## Description
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
## Badges
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
## Visuals
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
## Installation ## Installation
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
## Usage ### 1. Git submodules install
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
## Support ```
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. git submodule update --init --recursive
```
## Roadmap ### 2. Dependency install
If you have ideas for releases in the future, it is a good idea to list them in the README.
## Contributing ```shell
State if you are open to contributions and what your requirements are for accepting them. # basic
sudo apt-get install build-essential -y
sudo apt-get install liblttng-ust-dev -y
sudo apt-get install lttng-tools -y
sudo apt install libboost-all-dev libssl-dev -y
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. # json
sudo apt install libjsoncpp-dev -y
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. # google
sudo apt install libgoogle-glog-dev -y
## Authors and acknowledgment # modbus
Show your appreciation to those who have contributed to the project. sudo apt install libmodbus-dev -y
## License # vision
For open source projects, say how it is licensed. sudo apt install libeigen3-dev -y
sudo apt install libopencv-dev python3-opencv -y
## Project status # fcl
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. sudo apt install -y libfcl-dev
# flann
sudo apt-get install libflann-dev -y
# ffmpeg (deprecated)
#sudo apt install ffmpeg
#alas
sudo apt-get install libasound2-dev -y
# gstreamer
sudo apt install gstreamer1.0-plugins-good gstreamer1.0-plugins-bad -y
sudo apt install gstreamer1.0-plugins-ugly gstreamer1.0-libav -y
# tinyxml2
sudo apt install libtinyxml2-dev -y
```
### 3. gRPC install (build from source)
version: https://grpc.io/docs/languages/cpp/quickstart/grpc官网地址 v1.73.0
#### 安装完成之后要配置环境变量
vim ~/.bashrc
在末尾添加
### 4. ffmpeg install (build from source)
#### 4.1 install dependencies
```shell
sudo apt-get update
sudo apt install build-essential yasm nasm git -y
sudo apt install libx264-dev libx265-dev libvpx-dev libfdk-aac-dev libmp3lame-dev libopus-dev -y
```
#### 4.2 build from source
```shell
cd assets
tar xjvf ffmpeg-4.4.tar.bz2
cd ffmpeg-4.4
# set configurations
./configure \
--extra-libs="-lpthread -lm" \
--enable-gpl \
--enable-libass \
--enable-libfdk-aac \
--enable-libfreetype \
--enable-libmp3lame \
--enable-libopus \
--enable-libvorbis \
--enable-libvpx \
--enable-libx264 \
--enable-libx265 \
--enable-pic \
--enable-shared \
--enable-nonfree \
# build and install
make -j4
sudo make install
```
### 5. librealsense2 2.55.1 install
```shell
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-key F6E65AC044F831AC80A06380C8B3A55A6F3EFCDE || sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-key F6E65AC044F831AC80A06380C8B3A55A6F3EFCDE
sudo add-apt-repository "deb https://librealsense.intel.com/Debian/apt-repo $(lsb_release -cs) main" -u
sudo apt-get install librealsense2-dkms=1.3.24-0ubuntu1 -y
sudo apt-get install \
librealsense2=2.55.1-0~realsense.12473 \
librealsense2-utils=2.55.1-0~realsense.12473 \
librealsense2-dev=2.55.1-0~realsense.12473 \
librealsense2-dbg=2.55.1-0~realsense.12473 -y
```
### 5. OSQPEigen install(build from source)
#### 5.1 install osqp (v0.6.3)
```shell
git clone --branch v0.6.3 https://github.com/osqp/osqp.git
cd osqp
git submodule init
git submodule update
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr/local ..
make -j
sudo make install
```
#### 5.2 install OsqpEigen (v0.10.1)
```shell
git clone --branch v0.10.1 https://github.com/robotology/osqp-eigen.git
cd osqp-eigen
git submodule init
git submodule update
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr/local ..
make -j
sudo make install
```
#### 6 mech-eye-sdk
```shell
cd assets
sudo dkpg -i Mech-Eye_API_2.5.1_amd64.deb
```
### 串口冲突问题
```shell
sudo systemctl stop brltty
sudo systemctl disable brltty
sudo apt remove brltty
```

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

BIN
assets/ffmpeg-4.4.tar.bz2 Normal file

Binary file not shown.

Binary file not shown.

1
assets/toppra Submodule

@ -0,0 +1 @@
Subproject commit fab1f402ef8677beac43d2226eb1cc6ce0d54735

144
config/cabin_robot.xml Normal file
View File

@ -0,0 +1,144 @@
<CMVR-ES>
<Constants rootDir="/home/xtkuang/projects/cmvr-es"/>
<Logger dir="../log" level="info" bufSize="5" logSize="1024"/>
<DeviceManager name="cmvr_es" ver="0.1" description="cmvr edge system version 0.1">
<Devices>
<AGV>
</AGV>
<Battery>
</Battery>
<Camera>
<!-- <UVCCamera id="cam1" serial="/dev/video6" w="640" h="480" fps="30" mode="video" codec="H265"/>-->
<!-- <UVCCamera id="cam2" serial="/dev/video14" w="640" h="480" fps="30" mode="video" codec="H265"/>-->
<!-- <RealsenseCamera id="cam3" serial="243122072252" w="640" h="480" fps="30" mode="video" stream_mode="rgbd" align_mode="color" codec="H265"/>-->
<!-- <RealsenseCamera id="cam4" serial="243122075614" w="1280" h="720" fps="30" mode="video" stream_mode="rgbd" align_mode="color" codec="H265"/>-->
<!-- <MechMind id="cam5" ip="10.148.108.111" align="true" _2dtype="color"/>-->
<!-- <RealsenseCamera id="cam6" serial="243122075389" w="640" h="480" fps="30" mode="video" stream_mode="rgbd" align_mode="color" codec="H265"/>-->
</Camera>
<DexHand>
<!-- <RH56DFTP id="hand1" default_force="500" default_speed="500" ip_address="192.168.1.223" port="6000">-->
<!-- <Freedom order="01" default_force="500" default_speed="500" />-->
<!-- </RH56DFTP>-->
<!-- <RH56DFTP id="hand2" default_force="500" default_speed="500" ip_address="192.168.1.224" port="6000">-->
<!-- <Freedom order="01" default_force="500" default_speed="500" />-->
<!-- </RH56DFTP>-->
</DexHand>
<Robot>
<!-- <LeftArm id="left_arm" devtype="ti5Robot" />-->
<!-- <RightArm />-->
<!-- <Neck/>-->
<Humanoid id="hc01" dof="14"
urdf="/home/lgv/cmvr/cmvr-es/config/robot_description/hc_description/dual_arm.urdf"
baseLink="PELVIS_S"
jointNames="L_SHOULDER_P,L_SHOULDER_R,L_SHOULDER_Y,L_ELBOW_R,L_WRIST_P,L_WRIST_Y,L_WRIST_R,R_SHOULDER_P,R_SHOULDER_R,R_SHOULDER_Y,R_ELBOW_R,R_WRIST_P,R_WRIST_Y,R_WRIST_R"
linkNames="PELVIS_S,L_SHOULDER_P_S,L_SHOULDER_R_S,L_SHOULDER_Y_S,L_ELBOW_R_S,L_WRIST_P_S,L_WRIST_Y_S,L_WRIST_R_S,R_SHOULDER_P_S,R_SHOULDER_R_S,R_SHOULDER_Y_S,R_ELBOW_R_S,R_WRIST_P_S,R_WRIST_Y_S,R_WRIST_R_S,R_FINGER_TIP,R_CAM"
bufferSize="50"
verbose="false">
<CanManger id="" devId="">
<LeftArmCan id = " " devId = " " channelId ="0" enable="false" toolFrame="L_FINGER_TIP">
<Motor id="23" jointName="L_SHOULDER_P" limitQLb="3.14" limitQUb="3.14" limitQd="3.0"/>
<Motor id="24" jointName="L_SHOULDER_R" limitQLb="3.14" limitQUb="3.14" limitQd="3.0"/>
<Motor id="25" jointName="L_SHOULDER_Y" limitQLb="3.14" limitQUb="3.14" limitQd="3.0"/>
<Motor id="26" jointName="L_ELBOW_R" limitQLb="3.14" limitQUb="3.14" limitQd="3.0"/>
<Motor id="27" jointName="L_WRIST_P" limitQLb="3.14" limitQUb="3.14" limitQd="3.0"/>
<Motor id="28" jointName="L_WRIST_Y" limitQLb="3.14" limitQUb="3.14" limitQd="3.0"/>
<Motor id="1" jointName="L_WRIST_R" limitQLb="3.14" limitQUb="3.14" limitQd="3.0"/>
</LeftArmCan>
<RightArmCan id = " " devId = " " channelId ="1" enable="true" toolFrame="R_FINGER_TIP">
<Motor id="16" jointName="R_SHOULDER_P" limitQLb="3.14" limitQUb="3.14" limitQd="3.0"/>
<Motor id="17" jointName="R_SHOULDER_R" limitQLb="3.14" limitQUb="3.14" limitQd="3.0"/>
<Motor id="18" jointName="R_SHOULDER_Y" limitQLb="3.14" limitQUb="3.14" limitQd="3.0"/>
<Motor id="19" jointName="R_ELBOW_R" limitQLb="3.14" limitQUb="3.14" limitQd="3.0"/>
<Motor id="20" jointName="R_WRIST_P" limitQLb="-3.14" limitQUb="3.14" limitQd="3.0"/>
<Motor id="21" jointName="R_WRIST_Y" limitQLb="-1.102" limitQUb="1.02" limitQd="3.0"/>
<Motor id="22" jointName="R_WRIST_R" limitQLb="-0.293" limitQUb="1.57079" limitQd="3.0"/>
</RightArmCan>
<HeadCan id = " " devId = " " channelId ="2" enable="false">
<Motor id="32" jointName="HEAD_Y" limitQLb="3.14" limitQUb="3.14" limitQd="3.0"/>
<Motor id="30" jointName="HEAD_P" limitQLb="3.14" limitQUb="3.14" limitQd="3.0"/>
<Motor id="31" jointName="HEAD_R" limitQLb="3.14" limitQUb="3.14" limitQd="3.0"/>
</HeadCan>
<WaistCan id = " " devId = " " channelId ="3" enable="false">
<Motor id="14" jointName="WAIST_Y" limitQLb="3.14" limitQUb="3.14" limitQd="3.0"/>
<Motor id="15" jointName="WAIST_P" limitQLb="3.14" limitQUb="3.14" limitQd="3.0"/>
</WaistCan>
</CanManger>
</Humanoid>
</Robot>
<BioHead>
<!-- <esp32 id="bio_head" serial="/dev/ttyUSB0" ctrlFreq="50">-->
<!-- &lt;!&ndash; 配置左眉毛,舵机通道 0~3 &ndash;&gt;-->
<!-- <EyeBrow serial="64:0~3" offest="90 90 90 90"-->
<!-- jLmtUp="170 170 170 170" jLmtLow="10 10 10 10"/>-->
<!-- &lt;!&ndash; 配置眼睛,舵机通道 4~9 &ndash;&gt;-->
<!-- <Eye serial="64:4~9" offest="90 90 90 90 90 90"-->
<!-- jLmtUp="170 170 170 170 170 170" jLmtLow="10 10 10 10 10 10"/>-->
<!-- &lt;!&ndash; 配置嘴巴,舵机通道 0~8 &ndash;&gt;-->
<!-- <Mouth serial="65:0~8" offest="90 90 90 90 90 90 90 90 90"-->
<!-- jLmtUp="170 170 170 170 170 170 170 170 170" jLmtLow="10 10 10 10 10 10 10 10 10"/>-->
<!-- </esp32>-->
</BioHead >
<Microphone>
<!-- <ffmpegMicPhone id="mic1" alsa="hw:0" channels="2" sampleRate="44100" volume="80"/>-->
<!-- <ffmpegMicPhone id="mic2" alsa="hw:1" channels="1" sampleRate="44100" volume="80"/>-->
</Microphone>
<Speaker>
<ffmpegSpeaker id="spk1" serial="" alas="hw:0,0" channels="2" sampleRate="44100" softResample="1" latency="50000" volume="100"/>
</Speaker>
<Canbus>
<!-- <rightArmCan id="can1" brand="SOCKET_CAN_RAW" type="USB_CARD" channel_id="CHANNEL_ID_ZERO" interface="NATIVE" baudrate="BCAN_BAUDRATE_500K"/>-->
</Canbus>
</Devices>
<HighLevelController>
<BioHeadExpre headId="bio_head" />
<CartesianWBC urdf="" />
<ScreenTouch robotID="" DexhandID="" />
</HighLevelController>
</DeviceManager>
<MonitorManager>
<DiskMonitor id="file_monitor" freq="1">
<!-- <Folder fileDir="/home/share/assets/audio" maxVolume="1000"/>-->
<!-- <Folder fileDir="/home/share/assets/image" maxVolume="1000"/>-->
<!-- <Folder fileDir="/home/share/assets/video" maxVolume="1000"/>-->
<!-- <Folder fileDir="../log" maxVolume="1000"/>-->
</DiskMonitor>
<JointMonitor id="robot_joint_monitor" freq="200">
<RobotJoint robotID="left_arm" motorID="0" maxTemp="80" maxCurrent="5" maxVel="2"/>
<RobotJoint robotID="left_arm" motorID="1" maxTemp="80" maxCurrent="5" maxVel="2"/>
<RobotJoint robotID="left_arm" motorID="2" maxTemp="80" maxCurrent="5" maxVel="2"/>
<RobotJoint robotID="left_arm" motorID="3" maxTemp="80" maxCurrent="5" maxVel="2"/>
<RobotJoint robotID="left_arm" motorID="4" maxTemp="80" maxCurrent="5" maxVel="2"/>
<RobotJoint robotID="left_arm" motorID="6" maxTemp="80" maxCurrent="5" maxVel="2"/>
<RobotJoint robotID="left_arm" motorID="7" maxTemp="80" maxCurrent="5" maxVel="2"/>
<RobotJoint robotID="right_arm" motorID="0" maxTemp="80" maxCurrent="5" maxVel="2"/>
<RobotJoint robotID="right_arm" motorID="1" maxTemp="80" maxCurrent="5" maxVel="2"/>
<RobotJoint robotID="right_arm" motorID="2" maxTemp="80" maxCurrent="5" maxVel="2"/>
<RobotJoint robotID="right_arm" motorID="3" maxTemp="80" maxCurrent="5" maxVel="2"/>
<RobotJoint robotID="right_arm" motorID="4" maxTemp="80" maxCurrent="5" maxVel="2"/>
<RobotJoint robotID="right_arm" motorID="6" maxTemp="80" maxCurrent="5" maxVel="2"/>
<RobotJoint robotID="right_arm" motorID="7" maxTemp="80" maxCurrent="5" maxVel="2"/>
</JointMonitor>
</MonitorManager>
<gRPCServer port="50052">
</gRPCServer>
</CMVR-ES>

View File

@ -0,0 +1,613 @@
<?xml version="1.0" encoding="utf-8"?>
<robot name="dual_arm">
<link name="PELVIS_S">
<inertial>
<origin xyz="3.78529087037144E-05 3.81781425684836E-07 0.0386396273530852" rpy="0 0 0" />
<mass value="2.10624590271277" />
<inertia
ixx="0.00165706865324979"
ixy="3.13663044821662E-09"
ixz="6.84209533216046E-07"
iyy="0.00136736758630241"
iyz="-1.01014607878816E-10"
izz="0.00168295663089359" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/PELVIS_S.STL" />
</geometry>
<material name="">
<color rgba="0.698039215686274 0.698039215686274 0.698039215686274 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/PELVIS_S.STL" />
</geometry>
</collision>
</link>
<link name="L_SHOULDER_P_S">
<inertial>
<origin xyz="-0.00982258725282134 0.0704593083751867 1.15261874861217E-06" rpy="0 0 0" />
<mass value="0.880737519698403" />
<inertia
ixx="0.000583190308378148"
ixy="-1.53153074560473E-05"
ixz="6.58466471754072E-09"
iyy="0.000445532440067177"
iyz="6.37001404038516E-09"
izz="0.000465648071069952" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_SHOULDER_P_S.STL" />
</geometry>
<material name="">
<color rgba="0.898039215686275 0.917647058823529 0.929411764705882 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_SHOULDER_P_S.STL" />
</geometry>
</collision>
</link>
<joint name="L_SHOULDER_P" type="revolute">
<origin xyz="0 0.0945 0.042" rpy="0 0 0" />
<parent link="PELVIS_S" />
<child link="L_SHOULDER_P_S" />
<axis xyz="0 1 0" />
<limit lower="-1.57" upper="1.57" effort="120" velocity="3.351" />
</joint>
<link name="L_SHOULDER_R_S">
<inertial>
<origin xyz="-0.0346025282975857 0.091739327988169 -1.67085072999562E-08" rpy="0 0 0" />
<mass value="0.594788424442483" />
<inertia
ixx="0.000380970396712656"
ixy="4.80751844573946E-05"
ixz="-1.34913746586865E-11"
iyy="0.000320962178597474"
iyz="-1.00039763442409E-09"
izz="0.000414771047901155" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_SHOULDER_R_S.STL" />
</geometry>
<material name="">
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_SHOULDER_R_S.STL" />
</geometry>
</collision>
</link>
<joint name="L_SHOULDER_R" type="revolute">
<origin xyz="0.035 0.0765 0" rpy="0 0 0" />
<parent link="L_SHOULDER_P_S" />
<child link="L_SHOULDER_R_S" />
<axis xyz="1 0 0" />
<limit lower="-2" upper="2" effort="120" velocity="3.351" />
</joint>
<link name="L_SHOULDER_Y_S">
<inertial>
<origin xyz="-0.00440976862014801 0.0863620459174068 9.50748668682166E-09"
rpy="0 0 0" />
<mass value="0.563406026626801" />
<inertia
ixx="0.000327003834287552"
ixy="-1.8057438966771E-05"
ixz="7.28778136267901E-10"
iyy="0.000213830709361531"
iyz="1.49273668517817E-10"
izz="0.000297341029639189" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_SHOULDER_Y_S.STL" />
</geometry>
<material name="">
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_SHOULDER_Y_S.STL" />
</geometry>
</collision>
</link>
<joint name="L_SHOULDER_Y" type="revolute">
<origin xyz="-0.035 0.1475 0" rpy="0 0 0" />
<parent link="L_SHOULDER_R_S" />
<child link="L_SHOULDER_Y_S" />
<axis xyz="0 1 0" />
<limit lower="-2.18" upper="0" effort="80" velocity="3.8758" />
</joint>
<link name="L_ELBOW_R_S">
<inertial>
<origin xyz="-0.0335624237303443 0.0603199964106564 2.99655911639718E-07" rpy="0 0 0" />
<mass value="0.393571904406493" />
<inertia
ixx="0.00017277119386253"
ixy="2.34549801867355E-05"
ixz="-1.90560556659271E-09"
iyy="0.000155340245267897"
iyz="8.82493073600007E-09"
izz="0.00018104232734159" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_ELBOW_R_S.STL" />
</geometry>
<material name="">
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_ELBOW_R_S.STL" />
</geometry>
</collision>
</link>
<joint name="L_ELBOW_R" type="revolute">
<origin xyz="0.034 0.1025 0" rpy="0 0 0" />
<parent link="L_SHOULDER_Y_S" />
<child link="L_ELBOW_R_S" />
<axis xyz="1 0 0" />
<limit lower="-2.05" upper="0" effort="50" velocity="4.71" />
</joint>
<link name="L_WRIST_P_S">
<inertial>
<origin xyz="-1.39659173115092E-10 0.0675972604744393 0.019200551565574" rpy="0 0 0" />
<mass value="0.442332465815496" />
<inertia
ixx="0.000476754055455895"
ixy="-4.61505824713347E-15"
ixz="6.03808112272229E-18"
iyy="0.000103466585850499"
iyz="-4.88426705501198E-05"
izz="0.000482956345754213" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_WRIST_P_S.STL" />
</geometry>
<material name="">
<color rgba="0.698039215686274 0.698039215686274 0.698039215686274 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_WRIST_P_S.STL" />
</geometry>
</collision>
</link>
<joint name="L_WRIST_P" type="revolute">
<origin xyz="-0.034 0.0965 0" rpy="0 0 0" />
<parent link="L_ELBOW_R_S" />
<child link="L_WRIST_P_S" />
<axis xyz="0 1 0" />
<limit lower="0" upper="3.14" effort="50" velocity="4.71" />
</joint>
<link name="L_WRIST_Y_S">
<inertial>
<origin xyz="-0.00464135887331864 -5.06426789392833E-10 -0.0341253783666609" rpy="0 0 0" />
<mass value="0.23573847772002" />
<inertia
ixx="5.10686940455785E-05"
ixy="7.45706654358429E-16"
ixz="6.2619568923368E-06"
iyy="6.00636019624519E-05"
iyz="1.27989654155383E-16"
izz="5.32182903609189E-05" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_WRIST_Y_S.STL" />
</geometry>
<material name="">
<color rgba="0.647058823529412 0.619607843137255 0.588235294117647 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_WRIST_Y_S.STL" />
</geometry>
</collision>
</link>
<joint name="L_WRIST_Y" type="revolute">
<origin xyz="0 0.1525 0.039" rpy="0 0 0" />
<parent link="L_WRIST_P_S" />
<child link="L_WRIST_Y_S" />
<axis xyz="0 0 1" />
<limit lower="-0.78" upper="0.78" effort="50" velocity="0.79" />
</joint>
<link name="L_WRIST_R_S">
<inertial>
<origin xyz="-0.0161477357620243 0.0955046558857351 -0.00499392489444117" rpy="0 0 0" />
<mass value="0.504894112043562" />
<inertia
ixx="0.000186833711781125"
ixy="-3.99488705622731E-06"
ixz="-1.51920720398336E-06"
iyy="0.000179960980467837"
iyz="3.6992669535716E-06"
izz="0.000280756101568308" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_WRIST_R_S.STL" />
</geometry>
<material name="">
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_WRIST_R_S.STL" />
</geometry>
</collision>
</link>
<joint name="L_WRIST_R" type="revolute">
<origin xyz="0.0258 0 -0.039" rpy="0 0 0" />
<parent link="L_WRIST_Y_S" />
<child link="L_WRIST_R_S" />
<axis xyz="1 0 0" />
<limit lower="-1.57" upper="0.26" effort="50" velocity="4.71" />
</joint>
<link name="R_SHOULDER_P_S">
<inertial>
<origin xyz="-0.00982258725282141 -0.0704593093873431 -1.15069920925137E-06" rpy="0 0 0" />
<mass value="0.880737519698404" />
<inertia
ixx="0.000583190308378149"
ixy="1.53153074560471E-05"
ixz="-6.58466471736542E-09"
iyy="0.000445532440067178"
iyz="6.37001403998779E-09"
izz="0.000465648071069953" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_SHOULDER_P_S.STL" />
</geometry>
<material name="">
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_SHOULDER_P_S.STL" />
</geometry>
</collision>
</link>
<joint name="R_SHOULDER_P" type="revolute">
<origin xyz="0 -0.0945 0.042" rpy="0 0 0" />
<parent link="PELVIS_S" />
<child link="R_SHOULDER_P_S" />
<axis xyz="0 -1 0" />
<limit lower="-1.57" upper="1.57" effort="120" velocity="3.351" />
</joint>
<link name="R_SHOULDER_R_S">
<inertial>
<origin xyz="-0.0346025282975784 -0.09173932900033 1.86280643132974E-08" rpy="0 0 0" />
<mass value="0.59478842444248" />
<inertia
ixx="0.000380970396712653"
ixy="-4.80751844573946E-05"
ixz="1.34913746041655E-11"
iyy="0.000320962178597472"
iyz="-1.00039763417375E-09"
izz="0.000414771047901152" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_SHOULDER_R_S.STL" />
</geometry>
<material name="">
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_SHOULDER_R_S.STL" />
</geometry>
</collision>
</link>
<joint name="R_SHOULDER_R" type="revolute">
<origin xyz="0.035 -0.0765 0" rpy="0 0 0" />
<parent link="R_SHOULDER_P_S" />
<child link="R_SHOULDER_R_S" />
<axis xyz="1 0 0" />
<limit lower="-2" upper="2" effort="120" velocity="3.351" />
</joint>
<link name="R_SHOULDER_Y_S">
<inertial>
<origin xyz="-0.00440976862014946 -0.0863620469295699 -7.58791862676134E-09" rpy="0 0 0" />
<mass value="0.563406026626801" />
<inertia
ixx="0.000327003834287551"
ixy="1.80574389667711E-05"
ixz="-7.28778136077729E-10"
iyy="0.000213830709361532"
iyz="1.49273668428957E-10"
izz="0.000297341029639189" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_SHOULDER_Y_S.STL" />
</geometry>
<material
name="">
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_SHOULDER_Y_S.STL" />
</geometry>
</collision>
</link>
<joint name="R_SHOULDER_Y" type="revolute">
<origin xyz="-0.035 -0.1475 0" rpy="0 0 0" />
<parent link="R_SHOULDER_R_S" />
<child link="R_SHOULDER_Y_S" />
<axis xyz="0 -1 0" />
<limit lower="0" upper="3.14" effort="80" velocity="3.8758" />
</joint>
<link name="R_ELBOW_R_S">
<inertial>
<origin xyz="-0.0335624237303424 -0.0603199974228191 -2.97736340082455E-07" rpy="0 0 0" />
<mass value="0.393571904406492" />
<inertia
ixx="0.000172771193862529"
ixy="-2.34549801867353E-05"
ixz="1.90560556668771E-09"
iyy="0.000155340245267897"
iyz="8.82493073602971E-09"
izz="0.00018104232734159" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_ELBOW_R_S.STL" />
</geometry>
<material name="">
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_ELBOW_R_S.STL" />
</geometry>
</collision>
</link>
<joint name="R_ELBOW_R" type="revolute">
<origin xyz="0.034 -0.1025 0" rpy="0 0 0" />
<parent link="R_SHOULDER_Y_S" />
<child link="R_ELBOW_R_S" />
<axis xyz="1 0 0" />
<limit lower="0" upper="2.05" effort="80" velocity="3.8758" />
</joint>
<link name="R_WRIST_P_S">
<inertial>
<origin xyz="-1.39656577968772E-10 -0.0675972614865965 0.0192005515655728" rpy="0 0 0" />
<mass value="0.442332465815497" />
<inertia
ixx="0.000476754055455896"
ixy="-4.61462558956188E-15"
ixz="-5.91762926004267E-18"
iyy="0.0001034665858505"
iyz="4.88426705501212E-05"
izz="0.000482956345754214" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_WRIST_P_S.STL" />
</geometry>
<material name="">
<color rgba="0.647058823529412 0.619607843137255 0.588235294117647 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_WRIST_P_S.STL" />
</geometry>
</collision>
</link>
<joint name="R_WRIST_P" type="revolute">
<origin xyz="-0.034 -0.0965 0" rpy="0 0 0" />
<parent link="R_ELBOW_R_S" />
<child link="R_WRIST_P_S" />
<axis xyz="0 -1 0" />
<limit lower="-3.14" upper="0" effort="50" velocity="4.71" />
</joint>
<link name="R_WRIST_Y_S">
<inertial>
<origin xyz="-0.00464135887330083 -5.06426456325926E-10 -0.0341253783666614" rpy="0 0 0" />
<mass value="0.235738477720019" />
<inertia
ixx="5.1068694045578E-05"
ixy="7.45771487459288E-16"
ixz="6.26195689233664E-06"
iyy="6.00636019624515E-05"
iyz="1.27828046342987E-16"
izz="5.32182903609188E-05" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_WRIST_Y_S.STL" />
</geometry>
<material name="">
<color rgba="0.647058823529412 0.619607843137255 0.588235294117647 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_WRIST_Y_S.STL" />
</geometry>
</collision>
</link>
<joint name="R_WRIST_Y" type="revolute">
<origin xyz="0 -0.1525 0.039" rpy="0 0 0" />
<parent link="R_WRIST_P_S" />
<child link="R_WRIST_Y_S" />
<axis xyz="0 0 1" />
<limit lower="-0.78" upper="0.78" effort="50" velocity="0.79" />
</joint>
<link name="R_WRIST_R_S">
<inertial>
<origin xyz="-0.0201642233698132 -0.11074968386657 -0.00598955339232021" rpy="0 0 0" />
<mass value="0.504366058218534" />
<inertia
ixx="0.000185559065855467"
ixy="5.75889766751509E-06"
ixz="2.40683898454438E-06"
iyy="0.000131246007872084"
iyz="1.60533277040148E-06"
izz="0.000271800951396149" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_WRIST_R_S.STL" />
</geometry>
<material
name="">
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_WRIST_R_S.STL" />
</geometry>
</collision>
</link>
<joint name="R_WRIST_R" type="revolute">
<origin xyz="0.03 0 -0.039" rpy="0 0 0" />
<parent link="R_WRIST_Y_S" />
<child link="R_WRIST_R_S" />
<axis xyz="1 0 0" />
<limit lower="-0.26" upper="1.57" effort="50" velocity="4.71" />
</joint>
<link name="R_FINGER_TIP">
<inertial>
<origin xyz="0 0 0" rpy="0 0 0"/>
<mass value="0"/>
<inertia ixx="1e-6" ixy="0" ixz="0" iyy="1e-6" iyz="0" izz="1e-6"/>
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<sphere radius="0.004"/>
</geometry>
<material name="">
<color rgba="0 1 1 1"/> <!-- 绿色 -->
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<sphere radius="0.005"/>
</geometry>
</collision>
</link>
<joint name="R_FINGER_TIP_FIXED" type="fixed">
<origin xyz="0.00684256 -0.284077 0.00801525" rpy="0 0 0"/>
<parent link="R_WRIST_R_S"/>
<child link="R_FINGER_TIP"/>
<axis xyz="0 0 1"/>
</joint>
<link name="R_CAM">
<inertial>
<origin xyz="0 0 0" rpy="0 0 0"/>
<mass value="0"/>
<inertia ixx="1e-6" ixy="0" ixz="0" iyy="1e-6" iyz="0" izz="1e-6"/>
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<sphere radius="0.004"/>
</geometry>
<material name="">
<color rgba="0 1 0 1"/> <!-- 绿色 -->
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<sphere radius="0.005"/>
</geometry>
</collision>
</link>
<joint name="R_CAM_FIXED" type="fixed">
<origin xyz="-0.01212 -0.17655 0.07506" rpy="-1.5707963267 0 3.1415926535"/>
<parent link="R_WRIST_R_S"/>
<child link="R_CAM"/>
<axis xyz="0 0 1"/>
</joint>
</robot>

View File

@ -0,0 +1,275 @@
<?xml version="1.0" encoding="utf-8"?>
<robot name="left_arm">
<link name="base_link">
<visual>
<geometry>
<cylinder radius="0.05" length="1.2"/>
</geometry>
<material name="gray">
<color rgba="0.5 0.5 0.5 1.0"/>
</material>
</visual>
<collision>
<geometry>
<cylinder radius="0.2" length="1.2"/>
</geometry>
</collision>
<inertial>
<mass value="20.0"/>
<origin xyz="0 0 0" rpy="0 0 0"/>
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
</inertial>
</link>
<joint name="base_fixed" type="fixed">
<origin rpy="0 0 0.0" xyz="0 0 0.6"/>
<parent link="base_link"/>
<child link="PELVIS_S"/>
<axis xyz="0 0 0"/>
</joint>
<link name="PELVIS_S">
<inertial>
<origin xyz="3.78529087037144E-05 3.81781425684836E-07 0.0386396273530852" rpy="0 0 0" />
<mass value="2.10624590271277" />
<inertia ixx="0.00165706865324979" ixy="3.13663044821662E-09" ixz="6.84209533216046E-07" iyy="0.00136736758630241" iyz="-1.01014607878816E-10" izz="0.00168295663089359" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/PELVIS_S.STL" />
</geometry>
<material name="">
<color rgba="0.698039215686274 0.698039215686274 0.698039215686274 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/PELVIS_S.STL" />
</geometry>
</collision>
</link>
<joint name="L_SHOULDER_P" type="revolute">
<origin xyz="0 0.0945 0.042" rpy="0 0 0" />
<parent link="PELVIS_S" />
<child link="L_SHOULDER_P_S" />
<axis xyz="0 1 0" />
<limit lower="-3.14" upper="3.14" effort="100" velocity="3.351" />
</joint>
<link name="L_SHOULDER_P_S">
<inertial>
<origin xyz="-0.00982258725282134 0.0704593083751867 1.15261874861217E-06" rpy="0 0 0" />
<mass value="0.880737519698403" />
<inertia ixx="0.000583190308378148" ixy="-1.53153074560473E-05" ixz="6.58466471754072E-09" iyy="0.000445532440067177" iyz="6.37001404038516E-09" izz="0.000465648071069952" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_SHOULDER_P_S.STL" />
</geometry>
<material
name="">
<color rgba="0.898039215686275 0.917647058823529 0.929411764705882 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_SHOULDER_P_S.STL" />
</geometry>
</collision>
</link>
<joint name="L_SHOULDER_R" type="revolute">
<origin xyz="0.035 0.0765 0" rpy="0 0 0" />
<parent link="L_SHOULDER_P_S" />
<child link="L_SHOULDER_R_S" />
<axis xyz="1 0 0" />
<limit lower="-3.14" upper="3.14" effort="100" velocity="3.351" />
</joint>
<link name="L_SHOULDER_R_S">
<inertial>
<origin xyz="-0.0346025282975857 0.091739327988169 -1.67085072999562E-08" rpy="0 0 0" />
<mass value="0.594788424442483" />
<inertia ixx="0.000380970396712656" ixy="4.80751844573946E-05" ixz="-1.34913746586865E-11" iyy="0.000320962178597474" iyz="-1.00039763442409E-09" izz="0.000414771047901155" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_SHOULDER_R_S.STL" />
</geometry>
<material name="">
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_SHOULDER_R_S.STL" />
</geometry>
</collision>
</link>
<joint name="L_SHOULDER_Y" type="revolute">
<origin xyz="-0.035 0.1475 0" rpy="0 0 0" />
<parent link="L_SHOULDER_R_S" />
<child link="L_SHOULDER_Y_S" />
<axis xyz="0 1 0" />
<limit lower="-3.14" upper="3.14" effort="49" velocity="3.8758" />
</joint>
<link name="L_SHOULDER_Y_S">
<inertial>
<origin xyz="-0.00440976862014801 0.0863620459174068 9.50748668682166E-09" rpy="0 0 0" />
<mass value="0.563406026626801" />
<inertia ixx="0.000327003834287552" ixy="-1.8057438966771E-05" ixz="7.28778136267901E-10" iyy="0.000213830709361531" iyz="1.49273668517817E-10" izz="0.000297341029639189" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_SHOULDER_Y_S.STL" />
</geometry>
<material name="">
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_SHOULDER_Y_S.STL" />
</geometry>
</collision>
</link>
<joint name="L_ELBOW_R" type="revolute">
<origin xyz="0.034 0.1025 0" rpy="0 0 0" />
<parent link="L_SHOULDER_Y_S" />
<child link="L_ELBOW_R_S" />
<axis xyz="1 0 0" />
<limit lower="-3.14" upper="3.14" effort="49" velocity="3.8758" />
</joint>
<link name="L_ELBOW_R_S">
<inertial>
<origin xyz="-0.0335624237303443 0.0603199964106564 2.99655911639718E-07" rpy="0 0 0" />
<mass value="0.393571904406493" />
<inertia ixx="0.00017277119386253" ixy="2.34549801867355E-05" ixz="-1.90560556659271E-09" iyy="0.000155340245267897" iyz="8.82493073600007E-09" izz="0.00018104232734159" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_ELBOW_R_S.STL" />
</geometry>
<material name="">
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_ELBOW_R_S.STL" />
</geometry>
</collision>
</link>
<joint name="L_WRIST_P" type="revolute">
<origin xyz="-0.034 0.0965 0" rpy="0 0 0" />
<parent link="L_ELBOW_R_S" />
<child link="L_WRIST_P_S" />
<axis xyz="0 1 0" />
<limit lower="-3.14" upper="3.14" effort="26" velocity="4.19" />
</joint>
<link name="L_WRIST_P_S">
<inertial>
<origin xyz="-1.39659173115092E-10 0.0675972604744393 0.019200551565574" rpy="0 0 0" />
<mass value="0.442332465815496" />
<inertia ixx="0.000476754055455895" ixy="-4.61505824713347E-15" ixz="6.03808112272229E-18" iyy="0.000103466585850499" iyz="-4.88426705501198E-05" izz="0.000482956345754213" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_WRIST_P_S.STL" />
</geometry>
<material name="">
<color rgba="0.698039215686274 0.698039215686274 0.698039215686274 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_WRIST_P_S.STL" />
</geometry>
</collision>
</link>
<joint name="L_WRIST_Y" type="revolute">
<origin xyz="0 0.1525 0.039" rpy="0 0 0" />
<parent link="L_WRIST_P_S" />
<child link="L_WRIST_Y_S" />
<axis xyz="0 0 1" />
<limit lower="-3.14" upper="3.14" effort="26" velocity="4.71" />
</joint>
<link name="L_WRIST_Y_S">
<inertial>
<origin xyz="-0.00464135887331864 -5.06426789392833E-10 -0.0341253783666609" rpy="0 0 0" />
<mass value="0.23573847772002" />
<inertia ixx="5.10686940455785E-05" ixy="7.45706654358429E-16" ixz="6.2619568923368E-06" iyy="6.00636019624519E-05" iyz="1.27989654155383E-16" izz="5.32182903609189E-05" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_WRIST_Y_S.STL" />
</geometry>
<material name="">
<color rgba="0.647058823529412 0.619607843137255 0.588235294117647 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_WRIST_Y_S.STL" />
</geometry>
</collision>
</link>
<joint name="L_WRIST_R" type="revolute">
<origin xyz="0.0258 0 -0.039" rpy="0 0 0" />
<parent link="L_WRIST_Y_S" />
<child link="L_WRIST_R_S" />
<axis xyz="1 0 0" />
<limit lower="-3.14" upper="3.14" effort="26" velocity="4.71" />
</joint>
<link name="L_WRIST_R_S">
<inertial>
<origin xyz="-0.0161477357620243 0.0955046558857351 -0.00499392489444117" rpy="0 0 0" />
<mass value="0.504894112043562" />
<inertia ixx="0.000186833711781125" ixy="-3.99488705622731E-06" ixz="-1.51920720398336E-06" iyy="0.000179960980467837" iyz="3.6992669535716E-06" izz="0.000280756101568308" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_WRIST_R_S.STL" />
</geometry>
<material name="">
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/L_WRIST_R_S.STL" />
</geometry>
</collision>
</link>
</robot>

View File

@ -0,0 +1,316 @@
<?xml version="1.0" encoding="utf-8"?>
<robot name="right_arm">
<link name="PELVIS_S">
<inertial>
<origin xyz="3.78529e-05 3.81781e-07 0.0386396" rpy="0 0 0"/>
<mass value="2.10624590271277"/>
<inertia
ixx="0.00165706865324979" ixy="3.13663e-09" ixz="6.84210e-07"
iyy="0.00136736758630241" iyz="-1.01015e-10" izz="0.00168295663089359"/>
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<mesh filename="meshes/PELVIS_S.STL"/>
</geometry>
<material name="light_gray">
<color rgba="0.698 0.698 0.698 1"/>
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<mesh filename="meshes/PELVIS_S.STL"/>
</geometry>
</collision>
</link>
<link name="R_SHOULDER_P_S">
<inertial>
<origin xyz="-0.00982258725282141 -0.0704593093873431 -1.15069920925137E-06" rpy="0 0 0" />
<mass value="0.880737519698404" />
<inertia
ixx="0.000583190308378149"
ixy="1.53153074560471E-05"
ixz="-6.58466471736542E-09"
iyy="0.000445532440067178"
iyz="6.37001403998779E-09"
izz="0.000465648071069953" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_SHOULDER_P_S.STL" />
</geometry>
<material name="">
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
</material>
</visual>
<collision>
<origin
xyz="0 0 0"
rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_SHOULDER_P_S.STL" />
</geometry>
</collision>
</link>
<joint name="R_SHOULDER_P" type="revolute">
<origin xyz="0 -0.0945 0.042" rpy="0 0 0" />
<parent link="PELVIS_S" />
<child link="R_SHOULDER_P_S" />
<axis xyz="0 -1 0" />
<limit lower="-1.57" upper="1.57" effort="120" velocity="3.351" />
</joint>
<link name="R_SHOULDER_R_S">
<inertial>
<origin xyz="-0.0346025282975784 -0.09173932900033 1.86280643132974E-08" rpy="0 0 0" />
<mass value="0.59478842444248" />
<inertia
ixx="0.000380970396712653" ixy="-4.80751844573946E-05" ixz="1.34913746041655E-11"
iyy="0.000320962178597472" iyz="-1.00039763417375E-09" izz="0.000414771047901152" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_SHOULDER_R_S.STL" />
</geometry>
<material name="">
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_SHOULDER_R_S.STL" />
</geometry>
</collision>
</link>
<joint name="R_SHOULDER_R" type="revolute">
<origin xyz="0.035 -0.0765 0" rpy="0 0 0" />
<parent link="R_SHOULDER_P_S" />
<child link="R_SHOULDER_R_S" />
<axis xyz="1 0 0" />
<limit lower="-2" upper="2" effort="120" velocity="3.351" />
</joint>
<link name="R_SHOULDER_Y_S">
<inertial>
<origin xyz="-0.00440976862014946 -0.0863620469295699 -7.58791862676134E-09" rpy="0 0 0" />
<mass value="0.563406026626801" />
<inertia
ixx="0.000327003834287551"
ixy="1.80574389667711E-05"
ixz="-7.28778136077729E-10"
iyy="0.000213830709361532"
iyz="1.49273668428957E-10"
izz="0.000297341029639189" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_SHOULDER_Y_S.STL" />
</geometry>
<material name="">
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_SHOULDER_Y_S.STL" />
</geometry>
</collision>
</link>
<joint name="R_SHOULDER_Y" type="revolute">
<origin xyz="-0.035 -0.1475 0" rpy="0 0 0" />
<parent link="R_SHOULDER_R_S" />
<child link="R_SHOULDER_Y_S" />
<axis xyz="0 -1 0" />
<limit lower="0" upper="3.14" effort="80" velocity="3.8758" />
</joint>
<link name="R_ELBOW_R_S">
<inertial>
<origin xyz="-0.0335624237303424 -0.0603199974228191 -2.97736340082455E-07" rpy="0 0 0" />
<mass value="0.393571904406492" />
<inertia
ixx="0.000172771193862529"
ixy="-2.34549801867353E-05"
ixz="1.90560556668771E-09"
iyy="0.000155340245267897"
iyz="8.82493073602971E-09"
izz="0.00018104232734159" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_ELBOW_R_S.STL" />
</geometry>
<material name="">
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_ELBOW_R_S.STL" />
</geometry>
</collision>
</link>
<joint name="R_ELBOW_R" type="revolute">
<origin xyz="0.034 -0.1025 0" rpy="0 0 0" />
<parent link="R_SHOULDER_Y_S" />
<child link="R_ELBOW_R_S" />
<axis xyz="1 0 0" />
<limit lower="0" upper="2.18" effort="80" velocity="3.8758" />
</joint>
<link name="R_WRIST_P_S">
<inertial>
<origin xyz="-1.39656577968772E-10 -0.0675972614865965 0.0192005515655728" rpy="0 0 0" />
<mass value="0.442332465815497" />
<inertia
ixx="0.000476754055455896"
ixy="-4.61462558956188E-15"
ixz="-5.91762926004267E-18"
iyy="0.0001034665858505"
iyz="4.88426705501212E-05"
izz="0.000482956345754214" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_WRIST_P_S.STL" />
</geometry>
<material name="">
<color rgba="0.647058823529412 0.619607843137255 0.588235294117647 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_WRIST_P_S.STL" />
</geometry>
</collision>
</link>
<joint name="R_WRIST_P" type="revolute">
<origin xyz="-0.034 -0.0965 0" rpy="0 0 0" />
<parent link="R_ELBOW_R_S" />
<child link="R_WRIST_P_S" />
<axis xyz="0 -1 0" />
<limit lower="-3.14" upper="0" effort="50" velocity="4.71" />
</joint>
<link name="R_WRIST_Y_S">
<inertial>
<origin xyz="-0.00464135887330083 -5.06426456325926E-10 -0.0341253783666614" rpy="0 0 0" />
<mass value="0.235738477720019" />
<inertia
ixx="5.1068694045578E-05"
ixy="7.45771487459288E-16"
ixz="6.26195689233664E-06"
iyy="6.00636019624515E-05"
iyz="1.27828046342987E-16"
izz="5.32182903609188E-05" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_WRIST_Y_S.STL" />
</geometry>
<material name="">
<color rgba="0.647058823529412 0.619607843137255 0.588235294117647 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_WRIST_Y_S.STL" />
</geometry>
</collision>
</link>
<joint name="R_WRIST_Y" type="revolute">
<origin xyz="0 -0.1525 0.039" rpy="0 0 0" />
<parent link="R_WRIST_P_S" />
<child link="R_WRIST_Y_S" />
<axis xyz="0 0 1" />
<limit lower="0" upper="0.78" effort="50" velocity="0.79" />
</joint>
<link name="R_WRIST_R_S">
<inertial>
<origin xyz="-0.0201642233698132 -0.11074968386657 -0.00598955339232021" rpy="0 0 0" />
<mass value="0.204366058218534" />
<inertia
ixx="0.000185559065855467"
ixy="5.75889766751509E-06"
ixz="2.40683898454438E-06"
iyy="0.000131246007872084"
iyz="1.60533277040148E-06"
izz="0.000271800951396149" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_WRIST_R_S.STL" />
</geometry>
<material name="">
<color rgba="0.890196078431372 0.890196078431372 0.913725490196078 1" />
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="meshes/R_WRIST_R_S.STL" />
</geometry>
</collision>
</link>
<joint name="R_WRIST_R" type="revolute">
<origin xyz="0.03 0 -0.039" rpy="0 0 0" />
<parent link="R_WRIST_Y_S" />
<child link="R_WRIST_R_S" />
<axis xyz="1 0 0" />
<limit lower="-0.26" upper="1.57" effort="50" velocity="4.71" />
</joint>
<link name="R_FINGER_TIP">
<inertial>
<origin xyz="0 0 0" rpy="0 0 0"/>
<mass value="0"/>
<inertia ixx="1e-6" ixy="0" ixz="0" iyy="1e-6" iyz="0" izz="1e-6"/>
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<sphere radius="0.002"/>
</geometry>
<material name="">
<color rgba="0 1 0 1"/> <!-- 绿色 -->
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<sphere radius="0.005"/>
</geometry>
</collision>
</link>
<joint name="R_FINGER_TIP_FIXED" type="fixed">
<origin xyz="-0.01212 -0.17655 0.07506" rpy="3.14159 0 -1.5708"/>
<parent link="R_WRIST_R_S"/>
<child link="R_FINGER_TIP"/>
</joint>
</robot>

2908
data/ik/ik_psi_sweep.csv Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,73 @@
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
CSV = '/home/lgv/cmvr/cmvr-es/data/ik_psi_sweep.csv'
df = pd.read_csv(CSV)
# ---- 曲线图q1~q7 (+ 可选 psi) vs index ----
joint_cols_expect = ['q1','q2','q3','q4','q5','q6','q7']
joint_cols = [c for c in joint_cols_expect if c in df.columns]
assert len(joint_cols) == 7, f"CSV 缺少关节列,期望 {joint_cols_expect},实际 {list(df.columns)}"
x = np.arange(len(df))
plt.figure(figsize=(12, 5))
for c in joint_cols:
plt.plot(x, df[c].to_numpy(), label=c, linewidth=1.2)
if 'psi' in df.columns:
plt.plot(x, df['psi'].to_numpy(), '--', label='psi', linewidth=1.2)
plt.xlabel('index')
plt.ylabel('angle (rad)')
plt.title('q1..q7 (and psi) vs index')
plt.grid(True, alpha=0.35)
plt.legend(ncol=4, fontsize=9)
plt.tight_layout()
plt.show()
# ---- 柱状图:最近限位距离(选“最危险帧”) ----
limits = np.array([
[-0.26, 1.57],
[-0.78, 1.57],
[-np.pi, np.pi],
[ 0.00, 2.05],
[-3.00, 3.00],
[-2.00, 2.00],
[-0.57, 1.57],
])
Q = df[joint_cols].to_numpy() # [N,7]
lo = limits[:, 0][None, :] # [1,7]
hi = limits[:, 1][None, :]
dist_low = Q - lo # 到下限的距离
dist_high = hi - Q # 到上限的距离
nearest = np.minimum(dist_low, dist_high) # 最近限位(可为负,负值=超限)
# 找“最危险”的 index全关节最小裕度最小
min_margin_per_row = nearest.min(axis=1) # 每帧的最小关节裕度
worst_idx = int(np.argmin(min_margin_per_row))
vals = nearest[worst_idx, :]
psi_text = f", psi={df['psi'].iloc[worst_idx]:.4f}" if 'psi' in df.columns else ""
plt.figure(figsize=(9, 4.5))
plt.bar(joint_cols, vals)
plt.axhline(0.0, linewidth=1, color='k')
plt.ylabel('Nearest distance to limit (rad)')
plt.title(f'Per-joint margin at worst frame (index={worst_idx}{psi_text})')
plt.grid(True, axis='y', alpha=0.35)
plt.tight_layout()
plt.show()
# ---- 可选:整段最小裕度曲线(帮助定位危险段)----
plt.figure(figsize=(12, 3.2))
plt.plot(min_margin_per_row, linewidth=1.2)
plt.axhline(0.0, linewidth=1, color='k')
plt.xlabel('index')
plt.ylabel('min margin (rad)')
plt.title('Minimum per-frame joint margin over sweep (rad)')
plt.grid(True, alpha=0.35)
plt.tight_layout()
plt.show()

View File

@ -0,0 +1,59 @@
# pip install toppra numpy scipy pandas matplotlib
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import toppra as ta
import toppra.algorithm as algo
import toppra.constraint as constraint
import toppra.interpolator as interp
# === 1) 读取 CSV只取 q1..q7===
CSV_PATH = "/home/lgv/cmvr/cmvr-es/data/ik_psi_sweep.csv" #
joint_cols = ["q1","q2","q3","q4","q5","q6","q7"]
df = pd.read_csv(CSV_PATH)
assert all(c in df.columns for c in joint_cols), "CSV 缺少关节列 q1..q7"
waypoints = df[joint_cols].to_numpy()
N, dof = waypoints.shape
assert N >= 2, "至少需要两行关节路点"
# === 2) 构造样条路径(路径参数 s∈[0,1]===
s_grid = np.linspace(0, 1, N)
path = interp.SplineInterpolator(s_grid, waypoints)
# === 3) 约束(示例值:请改成你的真实上限)===
vmax = np.array([1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5]) # rad/s
amax = np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]) # rad/s^2
vlim = np.vstack([-vmax, vmax]).T
alim = np.vstack([-amax, amax]).T
pc_vel = constraint.JointVelocityConstraint(vlim)
pc_acc = constraint.JointAccelerationConstraint(alim)
# === 4) toppra 时间最优轨迹(起止速度=0===
topp = algo.TOPPRA([pc_vel, pc_acc], path, solver_wrapper="seidel")
traj = topp.compute_trajectory(0.0, 0.0)
T = traj.get_duration()
print(f"Total duration: {T:.4f} s")
# === 5) 采样并绘图 ===
ts = np.linspace(0, T, 300)
q = traj.eval(ts) # (300,7)
qd = traj.evald(ts)
qdd = traj.evaldd(ts)
# 位置
plt.figure()
for i in range(dof):
plt.plot(ts, q[:, i], label=f"q{i+1}")
plt.xlabel("Time (s)"); plt.ylabel("Position (rad)"); plt.title("Joint Positions"); plt.legend(); plt.tight_layout(); plt.show()
# 速度
plt.figure()
for i in range(dof):
plt.plot(ts, qd[:, i], label=f"qd{i+1}")
plt.xlabel("Time (s)"); plt.ylabel("Velocity (rad/s)"); plt.title("Joint Velocities"); plt.legend(); plt.tight_layout(); plt.show()
# 加速度
plt.figure()
for i in range(dof):
plt.plot(ts, qdd[:, i], label=f"qdd{i+1}")
plt.xlabel("Time (s)"); plt.ylabel("Acceleration (rad/s²)"); plt.title("Joint Accelerations"); plt.legend(); plt.tight_layout(); plt.show()

59
data/ik/plot_psi_data.py Normal file
View File

@ -0,0 +1,59 @@
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
df = pd.read_csv('/home/lgv/cmvr/cmvr-es/data/ik_psi_sweep.csv')
joints = ['q1','q2','q3','q4','q5','q6','q7']
fig, axes = plt.subplots(len(joints), 1, figsize=(10, 2.6*len(joints)), sharex=True)
x = df['psi'].to_numpy()
for ax, col in zip(axes, joints):
y = df[col].to_numpy()
# 过滤 NaN
mask = ~np.isnan(x) & ~np.isnan(y)
xv, yv = x[mask], y[mask]
if len(xv) == 0:
ax.set_title(f'{col}: no data')
continue
# 散点图(不画连线)
ax.scatter(xv, yv, s=10, alpha=0.8) # s 调整点大小
# 极值与对应 psi
i_min = int(np.argmin(yv))
i_max = int(np.argmax(yv))
y_min, psi_min = float(yv[i_min]), float(xv[i_min])
y_max, psi_max = float(yv[i_max]), float(xv[i_max])
# 水平红虚线(值)
ax.axhline(y_min, color='red', linestyle='--', linewidth=1)
ax.axhline(y_max, color='red', linestyle='--', linewidth=1)
# 垂直红虚线psi
ax.axvline(psi_min, color='red', linestyle='--', linewidth=1, alpha=0.7)
ax.axvline(psi_max, color='red', linestyle='--', linewidth=1, alpha=0.7)
# 极值点标记
ax.plot(psi_min, y_min, 'ro', markersize=4)
ax.plot(psi_max, y_max, 'ro', markersize=4)
# 标注:值 + psi
ax.annotate(f"min={y_min:.4f}\nψ={psi_min:.4f}",
xy=(psi_min, y_min), xytext=(8, -10),
textcoords='offset points', color='red',
ha='left', va='top', fontsize=9,
bbox=dict(boxstyle="round,pad=0.2", fc="white", ec="none"))
ax.annotate(f"max={y_max:.4f}\nψ={psi_max:.4f}",
xy=(psi_max, y_max), xytext=(8, 10),
textcoords='offset points', color='red',
ha='left', va='bottom', fontsize=9,
bbox=dict(boxstyle="round,pad=0.2", fc="white", ec="none"))
ax.set_ylabel(f"{col} (rad)")
ax.grid(True, alpha=0.35)
axes[-1].set_xlabel('psi (rad)')
fig.suptitle('IK joints vs arm-angle psi', y=0.995)
plt.tight_layout()
plt.show()

63
data/planner/plot_traj.py Normal file
View File

@ -0,0 +1,63 @@
import os
import re
import sys
import pandas as pd
import matplotlib.pyplot as plt
def main(csv_path: str):
# 更健壮的读取
df = pd.read_csv(csv_path, sep=None, engine="python", comment="#")
if 't' not in df.columns:
raise RuntimeError("CSV missing 't' column")
# ——严格区分列名——
# 允许列名形如q0, q1, ... | qd0, qd1, ... | qdd0, qdd1, ...
def grep(pattern):
r = re.compile(pattern)
return [c for c in df.columns if r.fullmatch(c)]
q_cols = grep(r"q\d+")
qd_cols = grep(r"qd\d+")
qdd_cols = grep(r"qdd\d+")
# 如果你的列名不是纯数字后缀(比如 q_joint1把上面的正则改成更宽松的
# q_cols = [c for c in df.columns if c.startswith("q") and not c.startswith(("qd","qdd"))]
# qd_cols = [c for c in df.columns if c.startswith("qd") and not c.startswith("qdd")]
# qdd_cols = [c for c in df.columns if c.startswith("qdd")]
t = df['t'].values
# 位置
plt.figure()
for c in q_cols:
plt.plot(t, df[c].values, label=c)
plt.xlabel('time [s]')
plt.ylabel('position [rad]')
plt.title('Joint Positions')
plt.legend()
plt.grid(True)
# 速度(只画 qd*
plt.figure()
for c in qd_cols:
plt.plot(t, df[c].values, label=c)
plt.xlabel('time [s]')
plt.ylabel('velocity [rad/s]')
plt.title('Joint Velocities')
plt.legend()
plt.grid(True)
# 加速度(只画 qdd*
plt.figure()
for c in qdd_cols:
plt.plot(t, df[c].values, label=c)
plt.xlabel('time [s]')
plt.ylabel('acceleration [rad/s^2]')
plt.title('Joint Accelerations')
plt.legend()
plt.grid(True)
plt.show()
if __name__ == '__main__':
main("/home/lgv/cmvr/cmvr-es/data/planner/traj.csv")

148
data/planner/traj.csv Normal file
View File

@ -0,0 +1,148 @@
t,q1,q2,q3,q4,q5,q6,q7,qd1,qd2,qd3,qd4,qd5,qd6,qd7,qdd1,qdd2,qdd3,qdd4,qdd5,qdd6,qdd7
0.0000000000,0.0000000000,-0.5000000000,0.8000000000,0.0000000000,0.2000000000,-0.3000000000,0.1000000000,0.0000000000,0.0000000000,0.0000000000,0.0000000000,0.0000000000,0.0000000000,0.0000000000,0.0000000000,0.0000000000,0.0000000000,0.0000000000,0.0000000000,0.0000000000,0.0000000000
0.0100000000,0.0000303310,-0.4999823069,0.7999646138,0.0000176931,0.1999848345,-0.2999797793,0.0999924172,0.0118947055,0.0069385782,-0.0138771564,0.0069385782,-0.0059473527,0.0079298037,-0.0029736764,2.5705569358,1.4994915459,-2.9989830918,1.4994915459,-1.2852784679,1.7137046239,-0.6426392339
0.0200000000,0.0002706117,-0.4998421432,0.7996842864,0.0001578568,0.1998646942,-0.2998195922,0.0999323471,0.0362504791,0.0211461128,-0.0422922256,0.0211461128,-0.0181252396,0.0241669861,-0.0090626198,2.5169090310,1.4681969348,-2.9363938695,1.4681969348,-1.2584545155,1.6779393540,-0.6292272578
0.0300000000,0.0007555952,-0.4995592361,0.7991184723,0.0004407639,0.1996222024,-0.2994962699,0.0998111012,0.0607600493,0.0354433621,-0.0708867242,0.0354433621,-0.0303800246,0.0405066995,-0.0151900123,2.5596209442,1.4931122175,-2.9862244349,1.4931122175,-1.2798104721,1.7064139628,-0.6399052361
0.0400000000,0.0014880673,-0.4991319607,0.7982639215,0.0008680393,0.1992559664,-0.2990079551,0.0996279832,0.0857190835,0.0500027987,-0.1000055974,0.0500027987,-0.0428595417,0.0571460556,-0.0214297709,2.4658651556,1.4384213408,-2.8768426816,1.4384213408,-1.2329325778,1.6439101038,-0.6164662889
0.0500000000,0.0024696657,-0.4985593617,0.7971187233,0.0014406383,0.1987651671,-0.2983535562,0.0993825836,0.1106444598,0.0645426015,-0.1290852031,0.0645426015,-0.0553222299,0.0737629732,-0.0276611149,2.5568927194,1.4915207530,-2.9830415059,1.4915207530,-1.2784463597,1.7045951462,-0.6392231798
0.0600000000,0.0037018685,-0.4978405767,0.7956811534,0.0021594233,0.1981490657,-0.2975320877,0.0990745329,0.1358094448,0.0792221761,-0.1584443523,0.0792221761,-0.0679047224,0.0905396299,-0.0339523612,2.5158582466,1.4675839772,-2.9351679544,1.4675839772,-1.2579291233,1.6772388311,-0.6289645616
0.0700000000,0.0051853943,-0.4969751867,0.7939503733,0.0030248133,0.1974073029,-0.2965430705,0.0987036514,0.1609332845,0.0938777493,-0.1877554986,0.0938777493,-0.0804666423,0.1072888563,-0.0402333211,2.4840420418,1.4490245244,-2.8980490488,1.4490245244,-1.2420210209,1.6560280279,-0.6210105105
0.0800000000,0.0069207211,-0.4959629127,0.7919258254,0.0040370873,0.1965396394,-0.2953861859,0.0982698197,0.1861077050,0.1085628279,-0.2171256559,0.1085628279,-0.0930538525,0.1240718034,-0.0465269263,2.5667165306,1.4972513095,-2.9945026190,1.4972513095,-1.2833582653,1.7111443537,-0.6416791326
0.0900000000,0.0089085479,-0.4948033471,0.7896066941,0.0051966529,0.1955457261,-0.2940609681,0.0977728630,0.2114304418,0.1233344244,-0.2466688488,0.1233344244,-0.1057152209,0.1409536279,-0.0528576105,2.5507009528,1.4879088891,-2.9758177783,1.4879088891,-1.2753504764,1.7004673019,-0.6376752382
0.1000000000,0.0111492914,-0.4934962467,0.7869924933,0.0065037533,0.1944253543,-0.2925671391,0.0972126771,0.2367541946,0.1381066135,-0.2762132270,0.1381066135,-0.1183770973,0.1578361297,-0.0591885486,2.5385172632,1.4808017369,-2.9616034738,1.4808017369,-1.2692586316,1.6923448422,-0.6346293158
0.1100000000,0.0136432400,-0.4920414433,0.7840828866,0.0079585567,0.1931783800,-0.2909045066,0.0965891900,0.2620885162,0.1528849678,-0.3057699355,0.1528849678,-0.1310442581,0.1747256774,-0.0655221290,2.5296551441,1.4756321674,-2.9512643348,1.4756321674,-1.2648275720,1.6864367627,-0.6324137860
0.1200000000,0.0163906632,-0.4904387798,0.7808775596,0.0095612202,0.1918046684,-0.2890728912,0.0959023342,0.2874390193,0.1676727613,-0.3353455225,0.1676727613,-0.1437195097,0.1916260129,-0.0718597548,2.5235281251,1.4720580730,-2.9441161460,1.4720580730,-1.2617640626,1.6823520834,-0.6308820313
0.1300000000,0.0193918053,-0.4886881136,0.7773762272,0.0113118864,0.1903040974,-0.2870721298,0.0951520487,0.3128084890,0.1824716186,-0.3649432372,0.1824716186,-0.1564042445,0.2085389927,-0.0782021222,2.5195885283,1.4697599748,-2.9395199497,1.4697599748,-1.2597942641,1.6797256855,-0.6298971321
0.1400000000,0.0226468840,-0.4867893176,0.7735786353,0.0132106824,0.1886765580,-0.2849020773,0.0943382790,0.3381978099,0.1972820558,-0.3945641116,0.1972820558,-0.1690989050,0.2254652066,-0.0845494525,2.5173649797,1.4684629048,-2.9369258096,1.4684629048,-1.2586824898,1.6782433198,-0.6293412449
0.1500000000,0.0261560917,-0.4847422798,0.7694845596,0.0152577202,0.1869219541,-0.2825626055,0.0934609771,0.3636066556,0.2121038824,-0.4242077649,0.2121038824,-0.1818033278,0.2424044371,-0.0909016639,2.5164678157,1.4679395592,-2.9358791183,1.4679395592,-1.2582339079,1.6776452105,-0.6291169539
0.1600000000,0.0299195974,-0.4825469015,0.7650938031,0.0174530985,0.1850402013,-0.2800536018,0.0925201007,0.3890339729,0.2269364842,-0.4538729683,0.2269364842,-0.1945169864,0.2593559819,-0.0972584932,2.5165820925,1.4680062206,-2.9360124412,1.4680062206,-1.2582910462,1.6777213950,-0.6291455231
0.1700000000,0.0339375494,-0.4802030962,0.7604061924,0.0197969038,0.1830312253,-0.2773749671,0.0915156127,0.4144804821,0.2417802812,-0.4835605625,0.2417802812,-0.2072402411,0.2763203214,-0.1036201205,2.5712342052,1.4998866197,-2.9997732394,1.4998866197,-1.2856171026,1.7141561368,-0.6428085513
0.1800000000,0.0382100796,-0.4777107869,0.7554215738,0.0222892131,0.1808949602,-0.2745266136,0.0904474801,0.4399496705,0.2566373078,-0.5132746156,0.2566373078,-0.2199748352,0.2932997803,-0.1099874176,2.5703909559,1.4993947243,-2.9987894485,1.4993947243,-1.2851954779,1.7135939706,-0.6425977390
0.1900000000,0.0427373015,-0.4750699074,0.7501398149,0.0249300926,0.1786313492,-0.2715084657,0.0893156746,0.4654267687,0.2714989484,-0.5429978969,0.2714989484,-0.2327133844,0.3102845125,-0.1163566922,2.5700679475,1.4992063027,-2.9984126055,1.4992063027,-1.2850339738,1.7133786317,-0.6425169869
0.2000000000,0.0475193158,-0.4722803991,0.7445607983,0.0277196009,0.1762403421,-0.2683204561,0.0881201711,0.4909112306,0.2863648845,-0.5727297690,0.2863648845,-0.2454556153,0.3272741537,-0.1227278076,2.5701631579,1.4992618421,-2.9985236842,1.4992618421,-1.2850815790,1.7134421053,-0.6425407895
0.2100000000,0.0525562127,-0.4693422093,0.7386844185,0.0306577907,0.1737218937,-0.2649625249,0.0868609468,0.5164024132,0.3012347410,-0.6024694820,0.3012347410,-0.2582012066,0.3442682754,-0.1291006033,2.5705935321,1.4995128937,-2.9990257875,1.4995128937,-1.2852967661,1.7137290214,-0.6426483830
0.2200000000,0.0578480733,-0.4662552906,0.7325105811,0.0337447094,0.1710759633,-0.2614346178,0.0855379817,0.5418996246,0.3161081144,-0.6322162287,0.3161081144,-0.2709498123,0.3612664164,-0.1354749062,2.5712921239,1.4999204056,-2.9998408112,1.4999204056,-1.2856460620,1.7141947493,-0.6428230310
0.2300000000,0.0633949692,-0.4630196013,0.7260392026,0.0369803987,0.1683025154,-0.2577366872,0.0841512577,0.5674109491,0.3309897203,-0.6619794407,0.3309897203,-0.2837054746,0.3782739661,-0.1418527373,2.5301339481,1.4759114697,-2.9518229395,1.4759114697,-1.2650669741,1.6867559654,-0.6325334870
0.2400000000,0.0691969624,-0.4596351052,0.7192702105,0.0403648948,0.1654015188,-0.2538686917,0.0827007594,0.5929303912,0.3458760615,-0.6917521231,0.3458760615,-0.2964651956,0.3952869275,-0.1482325978,2.5326648409,1.4773878239,-2.9547756477,1.4773878239,-1.2663324205,1.6884432273,-0.6331662102
0.2500000000,0.0752541086,-0.4561017700,0.7122035400,0.0438982300,0.1623729457,-0.2498305943,0.0811864729,0.6184553299,0.3607656091,-0.7215312182,0.3607656091,-0.3092276649,0.4123035533,-0.1546138325,2.5351903243,1.4788610225,-2.9577220450,1.4788610225,-1.2675951621,1.6901268829,-0.6337975811
0.2600000000,0.0815664568,-0.4524195669,0.7048391338,0.0475804331,0.1592167716,-0.2456223622,0.0796083858,0.6439847927,0.3756577957,-0.7513155914,0.3756577957,-0.3219923963,0.4293231951,-0.1609961982,2.5376890165,1.4803185930,-2.9606371859,1.4803185930,-1.2688445083,1.6917926777,-0.6344222541
0.2700000000,0.0881340499,-0.4485884709,0.6971769418,0.0514115291,0.1559329750,-0.2412439667,0.0779664875,0.6695179008,0.3905521088,-0.7811042176,0.3905521088,-0.3347589504,0.4463452672,-0.1673794752,2.5401463450,1.4817520346,-2.9635040692,1.4817520346,-1.2700731725,1.6934308967,-0.6350365863
0.2800000000,0.0949569253,-0.4446084602,0.6892169205,0.0553915398,0.1525215373,-0.2366953831,0.0762607687,0.6950538573,0.4054480834,-0.8108961669,0.4054480834,-0.3475269287,0.4633692382,-0.1737634643,2.5425531142,1.4831559833,-2.9663119666,1.4831559833,-1.2712765571,1.6950354095,-0.6356382786
0.2900000000,0.1020351148,-0.4404795164,0.6809590328,0.0595204836,0.1489824426,-0.2319765902,0.0744912213,0.7205919350,0.4203452954,-0.8406905908,0.4203452954,-0.3602959675,0.4803946233,-0.1801479838,2.5449043618,1.4845275444,-2.9690550888,1.4845275444,-1.2724521809,1.6966029079,-0.6362260904
0.3000000000,0.1093686449,-0.4362016238,0.6724032476,0.0637983762,0.1453156776,-0.2270875701,0.0726578388,0.7461314654,0.4352433548,-0.8704867096,0.4352433548,-0.3730657327,0.4974209769,-0.1865328663,2.5471984408,1.4858657571,-2.9717315143,1.4858657571,-1.2735992204,1.6981322939,-0.6367996102
0.3100000000,0.1169575373,-0.4317747699,0.6635495398,0.0682252301,0.1415212313,-0.2220283085,0.0707606157,0.7716718282,0.4501418998,-0.9002837996,0.4501418998,-0.3858359141,0.5144478855,-0.1929179571,2.5494362796,1.4871711631,-2.9743423262,1.4871711631,-1.2747181398,1.6996241864,-0.6373590699
0.3200000000,0.1248018088,-0.4271989449,0.6543978897,0.0728010551,0.1375990956,-0.2167987941,0.0687995478,0.7972124423,0.4650405913,-0.9300811826,0.4650405913,-0.3986062211,0.5314749615,-0.1993031106,2.5516207797,1.4884454548,-2.9768909096,1.4884454548,-1.2758103898,1.7010805198,-0.6379051949
0.3300000000,0.1329014713,-0.4224741417,0.6449482835,0.0775258583,0.1335492643,-0.2113990191,0.0667746322,0.8227527569,0.4799391082,-0.9598782164,0.4799391082,-0.4113763785,0.5485018379,-0.2056881892,2.5537563207,1.4896911871,-2.9793823741,1.4896911871,-1.2768781603,1.7025042138,-0.6384390802
0.3400000000,0.1412565321,-0.4176003563,0.6352007125,0.0823996437,0.1293717339,-0.2058289786,0.0646858670,0.8482922453,0.4948371431,-0.9896742862,0.4948371431,-0.4241461227,0.5655281636,-0.2120730613,2.5558483480,1.4909115363,-2.9818230726,1.4909115363,-1.2779241740,1.7038988986,-0.6389620870
0.3500000000,0.1498669938,-0.4125775870,0.6251551739,0.0874224130,0.1250665031,-0.2000886708,0.0625332516,0.8738303983,0.5097343990,-1.0194687980,0.5097343990,-0.4369151991,0.5825535989,-0.2184575996,2.5579030214,1.4921100958,-2.9842201917,1.4921100958,-1.2789515107,1.7052686810,-0.6394757554
0.3600000000,0.1587328541,-0.4074058351,0.6148116702,0.0925941649,0.1206335729,-0.1941780973,0.0603167865,0.8993667191,0.5246305861,-1.0492611723,0.5246305861,-0.4496833595,0.5995778127,-0.2248416798,2.5599269098,1.4932906974,-2.9865813948,1.4932906974,-1.2799634549,1.7066179399,-0.6399817275
0.3700000000,0.1678541063,-0.4020851047,0.6041702093,0.0979148953,0.1160729469,-0.1880972625,0.0580364734,0.9249007197,0.5395254198,-1.0790508397,0.5395254198,-0.4624503599,0.6166004798,-0.2312251799,2.5619267159,1.4944572509,-2.9889145019,1.4944572509,-1.2809633580,1.7079511439,-0.6404816790
0.3800000000,0.1772307386,-0.3966154025,0.5932308050,0.1033845975,0.1113846307,-0.1818461743,0.0556923153,0.9504319178,0.5544186187,-1.1088372375,0.5544186187,-0.4752159589,0.6336212785,-0.2376079795,2.5639090208,1.4956135955,-2.9912271910,1.4956135955,-1.2819545104,1.7092726806,-0.6409772552
0.3900000000,0.1868627346,-0.3909967382,0.5819934763,0.1090032618,0.1065686327,-0.1754248436,0.0532843164,0.9759598343,0.5693099034,-1.1386198067,0.5693099034,-0.4879799172,0.6506398895,-0.2439899586,2.5658800374,1.4967633551,-2.9935267103,1.4967633551,-1.2829400187,1.7105866916,-0.6414700093
0.4000000000,0.1967500727,-0.3852291242,0.5704582485,0.1147708758,0.1016249636,-0.1688332849,0.0508124818,1.0014839922,0.5841989955,-1.1683979909,0.5841989955,-0.5007419961,0.6676559948,-0.2503709981,2.5678453619,1.4979097944,-2.9958195888,1.4979097944,-1.2839226809,1.7118969079,-0.6419613405
0.4100000000,0.2068927264,-0.3793125763,0.5586251526,0.1206874237,0.0965536368,-0.1620715158,0.0482768184,1.0270039158,0.5990856175,-1.1981712351,0.5990856175,-0.5135019579,0.6846692772,-0.2567509789,2.5698097166,1.4990556680,-2.9981113360,1.4990556680,-1.2849048583,1.7132064777,-0.6424524291
0.4200000000,0.2172906634,-0.3732471130,0.5464942260,0.1267528870,0.0913546683,-0.1551395577,0.0456773341,1.0525228938,0.6139716881,-1.2279433761,0.6139716881,-0.5262614469,0.7016819292,-0.2631307235,2.5334478139,1.4778445581,-2.9556891162,1.4778445581,-1.2667239069,1.6889652093,-0.6333619535
0.4300000000,0.2279438391,-0.3670327605,0.5340655210,0.1329672395,0.0860280804,-0.1480374406,0.0430140402,1.0780541229,0.6288649050,-1.2577298101,0.6288649050,-0.5390270615,0.7187027486,-0.2695135307,2.5346702833,1.4785576653,-2.9571153305,1.4785576653,-1.2673351417,1.6897801889,-0.6336675708
0.4400000000,0.2388522072,-0.3606695458,0.5213390916,0.1393304542,0.0805738964,-0.1407651952,0.0402869482,1.1035795454,0.6437547348,-1.2875094697,0.6437547348,-0.5517897727,0.7357196970,-0.2758948864,2.5357608795,1.4791938464,-2.9583876928,1.4791938464,-1.2678804398,1.6905072530,-0.6339402199
0.4500000000,0.2500157197,-0.3541574968,0.5083149936,0.1458425032,0.0749921401,-0.1333228535,0.0374960701,1.1290986643,0.6586408875,-1.3172817751,0.6586408875,-0.5645493322,0.7527324429,-0.2822746661,2.5367138257,1.4797497317,-2.9594994633,1.4797497317,-1.2683569129,1.6911425505,-0.6341784564
0.4600000000,0.2614343228,-0.3474966450,0.4949932901,0.1525033550,0.0692828386,-0.1257104515,0.0346414193,1.1546109590,0.6735230594,-1.3470461188,0.6735230594,-0.5773054795,0.7697406393,-0.2886527397,2.5375199658,1.4802199800,-2.9604399601,1.4802199800,-1.2687599829,1.6916799772,-0.6343799914
0.4700000000,0.2731079561,-0.3406870256,0.4813740513,0.1593129744,0.0634460220,-0.1179280293,0.0317230110,1.1801158814,0.6884009308,-1.3768018617,0.6884009308,-0.5900579407,0.7867439210,-0.2950289704,2.5381662432,1.4805969752,-2.9611939504,1.4805969752,-1.2690831216,1.6921108288,-0.6345415608
0.4800000000,0.2850365524,-0.3337286778,0.4674573555,0.1662713222,0.0574817238,-0.1099756317,0.0287408619,1.2056128523,0.7032741638,-1.4065483277,0.7032741638,-0.6028064261,0.8037419015,-0.3014032131,2.5386350939,1.4808704715,-2.9617409429,1.4808704715,-1.2693175470,1.6924233960,-0.6346587735
0.4900000000,0.2972200378,-0.3266216446,0.4532432892,0.1733783554,0.0513899811,-0.1018533081,0.0256949906,1.2311012549,0.7181423987,-1.4362847974,0.7181423987,-0.6155506275,0.8207341699,-0.3077753137,2.5389037380,1.4810271805,-2.9620543610,1.4810271805,-1.2694518690,1.6926024920,-0.6347259345
0.5000000000,0.3096583306,-0.3193659738,0.4387319477,0.1806340262,0.0451708347,-0.0935611130,0.0225854174,1.2565804284,0.7330052499,-1.4660104998,0.7330052499,-0.6282902142,0.8377202856,-0.3141451071,2.5389433529,1.4810502892,-2.9621005783,1.4810502892,-1.2694716764,1.6926289019,-0.6347358382
0.5100000000,0.3223398040,-0.3119684476,0.4239368953,0.1880315524,0.0388300980,-0.0851067973,0.0194150490,1.2785479637,0.7458196455,-1.4916392910,0.7458196455,-0.6392739819,0.8523653091,-0.3196369909,2.0023556732,1.1680408094,-2.3360816187,1.1680408094,-1.0011778366,1.3349037821,-0.5005889183
0.5200000000,0.3351850019,-0.3044754155,0.4089508311,0.1955245845,0.0324074990,-0.0765433320,0.0162037495,1.2859026483,0.7501098782,-1.5002197564,0.7501098782,-0.6429513242,0.8572684322,-0.3214756621,-0.0191931251,-0.0111959897,0.0223919793,-0.0111959897,0.0095965626,-0.0127954167,0.0047982813
0.5300000000,0.3480434171,-0.2969746734,0.3939493467,0.2030253266,0.0259782915,-0.0679710553,0.0129891457,1.2858989734,0.7501077345,-1.5002154690,0.7501077345,-0.6429494867,0.8572659823,-0.3214747434,-0.0127286032,-0.0074250186,0.0148500371,-0.0074250186,0.0063643016,-0.0084857355,0.0031821508
0.5400000000,0.3609017634,-0.2894739713,0.3789479427,0.2105260287,0.0195491183,-0.0593988244,0.0097745591,1.2858943791,0.7501050544,-1.5002101089,0.7501050544,-0.6429471895,0.8572629194,-0.3214735948,-0.0053671710,-0.0031308497,0.0062616995,-0.0031308497,0.0026835855,-0.0035781140,0.0013417927
0.5500000000,0.3737600481,-0.2819733053,0.3639466106,0.2180266947,0.0131199760,-0.0508266346,0.0065599880,1.2858866790,0.7501005628,-1.5002011255,0.7501005628,-0.6429433395,0.8572577860,-0.3214716698,0.0025824903,0.0015064527,-0.0030129053,0.0015064527,-0.0012912451,0.0017216602,-0.0006456226
0.5600000000,0.3866182799,-0.2744726700,0.3489453401,0.2255273300,0.0066908600,-0.0422544800,0.0033454300,1.2858738787,0.7500930959,-1.5001861918,0.7500930959,-0.6429369394,0.8572492525,-0.3214684697,0.0108938667,0.0063547556,-0.0127095112,0.0063547556,-0.0054469334,0.0072625778,-0.0027234667
0.5700000000,0.3994764703,-0.2669720590,0.3339441180,0.2330279410,0.0002617648,-0.0336823531,0.0001308824,1.2858542266,0.7500816322,-1.5001632644,0.7500816322,-0.6429271133,0.8572361511,-0.3214635567,0.0194052306,0.0113197179,-0.0226394357,0.0113197179,-0.0097026153,0.0129368204,-0.0048513077
0.5800000000,0.4123346333,-0.2594714639,0.3189429278,0.2405285361,-0.0061673166,-0.0251102445,-0.0030836583,1.2858262209,0.7500652955,-1.5001305911,0.7500652955,-0.6429131105,0.8572174806,-0.3214565552,0.0280060331,0.0163368526,-0.0326737053,0.0163368526,-0.0140030165,0.0186706887,-0.0070015083
0.5900000000,0.4251927857,-0.2519708750,0.3039417500,0.2480291250,-0.0125963928,-0.0165381429,-0.0062981964,1.2857885885,0.7500433433,-1.5000866865,0.7500433433,-0.6428942942,0.8571923923,-0.3214471471,0.0366262505,0.0213653128,-0.0427306256,0.0213653128,-0.0183131252,0.0244175003,-0.0091565626
0.6000000000,0.4380509470,-0.2444702809,0.2889405618,0.2555297191,-0.0190254735,-0.0079660353,-0.0095127368,1.2857402461,0.7500151436,-1.5000302872,0.7500151436,-0.6428701231,0.8571601641,-0.3214350615,0.0452280513,0.0263830299,-0.0527660599,0.0263830299,-0.0226140257,0.0301520342,-0.0113070128
0.6100000000,0.4509091177,-0.2369696813,0.2739393626,0.2630303187,-0.0254545589,0.0006060785,-0.0127272794,1.2857455136,0.7500182163,-1.5000364326,0.7500182163,-0.6428727568,0.8571636757,-0.3214363784,-0.0437967180,-0.0255480855,0.0510961709,-0.0255480855,0.0218983590,-0.0291978120,0.0109491795
0.6200000000,0.4637672073,-0.2294691291,0.2589382582,0.2705308709,-0.0318836036,0.0091781382,-0.0159418018,1.2857916427,0.7500451249,-1.5000902498,0.7500451249,-0.6428958213,0.8571944285,-0.3214479107,-0.0311906849,-0.0181945662,0.0363891324,-0.0181945662,0.0155953425,-0.0207937899,0.0077976712
0.6300000000,0.4766252180,-0.2219686228,0.2439372456,0.2780313772,-0.0383126090,0.0177501453,-0.0191563045,1.2858225124,0.7500631322,-1.5001262644,0.7500631322,-0.6429112562,0.8572150083,-0.3214556281,-0.0191112428,-0.0111482250,0.0222964499,-0.0111482250,0.0095556214,-0.0127408285,0.0047778107
0.6400000000,0.4894831709,-0.2144681503,0.2289363006,0.2855318497,-0.0447415854,0.0263221139,-0.0223707927,1.2858377872,0.7500720425,-1.5001440850,0.7500720425,-0.6429188936,0.8572251914,-0.3214594468,-0.0074889372,-0.0043685467,0.0087370934,-0.0043685467,0.0037444686,-0.0049926248,0.0018722343
0.6500000000,0.5023410897,-0.2069676977,0.2139353954,0.2930323023,-0.0511705448,0.0348940598,-0.0255852724,1.2858372226,0.7500717132,-1.5001434264,0.7500717132,-0.6429186113,0.8572248151,-0.3214593056,0.0037526389,0.0021890394,-0.0043780787,0.0021890394,-0.0018763195,0.0025017593,-0.0009381597
0.6600000000,0.5151990005,-0.1994672497,0.1989344995,0.3005327503,-0.0575995002,0.0434660003,-0.0287997501,1.2858205995,0.7500620164,-1.5001240328,0.7500620164,-0.6429102998,0.8572137330,-0.3214551499,0.0146953785,0.0085723041,-0.0171446083,0.0085723041,-0.0073476893,0.0097969190,-0.0036738446
0.6700000000,0.5280569313,-0.1919667901,0.1839335801,0.3080332099,-0.0640284657,0.0520379542,-0.0320142328,1.2857876672,0.7500428059,-1.5000856117,0.7500428059,-0.6428938336,0.8571917781,-0.3214469168,0.0254256344,0.0148316201,-0.0296632401,0.0148316201,-0.0127128172,0.0169504229,-0.0063564086
0.6800000000,0.5409149122,-0.1844663012,0.1689326025,0.3155336988,-0.0704574561,0.0606099414,-0.0352287280,1.2857380953,0.7500138890,-1.5000277779,0.7500138890,-0.6428690477,0.8571587302,-0.3214345238,0.0360335417,0.0210195660,-0.0420391319,0.0210195660,-0.0180167708,0.0240223611,-0.0090083854
0.6900000000,0.5537729351,-0.1769657879,0.1539315757,0.3230342121,-0.0768864675,0.0691819567,-0.0384432338,1.2857507896,0.7500212939,-1.5000425878,0.7500212939,-0.6428753948,0.8571671931,-0.3214376974,-0.0333854524,-0.0194748473,0.0389496945,-0.0194748473,0.0166927262,-0.0222569683,0.0083463631
0.7000000000,0.5666308776,-0.1694653214,0.1389306428,0.3305346786,-0.0833154388,0.0777539184,-0.0416577194,1.2857951947,0.7500471969,-1.5000943938,0.7500471969,-0.6428975973,0.8571967965,-0.3214487987,-0.0217846478,-0.0127077112,0.0254154225,-0.0127077112,0.0108923239,-0.0145230985,0.0054461620
0.7100000000,0.5794887561,-0.1619648923,0.1239297846,0.3380351077,-0.0897443780,0.0863258374,-0.0448721890,1.2858210399,0.7500622732,-1.5001245465,0.7500622732,-0.6429105199,0.8572140266,-0.3214552600,-0.0104249177,-0.0060812020,0.0121624040,-0.0060812020,0.0052124588,-0.0069499451,0.0026062294
0.7200000000,0.5923466031,-0.1544644815,0.1089289631,0.3455355185,-0.0961733015,0.0948977354,-0.0480866508,1.2858285872,0.7500666758,-1.5001333517,0.7500666758,-0.6429142936,0.8572190581,-0.3214571468,0.0008015257,0.0004675566,-0.0009351133,0.0004675566,-0.0004007628,0.0005343505,-0.0002003814
0.7300000000,0.6052044511,-0.1469640702,0.0939281404,0.3530359298,-0.1026022255,0.1034696341,-0.0513011128,1.2858179203,0.7500604535,-1.5001209070,0.7500604535,-0.6429089601,0.8572119468,-0.3214544801,0.0120022973,0.0070013401,-0.0140026802,0.0070013401,-0.0060011487,0.0080015315,-0.0030005743
0.7400000000,0.6180623328,-0.1394636392,0.0789272783,0.3605363608,-0.1090311664,0.1120415552,-0.0545155832,1.2857889366,0.7500435463,-1.5000870926,0.7500435463,-0.6428944683,0.8571926244,-0.3214472341,0.0232851657,0.0135830133,-0.0271660267,0.0135830133,-0.0116425829,0.0155234438,-0.0058212914
0.7500000000,0.6309202813,-0.1319631693,0.0639263385,0.3680368307,-0.1154601406,0.1206135208,-0.0577300703,1.2857413468,0.7500157856,-1.5000315712,0.7500157856,-0.6428706734,0.8571608978,-0.3214353367,0.0347583962,0.0202757311,-0.0405514623,0.0202757311,-0.0173791981,0.0231722642,-0.0086895991
0.7600000000,0.6437782961,-0.1244626606,0.0489253212,0.3755373394,-0.1218891481,0.1291855307,-0.0609445740,1.2857477706,0.7500195328,-1.5000390656,0.7500195328,-0.6428738853,0.8571651804,-0.3214369426,-0.0335512026,-0.0195715349,0.0391430697,-0.0195715349,0.0167756013,-0.0223674684,0.0083878007
0.7700000000,0.6566362507,-0.1169621871,0.0339243741,0.3830378129,-0.1283181254,0.1377575005,-0.0641590627,1.2857940819,0.7500465478,-1.5000930956,0.7500465478,-0.6428970410,0.8571960546,-0.3214485205,-0.0227620987,-0.0132778909,0.0265557818,-0.0132778909,0.0113810493,-0.0151747324,0.0056905247
0.7800000000,0.6694941565,-0.1094617420,0.0189234840,0.3905382580,-0.1347470783,0.1463294377,-0.0673735391,1.2858231905,0.7500635278,-1.5001270556,0.7500635278,-0.6429115953,0.8572154604,-0.3214557976,-0.0118826836,-0.0069315654,0.0138631309,-0.0069315654,0.0059413418,-0.0079217891,0.0029706709
0.7900000000,0.6823520444,-0.1019613075,0.0039226149,0.3980386925,-0.1411760222,0.1549013629,-0.0705880111,1.2858353651,0.7500706296,-1.5001412593,0.7500706296,-0.6429176825,0.8572235767,-0.3214588413,-0.0008163663,-0.0004762137,0.0009524274,-0.0004762137,0.0004081832,-0.0005442442,0.0002040916
0.8000000000,0.6952099436,-0.0944608662,-0.0110782675,0.4055391338,-0.1476049718,0.1634732957,-0.0738024859,1.2858307604,0.7500679436,-1.5001358872,0.7500679436,-0.6429153802,0.8572205070,-0.3214576901,0.0105308698,0.0061430074,-0.0122860148,0.0061430074,-0.0052654349,0.0070205799,-0.0026327175
0.8100000000,0.7080678820,-0.0869604022,-0.0260791956,0.4130395978,-0.1540339410,0.1720452546,-0.0770169705,1.2858094584,0.7500555174,-1.5001110348,0.7500555174,-0.6429047292,0.8572063056,-0.3214523646,0.0222501448,0.0129792511,-0.0259585022,0.0129792511,-0.0111250724,0.0148334299,-0.0055625362
0.8200000000,0.7209258854,-0.0794599002,-0.0410801996,0.4205400998,-0.1604629427,0.1806172569,-0.0802314713,1.2857715166,0.7500333847,-1.5000667693,0.7500333847,-0.6428857583,0.8571810110,-0.3214428791,0.0344291026,0.0200836432,-0.0401672864,0.0200836432,-0.0172145513,0.0229527351,-0.0086072757
0.8300000000,0.7337839772,-0.0719593466,-0.0560813067,0.4280406534,-0.1668919886,0.1891893181,-0.0834459943,1.2857170274,0.7500015993,-1.5000031986,0.7500015993,-0.6428585137,0.8571446849,-0.3214292568,0.0471510061,0.0275047535,-0.0550095071,0.0275047535,-0.0235755030,0.0314340041,-0.0117877515
0.8400000000,0.7466421031,-0.0644587732,-0.0710824537,0.4355412268,-0.1733210516,0.1977614021,-0.0866605258,1.2857671470,0.7500308357,-1.5000616714,0.7500308357,-0.6428835735,0.8571780980,-0.3214417867,-0.0374598641,-0.0218515874,0.0437031747,-0.0218515874,0.0187299320,-0.0249732427,0.0093649660
0.8500000000,0.7595001974,-0.0569582182,-0.0860835636,0.4430417818,-0.1797500987,0.2063334649,-0.0898750494,1.2858100610,0.7500558689,-1.5001117378,0.7500558689,-0.6429050305,0.8572067073,-0.3214525152,-0.0280984104,-0.0163907394,0.0327814788,-0.0163907394,0.0140492052,-0.0187322736,0.0070246026
0.8600000000,0.7723582828,-0.0494576683,-0.1010846633,0.4505423317,-0.1861791414,0.2149055219,-0.0930895707,1.2858411637,0.7500740122,-1.5001480244,0.7500740122,-0.6429205819,0.8572274425,-0.3214602909,-0.0185986909,-0.0108492364,0.0216984727,-0.0108492364,0.0092993455,-0.0123991273,0.0046496727
0.8700000000,0.7852163798,-0.0419571118,-0.1160857764,0.4580428882,-0.1926081899,0.2234775865,-0.0963040950,1.2858614075,0.7500858211,-1.5001716421,0.7500858211,-0.6429307038,0.8572409384,-0.3214653519,-0.0089609708,-0.0052272330,0.0104544660,-0.0052272330,0.0044804854,-0.0059739806,0.0022402427
0.8800000000,0.7980745057,-0.0344565383,-0.1310869234,0.4655434617,-0.1990372529,0.2320496705,-0.0995186264,1.2858719343,0.7500919616,-1.5001839233,0.7500919616,-0.6429359671,0.8572479562,-0.3214679836,0.0007908084,0.0004613049,-0.0009226098,0.0004613049,-0.0003954042,0.0005272056,-0.0001977021
0.8900000000,0.8109326749,-0.0269559396,-0.1460881208,0.4730440604,-0.2054663375,0.2406217833,-0.1027331687,1.2858741350,0.7500932454,-1.5001864908,0.7500932454,-0.6429370675,0.8572494233,-0.3214685337,0.0106028607,0.0061850021,-0.0123700041,0.0061850021,-0.0053014303,0.0070685738,-0.0026507152
0.9000000000,0.8237908984,-0.0194553093,-0.1610893814,0.4805446907,-0.2118954492,0.2491939322,-0.1059477246,1.2858697039,0.7500906606,-1.5001813212,0.7500906606,-0.6429348519,0.8572464692,-0.3214674260,0.0203836296,0.0118904506,-0.0237809012,0.0118904506,-0.0101918148,0.0135890864,-0.0050959074
0.9100000000,0.8366491838,-0.0119546428,-0.1760907144,0.4880453572,-0.2183245919,0.2577661225,-0.1091622959,1.2858606794,0.7500853963,-1.5001707926,0.7500853963,-0.6429303397,0.8572404529,-0.3214651698,0.0299936294,0.0174962838,-0.0349925677,0.0174962838,-0.0149968147,0.0199957530,-0.0074984074
0.9200000000,0.8495075359,-0.0044539374,-0.1910921252,0.4955460626,-0.2247537679,0.2663383572,-0.1123768840,1.2858494625,0.7500788531,-1.5001577062,0.7500788531,-0.6429247312,0.8572329750,-0.3214623656,0.0392324386,0.0228855892,-0.0457711784,0.0228855892,-0.0196162193,0.0261549591,-0.0098081096
0.9300000000,0.8623659570,0.0030468083,-0.2060936165,0.5030468083,-0.2311829785,0.2749106380,-0.1155914893,1.2858387981,0.7500726322,-1.5001452645,0.7500726322,-0.6429193991,0.8572258654,-0.3214596995,0.0478220500,0.0278961958,-0.0557923917,0.0278961958,-0.0239110250,0.0318813667,-0.0119555125
0.9400000000,0.8752214871,0.0105458675,-0.2210917349,0.5105458675,-0.2376107435,0.2834809914,-0.1188053718,1.2823483150,0.7480365171,-1.4960730342,0.7480365171,-0.6411741575,0.8548988767,-0.3205870788,-1.9883869907,-1.1598924113,2.3197848225,-1.1598924113,0.9941934954,-1.3255913271,0.4970967477
0.9500000000,0.8879438235,0.0179672304,-0.2359344608,0.5179672304,-0.2439719118,0.2919625490,-0.1219859559,1.2614071813,0.7358208557,-1.4716417115,0.7358208557,-0.6307035906,0.8409381209,-0.3153517953,-2.5295909024,-1.4755946930,2.9511893861,-1.4755946930,1.2647954512,-1.6863939349,0.6323977256
0.9600000000,0.9004306434,0.0252512086,-0.2505024173,0.5252512086,-0.2502153217,0.3002870956,-0.1251076608,1.2359282906,0.7209581695,-1.4419163390,0.7209581695,-0.6179641453,0.8239521937,-0.3089820726,-2.5299285135,-1.4757916329,2.9515832658,-1.4757916329,1.2649642568,-1.6866190090,0.6324821284
0.9700000000,0.9126626739,0.0323865598,-0.2647731195,0.5323865598,-0.2563313369,0.3084417826,-0.1281656685,1.2104396979,0.7060898238,-1.4121796475,0.7060898238,-0.6052198489,0.8069597986,-0.3026099245,-2.5299985479,-1.4758324863,2.9516649726,-1.4758324863,1.2649992740,-1.6866656986,0.6324996370
0.9800000000,0.9246398321,0.0393732354,-0.2787464707,0.5393732354,-0.2623199160,0.3164265547,-0.1311599580,1.1849421216,0.6912162376,-1.3824324752,0.6912162376,-0.5924710608,0.7899614144,-0.2962355304,-2.5298324081,-1.4757355714,2.9514711428,-1.4757355714,1.2649162040,-1.6865549387,0.6324581020
0.9900000000,0.9363620426,0.0462111915,-0.2924223831,0.5462111915,-0.2681810213,0.3242413617,-0.1340905107,1.1594362237,0.6763377971,-1.3526755943,0.6763377971,-0.5797181118,0.7729574824,-0.2898590559,-2.5294551323,-1.4755154939,2.9510309877,-1.4755154939,1.2647275662,-1.6863034216,0.6323637831
1.0000000000,0.9478292357,0.0529003875,-0.3058007750,0.5529003875,-0.2739146179,0.3318861571,-0.1369573089,1.1339342694,0.6614616572,-1.3229233143,0.6614616572,-0.5669671347,0.7559561796,-0.2834835674,-2.5703310519,-1.4993597803,2.9987195605,-1.4993597803,1.2851655259,-1.7135540346,0.6425827630
1.0100000000,0.9590413433,0.0594407836,-0.3188815672,0.5594407836,-0.2795206716,0.3393608955,-0.1397603358,1.1084324370,0.6465855883,-1.2931711765,0.6465855883,-0.5542162185,0.7389549580,-0.2771081093,-2.5685655748,-1.4983299187,2.9966598373,-1.4983299187,1.2842827874,-1.7123770499,0.6421413937
1.0200000000,0.9699983086,0.0658323467,-0.3316646933,0.5658323467,-0.2849991543,0.3466655390,-0.1424995771,1.0829244674,0.6317059393,-1.2634118786,0.6317059393,-0.5414622337,0.7219496449,-0.2707311168,-2.5667757347,-1.4972858452,2.9945716905,-1.4972858452,1.2833878673,-1.7111838231,0.6416939337
1.0300000000,0.9807000815,0.0720750476,-0.3441500951,0.5720750476,-0.2903500408,0.3538000544,-0.1451750204,1.0574108312,0.6168229849,-1.2336459698,0.6168229849,-0.5287054156,0.7049405542,-0.2643527078,-2.5649647508,-1.4962294380,2.9924588760,-1.4962294380,1.2824823754,-1.7099765006,0.6412411877
1.0400000000,0.9911466182,0.0781688606,-0.3563377212,0.5781688606,-0.2955733091,0.3607644121,-0.1477866545,1.0318919990,0.6019369994,-1.2038739988,0.6019369994,-0.5159459995,0.6879279993,-0.2579729998,-2.5631334425,-1.4951611748,2.9903223496,-1.4951611748,1.2815667213,-1.7087556283,0.6407833606
1.0500000000,1.0013378802,0.0841137635,-0.3682275269,0.5841137635,-0.3006689401,0.3675585868,-0.1503344701,1.0063684401,0.5870482567,-1.1740965135,0.5870482567,-0.5031842201,0.6709122934,-0.2515921100,-2.5612806272,-1.4940803659,2.9881607317,-1.4940803659,1.2806403136,-1.7075204181,0.6403201568
1.0600000000,1.0112738348,0.0899097370,-0.3798194739,0.5899097370,-0.3056369174,0.3741825565,-0.1528184587,0.9808406229,0.5721570300,-1.1443140601,0.5721570300,-0.4904203115,0.6538937486,-0.2452101557,-2.5594034703,-1.4929853576,2.9859707153,-1.4929853576,1.2797017351,-1.7062689802,0.6398508676
1.0700000000,1.0209544544,0.0955567651,-0.3911135302,0.5955567651,-0.3104772272,0.3806363029,-0.1552386136,0.9553090146,0.5572635919,-1.1145271837,0.5572635919,-0.4776545073,0.6368726764,-0.2388272537,-2.5574977952,-1.4918737138,2.9837474277,-1.4918737138,1.2787488976,-1.7049985301,0.6393744488
1.0800000000,1.0303797167,0.1010548347,-0.4021096695,0.6010548347,-0.3151898583,0.3869198111,-0.1575949292,0.9297740819,0.5423682144,-1.0847364289,0.5423682144,-0.4648870410,0.6198493879,-0.2324435205,-2.5555583643,-1.4907423792,2.9814847584,-1.4907423792,1.2777791822,-1.7037055762,0.6388895911
1.0900000000,1.0395496042,0.1064039358,-0.4128078715,0.6064039358,-0.3197748021,0.3930330694,-0.1598874010,0.9042362922,0.5274711704,-1.0549423409,0.5274711704,-0.4521181461,0.6028241948,-0.2260590730,-2.5535791389,-1.4895878310,2.9791756620,-1.4895878310,1.2767895694,-1.7023860926,0.6383947847
1.1000000000,1.0484641043,0.1116040608,-0.4232081217,0.6116040608,-0.3242320521,0.3989760695,-0.1621160261,0.8786961153,0.5125727339,-1.0251454679,0.5125727339,-0.4393480577,0.5857974102,-0.2196740288,-2.5515535262,-1.4884062236,2.9768124472,-1.4884062236,1.2757767631,-1.7010356841,0.6378883815
1.1100000000,1.0571232093,0.1166552054,-0.4333104108,0.6166552054,-0.3285616046,0.4047488062,-0.1642808023,0.8531540263,0.4976731820,-0.9953463640,0.4976731820,-0.4265770132,0.5687693509,-0.2132885066,-2.5494746240,-1.4871935307,2.9743870614,-1.4871935307,1.2747373120,-1.6996497494,0.6373686560
1.1200000000,1.0655269161,0.1215573677,-0.4431147354,0.6215573677,-0.3327634580,0.4103512774,-0.1663817290,0.8276105090,0.4827727969,-0.9655455938,0.4827727969,-0.4138052545,0.5517403393,-0.2069026273,-2.5473354715,-1.4859456917,2.9718913835,-1.4859456917,1.2736677358,-1.6982236477,0.6368338679
1.1300000000,1.0736752262,0.1263105486,-0.4526210973,0.6263105486,-0.3368376131,0.4157834841,-0.1684188066,0.8020660604,0.4678718685,-0.9357437371,0.4678718685,-0.4010330302,0.5347107069,-0.2005165151,-2.5451293159,-1.4846587676,2.9693175352,-1.4846587676,1.2725646579,-1.6967528772,0.6362823290
1.1400000000,1.0815681460,0.1309147519,-0.4618295037,0.6309147519,-0.3407840730,0.4210454307,-0.1703920365,0.7765211961,0.4529706977,-0.9059413954,0.4529706977,-0.3882605980,0.5176807974,-0.1941302990,-2.5428499083,-1.4833291132,2.9666582264,-1.4833291132,1.2714249542,-1.6952332722,0.6357124771
1.1500000000,1.0892056864,0.1353699837,-0.4707399675,0.6353699837,-0.3446028432,0.4261371243,-0.1723014216,0.7509764575,0.4380696002,-0.8761392004,0.4380696002,-0.3754882287,0.5006509716,-0.1877441144,-2.5404918423,-1.4819535747,2.9639071494,-1.4819535747,1.2702459212,-1.6936612282,0.6351229606
1.1600000000,1.0965878630,0.1396762534,-0.4793525069,0.6396762534,-0.3482939315,0.4310585754,-0.1741469658,0.7254324190,0.4231689111,-0.8463378222,0.4231689111,-0.3627162095,0.4836216127,-0.1813581048,-2.5380509508,-1.4805297213,2.9610594425,-1.4805297213,1.2690254754,-1.6920339672,0.6345127377
1.1700000000,1.1037146963,0.1438335729,-0.4876671457,0.6438335729,-0.3518573482,0.4358097975,-0.1759286741,0.6998896978,0.4082689904,-0.8165379808,0.4082689904,-0.3499448489,0.4665931319,-0.1749724245,-2.5355247826,-1.4790561232,2.9581122464,-1.4790561232,1.2677623913,-1.6903498551,0.6338811957
1.1800000000,1.1105862113,0.1478419566,-0.4956839132,0.6478419566,-0.3552931056,0.4403908075,-0.1776465528,0.6743542226,0.3933732965,-0.7867465930,0.3933732965,-0.3371771113,0.4495694817,-0.1685885556,-2.5709641289,-1.4997290752,2.9994581504,-1.4997290752,1.2854820644,-1.7139760859,0.6427410322
1.1900000000,1.1172024324,0.1517014189,-0.5034028378,0.6517014189,-0.3586012162,0.4448016216,-0.1793006081,0.6488344346,0.3784867535,-0.7569735070,0.3784867535,-0.3244172173,0.4325562897,-0.1622086087,-2.5693566763,-1.4987913945,2.9975827890,-1.4987913945,1.2846783381,-1.7129044508,0.6423391691
1.2000000000,1.1235633946,0.1554119802,-0.5108239603,0.6554119802,-0.3617816973,0.4490422630,-0.1808908486,0.6233173954,0.3636018140,-0.7272036280,0.3636018140,-0.3116586977,0.4155449303,-0.1558293488,-2.5678204583,-1.4978952674,2.9957905347,-1.4978952674,1.2839102292,-1.7118803055,0.6419551146
1.2100000000,1.1296691411,0.1589736657,-0.5179473313,0.6589736657,-0.3648345706,0.4531127608,-0.1824172853,0.5978037924,0.3487188789,-0.6974377578,0.3487188789,-0.2989018962,0.3985358616,-0.1494509481,-2.5663727128,-1.4970507491,2.9941014982,-1.4970507491,1.2831863564,-1.7109151418,0.6415931782
1.2200000000,1.1355197216,0.1623865043,-0.5247730085,0.6623865043,-0.3677598608,0.4570131477,-0.1838799304,0.5722943469,0.3338383690,-0.6676767380,0.3338383690,-0.2861471734,0.3815295646,-0.1430735867,-2.5650370136,-1.4962715913,2.9925431826,-1.4962715913,1.2825185068,-1.7100246758,0.6412592534
1.2300000000,1.1411151920,0.1656505287,-0.5313010574,0.6656505287,-0.3705575960,0.4607434614,-0.1852787980,0.5467898141,0.3189607249,-0.6379214498,0.3189607249,-0.2733949071,0.3645265427,-0.1366974535,-2.5638446591,-1.4955760511,2.9911521022,-1.4955760511,1.2819223295,-1.7092297727,0.6409611648
1.2400000000,1.1464556158,0.1687657759,-0.5375315518,0.6687657759,-0.3732278079,0.4643037439,-0.1866139040,0.5212909808,0.3040864055,-0.6081728110,0.3040864055,-0.2606454904,0.3475273206,-0.1303227452,-2.5628363543,-1.4949878733,2.9899757467,-1.4949878733,1.2814181771,-1.7085575695,0.6407090886
1.2500000000,1.1515410639,0.1717322873,-0.5434645746,0.6717322873,-0.3757705320,0.4676940426,-0.1878852660,0.4957986575,0.2892158835,-0.5784317670,0.2892158835,-0.2478993287,0.3305324383,-0.1239496644,-2.5620642437,-1.4945374755,2.9890749510,-1.4945374755,1.2810321218,-1.7080428291,0.6405160609
1.2600000000,1.1563716160,0.1745501093,-0.5491002187,0.6745501093,-0.3781858080,0.4709144107,-0.1890929040,0.4703136626,0.2743496365,-0.5486992730,0.2743496365,-0.2351568313,0.3135424417,-0.1175784157,-2.5615943430,-1.4942633668,2.9885267336,-1.4942633668,1.2807971715,-1.7077295620,0.6403985858
1.2700000000,1.1609473610,0.1772192939,-0.5544385879,0.6772192939,-0.3804736805,0.4739649073,-0.1902368403,0.4448367972,0.2594881317,-0.5189762634,0.2594881317,-0.2224183986,0.2965578648,-0.1112091993,-2.5615094112,-1.4942138232,2.9884276464,-1.4942138232,1.2807547056,-1.7076729408,0.6403773528
1.2800000000,1.1652683983,0.1797398990,-0.5594797980,0.6797398990,-0.3826341992,0.4768455989,-0.1913170996,0.4193688029,0.2446318017,-0.4892636034,0.2446318017,-0.2096844014,0.2795792019,-0.1048422007,-2.5619122633,-1.4944488203,2.9888976406,-1.4944488203,1.2809561317,-1.7079415089,0.6404780658
1.2900000000,1.1693348387,0.1821119892,-0.5642239785,0.6821119892,-0.3846674194,0.4795565591,-0.1923337097,0.3939102985,0.2297810075,-0.4595620149,0.2297810075,-0.1969551492,0.2626068657,-0.0984775746,-2.5629294456,-1.4950421766,2.9900843532,-1.4950421766,1.2814647228,-1.7086196304,0.6407323614
1.3000000000,1.1731468056,0.1843356366,-0.5686712733,0.6843356366,-0.3865734028,0.4820978704,-0.1932867014,0.3684616868,0.2149359840,-0.4298719679,0.2149359840,-0.1842308434,0.2456411245,-0.0921154217,-2.5647150151,-1.4960837588,2.9921675177,-1.4960837588,1.2823575076,-1.7098100101,0.6411787538
1.3100000000,1.1767044364,0.1864109213,-0.5728218425,0.6864109213,-0.3883522182,0.4844696243,-0.1941761091,0.3430230200,0.2000967617,-0.4001935233,0.2000967617,-0.1715115100,0.2286820133,-0.0857557550,-2.5674538230,-1.4976813968,2.9953627935,-1.4976813968,1.2837269115,-1.7116358820,0.6418634558
1.3200000000,1.1800078833,0.1883379319,-0.5766758638,0.6883379319,-0.3900039416,0.4866719222,-0.1950019708,0.3175938120,0.1852630570,-0.3705261140,0.1852630570,-0.1587969060,0.2117292080,-0.0793984530,-2.5713630021,-1.4999617513,2.9999235025,-1.4999617513,1.2856815011,-1.7142420014,0.6428407505
1.3300000000,1.1830573374,0.1901167802,-0.5802335603,0.6901167802,-0.3915286687,0.4887048916,-0.1957643344,0.2922301694,0.1704675988,-0.3409351976,0.1704675988,-0.1461150847,0.1948201129,-0.0730575423,-2.5074936059,-1.4627046034,2.9254092069,-1.4627046034,1.2537468030,-1.6716624039,0.6268734015
1.3400000000,1.1858530327,0.1917476024,-0.5834952048,0.6917476024,-0.3929265163,0.4905686885,-0.1964632582,0.2668903566,0.1556860413,-0.3113720827,0.1556860413,-0.1334451783,0.1779269044,-0.0667225891,-2.5125593872,-1.4656596425,2.9313192851,-1.4656596425,1.2562796936,-1.6750395915,0.6281398468
1.3500000000,1.1883952177,0.1932305437,-0.5864610873,0.6932305437,-0.3941976088,0.4922634785,-0.1970988044,0.2415719662,0.1409169803,-0.2818339606,0.1409169803,-0.1207859831,0.1610479775,-0.0603929916,-2.5203825534,-1.4702231562,2.9404463123,-1.4702231562,1.2601912767,-1.6802550356,0.6300956384
1.3600000000,1.1906841715,0.1945657667,-0.5891315334,0.6945657667,-0.3953420858,0.4937894477,-0.1976710429,0.2162706052,0.1261578530,-0.2523157061,0.1261578530,-0.1081353026,0.1441804035,-0.0540676513,-2.5316526468,-1.4767973773,2.9535947546,-1.4767973773,1.2658263234,-1.6877684312,0.6329131617
1.3700000000,1.1927201997,0.1957534498,-0.5915068996,0.6957534498,-0.3963600998,0.4951467998,-0.1981800499,0.1909778832,0.1114037652,-0.2228075304,0.1114037652,-0.0954889416,0.1273185888,-0.0477444708,-2.5470729502,-1.4857925543,2.9715851086,-1.4857925543,1.2735364751,-1.6980486335,0.6367682376
1.3800000000,1.1945036227,0.1967937799,-0.5935875598,0.6967937799,-0.3972518113,0.4963357484,-0.1986259057,0.1656799741,0.0966466516,-0.1932933031,0.0966466516,-0.0828399870,0.1104533161,-0.0414199935,-2.5671424118,-1.4974997402,2.9949994805,-1.4974997402,1.2835712059,-1.7114282746,0.6417856030
1.3900000000,1.1960349526,0.1976870557,-0.5953741114,0.6976870557,-0.3980174763,0.4973566351,-0.1990087381,0.1405702472,0.0819993109,-0.1639986217,0.0819993109,-0.0702851236,0.0937134981,-0.0351425618,-2.4826683511,-1.4482232048,2.8964464096,-1.4482232048,1.2413341755,-1.6551122341,0.6206670878
1.4000000000,1.1973150119,0.1984337569,-0.5968675139,0.6984337569,-0.3986575059,0.4982100079,-0.1993287530,0.1154845751,0.0673660022,-0.1347320043,0.0673660022,-0.0577422876,0.0769897168,-0.0288711438,-2.5245291779,-1.4726420205,2.9452840409,-1.4726420205,1.2622645890,-1.6830194520,0.6311322945
1.4100000000,1.1983442694,0.1990341572,-0.5980683143,0.6990341572,-0.3991721347,0.4988961796,-0.1995860674,0.0903598362,0.0527099045,-0.1054198089,0.0527099045,-0.0451799181,0.0602398908,-0.0225899591,-2.4050999542,-1.4029749733,2.8059499465,-1.4029749733,1.2025499771,-1.6033999695,0.6012749885
1.4200000000,1.1991241143,0.1994890667,-0.5989781333,0.6994890667,-0.3995620571,0.4994160762,-0.1997810286,0.0655913792,0.0382616379,-0.0765232757,0.0382616379,-0.0327956896,0.0437275861,-0.0163978448,-2.5086534154,-1.4633811590,2.9267623180,-1.4633811590,1.2543267077,-1.6724356103,0.6271633539
1.4300000000,1.1996560710,0.1997993748,-0.5995987496,0.6997993748,-0.3998280355,0.4997707140,-0.1999140178,0.0410822945,0.0239646718,-0.0479293436,0.0239646718,-0.0205411473,0.0273881964,-0.0102705736,-2.3550691592,-1.3737903429,2.7475806858,-1.3737903429,1.1775345796,-1.5700461062,0.5887672898
1.4400000000,1.1999416939,0.1999659881,-0.5999319762,0.6999659881,-0.3999708469,0.4999611292,-0.1999854235,0.0165914466,0.0096783439,-0.0193566877,0.0096783439,-0.0082957233,0.0110609644,-0.0041478617,-2.2426221572,-1.3081962584,2.6163925167,-1.3081962584,1.1213110786,-1.4950814381,0.5606555393
1.4500000000,1.1999999970,0.1999999983,-0.5999999965,0.6999999983,-0.3999999985,0.4999999980,-0.1999999993,0.0000091079,0.0000053129,-0.0000106259,0.0000053129,-0.0000045540,0.0000060719,-0.0000022770,-0.0232361933,-0.0135544461,0.0271088922,-0.0135544461,0.0116180966,-0.0154907955,0.0058090483
1.4519588665,1.2000000000,0.2000000000,-0.6000000000,0.7000000000,-0.4000000000,0.5000000000,-0.2000000000,0.0000000000,-0.0000000000,0.0000000000,-0.0000000000,0.0000000000,0.0000000000,0.0000000000,0.0000000000,0.0000000000,-0.0000000000,0.0000000000,0.0000000000,-0.0000000000,0.0000000000
1 t q1 q2 q3 q4 q5 q6 q7 qd1 qd2 qd3 qd4 qd5 qd6 qd7 qdd1 qdd2 qdd3 qdd4 qdd5 qdd6 qdd7
2 0.0000000000 0.0000000000 -0.5000000000 0.8000000000 0.0000000000 0.2000000000 -0.3000000000 0.1000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000
3 0.0100000000 0.0000303310 -0.4999823069 0.7999646138 0.0000176931 0.1999848345 -0.2999797793 0.0999924172 0.0118947055 0.0069385782 -0.0138771564 0.0069385782 -0.0059473527 0.0079298037 -0.0029736764 2.5705569358 1.4994915459 -2.9989830918 1.4994915459 -1.2852784679 1.7137046239 -0.6426392339
4 0.0200000000 0.0002706117 -0.4998421432 0.7996842864 0.0001578568 0.1998646942 -0.2998195922 0.0999323471 0.0362504791 0.0211461128 -0.0422922256 0.0211461128 -0.0181252396 0.0241669861 -0.0090626198 2.5169090310 1.4681969348 -2.9363938695 1.4681969348 -1.2584545155 1.6779393540 -0.6292272578
5 0.0300000000 0.0007555952 -0.4995592361 0.7991184723 0.0004407639 0.1996222024 -0.2994962699 0.0998111012 0.0607600493 0.0354433621 -0.0708867242 0.0354433621 -0.0303800246 0.0405066995 -0.0151900123 2.5596209442 1.4931122175 -2.9862244349 1.4931122175 -1.2798104721 1.7064139628 -0.6399052361
6 0.0400000000 0.0014880673 -0.4991319607 0.7982639215 0.0008680393 0.1992559664 -0.2990079551 0.0996279832 0.0857190835 0.0500027987 -0.1000055974 0.0500027987 -0.0428595417 0.0571460556 -0.0214297709 2.4658651556 1.4384213408 -2.8768426816 1.4384213408 -1.2329325778 1.6439101038 -0.6164662889
7 0.0500000000 0.0024696657 -0.4985593617 0.7971187233 0.0014406383 0.1987651671 -0.2983535562 0.0993825836 0.1106444598 0.0645426015 -0.1290852031 0.0645426015 -0.0553222299 0.0737629732 -0.0276611149 2.5568927194 1.4915207530 -2.9830415059 1.4915207530 -1.2784463597 1.7045951462 -0.6392231798
8 0.0600000000 0.0037018685 -0.4978405767 0.7956811534 0.0021594233 0.1981490657 -0.2975320877 0.0990745329 0.1358094448 0.0792221761 -0.1584443523 0.0792221761 -0.0679047224 0.0905396299 -0.0339523612 2.5158582466 1.4675839772 -2.9351679544 1.4675839772 -1.2579291233 1.6772388311 -0.6289645616
9 0.0700000000 0.0051853943 -0.4969751867 0.7939503733 0.0030248133 0.1974073029 -0.2965430705 0.0987036514 0.1609332845 0.0938777493 -0.1877554986 0.0938777493 -0.0804666423 0.1072888563 -0.0402333211 2.4840420418 1.4490245244 -2.8980490488 1.4490245244 -1.2420210209 1.6560280279 -0.6210105105
10 0.0800000000 0.0069207211 -0.4959629127 0.7919258254 0.0040370873 0.1965396394 -0.2953861859 0.0982698197 0.1861077050 0.1085628279 -0.2171256559 0.1085628279 -0.0930538525 0.1240718034 -0.0465269263 2.5667165306 1.4972513095 -2.9945026190 1.4972513095 -1.2833582653 1.7111443537 -0.6416791326
11 0.0900000000 0.0089085479 -0.4948033471 0.7896066941 0.0051966529 0.1955457261 -0.2940609681 0.0977728630 0.2114304418 0.1233344244 -0.2466688488 0.1233344244 -0.1057152209 0.1409536279 -0.0528576105 2.5507009528 1.4879088891 -2.9758177783 1.4879088891 -1.2753504764 1.7004673019 -0.6376752382
12 0.1000000000 0.0111492914 -0.4934962467 0.7869924933 0.0065037533 0.1944253543 -0.2925671391 0.0972126771 0.2367541946 0.1381066135 -0.2762132270 0.1381066135 -0.1183770973 0.1578361297 -0.0591885486 2.5385172632 1.4808017369 -2.9616034738 1.4808017369 -1.2692586316 1.6923448422 -0.6346293158
13 0.1100000000 0.0136432400 -0.4920414433 0.7840828866 0.0079585567 0.1931783800 -0.2909045066 0.0965891900 0.2620885162 0.1528849678 -0.3057699355 0.1528849678 -0.1310442581 0.1747256774 -0.0655221290 2.5296551441 1.4756321674 -2.9512643348 1.4756321674 -1.2648275720 1.6864367627 -0.6324137860
14 0.1200000000 0.0163906632 -0.4904387798 0.7808775596 0.0095612202 0.1918046684 -0.2890728912 0.0959023342 0.2874390193 0.1676727613 -0.3353455225 0.1676727613 -0.1437195097 0.1916260129 -0.0718597548 2.5235281251 1.4720580730 -2.9441161460 1.4720580730 -1.2617640626 1.6823520834 -0.6308820313
15 0.1300000000 0.0193918053 -0.4886881136 0.7773762272 0.0113118864 0.1903040974 -0.2870721298 0.0951520487 0.3128084890 0.1824716186 -0.3649432372 0.1824716186 -0.1564042445 0.2085389927 -0.0782021222 2.5195885283 1.4697599748 -2.9395199497 1.4697599748 -1.2597942641 1.6797256855 -0.6298971321
16 0.1400000000 0.0226468840 -0.4867893176 0.7735786353 0.0132106824 0.1886765580 -0.2849020773 0.0943382790 0.3381978099 0.1972820558 -0.3945641116 0.1972820558 -0.1690989050 0.2254652066 -0.0845494525 2.5173649797 1.4684629048 -2.9369258096 1.4684629048 -1.2586824898 1.6782433198 -0.6293412449
17 0.1500000000 0.0261560917 -0.4847422798 0.7694845596 0.0152577202 0.1869219541 -0.2825626055 0.0934609771 0.3636066556 0.2121038824 -0.4242077649 0.2121038824 -0.1818033278 0.2424044371 -0.0909016639 2.5164678157 1.4679395592 -2.9358791183 1.4679395592 -1.2582339079 1.6776452105 -0.6291169539
18 0.1600000000 0.0299195974 -0.4825469015 0.7650938031 0.0174530985 0.1850402013 -0.2800536018 0.0925201007 0.3890339729 0.2269364842 -0.4538729683 0.2269364842 -0.1945169864 0.2593559819 -0.0972584932 2.5165820925 1.4680062206 -2.9360124412 1.4680062206 -1.2582910462 1.6777213950 -0.6291455231
19 0.1700000000 0.0339375494 -0.4802030962 0.7604061924 0.0197969038 0.1830312253 -0.2773749671 0.0915156127 0.4144804821 0.2417802812 -0.4835605625 0.2417802812 -0.2072402411 0.2763203214 -0.1036201205 2.5712342052 1.4998866197 -2.9997732394 1.4998866197 -1.2856171026 1.7141561368 -0.6428085513
20 0.1800000000 0.0382100796 -0.4777107869 0.7554215738 0.0222892131 0.1808949602 -0.2745266136 0.0904474801 0.4399496705 0.2566373078 -0.5132746156 0.2566373078 -0.2199748352 0.2932997803 -0.1099874176 2.5703909559 1.4993947243 -2.9987894485 1.4993947243 -1.2851954779 1.7135939706 -0.6425977390
21 0.1900000000 0.0427373015 -0.4750699074 0.7501398149 0.0249300926 0.1786313492 -0.2715084657 0.0893156746 0.4654267687 0.2714989484 -0.5429978969 0.2714989484 -0.2327133844 0.3102845125 -0.1163566922 2.5700679475 1.4992063027 -2.9984126055 1.4992063027 -1.2850339738 1.7133786317 -0.6425169869
22 0.2000000000 0.0475193158 -0.4722803991 0.7445607983 0.0277196009 0.1762403421 -0.2683204561 0.0881201711 0.4909112306 0.2863648845 -0.5727297690 0.2863648845 -0.2454556153 0.3272741537 -0.1227278076 2.5701631579 1.4992618421 -2.9985236842 1.4992618421 -1.2850815790 1.7134421053 -0.6425407895
23 0.2100000000 0.0525562127 -0.4693422093 0.7386844185 0.0306577907 0.1737218937 -0.2649625249 0.0868609468 0.5164024132 0.3012347410 -0.6024694820 0.3012347410 -0.2582012066 0.3442682754 -0.1291006033 2.5705935321 1.4995128937 -2.9990257875 1.4995128937 -1.2852967661 1.7137290214 -0.6426483830
24 0.2200000000 0.0578480733 -0.4662552906 0.7325105811 0.0337447094 0.1710759633 -0.2614346178 0.0855379817 0.5418996246 0.3161081144 -0.6322162287 0.3161081144 -0.2709498123 0.3612664164 -0.1354749062 2.5712921239 1.4999204056 -2.9998408112 1.4999204056 -1.2856460620 1.7141947493 -0.6428230310
25 0.2300000000 0.0633949692 -0.4630196013 0.7260392026 0.0369803987 0.1683025154 -0.2577366872 0.0841512577 0.5674109491 0.3309897203 -0.6619794407 0.3309897203 -0.2837054746 0.3782739661 -0.1418527373 2.5301339481 1.4759114697 -2.9518229395 1.4759114697 -1.2650669741 1.6867559654 -0.6325334870
26 0.2400000000 0.0691969624 -0.4596351052 0.7192702105 0.0403648948 0.1654015188 -0.2538686917 0.0827007594 0.5929303912 0.3458760615 -0.6917521231 0.3458760615 -0.2964651956 0.3952869275 -0.1482325978 2.5326648409 1.4773878239 -2.9547756477 1.4773878239 -1.2663324205 1.6884432273 -0.6331662102
27 0.2500000000 0.0752541086 -0.4561017700 0.7122035400 0.0438982300 0.1623729457 -0.2498305943 0.0811864729 0.6184553299 0.3607656091 -0.7215312182 0.3607656091 -0.3092276649 0.4123035533 -0.1546138325 2.5351903243 1.4788610225 -2.9577220450 1.4788610225 -1.2675951621 1.6901268829 -0.6337975811
28 0.2600000000 0.0815664568 -0.4524195669 0.7048391338 0.0475804331 0.1592167716 -0.2456223622 0.0796083858 0.6439847927 0.3756577957 -0.7513155914 0.3756577957 -0.3219923963 0.4293231951 -0.1609961982 2.5376890165 1.4803185930 -2.9606371859 1.4803185930 -1.2688445083 1.6917926777 -0.6344222541
29 0.2700000000 0.0881340499 -0.4485884709 0.6971769418 0.0514115291 0.1559329750 -0.2412439667 0.0779664875 0.6695179008 0.3905521088 -0.7811042176 0.3905521088 -0.3347589504 0.4463452672 -0.1673794752 2.5401463450 1.4817520346 -2.9635040692 1.4817520346 -1.2700731725 1.6934308967 -0.6350365863
30 0.2800000000 0.0949569253 -0.4446084602 0.6892169205 0.0553915398 0.1525215373 -0.2366953831 0.0762607687 0.6950538573 0.4054480834 -0.8108961669 0.4054480834 -0.3475269287 0.4633692382 -0.1737634643 2.5425531142 1.4831559833 -2.9663119666 1.4831559833 -1.2712765571 1.6950354095 -0.6356382786
31 0.2900000000 0.1020351148 -0.4404795164 0.6809590328 0.0595204836 0.1489824426 -0.2319765902 0.0744912213 0.7205919350 0.4203452954 -0.8406905908 0.4203452954 -0.3602959675 0.4803946233 -0.1801479838 2.5449043618 1.4845275444 -2.9690550888 1.4845275444 -1.2724521809 1.6966029079 -0.6362260904
32 0.3000000000 0.1093686449 -0.4362016238 0.6724032476 0.0637983762 0.1453156776 -0.2270875701 0.0726578388 0.7461314654 0.4352433548 -0.8704867096 0.4352433548 -0.3730657327 0.4974209769 -0.1865328663 2.5471984408 1.4858657571 -2.9717315143 1.4858657571 -1.2735992204 1.6981322939 -0.6367996102
33 0.3100000000 0.1169575373 -0.4317747699 0.6635495398 0.0682252301 0.1415212313 -0.2220283085 0.0707606157 0.7716718282 0.4501418998 -0.9002837996 0.4501418998 -0.3858359141 0.5144478855 -0.1929179571 2.5494362796 1.4871711631 -2.9743423262 1.4871711631 -1.2747181398 1.6996241864 -0.6373590699
34 0.3200000000 0.1248018088 -0.4271989449 0.6543978897 0.0728010551 0.1375990956 -0.2167987941 0.0687995478 0.7972124423 0.4650405913 -0.9300811826 0.4650405913 -0.3986062211 0.5314749615 -0.1993031106 2.5516207797 1.4884454548 -2.9768909096 1.4884454548 -1.2758103898 1.7010805198 -0.6379051949
35 0.3300000000 0.1329014713 -0.4224741417 0.6449482835 0.0775258583 0.1335492643 -0.2113990191 0.0667746322 0.8227527569 0.4799391082 -0.9598782164 0.4799391082 -0.4113763785 0.5485018379 -0.2056881892 2.5537563207 1.4896911871 -2.9793823741 1.4896911871 -1.2768781603 1.7025042138 -0.6384390802
36 0.3400000000 0.1412565321 -0.4176003563 0.6352007125 0.0823996437 0.1293717339 -0.2058289786 0.0646858670 0.8482922453 0.4948371431 -0.9896742862 0.4948371431 -0.4241461227 0.5655281636 -0.2120730613 2.5558483480 1.4909115363 -2.9818230726 1.4909115363 -1.2779241740 1.7038988986 -0.6389620870
37 0.3500000000 0.1498669938 -0.4125775870 0.6251551739 0.0874224130 0.1250665031 -0.2000886708 0.0625332516 0.8738303983 0.5097343990 -1.0194687980 0.5097343990 -0.4369151991 0.5825535989 -0.2184575996 2.5579030214 1.4921100958 -2.9842201917 1.4921100958 -1.2789515107 1.7052686810 -0.6394757554
38 0.3600000000 0.1587328541 -0.4074058351 0.6148116702 0.0925941649 0.1206335729 -0.1941780973 0.0603167865 0.8993667191 0.5246305861 -1.0492611723 0.5246305861 -0.4496833595 0.5995778127 -0.2248416798 2.5599269098 1.4932906974 -2.9865813948 1.4932906974 -1.2799634549 1.7066179399 -0.6399817275
39 0.3700000000 0.1678541063 -0.4020851047 0.6041702093 0.0979148953 0.1160729469 -0.1880972625 0.0580364734 0.9249007197 0.5395254198 -1.0790508397 0.5395254198 -0.4624503599 0.6166004798 -0.2312251799 2.5619267159 1.4944572509 -2.9889145019 1.4944572509 -1.2809633580 1.7079511439 -0.6404816790
40 0.3800000000 0.1772307386 -0.3966154025 0.5932308050 0.1033845975 0.1113846307 -0.1818461743 0.0556923153 0.9504319178 0.5544186187 -1.1088372375 0.5544186187 -0.4752159589 0.6336212785 -0.2376079795 2.5639090208 1.4956135955 -2.9912271910 1.4956135955 -1.2819545104 1.7092726806 -0.6409772552
41 0.3900000000 0.1868627346 -0.3909967382 0.5819934763 0.1090032618 0.1065686327 -0.1754248436 0.0532843164 0.9759598343 0.5693099034 -1.1386198067 0.5693099034 -0.4879799172 0.6506398895 -0.2439899586 2.5658800374 1.4967633551 -2.9935267103 1.4967633551 -1.2829400187 1.7105866916 -0.6414700093
42 0.4000000000 0.1967500727 -0.3852291242 0.5704582485 0.1147708758 0.1016249636 -0.1688332849 0.0508124818 1.0014839922 0.5841989955 -1.1683979909 0.5841989955 -0.5007419961 0.6676559948 -0.2503709981 2.5678453619 1.4979097944 -2.9958195888 1.4979097944 -1.2839226809 1.7118969079 -0.6419613405
43 0.4100000000 0.2068927264 -0.3793125763 0.5586251526 0.1206874237 0.0965536368 -0.1620715158 0.0482768184 1.0270039158 0.5990856175 -1.1981712351 0.5990856175 -0.5135019579 0.6846692772 -0.2567509789 2.5698097166 1.4990556680 -2.9981113360 1.4990556680 -1.2849048583 1.7132064777 -0.6424524291
44 0.4200000000 0.2172906634 -0.3732471130 0.5464942260 0.1267528870 0.0913546683 -0.1551395577 0.0456773341 1.0525228938 0.6139716881 -1.2279433761 0.6139716881 -0.5262614469 0.7016819292 -0.2631307235 2.5334478139 1.4778445581 -2.9556891162 1.4778445581 -1.2667239069 1.6889652093 -0.6333619535
45 0.4300000000 0.2279438391 -0.3670327605 0.5340655210 0.1329672395 0.0860280804 -0.1480374406 0.0430140402 1.0780541229 0.6288649050 -1.2577298101 0.6288649050 -0.5390270615 0.7187027486 -0.2695135307 2.5346702833 1.4785576653 -2.9571153305 1.4785576653 -1.2673351417 1.6897801889 -0.6336675708
46 0.4400000000 0.2388522072 -0.3606695458 0.5213390916 0.1393304542 0.0805738964 -0.1407651952 0.0402869482 1.1035795454 0.6437547348 -1.2875094697 0.6437547348 -0.5517897727 0.7357196970 -0.2758948864 2.5357608795 1.4791938464 -2.9583876928 1.4791938464 -1.2678804398 1.6905072530 -0.6339402199
47 0.4500000000 0.2500157197 -0.3541574968 0.5083149936 0.1458425032 0.0749921401 -0.1333228535 0.0374960701 1.1290986643 0.6586408875 -1.3172817751 0.6586408875 -0.5645493322 0.7527324429 -0.2822746661 2.5367138257 1.4797497317 -2.9594994633 1.4797497317 -1.2683569129 1.6911425505 -0.6341784564
48 0.4600000000 0.2614343228 -0.3474966450 0.4949932901 0.1525033550 0.0692828386 -0.1257104515 0.0346414193 1.1546109590 0.6735230594 -1.3470461188 0.6735230594 -0.5773054795 0.7697406393 -0.2886527397 2.5375199658 1.4802199800 -2.9604399601 1.4802199800 -1.2687599829 1.6916799772 -0.6343799914
49 0.4700000000 0.2731079561 -0.3406870256 0.4813740513 0.1593129744 0.0634460220 -0.1179280293 0.0317230110 1.1801158814 0.6884009308 -1.3768018617 0.6884009308 -0.5900579407 0.7867439210 -0.2950289704 2.5381662432 1.4805969752 -2.9611939504 1.4805969752 -1.2690831216 1.6921108288 -0.6345415608
50 0.4800000000 0.2850365524 -0.3337286778 0.4674573555 0.1662713222 0.0574817238 -0.1099756317 0.0287408619 1.2056128523 0.7032741638 -1.4065483277 0.7032741638 -0.6028064261 0.8037419015 -0.3014032131 2.5386350939 1.4808704715 -2.9617409429 1.4808704715 -1.2693175470 1.6924233960 -0.6346587735
51 0.4900000000 0.2972200378 -0.3266216446 0.4532432892 0.1733783554 0.0513899811 -0.1018533081 0.0256949906 1.2311012549 0.7181423987 -1.4362847974 0.7181423987 -0.6155506275 0.8207341699 -0.3077753137 2.5389037380 1.4810271805 -2.9620543610 1.4810271805 -1.2694518690 1.6926024920 -0.6347259345
52 0.5000000000 0.3096583306 -0.3193659738 0.4387319477 0.1806340262 0.0451708347 -0.0935611130 0.0225854174 1.2565804284 0.7330052499 -1.4660104998 0.7330052499 -0.6282902142 0.8377202856 -0.3141451071 2.5389433529 1.4810502892 -2.9621005783 1.4810502892 -1.2694716764 1.6926289019 -0.6347358382
53 0.5100000000 0.3223398040 -0.3119684476 0.4239368953 0.1880315524 0.0388300980 -0.0851067973 0.0194150490 1.2785479637 0.7458196455 -1.4916392910 0.7458196455 -0.6392739819 0.8523653091 -0.3196369909 2.0023556732 1.1680408094 -2.3360816187 1.1680408094 -1.0011778366 1.3349037821 -0.5005889183
54 0.5200000000 0.3351850019 -0.3044754155 0.4089508311 0.1955245845 0.0324074990 -0.0765433320 0.0162037495 1.2859026483 0.7501098782 -1.5002197564 0.7501098782 -0.6429513242 0.8572684322 -0.3214756621 -0.0191931251 -0.0111959897 0.0223919793 -0.0111959897 0.0095965626 -0.0127954167 0.0047982813
55 0.5300000000 0.3480434171 -0.2969746734 0.3939493467 0.2030253266 0.0259782915 -0.0679710553 0.0129891457 1.2858989734 0.7501077345 -1.5002154690 0.7501077345 -0.6429494867 0.8572659823 -0.3214747434 -0.0127286032 -0.0074250186 0.0148500371 -0.0074250186 0.0063643016 -0.0084857355 0.0031821508
56 0.5400000000 0.3609017634 -0.2894739713 0.3789479427 0.2105260287 0.0195491183 -0.0593988244 0.0097745591 1.2858943791 0.7501050544 -1.5002101089 0.7501050544 -0.6429471895 0.8572629194 -0.3214735948 -0.0053671710 -0.0031308497 0.0062616995 -0.0031308497 0.0026835855 -0.0035781140 0.0013417927
57 0.5500000000 0.3737600481 -0.2819733053 0.3639466106 0.2180266947 0.0131199760 -0.0508266346 0.0065599880 1.2858866790 0.7501005628 -1.5002011255 0.7501005628 -0.6429433395 0.8572577860 -0.3214716698 0.0025824903 0.0015064527 -0.0030129053 0.0015064527 -0.0012912451 0.0017216602 -0.0006456226
58 0.5600000000 0.3866182799 -0.2744726700 0.3489453401 0.2255273300 0.0066908600 -0.0422544800 0.0033454300 1.2858738787 0.7500930959 -1.5001861918 0.7500930959 -0.6429369394 0.8572492525 -0.3214684697 0.0108938667 0.0063547556 -0.0127095112 0.0063547556 -0.0054469334 0.0072625778 -0.0027234667
59 0.5700000000 0.3994764703 -0.2669720590 0.3339441180 0.2330279410 0.0002617648 -0.0336823531 0.0001308824 1.2858542266 0.7500816322 -1.5001632644 0.7500816322 -0.6429271133 0.8572361511 -0.3214635567 0.0194052306 0.0113197179 -0.0226394357 0.0113197179 -0.0097026153 0.0129368204 -0.0048513077
60 0.5800000000 0.4123346333 -0.2594714639 0.3189429278 0.2405285361 -0.0061673166 -0.0251102445 -0.0030836583 1.2858262209 0.7500652955 -1.5001305911 0.7500652955 -0.6429131105 0.8572174806 -0.3214565552 0.0280060331 0.0163368526 -0.0326737053 0.0163368526 -0.0140030165 0.0186706887 -0.0070015083
61 0.5900000000 0.4251927857 -0.2519708750 0.3039417500 0.2480291250 -0.0125963928 -0.0165381429 -0.0062981964 1.2857885885 0.7500433433 -1.5000866865 0.7500433433 -0.6428942942 0.8571923923 -0.3214471471 0.0366262505 0.0213653128 -0.0427306256 0.0213653128 -0.0183131252 0.0244175003 -0.0091565626
62 0.6000000000 0.4380509470 -0.2444702809 0.2889405618 0.2555297191 -0.0190254735 -0.0079660353 -0.0095127368 1.2857402461 0.7500151436 -1.5000302872 0.7500151436 -0.6428701231 0.8571601641 -0.3214350615 0.0452280513 0.0263830299 -0.0527660599 0.0263830299 -0.0226140257 0.0301520342 -0.0113070128
63 0.6100000000 0.4509091177 -0.2369696813 0.2739393626 0.2630303187 -0.0254545589 0.0006060785 -0.0127272794 1.2857455136 0.7500182163 -1.5000364326 0.7500182163 -0.6428727568 0.8571636757 -0.3214363784 -0.0437967180 -0.0255480855 0.0510961709 -0.0255480855 0.0218983590 -0.0291978120 0.0109491795
64 0.6200000000 0.4637672073 -0.2294691291 0.2589382582 0.2705308709 -0.0318836036 0.0091781382 -0.0159418018 1.2857916427 0.7500451249 -1.5000902498 0.7500451249 -0.6428958213 0.8571944285 -0.3214479107 -0.0311906849 -0.0181945662 0.0363891324 -0.0181945662 0.0155953425 -0.0207937899 0.0077976712
65 0.6300000000 0.4766252180 -0.2219686228 0.2439372456 0.2780313772 -0.0383126090 0.0177501453 -0.0191563045 1.2858225124 0.7500631322 -1.5001262644 0.7500631322 -0.6429112562 0.8572150083 -0.3214556281 -0.0191112428 -0.0111482250 0.0222964499 -0.0111482250 0.0095556214 -0.0127408285 0.0047778107
66 0.6400000000 0.4894831709 -0.2144681503 0.2289363006 0.2855318497 -0.0447415854 0.0263221139 -0.0223707927 1.2858377872 0.7500720425 -1.5001440850 0.7500720425 -0.6429188936 0.8572251914 -0.3214594468 -0.0074889372 -0.0043685467 0.0087370934 -0.0043685467 0.0037444686 -0.0049926248 0.0018722343
67 0.6500000000 0.5023410897 -0.2069676977 0.2139353954 0.2930323023 -0.0511705448 0.0348940598 -0.0255852724 1.2858372226 0.7500717132 -1.5001434264 0.7500717132 -0.6429186113 0.8572248151 -0.3214593056 0.0037526389 0.0021890394 -0.0043780787 0.0021890394 -0.0018763195 0.0025017593 -0.0009381597
68 0.6600000000 0.5151990005 -0.1994672497 0.1989344995 0.3005327503 -0.0575995002 0.0434660003 -0.0287997501 1.2858205995 0.7500620164 -1.5001240328 0.7500620164 -0.6429102998 0.8572137330 -0.3214551499 0.0146953785 0.0085723041 -0.0171446083 0.0085723041 -0.0073476893 0.0097969190 -0.0036738446
69 0.6700000000 0.5280569313 -0.1919667901 0.1839335801 0.3080332099 -0.0640284657 0.0520379542 -0.0320142328 1.2857876672 0.7500428059 -1.5000856117 0.7500428059 -0.6428938336 0.8571917781 -0.3214469168 0.0254256344 0.0148316201 -0.0296632401 0.0148316201 -0.0127128172 0.0169504229 -0.0063564086
70 0.6800000000 0.5409149122 -0.1844663012 0.1689326025 0.3155336988 -0.0704574561 0.0606099414 -0.0352287280 1.2857380953 0.7500138890 -1.5000277779 0.7500138890 -0.6428690477 0.8571587302 -0.3214345238 0.0360335417 0.0210195660 -0.0420391319 0.0210195660 -0.0180167708 0.0240223611 -0.0090083854
71 0.6900000000 0.5537729351 -0.1769657879 0.1539315757 0.3230342121 -0.0768864675 0.0691819567 -0.0384432338 1.2857507896 0.7500212939 -1.5000425878 0.7500212939 -0.6428753948 0.8571671931 -0.3214376974 -0.0333854524 -0.0194748473 0.0389496945 -0.0194748473 0.0166927262 -0.0222569683 0.0083463631
72 0.7000000000 0.5666308776 -0.1694653214 0.1389306428 0.3305346786 -0.0833154388 0.0777539184 -0.0416577194 1.2857951947 0.7500471969 -1.5000943938 0.7500471969 -0.6428975973 0.8571967965 -0.3214487987 -0.0217846478 -0.0127077112 0.0254154225 -0.0127077112 0.0108923239 -0.0145230985 0.0054461620
73 0.7100000000 0.5794887561 -0.1619648923 0.1239297846 0.3380351077 -0.0897443780 0.0863258374 -0.0448721890 1.2858210399 0.7500622732 -1.5001245465 0.7500622732 -0.6429105199 0.8572140266 -0.3214552600 -0.0104249177 -0.0060812020 0.0121624040 -0.0060812020 0.0052124588 -0.0069499451 0.0026062294
74 0.7200000000 0.5923466031 -0.1544644815 0.1089289631 0.3455355185 -0.0961733015 0.0948977354 -0.0480866508 1.2858285872 0.7500666758 -1.5001333517 0.7500666758 -0.6429142936 0.8572190581 -0.3214571468 0.0008015257 0.0004675566 -0.0009351133 0.0004675566 -0.0004007628 0.0005343505 -0.0002003814
75 0.7300000000 0.6052044511 -0.1469640702 0.0939281404 0.3530359298 -0.1026022255 0.1034696341 -0.0513011128 1.2858179203 0.7500604535 -1.5001209070 0.7500604535 -0.6429089601 0.8572119468 -0.3214544801 0.0120022973 0.0070013401 -0.0140026802 0.0070013401 -0.0060011487 0.0080015315 -0.0030005743
76 0.7400000000 0.6180623328 -0.1394636392 0.0789272783 0.3605363608 -0.1090311664 0.1120415552 -0.0545155832 1.2857889366 0.7500435463 -1.5000870926 0.7500435463 -0.6428944683 0.8571926244 -0.3214472341 0.0232851657 0.0135830133 -0.0271660267 0.0135830133 -0.0116425829 0.0155234438 -0.0058212914
77 0.7500000000 0.6309202813 -0.1319631693 0.0639263385 0.3680368307 -0.1154601406 0.1206135208 -0.0577300703 1.2857413468 0.7500157856 -1.5000315712 0.7500157856 -0.6428706734 0.8571608978 -0.3214353367 0.0347583962 0.0202757311 -0.0405514623 0.0202757311 -0.0173791981 0.0231722642 -0.0086895991
78 0.7600000000 0.6437782961 -0.1244626606 0.0489253212 0.3755373394 -0.1218891481 0.1291855307 -0.0609445740 1.2857477706 0.7500195328 -1.5000390656 0.7500195328 -0.6428738853 0.8571651804 -0.3214369426 -0.0335512026 -0.0195715349 0.0391430697 -0.0195715349 0.0167756013 -0.0223674684 0.0083878007
79 0.7700000000 0.6566362507 -0.1169621871 0.0339243741 0.3830378129 -0.1283181254 0.1377575005 -0.0641590627 1.2857940819 0.7500465478 -1.5000930956 0.7500465478 -0.6428970410 0.8571960546 -0.3214485205 -0.0227620987 -0.0132778909 0.0265557818 -0.0132778909 0.0113810493 -0.0151747324 0.0056905247
80 0.7800000000 0.6694941565 -0.1094617420 0.0189234840 0.3905382580 -0.1347470783 0.1463294377 -0.0673735391 1.2858231905 0.7500635278 -1.5001270556 0.7500635278 -0.6429115953 0.8572154604 -0.3214557976 -0.0118826836 -0.0069315654 0.0138631309 -0.0069315654 0.0059413418 -0.0079217891 0.0029706709
81 0.7900000000 0.6823520444 -0.1019613075 0.0039226149 0.3980386925 -0.1411760222 0.1549013629 -0.0705880111 1.2858353651 0.7500706296 -1.5001412593 0.7500706296 -0.6429176825 0.8572235767 -0.3214588413 -0.0008163663 -0.0004762137 0.0009524274 -0.0004762137 0.0004081832 -0.0005442442 0.0002040916
82 0.8000000000 0.6952099436 -0.0944608662 -0.0110782675 0.4055391338 -0.1476049718 0.1634732957 -0.0738024859 1.2858307604 0.7500679436 -1.5001358872 0.7500679436 -0.6429153802 0.8572205070 -0.3214576901 0.0105308698 0.0061430074 -0.0122860148 0.0061430074 -0.0052654349 0.0070205799 -0.0026327175
83 0.8100000000 0.7080678820 -0.0869604022 -0.0260791956 0.4130395978 -0.1540339410 0.1720452546 -0.0770169705 1.2858094584 0.7500555174 -1.5001110348 0.7500555174 -0.6429047292 0.8572063056 -0.3214523646 0.0222501448 0.0129792511 -0.0259585022 0.0129792511 -0.0111250724 0.0148334299 -0.0055625362
84 0.8200000000 0.7209258854 -0.0794599002 -0.0410801996 0.4205400998 -0.1604629427 0.1806172569 -0.0802314713 1.2857715166 0.7500333847 -1.5000667693 0.7500333847 -0.6428857583 0.8571810110 -0.3214428791 0.0344291026 0.0200836432 -0.0401672864 0.0200836432 -0.0172145513 0.0229527351 -0.0086072757
85 0.8300000000 0.7337839772 -0.0719593466 -0.0560813067 0.4280406534 -0.1668919886 0.1891893181 -0.0834459943 1.2857170274 0.7500015993 -1.5000031986 0.7500015993 -0.6428585137 0.8571446849 -0.3214292568 0.0471510061 0.0275047535 -0.0550095071 0.0275047535 -0.0235755030 0.0314340041 -0.0117877515
86 0.8400000000 0.7466421031 -0.0644587732 -0.0710824537 0.4355412268 -0.1733210516 0.1977614021 -0.0866605258 1.2857671470 0.7500308357 -1.5000616714 0.7500308357 -0.6428835735 0.8571780980 -0.3214417867 -0.0374598641 -0.0218515874 0.0437031747 -0.0218515874 0.0187299320 -0.0249732427 0.0093649660
87 0.8500000000 0.7595001974 -0.0569582182 -0.0860835636 0.4430417818 -0.1797500987 0.2063334649 -0.0898750494 1.2858100610 0.7500558689 -1.5001117378 0.7500558689 -0.6429050305 0.8572067073 -0.3214525152 -0.0280984104 -0.0163907394 0.0327814788 -0.0163907394 0.0140492052 -0.0187322736 0.0070246026
88 0.8600000000 0.7723582828 -0.0494576683 -0.1010846633 0.4505423317 -0.1861791414 0.2149055219 -0.0930895707 1.2858411637 0.7500740122 -1.5001480244 0.7500740122 -0.6429205819 0.8572274425 -0.3214602909 -0.0185986909 -0.0108492364 0.0216984727 -0.0108492364 0.0092993455 -0.0123991273 0.0046496727
89 0.8700000000 0.7852163798 -0.0419571118 -0.1160857764 0.4580428882 -0.1926081899 0.2234775865 -0.0963040950 1.2858614075 0.7500858211 -1.5001716421 0.7500858211 -0.6429307038 0.8572409384 -0.3214653519 -0.0089609708 -0.0052272330 0.0104544660 -0.0052272330 0.0044804854 -0.0059739806 0.0022402427
90 0.8800000000 0.7980745057 -0.0344565383 -0.1310869234 0.4655434617 -0.1990372529 0.2320496705 -0.0995186264 1.2858719343 0.7500919616 -1.5001839233 0.7500919616 -0.6429359671 0.8572479562 -0.3214679836 0.0007908084 0.0004613049 -0.0009226098 0.0004613049 -0.0003954042 0.0005272056 -0.0001977021
91 0.8900000000 0.8109326749 -0.0269559396 -0.1460881208 0.4730440604 -0.2054663375 0.2406217833 -0.1027331687 1.2858741350 0.7500932454 -1.5001864908 0.7500932454 -0.6429370675 0.8572494233 -0.3214685337 0.0106028607 0.0061850021 -0.0123700041 0.0061850021 -0.0053014303 0.0070685738 -0.0026507152
92 0.9000000000 0.8237908984 -0.0194553093 -0.1610893814 0.4805446907 -0.2118954492 0.2491939322 -0.1059477246 1.2858697039 0.7500906606 -1.5001813212 0.7500906606 -0.6429348519 0.8572464692 -0.3214674260 0.0203836296 0.0118904506 -0.0237809012 0.0118904506 -0.0101918148 0.0135890864 -0.0050959074
93 0.9100000000 0.8366491838 -0.0119546428 -0.1760907144 0.4880453572 -0.2183245919 0.2577661225 -0.1091622959 1.2858606794 0.7500853963 -1.5001707926 0.7500853963 -0.6429303397 0.8572404529 -0.3214651698 0.0299936294 0.0174962838 -0.0349925677 0.0174962838 -0.0149968147 0.0199957530 -0.0074984074
94 0.9200000000 0.8495075359 -0.0044539374 -0.1910921252 0.4955460626 -0.2247537679 0.2663383572 -0.1123768840 1.2858494625 0.7500788531 -1.5001577062 0.7500788531 -0.6429247312 0.8572329750 -0.3214623656 0.0392324386 0.0228855892 -0.0457711784 0.0228855892 -0.0196162193 0.0261549591 -0.0098081096
95 0.9300000000 0.8623659570 0.0030468083 -0.2060936165 0.5030468083 -0.2311829785 0.2749106380 -0.1155914893 1.2858387981 0.7500726322 -1.5001452645 0.7500726322 -0.6429193991 0.8572258654 -0.3214596995 0.0478220500 0.0278961958 -0.0557923917 0.0278961958 -0.0239110250 0.0318813667 -0.0119555125
96 0.9400000000 0.8752214871 0.0105458675 -0.2210917349 0.5105458675 -0.2376107435 0.2834809914 -0.1188053718 1.2823483150 0.7480365171 -1.4960730342 0.7480365171 -0.6411741575 0.8548988767 -0.3205870788 -1.9883869907 -1.1598924113 2.3197848225 -1.1598924113 0.9941934954 -1.3255913271 0.4970967477
97 0.9500000000 0.8879438235 0.0179672304 -0.2359344608 0.5179672304 -0.2439719118 0.2919625490 -0.1219859559 1.2614071813 0.7358208557 -1.4716417115 0.7358208557 -0.6307035906 0.8409381209 -0.3153517953 -2.5295909024 -1.4755946930 2.9511893861 -1.4755946930 1.2647954512 -1.6863939349 0.6323977256
98 0.9600000000 0.9004306434 0.0252512086 -0.2505024173 0.5252512086 -0.2502153217 0.3002870956 -0.1251076608 1.2359282906 0.7209581695 -1.4419163390 0.7209581695 -0.6179641453 0.8239521937 -0.3089820726 -2.5299285135 -1.4757916329 2.9515832658 -1.4757916329 1.2649642568 -1.6866190090 0.6324821284
99 0.9700000000 0.9126626739 0.0323865598 -0.2647731195 0.5323865598 -0.2563313369 0.3084417826 -0.1281656685 1.2104396979 0.7060898238 -1.4121796475 0.7060898238 -0.6052198489 0.8069597986 -0.3026099245 -2.5299985479 -1.4758324863 2.9516649726 -1.4758324863 1.2649992740 -1.6866656986 0.6324996370
100 0.9800000000 0.9246398321 0.0393732354 -0.2787464707 0.5393732354 -0.2623199160 0.3164265547 -0.1311599580 1.1849421216 0.6912162376 -1.3824324752 0.6912162376 -0.5924710608 0.7899614144 -0.2962355304 -2.5298324081 -1.4757355714 2.9514711428 -1.4757355714 1.2649162040 -1.6865549387 0.6324581020
101 0.9900000000 0.9363620426 0.0462111915 -0.2924223831 0.5462111915 -0.2681810213 0.3242413617 -0.1340905107 1.1594362237 0.6763377971 -1.3526755943 0.6763377971 -0.5797181118 0.7729574824 -0.2898590559 -2.5294551323 -1.4755154939 2.9510309877 -1.4755154939 1.2647275662 -1.6863034216 0.6323637831
102 1.0000000000 0.9478292357 0.0529003875 -0.3058007750 0.5529003875 -0.2739146179 0.3318861571 -0.1369573089 1.1339342694 0.6614616572 -1.3229233143 0.6614616572 -0.5669671347 0.7559561796 -0.2834835674 -2.5703310519 -1.4993597803 2.9987195605 -1.4993597803 1.2851655259 -1.7135540346 0.6425827630
103 1.0100000000 0.9590413433 0.0594407836 -0.3188815672 0.5594407836 -0.2795206716 0.3393608955 -0.1397603358 1.1084324370 0.6465855883 -1.2931711765 0.6465855883 -0.5542162185 0.7389549580 -0.2771081093 -2.5685655748 -1.4983299187 2.9966598373 -1.4983299187 1.2842827874 -1.7123770499 0.6421413937
104 1.0200000000 0.9699983086 0.0658323467 -0.3316646933 0.5658323467 -0.2849991543 0.3466655390 -0.1424995771 1.0829244674 0.6317059393 -1.2634118786 0.6317059393 -0.5414622337 0.7219496449 -0.2707311168 -2.5667757347 -1.4972858452 2.9945716905 -1.4972858452 1.2833878673 -1.7111838231 0.6416939337
105 1.0300000000 0.9807000815 0.0720750476 -0.3441500951 0.5720750476 -0.2903500408 0.3538000544 -0.1451750204 1.0574108312 0.6168229849 -1.2336459698 0.6168229849 -0.5287054156 0.7049405542 -0.2643527078 -2.5649647508 -1.4962294380 2.9924588760 -1.4962294380 1.2824823754 -1.7099765006 0.6412411877
106 1.0400000000 0.9911466182 0.0781688606 -0.3563377212 0.5781688606 -0.2955733091 0.3607644121 -0.1477866545 1.0318919990 0.6019369994 -1.2038739988 0.6019369994 -0.5159459995 0.6879279993 -0.2579729998 -2.5631334425 -1.4951611748 2.9903223496 -1.4951611748 1.2815667213 -1.7087556283 0.6407833606
107 1.0500000000 1.0013378802 0.0841137635 -0.3682275269 0.5841137635 -0.3006689401 0.3675585868 -0.1503344701 1.0063684401 0.5870482567 -1.1740965135 0.5870482567 -0.5031842201 0.6709122934 -0.2515921100 -2.5612806272 -1.4940803659 2.9881607317 -1.4940803659 1.2806403136 -1.7075204181 0.6403201568
108 1.0600000000 1.0112738348 0.0899097370 -0.3798194739 0.5899097370 -0.3056369174 0.3741825565 -0.1528184587 0.9808406229 0.5721570300 -1.1443140601 0.5721570300 -0.4904203115 0.6538937486 -0.2452101557 -2.5594034703 -1.4929853576 2.9859707153 -1.4929853576 1.2797017351 -1.7062689802 0.6398508676
109 1.0700000000 1.0209544544 0.0955567651 -0.3911135302 0.5955567651 -0.3104772272 0.3806363029 -0.1552386136 0.9553090146 0.5572635919 -1.1145271837 0.5572635919 -0.4776545073 0.6368726764 -0.2388272537 -2.5574977952 -1.4918737138 2.9837474277 -1.4918737138 1.2787488976 -1.7049985301 0.6393744488
110 1.0800000000 1.0303797167 0.1010548347 -0.4021096695 0.6010548347 -0.3151898583 0.3869198111 -0.1575949292 0.9297740819 0.5423682144 -1.0847364289 0.5423682144 -0.4648870410 0.6198493879 -0.2324435205 -2.5555583643 -1.4907423792 2.9814847584 -1.4907423792 1.2777791822 -1.7037055762 0.6388895911
111 1.0900000000 1.0395496042 0.1064039358 -0.4128078715 0.6064039358 -0.3197748021 0.3930330694 -0.1598874010 0.9042362922 0.5274711704 -1.0549423409 0.5274711704 -0.4521181461 0.6028241948 -0.2260590730 -2.5535791389 -1.4895878310 2.9791756620 -1.4895878310 1.2767895694 -1.7023860926 0.6383947847
112 1.1000000000 1.0484641043 0.1116040608 -0.4232081217 0.6116040608 -0.3242320521 0.3989760695 -0.1621160261 0.8786961153 0.5125727339 -1.0251454679 0.5125727339 -0.4393480577 0.5857974102 -0.2196740288 -2.5515535262 -1.4884062236 2.9768124472 -1.4884062236 1.2757767631 -1.7010356841 0.6378883815
113 1.1100000000 1.0571232093 0.1166552054 -0.4333104108 0.6166552054 -0.3285616046 0.4047488062 -0.1642808023 0.8531540263 0.4976731820 -0.9953463640 0.4976731820 -0.4265770132 0.5687693509 -0.2132885066 -2.5494746240 -1.4871935307 2.9743870614 -1.4871935307 1.2747373120 -1.6996497494 0.6373686560
114 1.1200000000 1.0655269161 0.1215573677 -0.4431147354 0.6215573677 -0.3327634580 0.4103512774 -0.1663817290 0.8276105090 0.4827727969 -0.9655455938 0.4827727969 -0.4138052545 0.5517403393 -0.2069026273 -2.5473354715 -1.4859456917 2.9718913835 -1.4859456917 1.2736677358 -1.6982236477 0.6368338679
115 1.1300000000 1.0736752262 0.1263105486 -0.4526210973 0.6263105486 -0.3368376131 0.4157834841 -0.1684188066 0.8020660604 0.4678718685 -0.9357437371 0.4678718685 -0.4010330302 0.5347107069 -0.2005165151 -2.5451293159 -1.4846587676 2.9693175352 -1.4846587676 1.2725646579 -1.6967528772 0.6362823290
116 1.1400000000 1.0815681460 0.1309147519 -0.4618295037 0.6309147519 -0.3407840730 0.4210454307 -0.1703920365 0.7765211961 0.4529706977 -0.9059413954 0.4529706977 -0.3882605980 0.5176807974 -0.1941302990 -2.5428499083 -1.4833291132 2.9666582264 -1.4833291132 1.2714249542 -1.6952332722 0.6357124771
117 1.1500000000 1.0892056864 0.1353699837 -0.4707399675 0.6353699837 -0.3446028432 0.4261371243 -0.1723014216 0.7509764575 0.4380696002 -0.8761392004 0.4380696002 -0.3754882287 0.5006509716 -0.1877441144 -2.5404918423 -1.4819535747 2.9639071494 -1.4819535747 1.2702459212 -1.6936612282 0.6351229606
118 1.1600000000 1.0965878630 0.1396762534 -0.4793525069 0.6396762534 -0.3482939315 0.4310585754 -0.1741469658 0.7254324190 0.4231689111 -0.8463378222 0.4231689111 -0.3627162095 0.4836216127 -0.1813581048 -2.5380509508 -1.4805297213 2.9610594425 -1.4805297213 1.2690254754 -1.6920339672 0.6345127377
119 1.1700000000 1.1037146963 0.1438335729 -0.4876671457 0.6438335729 -0.3518573482 0.4358097975 -0.1759286741 0.6998896978 0.4082689904 -0.8165379808 0.4082689904 -0.3499448489 0.4665931319 -0.1749724245 -2.5355247826 -1.4790561232 2.9581122464 -1.4790561232 1.2677623913 -1.6903498551 0.6338811957
120 1.1800000000 1.1105862113 0.1478419566 -0.4956839132 0.6478419566 -0.3552931056 0.4403908075 -0.1776465528 0.6743542226 0.3933732965 -0.7867465930 0.3933732965 -0.3371771113 0.4495694817 -0.1685885556 -2.5709641289 -1.4997290752 2.9994581504 -1.4997290752 1.2854820644 -1.7139760859 0.6427410322
121 1.1900000000 1.1172024324 0.1517014189 -0.5034028378 0.6517014189 -0.3586012162 0.4448016216 -0.1793006081 0.6488344346 0.3784867535 -0.7569735070 0.3784867535 -0.3244172173 0.4325562897 -0.1622086087 -2.5693566763 -1.4987913945 2.9975827890 -1.4987913945 1.2846783381 -1.7129044508 0.6423391691
122 1.2000000000 1.1235633946 0.1554119802 -0.5108239603 0.6554119802 -0.3617816973 0.4490422630 -0.1808908486 0.6233173954 0.3636018140 -0.7272036280 0.3636018140 -0.3116586977 0.4155449303 -0.1558293488 -2.5678204583 -1.4978952674 2.9957905347 -1.4978952674 1.2839102292 -1.7118803055 0.6419551146
123 1.2100000000 1.1296691411 0.1589736657 -0.5179473313 0.6589736657 -0.3648345706 0.4531127608 -0.1824172853 0.5978037924 0.3487188789 -0.6974377578 0.3487188789 -0.2989018962 0.3985358616 -0.1494509481 -2.5663727128 -1.4970507491 2.9941014982 -1.4970507491 1.2831863564 -1.7109151418 0.6415931782
124 1.2200000000 1.1355197216 0.1623865043 -0.5247730085 0.6623865043 -0.3677598608 0.4570131477 -0.1838799304 0.5722943469 0.3338383690 -0.6676767380 0.3338383690 -0.2861471734 0.3815295646 -0.1430735867 -2.5650370136 -1.4962715913 2.9925431826 -1.4962715913 1.2825185068 -1.7100246758 0.6412592534
125 1.2300000000 1.1411151920 0.1656505287 -0.5313010574 0.6656505287 -0.3705575960 0.4607434614 -0.1852787980 0.5467898141 0.3189607249 -0.6379214498 0.3189607249 -0.2733949071 0.3645265427 -0.1366974535 -2.5638446591 -1.4955760511 2.9911521022 -1.4955760511 1.2819223295 -1.7092297727 0.6409611648
126 1.2400000000 1.1464556158 0.1687657759 -0.5375315518 0.6687657759 -0.3732278079 0.4643037439 -0.1866139040 0.5212909808 0.3040864055 -0.6081728110 0.3040864055 -0.2606454904 0.3475273206 -0.1303227452 -2.5628363543 -1.4949878733 2.9899757467 -1.4949878733 1.2814181771 -1.7085575695 0.6407090886
127 1.2500000000 1.1515410639 0.1717322873 -0.5434645746 0.6717322873 -0.3757705320 0.4676940426 -0.1878852660 0.4957986575 0.2892158835 -0.5784317670 0.2892158835 -0.2478993287 0.3305324383 -0.1239496644 -2.5620642437 -1.4945374755 2.9890749510 -1.4945374755 1.2810321218 -1.7080428291 0.6405160609
128 1.2600000000 1.1563716160 0.1745501093 -0.5491002187 0.6745501093 -0.3781858080 0.4709144107 -0.1890929040 0.4703136626 0.2743496365 -0.5486992730 0.2743496365 -0.2351568313 0.3135424417 -0.1175784157 -2.5615943430 -1.4942633668 2.9885267336 -1.4942633668 1.2807971715 -1.7077295620 0.6403985858
129 1.2700000000 1.1609473610 0.1772192939 -0.5544385879 0.6772192939 -0.3804736805 0.4739649073 -0.1902368403 0.4448367972 0.2594881317 -0.5189762634 0.2594881317 -0.2224183986 0.2965578648 -0.1112091993 -2.5615094112 -1.4942138232 2.9884276464 -1.4942138232 1.2807547056 -1.7076729408 0.6403773528
130 1.2800000000 1.1652683983 0.1797398990 -0.5594797980 0.6797398990 -0.3826341992 0.4768455989 -0.1913170996 0.4193688029 0.2446318017 -0.4892636034 0.2446318017 -0.2096844014 0.2795792019 -0.1048422007 -2.5619122633 -1.4944488203 2.9888976406 -1.4944488203 1.2809561317 -1.7079415089 0.6404780658
131 1.2900000000 1.1693348387 0.1821119892 -0.5642239785 0.6821119892 -0.3846674194 0.4795565591 -0.1923337097 0.3939102985 0.2297810075 -0.4595620149 0.2297810075 -0.1969551492 0.2626068657 -0.0984775746 -2.5629294456 -1.4950421766 2.9900843532 -1.4950421766 1.2814647228 -1.7086196304 0.6407323614
132 1.3000000000 1.1731468056 0.1843356366 -0.5686712733 0.6843356366 -0.3865734028 0.4820978704 -0.1932867014 0.3684616868 0.2149359840 -0.4298719679 0.2149359840 -0.1842308434 0.2456411245 -0.0921154217 -2.5647150151 -1.4960837588 2.9921675177 -1.4960837588 1.2823575076 -1.7098100101 0.6411787538
133 1.3100000000 1.1767044364 0.1864109213 -0.5728218425 0.6864109213 -0.3883522182 0.4844696243 -0.1941761091 0.3430230200 0.2000967617 -0.4001935233 0.2000967617 -0.1715115100 0.2286820133 -0.0857557550 -2.5674538230 -1.4976813968 2.9953627935 -1.4976813968 1.2837269115 -1.7116358820 0.6418634558
134 1.3200000000 1.1800078833 0.1883379319 -0.5766758638 0.6883379319 -0.3900039416 0.4866719222 -0.1950019708 0.3175938120 0.1852630570 -0.3705261140 0.1852630570 -0.1587969060 0.2117292080 -0.0793984530 -2.5713630021 -1.4999617513 2.9999235025 -1.4999617513 1.2856815011 -1.7142420014 0.6428407505
135 1.3300000000 1.1830573374 0.1901167802 -0.5802335603 0.6901167802 -0.3915286687 0.4887048916 -0.1957643344 0.2922301694 0.1704675988 -0.3409351976 0.1704675988 -0.1461150847 0.1948201129 -0.0730575423 -2.5074936059 -1.4627046034 2.9254092069 -1.4627046034 1.2537468030 -1.6716624039 0.6268734015
136 1.3400000000 1.1858530327 0.1917476024 -0.5834952048 0.6917476024 -0.3929265163 0.4905686885 -0.1964632582 0.2668903566 0.1556860413 -0.3113720827 0.1556860413 -0.1334451783 0.1779269044 -0.0667225891 -2.5125593872 -1.4656596425 2.9313192851 -1.4656596425 1.2562796936 -1.6750395915 0.6281398468
137 1.3500000000 1.1883952177 0.1932305437 -0.5864610873 0.6932305437 -0.3941976088 0.4922634785 -0.1970988044 0.2415719662 0.1409169803 -0.2818339606 0.1409169803 -0.1207859831 0.1610479775 -0.0603929916 -2.5203825534 -1.4702231562 2.9404463123 -1.4702231562 1.2601912767 -1.6802550356 0.6300956384
138 1.3600000000 1.1906841715 0.1945657667 -0.5891315334 0.6945657667 -0.3953420858 0.4937894477 -0.1976710429 0.2162706052 0.1261578530 -0.2523157061 0.1261578530 -0.1081353026 0.1441804035 -0.0540676513 -2.5316526468 -1.4767973773 2.9535947546 -1.4767973773 1.2658263234 -1.6877684312 0.6329131617
139 1.3700000000 1.1927201997 0.1957534498 -0.5915068996 0.6957534498 -0.3963600998 0.4951467998 -0.1981800499 0.1909778832 0.1114037652 -0.2228075304 0.1114037652 -0.0954889416 0.1273185888 -0.0477444708 -2.5470729502 -1.4857925543 2.9715851086 -1.4857925543 1.2735364751 -1.6980486335 0.6367682376
140 1.3800000000 1.1945036227 0.1967937799 -0.5935875598 0.6967937799 -0.3972518113 0.4963357484 -0.1986259057 0.1656799741 0.0966466516 -0.1932933031 0.0966466516 -0.0828399870 0.1104533161 -0.0414199935 -2.5671424118 -1.4974997402 2.9949994805 -1.4974997402 1.2835712059 -1.7114282746 0.6417856030
141 1.3900000000 1.1960349526 0.1976870557 -0.5953741114 0.6976870557 -0.3980174763 0.4973566351 -0.1990087381 0.1405702472 0.0819993109 -0.1639986217 0.0819993109 -0.0702851236 0.0937134981 -0.0351425618 -2.4826683511 -1.4482232048 2.8964464096 -1.4482232048 1.2413341755 -1.6551122341 0.6206670878
142 1.4000000000 1.1973150119 0.1984337569 -0.5968675139 0.6984337569 -0.3986575059 0.4982100079 -0.1993287530 0.1154845751 0.0673660022 -0.1347320043 0.0673660022 -0.0577422876 0.0769897168 -0.0288711438 -2.5245291779 -1.4726420205 2.9452840409 -1.4726420205 1.2622645890 -1.6830194520 0.6311322945
143 1.4100000000 1.1983442694 0.1990341572 -0.5980683143 0.6990341572 -0.3991721347 0.4988961796 -0.1995860674 0.0903598362 0.0527099045 -0.1054198089 0.0527099045 -0.0451799181 0.0602398908 -0.0225899591 -2.4050999542 -1.4029749733 2.8059499465 -1.4029749733 1.2025499771 -1.6033999695 0.6012749885
144 1.4200000000 1.1991241143 0.1994890667 -0.5989781333 0.6994890667 -0.3995620571 0.4994160762 -0.1997810286 0.0655913792 0.0382616379 -0.0765232757 0.0382616379 -0.0327956896 0.0437275861 -0.0163978448 -2.5086534154 -1.4633811590 2.9267623180 -1.4633811590 1.2543267077 -1.6724356103 0.6271633539
145 1.4300000000 1.1996560710 0.1997993748 -0.5995987496 0.6997993748 -0.3998280355 0.4997707140 -0.1999140178 0.0410822945 0.0239646718 -0.0479293436 0.0239646718 -0.0205411473 0.0273881964 -0.0102705736 -2.3550691592 -1.3737903429 2.7475806858 -1.3737903429 1.1775345796 -1.5700461062 0.5887672898
146 1.4400000000 1.1999416939 0.1999659881 -0.5999319762 0.6999659881 -0.3999708469 0.4999611292 -0.1999854235 0.0165914466 0.0096783439 -0.0193566877 0.0096783439 -0.0082957233 0.0110609644 -0.0041478617 -2.2426221572 -1.3081962584 2.6163925167 -1.3081962584 1.1213110786 -1.4950814381 0.5606555393
147 1.4500000000 1.1999999970 0.1999999983 -0.5999999965 0.6999999983 -0.3999999985 0.4999999980 -0.1999999993 0.0000091079 0.0000053129 -0.0000106259 0.0000053129 -0.0000045540 0.0000060719 -0.0000022770 -0.0232361933 -0.0135544461 0.0271088922 -0.0135544461 0.0116180966 -0.0154907955 0.0058090483
148 1.4519588665 1.2000000000 0.2000000000 -0.6000000000 0.7000000000 -0.4000000000 0.5000000000 -0.2000000000 0.0000000000 -0.0000000000 0.0000000000 -0.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 -0.0000000000 0.0000000000 0.0000000000 -0.0000000000 0.0000000000

80
example/CMakeLists.txt Normal file
View File

@ -0,0 +1,80 @@
find_package(glog REQUIRED)
find_package(protobuf REQUIRED)
find_package(PkgConfig REQUIRED)
find_package(fcl REQUIRED)
find_package(OpenCV REQUIRED)
find_package(pybind11 REQUIRED)
include_directories(${CMAKE_SOURCE_DIR}/include)
add_executable(solve_fk solve_fk.cpp)
target_link_libraries(solve_fk PRIVATE cmvr_es::utils)
add_executable(solve_ik solve_ik.cpp)
target_link_libraries(solve_ik PRIVATE cmvr_es::utils)
add_executable(wbc_example wbc_example.cpp)
target_link_libraries(wbc_example PRIVATE cmvr_es::utils)
add_executable(follow_traj_example follow_traj_example.cpp)
target_link_libraries(follow_traj_example PRIVATE cmvr_es::utils)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
add_executable(moveJ ${CMAKE_CURRENT_SOURCE_DIR}/moveJ.cpp)
target_link_libraries(moveJ PRIVATE
cmvr_es::device::canbus
cmvr_es::device::ti5motor
cmvr_es::device::humanoid_robot
pthread glog::glog
proto-objects
ccd
fcl
cmvr_es::device_manager
${OpenCV_LIBS})
add_executable(torqueOff ${CMAKE_CURRENT_SOURCE_DIR}/torqueOff.cpp)
target_link_libraries(torqueOff PRIVATE
cmvr_es::device::canbus
cmvr_es::device::ti5motor
cmvr_es::device::humanoid_robot
pthread glog::glog
proto-objects
ccd
fcl
cmvr_es::device_manager
${OpenCV_LIBS})
add_executable(torqueOn ${CMAKE_CURRENT_SOURCE_DIR}/torqueOn.cpp)
target_link_libraries(torqueOn PRIVATE
cmvr_es::device::canbus
cmvr_es::device::ti5motor
cmvr_es::device::humanoid_robot
pthread
glog::glog
proto-objects
ccd
fcl
cmvr_es::device_manager
${OpenCV_LIBS})
# ---------------- pybind11 ----------------
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
pybind11_add_module(robot_wrapper ${CMAKE_CURRENT_SOURCE_DIR}/robot_wrapper.cpp)
target_link_libraries(robot_wrapper PRIVATE
cmvr_es::device::canbus
cmvr_es::device::ti5motor
cmvr_es::device::humanoid_robot
pthread
glog::glog
proto-objects
ccd
fcl
cmvr_es::device_manager
${OpenCV_LIBS})

View File

@ -0,0 +1,234 @@
// cartesian_controller_test.cpp
// ---------------------------------------------------------------------------
// Refactored test for CartesianController with trajectory timing & logging
// * Left arm: circle in YZ plane (normalX), r = 0.05m
// * Right arm: square in YZ plane (normalX), side = 0.05m
// * Prints joint angles (q[DOF]) and EE positions (x,y,z) every step
// ---------------------------------------------------------------------------
#include <chrono>
#include <iostream>
#include <memory>
#include <vector>
#include <cmath>
#include <iomanip>
#include "utils/dynamics/robot.h"
#include "utils/controller/cartesian_controller.h"
// ---------- CONFIG ---------------------------------------------------------
constexpr int DOF = 14; // robot DOF
using RobotT = cmvr::dyn::Robot<DOF>;
using StateT = cmvr::dyn::State<DOF>;
using ControllerT = cmvr::ctrl::CartesianController<DOF>;
static const char* kUrdfPath = "/home/xtkuang/projects/cmvr-es/config/robot_description/hc_description/dual_arm.urdf";
static const char* kBaseLink = "PELVIS_S";
static const char* kLeftEE = "L_WRIST_R_S";
static const char* kRightEE = "R_WRIST_R_S";
// ---------- TRAJECTORY GENERATORS -----------------------------------------
std::vector<Eigen::Matrix4d> generateCircle(const Eigen::Matrix4d& T_center,
double radius, int n_points)
{
std::vector<Eigen::Matrix4d> poses; poses.reserve(n_points);
const double x = T_center(0,3);
const double y0 = T_center(1,3);
const double z0 = T_center(2,3);
const Eigen::Matrix3d R = T_center.block<3,3>(0,0);
for (int i = 0; i < n_points; ++i) {
double th = 2.0 * M_PI * i / n_points;
double y = y0 + radius * std::cos(th);
double z = z0 + radius * std::sin(th);
Eigen::Matrix4d T = Eigen::Matrix4d::Identity();
T.block<3,3>(0,0) = R;
T(0,3) = x; T(1,3) = y; T(2,3) = z;
poses.push_back(T);
}
return poses;
}
std::vector<Eigen::Matrix4d> generateSquare(const Eigen::Matrix4d& T_center,
double side, int n_points)
{
std::vector<Eigen::Matrix4d> poses; poses.reserve(n_points);
const double half = side / 2.0;
const double x = T_center(0,3);
const double y0 = T_center(1,3);
const double z0 = T_center(2,3);
const Eigen::Matrix3d R = T_center.block<3,3>(0,0);
for (int i = 0; i < n_points; ++i) {
double u = static_cast<double>(i) / n_points; // 01
double seg = u * 4.0; // 4 edges
double y, z;
if (seg < 1.0) { // Y → +Z
y = -half; z = -half + seg*side;
} else if (seg < 2.0) { // +Z → +Y
y = -half + (seg-1)*side; z = half;
} else if (seg < 3.0) { // +Y → Z
y = half; z = half - (seg-2)*side;
} else { // Z → Y
y = half - (seg-3)*side; z = -half;
}
Eigen::Matrix4d T = Eigen::Matrix4d::Identity();
T.block<3,3>(0,0) = R;
T(0,3) = x; T(1,3) = y0 + y; T(2,3) = z0 + z;
poses.push_back(T);
}
return poses;
}
std::vector<Eigen::Matrix4d> generateLine(const Eigen::Matrix4d& T_center, double length, int n_points)
{
std::vector<Eigen::Matrix4d> poses; poses.reserve(n_points);
double delta_x = length / (double)n_points;
for (int i = 0; i < n_points; ++i) {
const Eigen::Matrix3d R = T_center.block<3,3>(0,0);
Eigen::Matrix4d T = Eigen::Matrix4d::Identity();
T.block<3,3>(0,0) = R;
T(0,3) = T_center(0,3) + delta_x * (i+1);
T(1,3) = T_center(1,3);
T(2,3) = T_center(2,3);
poses.push_back(T);
}
return poses;
}
// ---------- CSV HELPERS ----------------------------------------------------
// 写入表头
template<int DOF>
void writeCsvHeader(std::ofstream& csv)
{
csv << std::fixed << std::setprecision(6);
csv << "idx";
for (int d = 0; d < DOF; ++d) csv << ", q" << d;
csv << ", pLx, pLy, pLz, pRx, pRy, pRz\n";
}
// 写入一行数据
template<int DOF>
void writeCsvRow(std::ofstream& csv,
int idx,
const Eigen::Vector<double, DOF>& q,
const Eigen::Vector3d& pL,
const Eigen::Vector3d& pR)
{
csv << idx;
for (int d = 0; d < DOF; ++d)
csv << ", " << q[d];
csv << ',' << pL.x() << ',' << pL.y() << ',' << pL.z();
csv << ',' << pR.x() << ',' << pR.y() << ',' << pR.z();
csv << '\n';
}
// ---------- MAIN TEST ROUTINE ---------------------------------------------
void runTrajectoryTest(int n_points_circle = 200,
int n_points_square = 200,
double dt = 0.002)
{
// 1. Load robot ---------------------------------------------------------
auto rcfg = cmvr::dyn::LoadRobotFromURDF(kUrdfPath, kBaseLink);
auto robot = std::make_shared<RobotT>(rcfg);
std::vector<std::string> link_names = {
kBaseLink,
"L_SHOULDER_P_S", "L_SHOULDER_R_S", "L_SHOULDER_Y_S", "L_ELBOW_R_S", "L_WRIST_P_S", "L_WRIST_Y_S", kLeftEE,
"R_SHOULDER_P_S", "R_SHOULDER_R_S", "R_SHOULDER_Y_S", "R_ELBOW_R_S", "R_WRIST_P_S", "R_WRIST_Y_S", kRightEE
};
std::vector<std::string> joint_names = {
"L_SHOULDER_P", "L_SHOULDER_R", "L_SHOULDER_Y", "L_ELBOW_R", "L_WRIST_P", "L_WRIST_Y", "L_WRIST_R",
"R_SHOULDER_P", "R_SHOULDER_R", "R_SHOULDER_Y", "R_ELBOW_R", "R_WRIST_P", "R_WRIST_Y", "R_WRIST_R"
};
auto state = robot->MakeState(link_names, joint_names);
Eigen::Vector<double, DOF> q_init;
q_init << -0.1818, -0.573093, -1.15019, -1.82123, 2.14858, 0.436445, 0.0384556,
0.0734063, 1.16235, 1.72241, 1.81379, -2.70904, 0.0389824, 0.356423;
state->SetQ(q_init);
robot->ComputeForwardKinematics(state);
// EE centers -----------------------------------------------------------
const auto base_idx = robot->GetLinkIdx(kBaseLink);
const auto left_idx = robot->GetLinkIdx(kLeftEE);
const auto right_idx = robot->GetLinkIdx(kRightEE);
const Eigen::Matrix4d T_left_center = robot->GetTransformation(state, base_idx, left_idx);
const Eigen::Matrix4d T_right_center = robot->GetTransformation(state, base_idx, right_idx);
// Trajectories ---------------------------------------------------------
const auto circle_traj = generateCircle (T_left_center , 0.1, n_points_circle);
// const auto circle_traj = generateLine(T_left_center, 0.1, 200);
// const auto square_traj = generateSquare(T_right_center, 0.1, n_points_square);
const auto square_traj = generateLine(T_right_center, 0.15, n_points_square);
std::cout << "--- square_traj (" << square_traj.size() << " waypoints) ---\n";
std::cout << "--- end square_traj ---\n";
const int N = std::max(circle_traj.size(), square_traj.size());
// Controller -----------------------------------------------------------
ControllerT ctrl(robot);
// Print CSV header -----------------------------------------------------
std::cout << std::fixed << std::setprecision(6);
std::cout << "idx";
for (int d = 0; d < DOF; ++d) std::cout << ", q" << d;
std::cout << ", pLx, pLy, pLz, pRx, pRy, pRz\n";
// Write CSV ------------------------------------------------------------
std::string csv_path = "../../joint_positions.csv";
std::ofstream csv(csv_path);
if (!csv) throw std::runtime_error("cannot open " + csv_path);
writeCsvHeader<DOF>(csv); // ← 写表头
// Timing --------------------------------------------------------------
namespace chrono = std::chrono;
const auto t_start = chrono::high_resolution_clock::now();
for (int k = 0; k < N; ++k) {
const Eigen::Matrix4d& T_left = circle_traj [k % circle_traj.size()];
const Eigen::Matrix4d& T_right = square_traj [k % square_traj.size()];
std::vector<cmvr::ctrl::PoseTarget> targets = {
{kLeftEE , T_left , 0.5, 1.0},
{kRightEE, T_right, 0.5, 1.0}
};
Eigen::Vector<double, DOF> q_cmd;
bool ok = ctrl.compute(state, kBaseLink, targets, dt,
ControllerT::Mode::Position, q_cmd, 60, 1e-4);
if (!ok) std::cerr << "[WARN] IK failed at step " << k << '\n';
state->SetQ(q_cmd);
robot->ComputeForwardKinematics(state);
// Current EE positions -------------------------------------------
const Eigen::Matrix4d T_L_now = robot->GetTransformation(state, base_idx, left_idx);
const Eigen::Matrix4d T_R_now = robot->GetTransformation(state, base_idx, right_idx);
const Eigen::Vector3d pL = T_L_now.block<3,1>(0,3);
const Eigen::Vector3d pR = T_R_now.block<3,1>(0,3);
// CSVstyle print --------------------------------------------------
std::cout << k;
for (int d = 0; d < DOF; ++d) std::cout << ", " << q_cmd[d];
std::cout << ", " << pL.transpose() << ", " << pR.transpose() << '\n';
writeCsvRow<DOF>(csv, k, q_cmd, pL, pR);
}
const auto t_end = chrono::high_resolution_clock::now();
const double total_ms = chrono::duration<double, std::milli>(t_end - t_start).count();
csv.close();
// Summary -------------------------------------------------------------
std::cout << "---------- Trajectory Test Summary ----------\n";
std::cout << "Total points : " << N << "\n";
std::cout << "Total time : " << total_ms << " ms\n";
std::cout << "Average / pt : " << total_ms / N << " ms" << std::endl;
}
// ---------- MAIN ----------------------------------------------------------
int main() {
try { runTrajectoryTest(); }
catch (const std::exception &e) {
std::cout << e.what();
}
}

73
example/moveJ.cpp Normal file
View File

@ -0,0 +1,73 @@
//
// Created by lgv on 2025/8/13.
//
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib> // for std::atof
#include <glog/logging.h>
#include "device_manager/device_manager.h"
#include <libgen.h>
using namespace cmvr::device;
int main(int argc, char* argv[]) {
// 需要传入 side + 7 个关节值
if (argc != 9) {
LOG(ERROR) << "Usage: " << argv[0] << " <side:left|right> J1 J2 J3 J4 J5 J6 J7" << std::endl;
return 1;
}
std::string side = argv[1];
if (side != "left" && side != "right") {
LOG(ERROR) << "side must be 'left' or 'right'" << std::endl;
return 1;
}
// 输入的 7 个关节
std::vector<double> arm_q(7);
for (int i = 0; i < 7; ++i) {
arm_q[i] = std::atof(argv[i + 2]);
}
// 左右臂关节名称
std::vector<std::string> left_joint_names = {
"L_SHOULDER_P", "L_SHOULDER_R", "L_SHOULDER_Y",
"L_ELBOW_R", "L_WRIST_P", "L_WRIST_Y", "L_WRIST_R"
};
std::vector<std::string> right_joint_names = {
"R_SHOULDER_P", "R_SHOULDER_R", "R_SHOULDER_Y",
"R_ELBOW_R", "R_WRIST_P", "R_WRIST_Y", "R_WRIST_R"
};
std::vector<JointPositionCmd> cmd;
cmd.reserve(7);
if (side == "left") {
for (size_t i = 0; i < 7; ++i)
cmd.push_back({left_joint_names[i], arm_q[i]});
} else {
for (size_t i = 0; i < 7; ++i)
cmd.push_back({right_joint_names[i], arm_q[i]});
}
// 获取 robot
std::string config_path = "/home/lgv/cmvr/cmvr-es/config/cabin_robot.xml";
const XmlNode config(config_path);
if (!config.hasChild("DeviceManager")) {
LOG(ERROR) << "Device Manager node not found";
return 1;
}
auto dmgr_cfg = config.getChild("DeviceManager");
auto &dmgr = DeviceManager::getInstance(dmgr_cfg);
auto robot = dmgr.getDevice<AbstractRobot>("hc01");
robot->moveJ(cmd, 0.8);
return 0;
}

203
example/robot_wrapper.cpp Normal file
View File

@ -0,0 +1,203 @@
//
// Created by lgv on 2025/8/15.
//
#ifdef MAX_ITER
#undef MAX_ITER
#endif
#include <opencv2/opencv.hpp>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <mutex>
#include "devices/abstract_robot.h"
#include "device_manager/device_manager.h"
#include "cmvr/msgs/geometry.pb.h"
namespace py = pybind11;
using namespace cmvr::device;
class PyRobotWrapper {
public:
// 构造时只需要传入 config_path 和 robot_name只在第一次初始化有效
PyRobotWrapper(const std::string& config_path, const std::string& robot_name) {
std::lock_guard<std::mutex> lock(init_mutex); // 线程安全
if (!robot_) {
const XmlNode config(config_path);
if (!config.hasChild("DeviceManager")) {
throw std::runtime_error("Device Manager node not found");
}
auto dmgr_cfg = config.getChild("DeviceManager");
dmgr_ = &DeviceManager::getInstance(dmgr_cfg);
robot_ = dmgr_->getDevice<AbstractRobot>(robot_name);
}
}
void moveJ(const std::string &side, const std::vector<double> &q, double speed=0.8) {
if (q.size() != 7)
throw std::runtime_error("Expected 7 joint values");
const auto& joint_names = getJointNames(side);
std::vector<JointPoint> cmd = {{"WAIST_Y", 0}, {"WAIST_P", 0}};
for (size_t i = 0; i < 7; ++i)
cmd.push_back({joint_names[i], q[i]});
robot_->moveJ(cmd, speed);
}
void torqueOn() {
checkRobotInit();
robot_->torqueOn();
}
void torqueOn(const std::string& joint_name) {
checkRobotInit();
robot_->torqueOn(joint_name);
}
void torqueOff() {
checkRobotInit();
robot_->torqueOff();
}
void torqueOff(const std::string& joint_name) {
checkRobotInit();
robot_->torqueOff(joint_name);
}
void calibrateZeroQ(const std::string &joint_name) {
checkRobotInit();
robot_->calibrateZeroQ(joint_name);
}
std::vector<double> getJointQ(const std::string& side) const {
checkRobotInit();
auto joint_qs = robot_->getJointQ(); // unordered_map<std::string,double>
const auto& joint_names = getJointNames(side);
std::vector<double> values;
for (const auto& name : joint_names) {
values.push_back(joint_qs.at(name));
}
return values;
}
void move(const std::string &base_link, const std::string &ee_link,
double x, double y, double z, double rx, double ry, double rz,
double vel, double acc) {
checkRobotInit();
cmvr::msgs::Pose3d pose;
pose.mutable_position()->set_x(x);
pose.mutable_position()->set_y(y);
pose.mutable_position()->set_z(z);
pose.mutable_euler()->set_rx(rx);
pose.mutable_euler()->set_ry(ry);
pose.mutable_euler()->set_rz(rz);
robot_->moveJ(base_link, ee_link, pose,vel,acc);
}
std::vector<double> ik(const std::string& side,
const std::string &base_link,
const std::string &ee_link,
double x, double y, double z,
double rx, double ry, double rz)
{
checkRobotInit();
cmvr::msgs::Pose3d pose;
pose.mutable_position()->set_x(x);
pose.mutable_position()->set_y(y);
pose.mutable_position()->set_z(z);
pose.mutable_euler()->set_rx(rx);
pose.mutable_euler()->set_ry(ry);
pose.mutable_euler()->set_rz(rz);
auto js_cmd = robot_->ik(base_link, ee_link, pose);
if (js_cmd.size() < 14) {
throw std::runtime_error("IK solution size is smaller than expected");
}
if (side == "left") {
return std::vector<double>(js_cmd.begin(), js_cmd.begin() + 7);
} else if (side == "right") {
return std::vector<double>(js_cmd.begin() + 7, js_cmd.begin() + 14);
} else {
throw std::runtime_error("Side must be 'left' or 'right'");
}
}
std::tuple<double, double, double, double, double, double> fk(const std::string &base_link, const std::string &ee_link) {
checkRobotInit();
auto pose = robot_->fk(base_link, ee_link);
// 返回一个元组,包含 (x, y, z, rx, ry, rz)
return std::make_tuple(pose.position().x(), pose.position().y(), pose.position().z(), pose.euler().rx(), pose.euler().ry(), pose.euler().ry());
}
private:
static DeviceManager* dmgr_;
static std::shared_ptr<AbstractRobot> robot_;
static std::mutex init_mutex;
static const std::vector<std::string> LEFT_JOINTS;
static const std::vector<std::string> RIGHT_JOINTS;
void checkRobotInit() const {
if (!robot_)
throw std::runtime_error("Robot not initialized");
}
const std::vector<std::string>& getJointNames(const std::string& side) const {
if (side == "left") return LEFT_JOINTS;
if (side == "right") return RIGHT_JOINTS;
throw std::runtime_error("Side must be 'left' or 'right'");
}
};
// 静态成员初始化
DeviceManager* PyRobotWrapper::dmgr_ = nullptr;
std::shared_ptr<AbstractRobot> PyRobotWrapper::robot_ = nullptr;
std::mutex PyRobotWrapper::init_mutex;
const std::vector<std::string> PyRobotWrapper::LEFT_JOINTS = {"L_SHOULDER_P", "L_SHOULDER_R", "L_SHOULDER_Y",
"L_ELBOW_R", "L_WRIST_P", "L_WRIST_Y", "L_WRIST_R"};
const std::vector<std::string> PyRobotWrapper::RIGHT_JOINTS = {"R_SHOULDER_P", "R_SHOULDER_R", "R_SHOULDER_Y",
"R_ELBOW_R", "R_WRIST_P", "R_WRIST_Y", "R_WRIST_R"};
// Python 绑定
PYBIND11_MODULE(robot_wrapper, m) {
py::class_<PyRobotWrapper>(m, "Robot")
.def(py::init<const std::string&, const std::string&>(),
py::arg("config_path"), py::arg("robot_name"),
"Initialize the robot wrapper with config and robot name")
.def("moveJ", &PyRobotWrapper::moveJ, py::arg("side"), py::arg("q"), py::arg("speed")=0.8,
"Move robot joints in joint space with optional speed")
.def("torqueOn", py::overload_cast<>(&PyRobotWrapper::torqueOn))
.def("torqueOn", py::overload_cast<const std::string&>(&PyRobotWrapper::torqueOn))
.def("torqueOff", py::overload_cast<>(&PyRobotWrapper::torqueOff))
.def("torqueOff", py::overload_cast<const std::string&>(&PyRobotWrapper::torqueOff))
.def("calibrateZeroQ", &PyRobotWrapper::calibrateZeroQ)
.def("getJointQ", &PyRobotWrapper::getJointQ, py::arg("side"),
"Get joint positions for the specified side ('left' or 'right')")
.def("ik", &PyRobotWrapper::ik,
py::arg("side"), py::arg("base_link"), py::arg("ee_link"),
py::arg("x"), py::arg("y"), py::arg("z"),
py::arg("rx"), py::arg("ry"), py::arg("rz"),
"Compute inverse kinematics and return 7 joint values for the given side")
.def("moveJ", &PyRobotWrapper::move, "Move robot in joint space",
py::arg("base_link"), py::arg("ee_link"),
py::arg("x"), py::arg("y"), py::arg("z"),
py::arg("rx"), py::arg("ry"), py::arg("rz"),
py::arg("vel") = 0.5, py::arg("acc") = 0.1)
.def("fk", &PyRobotWrapper::fk, "Compute forward kinematics",
py::arg("base_link"), py::arg("ee_link"));
}

101
example/solve_fk.cpp Normal file
View File

@ -0,0 +1,101 @@
#include <iostream>
#include <fstream>
#include <memory>
#include <vector>
#include <string>
#include <iomanip>
#include "utils/dynamics/robot.h"
constexpr int DOF = 14;
using RobotT = cmvr::dyn::Robot<DOF>;
using StateT = cmvr::dyn::State<DOF>;
static const char* kUrdfPath = "/home/lgv/cmvr/cmvr-es/config/robot_description/hc_description/dual_arm.urdf";
int main(int argc, char** argv) {
if (argc < 10) {
std::cerr << "用法: solve_fk <base_line> <target_link> <q1> <q2> <q3> <q4> <q5> <q6> <q7> [-o <filename>]\n";
return 1;
}
bool write_file = false;
std::string output_file;
if (argc == 12 && std::string(argv[10]) == "-o") {
write_file = true;
output_file = argv[11];
}
std::string arm = argv[1];
std::vector<std::string> link_names = {
"PELVIS_S",
"L_SHOULDER_P_S", "L_SHOULDER_R_S", "L_SHOULDER_Y_S", "L_ELBOW_R_S", "L_WRIST_P_S", "L_WRIST_Y_S", "L_WRIST_R_S",
"R_SHOULDER_P_S", "R_SHOULDER_R_S", "R_SHOULDER_Y_S", "R_ELBOW_R_S", "R_WRIST_P_S", "R_WRIST_Y_S", "R_WRIST_R_S", "R_CAM", "R_FINGER_TIP"
};
std::vector<std::string> joint_names = {
"L_SHOULDER_P", "L_SHOULDER_R", "L_SHOULDER_Y", "L_ELBOW_R", "L_WRIST_P", "L_WRIST_Y", "L_WRIST_R",
"R_SHOULDER_P", "R_SHOULDER_R", "R_SHOULDER_Y", "R_ELBOW_R", "R_WRIST_P", "R_WRIST_Y", "R_WRIST_R"
};
std::string base_link = argv[1];
std::string target_link = argv[2];
bool find_base_link = false;
bool find_target_link = false;
for (const auto& link_name : link_names) {
if (base_link == link_name) {
find_base_link = true;
}
if (target_link == link_name) {
find_target_link = true;
}
}
if (!find_base_link) {
std::cerr << "base link 无效" << std::endl;
return -1;
}
if (!find_target_link) {
std::cerr << "target link 无效" << std::endl;
return -1;
}
Eigen::Vector<double, DOF> q;
q.setZero();
for (int i = 0; i < 7; ++i) {
if (target_link[0] == 'L') {
q[i] = std::stod(argv[i+3]);
}
else if (target_link[0] == 'R') {
q[i+7] = std::stod(argv[i+3]);
}
}
auto rcfg = cmvr::dyn::LoadRobotFromURDF(kUrdfPath, "PELVIS_S");
auto robot = std::make_shared<RobotT>(rcfg);
auto state = robot->MakeState(link_names, joint_names);
state->SetQ(q);
robot->ComputeForwardKinematics(state);
auto base_idx = robot->GetLinkIdx(base_link);
auto ee_idx = robot->GetLinkIdx(target_link);
Eigen::Matrix4d T = robot->GetTransformation(state, base_idx, ee_idx);
std::cout << std::fixed << std::setprecision(10);
std::cout << "变换矩阵T:\n" << T << "\n";
if (write_file) {
std::ofstream fout(output_file);
if (!fout) {
std::cerr << "无法创建输出文件 " << output_file << "\n";
return 1;
}
fout << std::fixed << std::setprecision(6);
fout << T(0,0) << "," << T(0,1) << "," << T(0,2) << "," << T(0,3) << ","
<< T(1,0) << "," << T(1,1) << "," << T(1,2) << "," << T(1,3) << ","
<< T(2,0) << "," << T(2,1) << "," << T(2,2) << "," << T(2,3) << "\n";
fout.close();
std::cout << "结果已保存到 " << output_file << "\n";
}
return 0;
}

130
example/solve_ik.cpp Normal file
View File

@ -0,0 +1,130 @@
//
// Created by xtkuang on 2025/7/31.
//
#include "utils/dynamics/robot.h"
#include "utils/controller/cartesian_controller.h"
#include <Eigen/Dense>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <cmath>
#include <glog/logging.h>
constexpr int DOF = 14;
using RobotT = cmvr::dyn::Robot<DOF>;
using ControllerT = cmvr::ctrl::CartesianController<DOF>;
// 将欧拉角(rx, ry, rz)转为旋转矩阵,旋转顺序 Z→Y→X
Eigen::Matrix3d eulerToRotationMatrix(double rx, double ry, double rz)
{
Eigen::Matrix3d R_x;
R_x << 1, 0, 0,
0, cos(rx), -sin(rx),
0, sin(rx), cos(rx);
Eigen::Matrix3d R_y;
R_y << cos(ry), 0, sin(ry),
0, 1, 0,
-sin(ry), 0, cos(ry);
Eigen::Matrix3d R_z;
R_z << cos(rz), -sin(rz), 0,
sin(rz), cos(rz), 0,
0, 0, 1;
// ✅ 按照输入顺序 X → Y → Z 旋转
return R_x * R_y * R_z;
}
int main(int argc, char **argv)
{
if (argc != 9)
{
std::cerr << "用法: " << argv[0] << " <base link> <target link> <x> <y> <z> <rx> <ry> <rz>\n";
return -1;
}
std::vector<std::string> link_names = {
"PELVIS_S",
"L_SHOULDER_P_S", "L_SHOULDER_R_S", "L_SHOULDER_Y_S", "L_ELBOW_R_S", "L_WRIST_P_S", "L_WRIST_Y_S", "L_WRIST_R_S",
"R_SHOULDER_P_S", "R_SHOULDER_R_S", "R_SHOULDER_Y_S", "R_ELBOW_R_S", "R_WRIST_P_S", "R_WRIST_Y_S", "R_WRIST_R_S", "R_CAM", "R_FINGER_TIP"
};
std::vector<std::string> joint_names = {
"L_SHOULDER_P", "L_SHOULDER_R", "L_SHOULDER_Y", "L_ELBOW_R", "L_WRIST_P", "L_WRIST_Y", "L_WRIST_R",
"R_SHOULDER_P", "R_SHOULDER_R", "R_SHOULDER_Y", "R_ELBOW_R", "R_WRIST_P", "R_WRIST_Y", "R_WRIST_R",
};
std::string BASE_LINK = argv[1];
std::string target_link = argv[2];
bool find_base_link = false;
bool find_target_link = false;
for (auto link_name : link_names) {
if (BASE_LINK == link_name) {
find_base_link = true;
}
if (target_link == link_name) {
find_target_link = true;
}
}
if (!find_base_link) {
std::cerr << "base link 无效" << std::endl;
return -1;
}
if (!find_target_link) {
std::cerr << "target link 无效" << std::endl;
return -1;
}
double x = std::stod(argv[3]);
double y = std::stod(argv[4]);
double z = std::stod(argv[5]);
double rx = std::stod(argv[6]) * M_PI / 180.0;
double ry = std::stod(argv[7]) * M_PI / 180.0;
double rz = std::stod(argv[8]) * M_PI / 180.0;
// 1. 加载机器人模型
auto rcfg = LoadRobotFromURDF(
"/home/lgv/cmvr/cmvr-es/config/robot_description/hc_description/dual_arm.urdf",
/*root*/ "PELVIS_S");
auto robot = std::make_shared<RobotT>(rcfg);
auto state = robot->MakeState(link_names, joint_names);
// 初始关节角度
Eigen::Vector<double, DOF> q_init;
q_init << -0.3647738137, -1.4556045962, 1.6057029118, -1.8483036779, 2.9024825461, 0.1850049007, -0.5602506899,
-0.23905230057945082, 1.2838583858530206, 1.8486727698400174, 1.3036511045462158, -2.824727848601091, -0.02012495463116552, -0.202540520242054;
state->SetQ(q_init);
robot->ComputeForwardKinematics(state);
// 2. 构造目标位姿矩阵
Eigen::Matrix4d T_target = Eigen::Matrix4d::Identity();
T_target.block<3,3>(0,0) = eulerToRotationMatrix(rx, ry, rz); // 输入为弧度
T_target(0,3) = x;
T_target(1,3) = y;
T_target(2,3) = z;
// 3. 创建控制器
ControllerT ctrl(robot);
constexpr double DT = 0.002; // 2ms
std::vector<cmvr::ctrl::PoseTarget> targets = {
{target_link, T_target, 0.5, 1.0}
};
Eigen::Vector<double, DOF> q_cmd;
bool ok = ctrl.compute(state, BASE_LINK, targets, DT, ControllerT::Mode::Position, q_cmd, 10000, 1e-6);
// ✅ 格式化输出
std::cout << "[IK Solve] success=" << std::boolalpha << ok << "\n";
std::cout << "left: ";
for(int i=0; i<7; ++i) std::cout << q_cmd[i] << (i<6?" ":"");
std::cout << "\nright: ";
for(int i=7; i<14; ++i) std::cout << q_cmd[i] << (i<13?" ":"");
std::cout << std::endl;
return 0;
}

34
example/torqueOff.cpp Normal file
View File

@ -0,0 +1,34 @@
//
// Created by lgv on 2025/8/13.
//
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib> // for std::atof
#include <glog/logging.h>
#include "device_manager/device_manager.h"
#include <libgen.h>
using namespace cmvr::device;
int main(int argc, char* argv[]) {
// 这里按你的原代码结构获取 robot
std::string config_path = "/home/lgv/cmvr/cmvr-es/config/cabin_robot.xml";
const XmlNode config(config_path);
if (!config.hasChild("DeviceManager")) {
LOG(ERROR) << "Device Manager node not found";
return 1;
}
auto dmgr_cfg = config.getChild("DeviceManager");
auto &dmgr = DeviceManager::getInstance(dmgr_cfg);
auto robot = dmgr.getDevice<AbstractRobot>("hc01");
robot->torqueOff();
return 0;
}

36
example/torqueOn.cpp Normal file
View File

@ -0,0 +1,36 @@
//
// Created by lgv on 2025/8/13.
//
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib> // for std::atof
#include <glog/logging.h>
#include "device_manager/device_manager.h"
#include <libgen.h>
using namespace cmvr::device;
int main(int argc, char* argv[]) {
// 这里按你的原代码结构获取 robot
std::string config_path = "/home/lgv/cmvr/cmvr-es/config/cabin_robot.xml";
const XmlNode config(config_path);
if (!config.hasChild("DeviceManager")) {
LOG(ERROR) << "Device Manager node not found";
return 1;
}
auto dmgr_cfg = config.getChild("DeviceManager");
auto &dmgr = DeviceManager::getInstance(dmgr_cfg);
auto robot = dmgr.getDevice<AbstractRobot>("hc01");
robot->eStop();
std::this_thread::sleep_for(std::chrono::milliseconds(500));
return 0;
}

94
example/wbc_example.cpp Normal file
View File

@ -0,0 +1,94 @@
//
// Created by xtkuang on 2025/7/9.
//
#include "utils/dynamics/robot.h"
#include "utils/controller/cartesian_controller.h"
constexpr int DOF = 14;
using RobotT = cmvr::dyn::Robot<DOF>;
//using StateT = cmvr::dyn::State<DOF>;
using ControllerT = cmvr::ctrl::CartesianController<DOF>;
int main(int argc, char **argv) {
auto rcfg = LoadRobotFromURDF(
"/home/xtkuang/projects/cmvr-es/config/robot_description/hc_description/dual_arm.urdf",
/*root*/ "PELVIS_S");
auto robot = std::make_shared<RobotT>(rcfg);
std::vector<std::string> link_names = {
"PELVIS_S",
"L_SHOULDER_P_S", "L_SHOULDER_R_S", "L_SHOULDER_Y_S", "L_ELBOW_R_S", "L_WRIST_P_S", "L_WRIST_Y_S", "L_WRIST_R_S",
"R_SHOULDER_P_S", "R_SHOULDER_R_S", "R_SHOULDER_Y_S", "R_ELBOW_R_S", "R_WRIST_P_S", "R_WRIST_Y_S", "R_WRIST_R_S"
};
std::vector<std::string> joint_names = {
"L_SHOULDER_P", "L_SHOULDER_R", "L_SHOULDER_Y", "L_ELBOW_R", "L_WRIST_P", "L_WRIST_Y", "L_WRIST_R",
"R_SHOULDER_P", "R_SHOULDER_R", "R_SHOULDER_Y", "R_ELBOW_R", "R_WRIST_P", "R_WRIST_Y", "R_WRIST_R"
};
auto state = robot->MakeState(link_names, joint_names);
Eigen::Vector<double, DOF> q_init;
q_init << -0.3647738137, -1.4556045962, 1.6057029118, -1.8483036779, 2.9024825461, 0.1850049007, -0.5602506899,
-0.02679378, 0.9625459, 2.0013871, 1.4209224, -2.552366, 0.34969908, 0.10842471;
state->SetQ(q_init);
robot->ComputeForwardKinematics(state);
auto base_idx = robot->GetLinkIdx("PELVIS_S");
auto target_idx_left = robot->GetLinkIdx("L_WRIST_R_S");
auto target_idx_right = robot->GetLinkIdx("R_WRIST_R_S");
auto T_l = robot->GetTransformation(state, base_idx, target_idx_left);
auto T_r = robot->GetTransformation(state, base_idx, target_idx_right);
std::cout << "q_init: " << std::endl;
std::cout << "PELVIS_S -> L_WRIST_R_S:" << std::endl;
std::cout << T_l << std::endl << std::endl;
std::cout << "PELVIS_S -> R_WRIST_R_S:" << std::endl;
std::cout << T_r << std::endl << std::endl;
Eigen::Matrix4d T_target_left, T_target_right;
Eigen::Vector<double, DOF> q_result;
T_target_left <<
0. , 1. , 0. , 0.2,
-1. , 0. , 0.0 , 0.3,
0. , 0. , 1. , -0.15,
0, 0, 0, 1;
T_target_right <<
0. , -1 , 0. , 0.2 ,
1. , 0. , 0. , -0.3 ,
0. , 0. , 1. , -0.15 ,
0. , 0. , 0. , 1 ;
ControllerT ctrl(robot); // d_safe / lambda 用默认即可
constexpr char BASE_LINK[] = "PELVIS_S";
constexpr double DT = 0.002; // 控制周期 2 ms
std::vector<cmvr::ctrl::PoseTarget> targets = {
// {"L_WRIST_R_S", T_target_left, 0.5, 1.0},
{"R_WRIST_R_S", T_target_right, 0.5, 1.0}
};
/* --- 3.1 位置控制(输出关节位置) --- */
{
state->SetQ(q_init);
robot->ComputeForwardKinematics(state);
Eigen::Vector<double, DOF> q_cmd;
bool ok = ctrl.compute(
state, BASE_LINK, targets, DT,
ControllerT::Mode::Position, q_cmd, 80, 1e-6);
std::cout << "\n[Position] success=" << std::boolalpha << ok
<< "\nq_cmd = " << q_cmd.transpose() << "\n";
state->SetQ(q_cmd);
robot->ComputeForwardKinematics(state);
T_l = robot->GetTransformation(state, base_idx, target_idx_left);
T_r = robot->GetTransformation(state, base_idx, target_idx_right);
std::cout << "PELVIS_S -> L_WRIST_R_S:" << std::endl;
std::cout << T_l << std::endl << std::endl;
std::cout << "PELVIS_S -> R_WRIST_R_S" << ":" << std::endl;
std::cout << T_r << std::endl << std::endl;
}
return 0;
}

View File

@ -0,0 +1,114 @@
//
// Created by lgv on 2025/8/24.
//
#pragma once
#include <utility>
#include "devices/abstract_camera.h"
#include "devices/abstract_dexhand.h"
#include "devices/abstract_robot.h"
#include "cmvr/msgs/geometry.pb.h"
#include "librealsense2/rs.h"
#include "librealsense2/h/rs_frame.h"
namespace cmvr {
namespace ctrl {
// 简易版 PID 控制器,带死区、积分限幅、输出限幅和输出斜率限制
class PID {
public:
PID(double kp, double ki, double kd,
double i_max,
double output_max_pos, double output_max_neg,
double delta_max = 0.0) // 输出变化最大值0 表示不限制
: kp_(kp), ki_(ki), kd_(kd),
i_max_(i_max),
output_max_pos_(output_max_pos),
output_max_neg_(output_max_neg),
delta_max_(delta_max),
prev_error_(0), integral_(0), prev_output_(0) {}
double compute(double target, double current, double dt, double deadband = 0.0) {
double error = target - current;
// 死区处理
if (fabs(error) <= deadband) {
error = 0.0;
}
// 积分累加限幅
integral_ += error * dt;
if (integral_ > i_max_) integral_ = i_max_;
if (integral_ < -i_max_) integral_ = -i_max_;
// 微分
double derivative = (error - prev_error_) / dt;
prev_error_ = error;
// PID 输出
double output = kp_ * error + ki_ * integral_ + kd_ * derivative;
// 输出限幅
if (output > output_max_pos_) output = output_max_pos_;
if (output < -output_max_neg_) output = -output_max_neg_;
// 输出斜率限制
if (delta_max_ > 0.0) {
double delta = output - prev_output_;
if (delta > delta_max_) output = prev_output_ + delta_max_;
else if (delta < -delta_max_) output = prev_output_ - delta_max_;
}
prev_output_ = output;
return output;
}
private:
double kp_, ki_, kd_;
double prev_error_;
double integral_;
double i_max_; // 积分限幅
double output_max_pos_; // 向下按的最大输出
double output_max_neg_; // 向上抬的最大输出
double delta_max_; // 输出斜率限制
double prev_output_;
};
class TouchController {
public:
TouchController() {};
TouchController(std::shared_ptr<device::AbstractRobot> robot,std::shared_ptr<device::AbstractDexHand> hand,std::shared_ptr<device::AbstractCamera> cam)
:robot_(std::move(robot)),hand_(std::move(hand)),cam_(std::move(cam)),
pid_(std::make_shared<PID>(0.005, 0.001, 0.001, 5000.0, 0.5, 1.0)){}
~TouchController()=default;
bool isArrive(double max_force);
void touch(int u,int v ,double max_force);
void touch(std::shared_ptr<device::AbstractRobot> robot,const msgs::Pose3d pose,const msgs::Pose3d offset);
void touch( msgs::Pose3d pose, msgs::Pose3d offset,double max_force);
private:
std::shared_ptr<device::AbstractRobot> robot_{nullptr};
std::shared_ptr<device::AbstractDexHand> hand_{nullptr};
std::shared_ptr<device::AbstractCamera> cam_{nullptr};
std::shared_ptr<PID> pid_{nullptr};
const double touch_threshold_ = 5.0; // 触控判定阈值
// 从压阻矩阵提取触控点与压力
bool extractTouch(const std::vector<std::vector<uint16_t>>& matrix,double& force, int& x, int& y);
};
}
}

View File

@ -0,0 +1,43 @@
//
// Created by xtkuang on 2025/5/13.
//
#ifndef CMVR_ES_DEVICE_FACTORY_H
#define CMVR_ES_DEVICE_FACTORY_H
#pragma once
#include "devices/abstract_agv.h"
#include "devices/abstract_battery.h"
#include "devices/abstract_camera.h"
#include "devices/abstract_dexhand.h"
#include "devices/abstract_gripper.h"
#include "devices/abstract_robot.h"
#include "devices/abstract_microphone.h"
#include "devices/abstract_speaker.h"
#include "devices/abstract_biohead.h"
namespace cmvr::device {
class DeviceFactory {
public:
DeviceFactory() = default;
template <typename DeviceType>
std::shared_ptr<DeviceType> create(const XmlNode& cfg);
private:
std::shared_ptr<AbstractAGV> create_agv_(const XmlNode& cfg);
std::shared_ptr<AbstractBattery> create_battery_(const XmlNode& cfg);
std::shared_ptr<AbstractCamera> create_camera_(const XmlNode& cfg);
std::shared_ptr<AbstractDexHand> create_dexhand_(const XmlNode& cfg);
std::shared_ptr<AbstractGripper> create_gripper_(const XmlNode& cfg);
std::shared_ptr<AbstractMicrophone> create_mic_(const XmlNode& cfg);
std::shared_ptr<AbstractRobot> create_robot_(const XmlNode& cfg);
std::shared_ptr<AbstractSpeaker> create_speaker_(const XmlNode& cfg);
std::shared_ptr<AbstractBiohead> create_biohead_(const XmlNode& cfg);
};
}
#endif //CMVR_ES_DEVICE_FACTORY_H

View File

@ -0,0 +1,77 @@
//
// Created by xtkuang on 2025/5/6.
//
#ifndef CMVR_ES_DEVICE_MANAGER_H
#define CMVR_ES_DEVICE_MANAGER_H
#include <list>
#include <variant>
#include <sys/utsname.h>
#include <unordered_map>
#include "device_factory.h"
#include "system_monitor.h"
#include "../utils/base/thread_pool.h"
namespace cmvr::device {
using DeviceVariant = std::variant<
std::shared_ptr<AbstractAGV>,
std::shared_ptr<AbstractBattery>,
std::shared_ptr<AbstractCamera>,
std::shared_ptr<AbstractDexHand>,
std::shared_ptr<AbstractGripper>,
std::shared_ptr<AbstractMicrophone>,
std::shared_ptr<AbstractRobot>,
std::shared_ptr<AbstractSpeaker>,
std::shared_ptr<AbstractBiohead>
>;
typedef struct {
std::string version;
std::string name;
std::string description;
std::string os;
std::string kernel_version;
std::string architecture;
} SystemInfo;
class DeviceManager {
public:
DeviceManager(const DeviceManager&) = delete;
DeviceManager& operator=(const DeviceManager&) = delete;
static DeviceManager& getInstance(const XmlNode &cfg);
static DeviceManager& getInstance();
static void destroyInstance();
void start();
void restart();
void stop();
void updateParam(const std::string& id, const std::pair<std::string, std::string> &param);
void getDeviceList(std::list<std::pair<std::string, std::string>> &device_list);
void getSystemInfo(SystemInfo &info) const;
void getSystemStatus(device::SystemStatus &status) const;
template <class DeviceType>
std::shared_ptr<DeviceType> getDevice(const std::string &device_id);
private:
static std::once_flag init_flag_;
static std::shared_ptr<DeviceManager> instance_;
XmlNode cfg_;
SystemInfo info_;
std::unordered_map<std::string, DeviceVariant> devices_;
std::unique_ptr<DeviceFactory> dev_factory_;
std::unique_ptr<device::SystemMonitor> sys_monitor_;
explicit DeviceManager(const XmlNode &cfg);
void init_devices_();
void get_os_info_();
};
} // cmvr
#endif //CMVR_ES_DEVICE_MANAGER_H

View File

@ -0,0 +1,45 @@
//
// Created by xtkuang on 2025/5/13.
//
#ifndef CMVR_ES_MONITOR_H
#define CMVR_ES_MONITOR_H
#include <fstream>
#include <sstream>
#include <string>
#include <cmath>
#include <mutex>
#include <unistd.h>
#include <sys/statvfs.h>
#include <glog/logging.h>
#include "../utils/base/timer.h"
#include "rapidxml/xml_parser.h"
namespace cmvr::device {
struct SystemStatus {
float cpu_usage;
float used_memory;
float total_memory;
float used_disk;
float total_disk;
float cpu_temperature;
};
class SystemMonitor {
public:
SystemMonitor()=default;
~SystemMonitor()=default;
void getStatus(SystemStatus &status);
private:
SystemStatus status_{};
void get_cpu_();
void get_memory_();
void get_disk_();
};
}
#endif //CMVR_ES_MONITOR_H

View File

@ -0,0 +1,36 @@
//
// Created by xtkuang on 2025/5/8.
//
#ifndef CMVR_ES_ABSTRACT_AGV_H
#define CMVR_ES_ABSTRACT_AGV_H
#pragma once
#include "abstract_device.h"
namespace cmvr::device{
class AbstractAGV: public AbstractDevice {
public:
explicit AbstractAGV(const XmlNode &config): AbstractDevice(config) {};
~AbstractAGV() override=default;
virtual void getState(AGVState &state) {}
// navigation
virtual void eStop() {}
virtual void goHome() {}
virtual void moveto(math::Pose2d &location, double speed_ratio) {}
virtual void setVelocity(math::Vec3 linear, math::Vec3 angular) {}
// map
virtual void initMap(float resolution, int width, int height) {}
virtual void updateMap() {}
virtual void saveMap(const std::string& file_path) {}
virtual void loadMap(const std::string& file_path) {}
protected:
AGVState state_;
};
}
#endif //CMVR_ES_ABSTRACT_AGV_H

View File

@ -0,0 +1,25 @@
//
// Created by xtkuang on 2025/5/8.
//
#ifndef CMVR_ES_ABSTRACT_BATTERY_H
#define CMVR_ES_ABSTRACT_BATTERY_H
#pragma once
#include "abstract_device.h"
namespace cmvr::device{
class AbstractBattery: public AbstractDevice {
public:
explicit AbstractBattery(const XmlNode &config): AbstractDevice(config) {}
~AbstractBattery() override =default;
virtual void getState(BatteryState &state) {}
protected:
BatteryState state_{};
};
}
#endif //CMVR_ES_ABSTRACT_BATTERY_H

View File

@ -0,0 +1,83 @@
#ifndef ABSTRACT_BIOHEAD_H
#define ABSTRACT_BIOHEAD_H
#pragma once
#include "abstract_device.h"
namespace cmvr::device {
// 面部表情状态结构体
struct FacialExpressionState {
// 眉毛
float left_eyebrow_outside_y = 0.0f; // 左眉毛外侧垂直位置
float left_eyebrow_inside_y = 0.0f; // 左眉毛内侧垂直位置
float right_eyebrow_outside_y = 0.0f; // 右眉毛外侧垂直位置
float right_eyebrow_inside_y = 0.0f; // 右眉毛内侧垂直位置
// 眼睑
float left_eye_upper_lid_y = 0.0f; // 左眼上眼睑垂直位置
float left_eye_lower_lid_y = 0.0f; // 左眼下眼睑垂直位置
float right_eye_upper_lid_y = 0.0f; // 右眼上眼睑垂直位置
float right_eye_lower_lid_y = 0.0f; // 右眼下眼睑垂直位置
// 眼球
float left_eye_ball_x = 0.0f; // 左眼球水平位置X坐标
float left_eye_ball_y = 0.0f; // 左眼球垂直位置Y坐标
float right_eye_ball_x = 0.0f; // 右眼球水平位置X坐标
float right_eye_ball_y = 0.0f; // 右眼球垂直位置Y坐标
// 鼻子
float left_nose_y = 0.0f; // 左鼻孔垂直位置
float right_nose_y = 0.0f; // 右鼻孔垂直位置
// 嘴巴
float upper_lip_y = 0.0f; // 上唇的垂直位置
float upper_lip_z = 0.0f; // 上唇的前后位置Z坐标
float lower_lip_y = 0.0f; // 下唇的垂直位置
float lower_lip_z = 0.0f; // 下唇的前后位置Z坐标
// 左唇角
float upper_left_lip_x = 0.0f; // 左唇角上部水平位置X坐标
float upper_left_lip_y = 0.0f; // 左唇角上部垂直位置Y坐标
float left_corner_lip_x = 0.0f; // 左嘴角水平位置X坐标
float left_corner_lip_y = 0.0f; // 左嘴角垂直位置Y坐标
float lower_left_lip_x = 0.0f; // 左唇角下部水平位置X坐标
float lower_left_lip_y = 0.0f; // 左唇角下部垂直位置Y坐标
// 右唇角
float upper_right_lip_x = 0.0f; // 右唇角上部水平位置X坐标
float upper_right_lip_y = 0.0f; // 右唇角上部垂直位置Y坐标
float right_corner_lip_x = 0.0f; // 右嘴角水平位置X坐标
float right_corner_lip_y = 0.0f; // 右嘴角垂直位置Y坐标
float lower_right_lip_x = 0.0f; // 右唇角下部水平位置X坐标
float lower_right_lip_y = 0.0f; // 右唇角下部垂直位置Y坐标
// Jaw
float jaw_x = 0.0f;
float jaw_y = 0.0f;
};
// 抽象头部类
class AbstractBiohead : public AbstractDevice {
public:
explicit AbstractBiohead(const XmlNode &config) : AbstractDevice(config) {}
~AbstractBiohead() override = default;
virtual void getState(RobotState &state){};
virtual void eStop() {};
virtual void setExpressionPose(FacialExpressionState& expression_state, double vel=0, double acc=0) {}
virtual void streamFacialPose(FacialExpressionState& expression_state, double vel, double acc) {}
FacialExpressionState expression_state_;
std::atomic<bool> emergency_stop_requested = false;
};
} // namespace cmvr::device
#endif // ABSTRACT_BIOHEAD_H

View File

@ -0,0 +1,74 @@
#ifndef CMVR_ES_ABSTRACT_CAMERA_H
#define CMVR_ES_ABSTRACT_CAMERA_H
#pragma once
#include <opencv2/opencv.hpp>
#include "abstract_device.h"
#include <Eigen/Core>
namespace cmvr::device {
struct Rs2Intrinsics
{
float cx;
float cy;
float fx;
float fy;
float coeffs[5];
};
struct StreamFrameData
{
//原始图像数据
cv::Mat rgbImage;
//深度图原始数据
cv::Mat depthImage;
//彩色图像帧
std::vector<uint8_t> rgbFrame;
//深度图像帧
std::vector<uint8_t> depthFrame;
//编码格式
std::string codec = ".h264";
Rs2Intrinsics intrinsics;
int width;
int height;
int fps;
bool bKey;
bool depthKey;
};
class AbstractCamera : public AbstractDevice {
public:
// 录制状态
enum class RecordingState {
STOPPED,
RECORDING,
PAUSED
};
public:
explicit AbstractCamera(const XmlNode &cfg): AbstractDevice(cfg) {}
~AbstractCamera() override = default;
inline void getState(CameraState &state) {state = state_;}
virtual void getRGBImage(cv::Mat &color, Rs2Intrinsics& intrinsics) {}
virtual void getDepthImage(cv::Mat &depth, Rs2Intrinsics& intrinsics) {}
virtual void getRGBDImages(cv::Mat &color, cv::Mat &depth, Rs2Intrinsics& intrinsics) {}
virtual void startRecording(const std::string &video_path) {}
virtual void stopRecording() {}
virtual void pauseRecording() {}
virtual void resumeRecording() {}
virtual void getEncodedFrame(StreamFrameData& frame_data, size_t& index) {}
virtual bool startStreaming() {return true;}
virtual void stopStreaming() {}
virtual Eigen::Vector3f get3DPointFromPixel(int u, int v) {return {0,0,0};}
protected:
CameraState state_{};
void clear_error_() {
this->state_.is_error = false;
this->state_.error_message.clear();
}
};
}
#endif // CMVR_ES_ABSTRACT_CAMERA_H

View File

@ -0,0 +1,107 @@
//
// Created by lgv on 2025/7/14.
//
#pragma once
#include "abstract_device.h"
#include "cmvr/msgs/error_code.pb.h"
#include "canbus/common/byte.h"
namespace cmvr::device {
/**
* @class CanFrame
* @brief The class which defines the information to send and receive.
*/
struct CanFrame {
/// Message id
uint32_t id;
/// Message length
uint8_t len;
/// Message content
uint8_t data[8];
/// Time stamp
struct timeval timestamp;
/**
* @brief Constructor
*/
CanFrame() : id(0), len(0), timestamp{0} {
std::memset(data, 0, sizeof(data));
}
/**
* @brief CanFrame string including essential information about the message.
* @return The info string.
*/
std::string CanFrameString() const {
std::stringstream output_stream("");
output_stream << "id:0x" << Byte::byte_to_hex(id)
<< ",len:" << static_cast<int>(len) << ",data:";
for (uint8_t i = 0; i < len; ++i) {
output_stream << Byte::byte_to_hex(data[i]);
}
output_stream << ",";
return output_stream.str();
}
};
const int CAN_RESULT_SUCC = 0;
const int CAN_ERROR_BASE = 2000;
const int CAN_ERROR_OPEN_DEVICE_FAILED = CAN_ERROR_BASE + 1;
const int CAN_ERROR_FRAME_NUM = CAN_ERROR_BASE + 2;
const int CAN_ERROR_SEND_FAILED = CAN_ERROR_BASE + 3;
const int CAN_ERROR_RECV_FAILED = CAN_ERROR_BASE + 4;
class AbstractCanbus : public AbstractDevice {
public:
AbstractCanbus(const XmlNode &cfg) : AbstractDevice(cfg) {}
~AbstractCanbus() {}
/**
* @brief Send messages
* @param frames The messages to send.
* @param frame_num The amount of messages to send.
* @return The status of the sending action
*/
virtual cmvr::msgs::ErrorCode send(const std::vector<CanFrame> &frames,
int32_t *const frame_num) = 0;
/**
* @brief Send a single message.
* @param frames A single-element vector containing only one message.
* @return The status of the sending single message action
*/
virtual cmvr::msgs::ErrorCode sendSingleFrame(
const std::vector<CanFrame> &frames) {
CHECK_EQ(frames.size(), 1U)
<< "frames size not equal to 1, actual frame size :" << frames.size();
int32_t n = 1;
return send(frames, &n);
}
/**
* @brief Receive messages
* @param frames The messages to receive.
* @param frame_num The amount of messages to receive.
* @return The status of the receiving action which is defined by
* apollo::common::ErrorCode.
*/
virtual cmvr::msgs::ErrorCode receive(std::vector<CanFrame> *const frames,
int32_t *const frame_num) = 0;
/**
* @brief Get the error string.
* @param status The status to get the error string.
*/
virtual std::string getErrorString(const int32_t status) = 0;
protected:
/// The CAN client is started.
bool is_started_ = false;
/// CAN clientstatus
cmvr::msgs::ErrorCode status_;
//
bool enable_log_{false};
};
}

View File

@ -0,0 +1,42 @@
//
// Created by xtkuang on 2025/5/6.
//
#ifndef CMVR_ES_ABSTRACT_DEVICES_H
#define CMVR_ES_ABSTRACT_DEVICES_H
#include <thread>
#include <jsoncpp/json/json.h>
#include "rapidxml/xml_parser.h"
#include "state_define.h"
#pragma warning(disable:4996)
#define GLOG_USE_GLOG_EXPORT
#include <glog/logging.h>
namespace cmvr::device {
class AbstractDevice {
public:
explicit AbstractDevice(const XmlNode& config) {cfg_ = config;}
virtual ~AbstractDevice() = default;
[[maybe_unused]] XmlNode getConfig() {return cfg_;}
virtual void getState() {}
virtual void init() {}
virtual void start() {}
virtual void stop() {}
virtual void update() {}
virtual void updateParams(const std::pair<std::string, std::string>& param) {}
virtual void customCommand(const Json::Value &cmd, Json::Value &feedback) {}
protected:
XmlNode cfg_;
std::string id_; // 设备名称
};
}
#endif //CMVR_ES_ABSTRACT_DEVICES_H

View File

@ -0,0 +1,227 @@
//
// Created by xtkuang on 2025/5/8.
//
#ifndef CMVR_ES_ABSTRACT_DEXHAND_H
#define CMVR_ES_ABSTRACT_DEXHAND_H
#pragma once
#include "abstract_device.h"
namespace cmvr::device{
// 单个触觉点数据16位无符号整数
using TactilePoint = uint16_t;
// 手指触觉数据结构体(支持从数组任意位置解析)
struct FingerTactileData {
std::vector<std::vector<TactilePoint>> data; // 触觉数据二维数组
int rows; // 行数
int cols; // 列数
int byteSize; // 总字节数rows * cols * 2字节/点)
std::string name; // 部位名称
// 初始化数据数组
void init() {
data.resize(rows, std::vector<TactilePoint>(cols, 0));
}
// 从 std::vector<uint16_t> 中赋值数据
void assignFromVector(const std::vector<uint16_t>& values, int startIndex = 0) {
int index = startIndex;
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
if (index < values.size()) {
data[i][j] = values[index];
index++;
}
}
}
}
};
// 手掌触觉数据结构体(支持从数组任意位置解析)
struct PalmTactileData {
std::vector<std::vector<TactilePoint>> data; // 触觉数据二维数组
int rows = 8; // 行数掌心固定为8行
int cols = 14; // 列数掌心固定为14列
int byteSize = 224; // 总字节数8*14*2=224
std::string name = "掌心"; // 部位名称
// 初始化数据数组
void init() {
data.resize(rows, std::vector<TactilePoint>(cols, 0));
}
// 从 std::vector<uint16_t> 中赋值数据
void assignFromVector(const std::vector<uint16_t>& values, int startIndex = 0) {
int index = startIndex;
for (int j = 0; j < cols; ++j) {
for (int i = rows - 1; i >= 0; --i) {
if (index < values.size()) {
data[i][j] = values[index];
index++;
}
}
}
}
};
// 手指枚举(方便按手指类型解析)
enum FingerType {
PINKY, // 小拇指
RING, // 无名指
MIDDLE, // 中指
INDEX, // 食指
THUMB // 大拇指
};
// 整只手的触觉传感器数据
struct HandTactileSensors {
// 五指的触觉数据(每根手指包含指端、指尖、指腹)
struct {
FingerTactileData tip; // 指端
FingerTactileData finger; // 指尖
FingerTactileData pad; // 指腹
} pinky, ring, middle, index; // 小拇指、无名指、中指、食指
// 大拇指(特殊:多一个指中)
struct {
FingerTactileData tip; // 指端
FingerTactileData finger; // 指尖
FingerTactileData middle; // 指中
FingerTactileData pad; // 指腹
} thumb;
// 掌心触觉数据
PalmTactileData palm;
// 初始化所有传感器数据(设置相对偏移量)
void init() {
// 小拇指总370byte
pinky.tip = {.rows = 3, .cols = 3, .byteSize = 18, .name = "小拇指指端"};
pinky.finger = {.rows = 12, .cols = 8, .byteSize = 192, .name = "小拇指指尖"};
pinky.pad = {.rows = 10, .cols = 8, .byteSize = 160, .name = "小拇指指腹"};
// 无名指总370byte
ring.tip = {.rows = 3, .cols = 3, .byteSize = 18, .name = "无名指指端"};
ring.finger = {.rows = 12, .cols = 8, .byteSize = 192, .name = "无名指指尖"};
ring.pad = {.rows = 10, .cols = 8, .byteSize = 160, .name = "无名指指腹"};
// 中指总370byte
middle.tip = {.rows = 3, .cols = 3, .byteSize = 18, .name = "中指指端"};
middle.finger = {.rows = 12, .cols = 8, .byteSize = 192, .name = "中指指尖"};
middle.pad = {.rows = 10, .cols = 8, .byteSize = 160, .name = "中指指腹"};
// 食指总370byte
index.tip = {.rows = 3, .cols = 3, .byteSize = 18, .name = "食指指端"};
index.finger = {.rows = 12, .cols = 8, .byteSize = 192, .name = "食指指尖"};
index.pad = {.rows = 10, .cols = 8, .byteSize = 160, .name = "食指指腹"};
// 大拇指总420byte
thumb.tip = {.rows = 3, .cols = 3, .byteSize = 18, .name = "大拇指指端"};
thumb.finger = {.rows = 12, .cols = 8, .byteSize = 192, .name = "大拇指尖"};
thumb.middle = {.rows = 3, .cols = 3, .byteSize = 18, .name = "大拇指指中"};
thumb.pad = {.rows = 12, .cols = 8, .byteSize = 192, .name = "大拇指指腹"};
// 掌心总224byte
palm = { .name = "掌心"};
// 初始化所有数据数组
pinky.tip.init();
pinky.finger.init();
pinky.pad.init();
ring.tip.init();
ring.finger.init();
ring.pad.init();
middle.tip.init();
middle.finger.init();
middle.pad.init();
index.tip.init();
index.finger.init();
index.pad.init();
thumb.tip.init();
thumb.finger.init();
thumb.middle.init();
thumb.pad.init();
palm.init();
}
// 按手指类型解析整个手指的数据
void parseFinger(FingerType fingerType, const std::vector<uint16_t>& values) {
switch (fingerType) {
case PINKY:
pinky.tip.assignFromVector(values);
pinky.finger.assignFromVector(values, 9);
pinky.pad.assignFromVector(values, 9 + 96);
break;
case RING:
ring.tip.assignFromVector(values);
ring.finger.assignFromVector(values, 9);
ring.pad.assignFromVector(values, 9 + 96);
break;
case MIDDLE:
middle.tip.assignFromVector(values);
middle.finger.assignFromVector(values, 9);
middle.pad.assignFromVector(values, 9 + 96);
break;
case INDEX:
index.tip.assignFromVector(values);
index.finger.assignFromVector(values, 9);
index.pad.assignFromVector(values, 9 + 96);
break;
case THUMB:
thumb.tip.assignFromVector(values);
thumb.finger.assignFromVector(values, 9);
thumb.middle.assignFromVector(values, 9 + 96);
thumb.pad.assignFromVector(values, 9 + 96 + 9);
break;
}
}
// 解析手心(掌心)数据
void parsePalm(const std::vector<uint16_t>& values) {
palm.assignFromVector(values);
}
// 获取手指名称(用于调试)
std::string getFingerName(FingerType fingerType) {
switch (fingerType) {
case PINKY: return "小拇指";
case RING: return "无名指";
case MIDDLE: return "中指";
case INDEX: return "食指";
case THUMB: return "大拇指";
default: return "未知";
}
}
};
class AbstractDexHand: public AbstractDevice{
public:
explicit AbstractDexHand(const XmlNode& cfg): AbstractDevice(cfg) {}
~AbstractDexHand() override = default;
virtual void getState(DexHandState &state) {}
// control
virtual void setPositions(const std::vector<int>& finger_joint_targets) {}
virtual void setAngles(const std::vector<int>& finger_joint_angles) {}
virtual void setVelocities(const std::vector<int>& finger_joint_velocities) {}
virtual void setPresetAct(int action_id) {}
virtual void execPresetAct(int action_id) {}
virtual void setForce(const std::vector<int>& finger_joint_force) {}
virtual HandTactileSensors& getSensorData() { return hand_tactile_sensors_;}
protected:
DexHandState status_;
HandTactileSensors hand_tactile_sensors_;
};
}
#endif //CMVR_ES_ABSTRACT_DEXHAND_H

View File

@ -0,0 +1,30 @@
//
// Created by xtkuang on 2025/5/8.
//
#ifndef CMVR_ES_ABSTRACT_GRIPPER_H
#define CMVR_ES_ABSTRACT_GRIPPER_H
#pragma once
#include "abstract_device.h"
namespace cmvr::device{
class AbstractGripper: public AbstractDevice {
public:
explicit AbstractGripper(const XmlNode &cfg): AbstractDevice(cfg) {}
~AbstractGripper() override = default;
virtual void getState(GripperState &state) {}
virtual void openGripper(float vel) {}
virtual void closeGripper(float vel) {}
virtual void setPosition(float position, float vel) {}
virtual void setForce(float value) {}
protected:
GripperState state_;
};
}
#endif //CMVR_ES_ABSTRACT_GRIPPER_H

View File

@ -0,0 +1,30 @@
//
// Created by xtkuang on 2025/5/8.
//
#ifndef CMVR_ES_ABSTRACT_MICROPHONE_H
#define CMVR_ES_ABSTRACT_MICROPHONE_H
#pragma once
#include "abstract_device.h"
namespace cmvr::device{
class AbstractMicrophone: public AbstractDevice {
public:
explicit AbstractMicrophone(const XmlNode &config): AbstractDevice(config) {}
~AbstractMicrophone() override = default;
virtual void getState(MicrophoneState &state) {}
virtual void startRecording(const std::string& outputFilePath) {}
virtual void stopRecording() {}
virtual void pause() {}
virtual void resume() {}
virtual void setVolume(const int volume) {}
virtual int getVolume() {return 0;}
protected:
MicrophoneState state_{};
};
}
#endif //CMVR_ES_ABSTRACT_MICROPHONE_H

View File

@ -0,0 +1,178 @@
//
// Created by xtkuang on 2025/7/30.
//
#ifndef CMVR_ES_ABSTRACT_MOTOR_H
#define CMVR_ES_ABSTRACT_MOTOR_H
#pragma once
#include "abstract_device.h"
#include "utils/dynamics/joint.h"
#include "motor/motor_protocol_interface.h"
#include <mutex>
namespace cmvr::device{
class AbstractMotor: public AbstractDevice {
typedef struct {
} MotorProfile;
// xml 使用
struct MotorInfo {
int id;
std::string joint_name;
float limitQ;
float limitQd;
};
typedef struct {
double position;
double velocity;
double acceleration;
double torque;
double temperature;
double voltage;
double current;
std::string error_msg;
} JointStatus;
public:
explicit AbstractMotor(const XmlNode &config): AbstractDevice(config) {}
AbstractMotor(const XmlNode &config,uint8_t node_id): AbstractDevice(config) ,node_id_(node_id) {}
~AbstractMotor() override = default;
virtual void setMode(msgs::RunMode mode) {
std::scoped_lock lock(mtx_);
if (!protocol_) {
throw std::runtime_error("Protocol not set for motor");
}
protocol_->setMode(node_id_, mode);
}
virtual msgs::RunMode getMode() {
std::scoped_lock lock(mtx_);
if (!protocol_) {
throw std::runtime_error("Protocol not set for motor");
}
return protocol_->getMode(node_id_);
}
void torqueOff() {
std::scoped_lock lock(mtx_);
if (!protocol_) {
throw std::runtime_error("Protocol not set for motor");
}
protocol_->torqueOff(node_id_);
}
virtual void setLimitQ(double ub, double lb) {
std::scoped_lock lock(mtx_);
if (!protocol_) {
throw std::runtime_error("Protocol not set for motor");
}
protocol_->setLimitQ(node_id_, ub,lb);
}
virtual void setLimitQd(double qd) {
std::scoped_lock lock(mtx_);
if (!protocol_) {
throw std::runtime_error("Protocol not set for motor");
}
protocol_->setLimitQd(node_id_, qd);
}
virtual void setLimitQdd(double u_qdd,double l_qdd) {
std::scoped_lock lock(mtx_);
if (!protocol_) {
throw std::runtime_error("Protocol not set for motor");
}
protocol_->setLimitQdd(node_id_, u_qdd,l_qdd);
}
// virtual void setLimitTau(double tau) = 0;
// virtual void setLimitCurrent(double tau) = 0;
virtual void brake() {
std::scoped_lock lock(mtx_);
if (!protocol_) {
throw std::runtime_error("Protocol not set for motor");
}
protocol_->brake(node_id_);
}
/**
*
* @param q unit : rad
*/
virtual void setQ(double q) {
std::scoped_lock lock(mtx_);
if (!protocol_) {
throw std::runtime_error("Protocol not set for motor");
}
protocol_->setQ(node_id_, q);
}
virtual bool calibrateZeroQ() {
std::scoped_lock lock(mtx_);
if (!protocol_) {
throw std::runtime_error("Protocol not set for motor");
}
return protocol_->calibrateZeroQ(node_id_);
}
virtual bool reachedTargetQ() {
if (!protocol_) {
throw std::runtime_error("Protocol not set for motor");
}
return protocol_->reachedTargetQ(node_id_);
}
// rad /s
virtual void setQd(double qd) {
std::scoped_lock lock(mtx_);
if (!protocol_) {
throw std::runtime_error("Protocol not set for motor");
}
return protocol_->setQd(node_id_,qd);
}
// virtual void setQdd(double qdd) = 0; // rad /s^2
// virtual void setTau(double tau) = 0; // N m
// virtual void clear_err() = 0;
// virtual void getStatus() = 0;
// virtual MotorProfile getProfile() = 0;
virtual double getQ() {
if (!protocol_) {
throw std::runtime_error("Protocol not set for motor");
}
return protocol_->getQ(node_id_);
}
virtual double getQd() {
if (!protocol_) {
throw std::runtime_error("Protocol not set for motor");
}
return protocol_->getQd(node_id_);
}
// 使用的通讯协议
virtual void setProtocol(std::shared_ptr<MotorProtocolInterface> protocol) {
std::scoped_lock lock(mtx_);
protocol_ = std::move(protocol);
protocol_->initNode(node_id_);
}
uint8_t id() const {
return node_id_;
}
std::string jointName() const {
return info_.joint_name;
}
protected:
mutable std::mutex mtx_;
MotorInfo info_{};
uint8_t node_id_;
// 使用的通讯协议
std::shared_ptr<MotorProtocolInterface> protocol_;
};
}
#endif //CMVR_ES_ABSTRACT_MOTOR_H

View File

@ -0,0 +1,128 @@
//
// Created by xtkuang on 2025/5/8.
//
#ifndef CMVR_ES_ABSTRACT_ROBOT_H
#define CMVR_ES_ABSTRACT_ROBOT_H
#pragma once
#include "jsoncpp/json/json.h"
#include "abstract_device.h"
#include "utils/controller/cartesian_controller.h"
#include "cmvr/msgs/geometry.pb.h"
#include "cmvr/msgs/motor.pb.h"
namespace cmvr::device{
struct JointPoint{
std::string joint_name;
double rad; // rad
double vel; // rad / s
JointPoint(const std::string& name, double r, double v)
: joint_name(name), rad(r), vel(v) {}
JointPoint(const std::string& name, double r)
: joint_name(name), rad(r), vel(0) {}
JointPoint()
: joint_name(""), rad(0), vel(0) {}
} ;
typedef struct {
std::string joint_name;
double vel; // rad / s
} JointVelocityCommand;
typedef struct {
std::string joint_name;
double current; //
} JointCurrentCommand;
class AbstractRobot: public AbstractDevice {
public:
explicit AbstractRobot(const XmlNode &config): AbstractDevice(config) {}
~AbstractRobot() override=default;
virtual int getDOF() { throw std::runtime_error("Not implemented"); }
virtual std::vector<std::string> getJointNames() { throw std::runtime_error("Not implemented"); }
virtual std::unordered_map<std::string,double> getJointQ() const { throw std::runtime_error("Not implemented"); }
/**
*
* @param joint_qs joint_qs joint name
*/
virtual void getJointQ(std::unordered_map<std::string,double> &joint_qs) const {throw std::runtime_error("Not implemented");}
virtual std::vector<std::string> getLinkNames() { throw std::runtime_error("Not implemented"); }
virtual void getJointsState(std::vector<JointState>& states) = 0;
virtual void getState(RobotState &state) { throw std::runtime_error("Not implemented"); }
virtual math::Pose3d getTransform(std::string &bask_link, std::string &target_link) {throw std::runtime_error("Not implemented");}
virtual void torqueOn() { throw std::runtime_error("Not implemented"); }
virtual void torqueOn(const std::string &joint_name) { throw std::runtime_error("Not implemented"); }
virtual void torqueOff() { throw std::runtime_error("Not implemented"); }
virtual void torqueOff(const std::string &joint_name) { throw std::runtime_error("Not implemented"); }
virtual void eStop() { throw std::runtime_error("Not implemented"); }
virtual void moveJ(std::vector<double> &joints, double vel=0.5, double acc=0.1) { throw std::runtime_error("Not implemented"); }
virtual void moveJ(std::vector<JointPoint> &cmd, double vel=0.5, double acc=0.1) { throw std::runtime_error("Not implemented"); }
virtual void moveJ(const std::string &base_link, const std::string &ee_link, msgs::Pose3d pose,double vel = 0.5, double acc = 0.1) { throw std::runtime_error("Not implemented"); }
virtual void moveDeltaJ(const std::string &base_link, const std::string &ee_link, msgs::Pose3d delta_pose,double vel = 0.5, double acc = 0.1) { throw std::runtime_error("Not implemented"); }
virtual void moveJ_IK(math::Pose3d &pose, double vel=0.5, double acc=0.1) { throw std::runtime_error("Not implemented"); }
virtual void moveJ_IK(const std::string &base_link, const std::vector<cmvr::ctrl::PoseTarget> &targets, double vel=0.5, double acc=0.1) { throw std::runtime_error("Not implemented"); }
virtual void moveL(math::Pose3d &pose, double vel=0.5, double acc=0.1) { throw std::runtime_error("Not implemented"); }
virtual void moveL(std::string &base_link, std::vector<cmvr::ctrl::PoseTarget> &targets, double vel=0.5, double acc=0.1) { throw std::runtime_error("Not implemented"); }
virtual void moveL(const std::string &base_link, const std::string &ee_link,msgs::Pose3d target_pose, double vel, double acc) { throw std::runtime_error("Not implemented"); }
virtual void moveDeltaL(const std::string &base_link, const std::string &ee_link,msgs::Pose3d delta_pose, double vel, double acc) { throw std::runtime_error("Not implemented"); }
virtual void speedJ(std::string &joint_name, RobotJointIndexDirection dir, double vel, double acc=0.5) { throw std::runtime_error("Not implemented"); }
virtual void speedL(RobotCartesian cart, RobotJointIndexDirection dir, double vel, double acc=0.5) { throw std::runtime_error("Not implemented"); }
virtual void followJointTrajectory(std::vector<std::vector<double>> &traj, double dt) { throw std::runtime_error("Not implemented"); }
virtual void followJointTrajectory(std::vector<std::vector<JointPoint>> &traj, double dt) { throw std::runtime_error("Not implemented"); }
virtual void followPoseTrajectory(std::vector<math::Pose3d> &traj, double dt) { throw std::runtime_error("Not implemented"); }
virtual void followPoseTrajectory(std::string &base_link, std::vector<std::vector<cmvr::ctrl::PoseTarget>> &targets, double dt) { throw std::runtime_error("Not implemented"); }
virtual void servoJ(std::vector<double> &joints, double dt) { throw std::runtime_error("Not implemented"); }
virtual void servoJ(std::vector<JointPoint> &joints, double dt) { throw std::runtime_error("Not implemented"); }
virtual void servoJ(std::vector<JointPoint> &joints, double vel, double dt) { throw std::runtime_error("Not implemented"); }
virtual void servoJ(const std::string &base_link, const std::string &ee_link, msgs::Pose3d pose,double vel = 0.1, double acc = 0.1) { throw std::runtime_error("Not implemented"); }
virtual void servoDeltaJ(const std::string &base_link, const std::string &ee_link, msgs::Pose3d delta_pose,double vel = 0.1, double acc = 0.1) { throw std::runtime_error("Not implemented"); }
virtual void servoL(math::Pose3d &pose, double dt) { throw std::runtime_error("Not implemented"); }
virtual void servoL(std::string &base_link, std::vector<cmvr::ctrl::PoseTarget> &targets, double dt) { throw std::runtime_error("Not implemented"); }
virtual void calibrateZeroQ(const std::string &joint_name) = 0;
void setToolFrame(const std::string& toolFrame)
{
toolFrame_ = toolFrame;
}
virtual msgs::Pose3d fk(const std::string &base_link, const std::string &ee_link) = 0;
virtual std::vector<double> ik(const std::string &base_link, const std::string &ee_link,msgs::Pose3d pose) = 0;
protected:
int dof_{};
RobotState state_{};
std::string toolFrame_;
};
}
#endif //CMVR_ES_ABSTRACT_ROBOT_H

View File

@ -0,0 +1,30 @@
//
// Created by xtkuang on 2025/5/8.
//
#ifndef CMVR_ES_ABSTRACT_SPEAKER_H
#define CMVR_ES_ABSTRACT_SPEAKER_H
#pragma once
#include "abstract_device.h"
namespace cmvr::device{
class AbstractSpeaker: public AbstractDevice {
public:
explicit AbstractSpeaker(const XmlNode &config): AbstractDevice(config) {}
~AbstractSpeaker() override = default;
virtual void getState(SpeakerState &state) {}
virtual void play(const std::string &file_path) {}
virtual void setVolume(int volume) {}
[[nodiscard]] virtual int getVolume() const {return 0;}
virtual void pause() {}
virtual void resume() {}
protected:
SpeakerState state_{};
};
}
#endif //CMVR_ES_ABSTRACT_SPEAKER_H

View File

@ -0,0 +1,156 @@
//
// Created by xtkuang on 2025/5/7.
//
#ifndef CMVR_ES_STATE_DEFINE_H
#define CMVR_ES_STATE_DEFINE_H
#include <atomic>
#include <cmath>
#include <iostream>
#include <vector>
#include <unordered_map>
#include <set>
#include "utils/math/geometry.h"
namespace cmvr::device{
enum Lifecycle{
INIT, // 初始化:设备刚创建或刚上电,正在初始化
READY, // 就绪:设备已初始化完成,可以开始工作
RUNNING,// 运行中:设备正在正常工作或采集
ERROR, // 错误:设备发生故障或异常,不能正常工作
STOP, // 停止:设备已停止工作,但没有严重错误
ESTOP // 急停:设备处于紧急停止状态,通常需要人工干预才能恢复
};
enum AudioFormat {
WAV,
MP3,
AAC,
OGG,
FLAC,
UNKNOWN
};
// ------------------------------------- AGV -------------------------------------
typedef struct{
} AGVState;
// ------------------------------------- robot -------------------------------------
typedef enum {
FORWARD, BACKWARD,
X_POSITIVE, // X轴正向
X_NEGATIVE, // X轴负向
Y_POSITIVE, // Y轴正向
Y_NEGATIVE, // Y轴负向
Z_POSITIVE, // Z轴正向
Z_NEGATIVE, // Z轴负向
// 角度方向也可以添加
ROTATE_X, // 绕X轴旋转
ROTATE_Y, // 绕Y轴旋转
ROTATE_Z // 绕Z轴旋转
} RobotJointIndexDirection;
/// robot cartesian index
typedef enum {
X, Y, Z, RX, RY, RZ
} RobotCartesian;
typedef struct {
std::string name;
bool is_ready;
bool power_on;
double position;
double velocity;
double current;
double torque;
double target_position;
double target_velocity;
int target_feedback_gain;
double target_feedforward_torque;
double temperature;
double voltage;
} JointState;
typedef struct{
std::vector<double> temperature;
std::vector<double> voltage;
std::vector<double> joint_positions;
bool error;
std::string error_msg;
} RobotState;
struct CameraState {
bool is_initialized; ///< 是否已初始化
bool is_opened;
bool is_streaming; ///< 是否正在采集视频数据
bool is_recording;
bool is_error;
std::string error_message;
int fps;
int width;
int height;
};
/// @brief 从 XML 或其他配置中读取的相机网络参数
struct CameraConfig {
std::string ipAddress; ///< 相机 IP 地址
};
typedef struct{
bool is_initialized; ///< 是否已初始化
bool is_running;
bool is_recording;
bool is_error;
int volume; // 0~100, 支持软音量调节
std::string error_message;
} MicrophoneState;
typedef struct{
} GripperState;
typedef struct{
int angle; //自由度角度
int speed; //自由度速度
int force; //实际受力
int position; //执行器位置
int current; //执行器实际电流
int temperature; //执行器温度
int error; //执行器故障信息
std::vector<std::string> error_message;
} RH56DFTPDexHand;
typedef struct{
bool is_initialized; //是否初始化
RH56DFTPDexHand hands[6]; // 包含6个自由度状态
} DexHandState;
typedef struct {
float voltage; //< 电压V
float current; //< 电流A
float temperature; //< 温度°C
int charge_percentage; //< 剩余电量(%
bool is_charging; //< 是否正在充电
Lifecycle health; //< 电池健康状态
std::string vendor_info; //< 厂商信息(可选)
} BatteryState;
typedef struct {
bool is_initialized;
bool is_running;
bool is_decoding;
bool is_paused;
int volume; // 0~100, 支持软音量调节
} SpeakerState;
}
#endif //CMVR_ES_STATE_DEFINE_H

View File

@ -0,0 +1,16 @@
//
// Created by xtkuang on 2025/5/6.
//
#ifndef CMVR_ES_CAN_INTERFACE_H
#define CMVR_ES_CAN_INTERFACE_H
namespace cmvr {
class can_interface {
};
} // cmvr
#endif //CMVR_ES_CAN_INTERFACE_H

View File

@ -0,0 +1,33 @@
//
// Created by tankaitao on 2025/6/27.
//
#ifndef SERIAL_PORT_H
#define SERIAL_PORT_H
#include <string>
#include <vector>
#include <cstdint>
namespace cmvr
{
class SerialPort{
public:
SerialPort()=default;
~SerialPort();
bool open(const std::string &port_name,unsigned int baud_rate);
void close();
bool is_open();
bool wakeupESP32(const std::string &port_name);
bool send(const std::vector<uint8_t>& data);
bool sendRawServoData(const std::vector<uint8_t>& raw);
static void printPacket(const std::vector<uint8_t>& packet);
private:
int fd_ = -1;
};
}
#endif //SERIAL_PORT_H

View File

@ -0,0 +1,14 @@
//
// Created by linbo on 2025/9/24.
//
#ifndef CMVR_ES_IO_INTERFACE_H
#define CMVR_ES_IO_INTERFACE_H
class io_interface
{
};
#endif //CMVR_ES_IO_INTERFACE_H

View File

@ -0,0 +1,120 @@
//
// Created by xtkuang on 2025/5/6.
//
#ifndef CMVR_ES_SERIAL_INTERFACE_H
#define CMVR_ES_SERIAL_INTERFACE_H
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <boost/asio.hpp>
#include <iomanip>
#include <thread>
using namespace std;
using namespace boost::asio;
namespace cmvr {
// 定义通信模式枚举
enum class CommunicationMode {
RS485,
CAN
};
// 寄存器字典
const struct {
const char* name;
int address;
} regdict[] = {
{"defaultSpeedSet",1032},
{"defaultForceSet",1044},
{"posSet",1474},
{"angleSet", 1486},
{"forceSet", 1498},
{"speedSet", 1522},
{"angleAct", 1546},
{"posAct",1534},
{"forceAct", 1582},
{"current",1594},
{"error",1606},
{"temperature",1618},
{"finger_one_touch",3000},
{"finger_two_touch",3370},
{"finger_the_touch",3740},
{"finger_or_touch",4110},
{"finger_fiv_touch",4480},
{"finger_palm_touch",4900}
};
// 串口通信接口类
class serial_interface {
public:
serial_interface(const string& port, unsigned int baudrate, CommunicationMode mode);
void write(const vector<unsigned char>& data);
vector<unsigned char> read(size_t length);
bool isInitialized();
CommunicationMode getCommunicationMode();
private:
void on_timeout(const boost::system::error_code& ec);
void on_read_complete(const boost::system::error_code& ec
, size_t bytes_transferred, boost::system::error_code* out_ec, size_t* out_bytes_transferred);
private:
bool is_initialized = false;
io_context io;
std::shared_ptr<serial_port> serial;
CommunicationMode comm_mode;
steady_timer timer;
bool timeout;
};
// 根据寄存器名称获取地址
int getAddressByName(const string& reg_name);
// 写寄存器函数
void write_register(serial_interface& serial, int address_decimal, const string& id_value, const vector<int>& values_to_write);
/**
*
*
* @param serial
* @param address_decimal
* @param id_value ID字符串值
* @param register_length
* @param length_to_read
* @return
*/
std::vector<unsigned char> read_register(serial_interface& serial, int address_decimal, const string& id_value
,size_t register_length, size_t length_to_read);
std::vector<int> read_register_can(serial_interface& serial, int address_decimal, const std::string& id_value
, size_t register_length, size_t length_to_read, bool parse_as_short = true);
std::vector<unsigned char> read_register_can_single(serial_interface& serial, int address_decimal
, const string& id_value, size_t register_length, size_t length_to_read);
/**
*
*
* @param data
* @param start_byte
* @param register_length
* @param per_byte
* @return
*/
std::vector<int> parse_register(const std::vector<unsigned char>& data,int start_byte, size_t register_length,int per_byte);
/**
*
*
* @param errorCode
* @return
* @note
*/
std::vector<std::string> parse_error(unsigned char errorCode);
} // cmvr
#endif //CMVR_ES_SERIAL_INTERFACE_H

88
include/http/httpclient.h Normal file
View File

@ -0,0 +1,88 @@
//
// Created by linbo on 2025/6/24.
//
#ifndef HTTPCLIENT_H
#define HTTPCLIENT_H
#include <string>
#include <map>
#include <vector>
#include <stdexcept>
#include <memory>
#include <utility>
// 控制是否使用libcurl的宏
#ifdef USE_LIBCURL
#include <curl/curl.h>
#endif
using namespace std;
namespace cmvr {
// HTTP响应结构
struct HttpResponse {
int statusCode;
std::string statusText;
std::map<std::string, std::string> headers;
std::string body;
};
// HTTP异常类
class HttpException : public std::runtime_error {
public:
HttpException(const std::string& message) : std::runtime_error(message) {}
};
// HTTP客户端接口
class HttpClientImpl {
public:
virtual ~HttpClientImpl() = default;
virtual void setBaseUrl(const std::string& baseUrl) = 0;
virtual void setTimeout(int timeout) = 0;
virtual void addHeader(const std::string& key, const std::string& value) = 0;
virtual void clearHeaders() = 0;
virtual HttpResponse get(const std::string& path,
const std::map<std::string, std::string>& params = {}) = 0;
virtual HttpResponse post(const std::string& path,
const std::map<std::string, std::string>& params = {},
const std::string& body = "",
const std::string& contentType = "application/x-www-form-urlencoded") = 0;
virtual HttpResponse postJson(const std::string& path,
const std::map<std::string, std::string>& params = {},
const std::string& jsonBody = "") = 0;
};
// HTTP客户端类
class HttpClient {
public:
HttpClient();
~HttpClient() = default;
void setBaseUrl(const std::string& baseUrl);
void setTimeout(int timeout);
void addHeader(const std::string& key, const std::string& value);
void clearHeaders();
HttpResponse get(const std::string& path,
const std::map<std::string, std::string>& params = {});
HttpResponse post(const std::string& path,
const std::map<std::string, std::string>& params = {},
const std::string& body = "",
const std::string& contentType = "application/x-www-form-urlencoded");
HttpResponse postJson(const std::string& path,
const std::map<std::string, std::string>& params = {},
const std::string& jsonBody = "");
private:
std::unique_ptr<HttpClientImpl> m_impl;
};
}
#endif //HTTPCLIENT_H

View File

@ -0,0 +1,42 @@
//
// Created by xtkuang on 2025/6/6.
//
#ifndef ABSTRACT_MONITOR_H
#define ABSTRACT_MONITOR_H
#include <mutex>
#include <glog/logging.h>
#include "rapidxml/xml_parser.h"
#include "../utils/base/timer.h"
namespace cmvr::monitor{
class AbstractMonitor {
public:
explicit AbstractMonitor(const XmlNode &cfg){
cfg_ = cfg;
freq_ = cfg_.getAttrDefault("freq", 1);
timer_ = std::make_unique<FDTimer>();
timer_->start(std::chrono::milliseconds(1000/freq_), [this](){run();});
}
virtual ~AbstractMonitor() {timer_->stop();}
void run() {
if (!check_()) {
execution_();
}
}
protected:
XmlNode cfg_;
int freq_;
std::unique_ptr<FDTimer> timer_;
virtual bool check_() = 0;
virtual bool execution_() = 0;
};
}
#endif //ABSTRACT_MONITOR_H

View File

@ -0,0 +1,27 @@
//
// Created by xtkuang on 2025/6/6.
//
#ifndef MONITOR_FACTORY_H
#define MONITOR_FACTORY_H
#include "monitor/abstract_monitor.h"
namespace cmvr::monitor
{
class MonitorFactory
{
public:
MonitorFactory() = default;
template <typename MonitorType>
std::shared_ptr<MonitorType> create(const XmlNode& cfg);
std::shared_ptr<AbstractMonitor> create(const XmlNode& cfg);
};
}
#endif //MONITOR_FACTORY_H

View File

@ -0,0 +1,37 @@
//
// Created by xtkuang on 2025/6/9.
//
#ifndef MONITOR_MANAGER_H
#define MONITOR_MANAGER_H
#include <unordered_map>
#include "rapidxml/xml_parser.h"
#include "monitor/monitor_factory.h"
namespace cmvr::monitor {
class MonitorManager {
public:
MonitorManager(const MonitorManager&) = delete;
MonitorManager& operator=(const MonitorManager&) = delete;
static MonitorManager& getInstance(const XmlNode &cfg);
static MonitorManager& getInstance();
static void destroyInstance();
private:
explicit MonitorManager (const XmlNode &cfg);
void init_monitors();
private:
static std::once_flag init_flag_;
static std::shared_ptr<MonitorManager> instance_;
XmlNode cfg_;
std::shared_ptr<MonitorFactory> monitor_factory_;
std::unordered_map<std::string, std::shared_ptr<AbstractMonitor>> monitors_;
};
}
#endif //MONITOR_MANAGER_H

View File

@ -0,0 +1,41 @@
//
// Created by xtkuang on 2025/6/1.
//
#ifndef GRPC_CAMERA_SERVICE_H
#define GRPC_CAMERA_SERVICE_H
#include "cmvr/api/camera_service.grpc.pb.h"
#include "../utils/base/grpc_utils.h"
#include "device_manager/device_manager.h"
namespace cmvr::service {
class gRPCCameraServiceImpl final: public api::CameraService::Service {
public:
gRPCCameraServiceImpl();
~gRPCCameraServiceImpl() override = default;
grpc::Status GetStatus(grpc::ServerContext* context, const api::GetCameraStateCommand_Request* request, api::GetCameraStateCommand_Feedback* response) override;
grpc::Status StartCamera(grpc::ServerContext* context, const api::StartCameraCommand_Request* request, api::StartCameraCommand_Feedback* response) override;
grpc::Status StopCamera(grpc::ServerContext* context, const api::StopCameraCommand_Request* request, api::StopCameraCommand_Feedback* response) override;
grpc::Status GetRGBImage(grpc::ServerContext* context, const api::GetRGBImageCommand_Request* request, api::GetRGBImageCommand_Feedback* response) override;
grpc::Status GetDepthImage(grpc::ServerContext* context, const api::GetDepthImageCommand_Request* request, api::GetDepthImageCommand_Feedback* response) override;
grpc::Status GetRGBDImages(grpc::ServerContext* context, const api::GetRGBDImagesCommand_Request* request, api::GetRGBDImagesCommand_Feedback* response) override;
grpc::Status StartRecording(grpc::ServerContext* context, const api::StartCameraRecordingCommand_Request* request, api::StartCameraRecordingCommand_Feedback* response) override;
grpc::Status StopRecording(grpc::ServerContext* context, const api::StopCameraRecordingCommand_Request* request, api::StopCameraRecordingCommand_Feedback* response) override;
grpc::Status GetDepthImageStream(grpc::ServerContext* context, grpc::ServerReaderWriter<cmvr::api::GetDepthImageStreamCommand_Feedback, cmvr::api::GetDepthImageStreamCommand_Request>* stream) override;
grpc::Status GetRGBDImagesStream(grpc::ServerContext* context, grpc::ServerReaderWriter<cmvr::api::GetRGBDImagesStreamCommand_Feedback, cmvr::api::GetRGBDImagesStreamCommand_Request>* stream) override;
grpc::Status GetRGBImageStream(grpc::ServerContext* context, grpc::ServerReaderWriter<cmvr::api::GetRGBImageStreamCommand_Feedback, cmvr::api::GetRGBImageStreamCommand_Request>* stream) override;
private:
device::DeviceManager& dmgr_;
//双向流读写线程
std::shared_ptr<std::thread> read_thread_ = nullptr;
std::shared_ptr<std::thread> write_thread_ = nullptr;
std::atomic<bool> running_{false};
};
}
#endif //GRPC_CAMERA_SERVICE_H

View File

@ -0,0 +1,30 @@
//
// Created by linbo on 2025/7/3.
//
#ifndef GRPC_DEXHAND_SERVICE_H
#define GRPC_DEXHAND_SERVICE_H
#include "cmvr/api/dexhand_service.grpc.pb.h"
#include "../utils/base/grpc_utils.h"
#include "device_manager/device_manager.h"
namespace cmvr::service {
class gRPCDexHandServiceImpl final: public api::DexHandService::Service {
public:
gRPCDexHandServiceImpl();
~gRPCDexHandServiceImpl() override = default;
grpc::Status GetStatus(grpc::ServerContext* context, const api::GetDexHandStateCommand_Request* request,api::GetDexHandStateCommand_Feedback* response) override;
grpc::Status SetDexHandPos(grpc::ServerContext* context, const cmvr::api::SetDexHandPositionsCommand_Request* request, cmvr::api::SetDexHandPositionsCommand_Feedback* response) override;
grpc::Status SetDexHandAngle(grpc::ServerContext* context, const cmvr::api::SetDexHandAnglesCommand_Request* request, cmvr::api::SetDexHandAnglesCommand_Feedback* response) override;
grpc::Status SetDexHandForce(grpc::ServerContext* context, const cmvr::api::SetDexHandForceCommand_Request* request, cmvr::api::SetDexHandForceCommand_Feedback* response) override;
grpc::Status SetDexHandSpeed(grpc::ServerContext* context, const cmvr::api::SetDexHandSpeedCommand_Request* request, cmvr::api::SetDexHandSpeedCommand_Feedback* response) override;
grpc::Status SetDexHandPresetAct(grpc::ServerContext* context, const cmvr::api::SetDexHandPresetActCommand_Request* request, cmvr::api::SetDexHandPresetActCommand_Feedback* response) override;
grpc::Status GetSensorData(grpc::ServerContext* context, const cmvr::api::GetSensorDataCommand_Request* request, cmvr::api::GetSensorDataCommand_Feedback* response) override;
grpc::Status GetSensorDataStream(grpc::ServerContext* context, grpc::ServerReaderWriter<cmvr::api::GetSensorDataStreamCommand_Feedback, cmvr::api::GetSensorDataStreamCommand_Request>* stream) override;
private:
device::DeviceManager& dmgr_;
};
}
#endif //GRPC_DEXHAND_SERVICE_H

View File

@ -0,0 +1,35 @@
#ifndef BIO_HEAD_SERVICE_H
#define BIO_HEAD_SERVICE_H
#include "cmvr/api/biohead_service.grpc.pb.h"
#include "device_manager/device_manager.h"
namespace cmvr::service
{
class gRPCMBioHeadServiceImpl : public api::BioHeadService::Service {
public:
gRPCMBioHeadServiceImpl();
~gRPCMBioHeadServiceImpl() override = default;
grpc::Status SetExpression(grpc::ServerContext* context,
const api::SetFacialExpression_Request* request,
api::SetFacialExpression_Feedback* response) override;
grpc::Status StreamExpression(grpc::ServerContext* context,
grpc::ServerReaderWriter<api::StreamFacialExpression_Feedback, api::StreamFacialExpression_Request>* stream) override;
grpc::Status GetSystemStatus(grpc::ServerContext* context,
const api::GetStatus_Request* request,
api::GetStatus_Feedback* response) override;
grpc::Status EmergencyStop(grpc::ServerContext* context,
const api::EmergencyStop_Request* request,
api::EmergencyStop_Feedback* response) override;
private:
device::DeviceManager& dmgr_;
};
} // namespace cmvr::service
#endif // BIO_HEAD_SERVICE_H

View File

@ -0,0 +1,25 @@
//
// Created by lgv on 2025/8/25.
//
#pragma once
#include "device_manager/device_manager.h"
#include "cmvr/api/hlc_service.grpc.pb.h"
namespace cmvr {
namespace service {
class gRPCHlcServiceImpl final : public api::HlcService::Service {
public:
gRPCHlcServiceImpl();
~gRPCHlcServiceImpl() = default;
grpc::Status touch(grpc::ServerContext *context, const cmvr::api::Touch_Request *request, cmvr::api::Touch_Response *response) override;
private:
device::DeviceManager& dmgr_;
};
}
}

View File

@ -0,0 +1,39 @@
//
// Created by lgv on 2025/8/15.
//
#pragma once
#include "device_manager/device_manager.h"
#include "cmvr/api/humanoid_robot_service.grpc.pb.h"
namespace cmvr {
namespace service {
class gRPCHumanoidRobotServiceImpl final : public api::HumanoidRobotService::Service {
public:
gRPCHumanoidRobotServiceImpl();
~gRPCHumanoidRobotServiceImpl() = default;
grpc::Status torqueOff(grpc::ServerContext *context,
const cmvr::api::CommandHeader_Request *request, cmvr::api::CommandHeader_Feedback *response) override;
grpc::Status torqueOn(grpc::ServerContext *context,
const cmvr::api::CommandHeader_Request *request, cmvr::api::CommandHeader_Feedback *response) override;
grpc::Status moveJ(grpc::ServerContext *context, const cmvr::api::MoveJ_Request *request, cmvr::api::MoveJ_Response *response) override;
grpc::Status moveL(grpc::ServerContext* context, const cmvr::api::MoveL_Request* request, cmvr::api::MoveL_Response* response) override;
grpc::Status speedJ(grpc::ServerContext* context, const cmvr::api::SpeedJ_Request* request, cmvr::api::SpeedJ_Response* response) override;
grpc::Status speedL(grpc::ServerContext* context, const cmvr::api::SpeedL_Request* request, cmvr::api::SpeedL_Response* response) override;
grpc::Status getJointState(grpc::ServerContext *context, const cmvr::api::JointRequest *request, cmvr::api::JointResponse *response) override;
grpc::Status getPose(grpc::ServerContext *context, const cmvr::api::GetPose_Request *request, cmvr::api::GetPose_Response *response) override;
private:
device::DeviceManager& dmgr_;
};
}
}

View File

@ -0,0 +1,30 @@
//
// Created by linbo on 2025/6/13.
// Created by xtkuang on 2025/6/13.
//
#ifndef GRPC_MICROPHONE_SERVICE_H
#define GRPC_MICROPHONE_SERVICE_H
#include "cmvr/api/microphone_service.grpc.pb.h"
#include "device_manager/device_manager.h"
#include "../utils/base/grpc_utils.h"
namespace cmvr::service
{
class gRPCMicroPhoneServiceImpl: public api::MicPhoneService::Service {
public:
gRPCMicroPhoneServiceImpl();
~gRPCMicroPhoneServiceImpl() override = default;
grpc::Status GetStatus(grpc::ServerContext* context, const api::GetMicStateCommand_Request* request,api::GetMicStateCommand_Feedback* response) override;
grpc::Status StartRecord(grpc::ServerContext* context, const api::StartMicRecordingCommand_Request* request,api::StartMicRecordingCommand_Feedback* response) override;
grpc::Status StopRecord(grpc::ServerContext* context, const api::StopMicRecordingCommand_Request* request,api::StopMicRecordingCommand_Feedback* response) override;
grpc::Status PauseRecord(grpc::ServerContext* context, const api::PauseMicRecordingCommand_Request* request,api::PauseMicRecordingCommand_Feedback* response) override;
grpc::Status ResumeRecord(grpc::ServerContext* context, const api::ResumeMicRecordingCommand_Request* request,api::ResumeMicRecordingCommand_Feedback* response) override;
grpc::Status SetVolume(grpc::ServerContext* context, const api::SetMicPhoneVolumeCommand_Request* request,api::SetMicPhoneVolumeCommand_Feedback* response) override;
grpc::Status GetVolume(grpc::ServerContext* context, const api::GetMicPhoneVolumeCommand_Request* request,api::GetMicPhoneVolumeCommand_Feedback* response) override;
private:
device::DeviceManager& dmgr_;
};
}
#endif //GRPC_MICROPHONE_SERVICE_H

View File

@ -0,0 +1,30 @@
//
// Created by xtkuang on 2025/6/10.
//
#ifndef GRPC_SPEAKER_SERVICE_H
#define GRPC_SPEAKER_SERVICE_H
#include "cmvr/api/speaker_service.grpc.pb.h"
#include "device_manager/device_manager.h"
#include "../utils/base/grpc_utils.h"
namespace cmvr::service {
class gRPCSpeakerServiceImpl: public api::SpeakerService::Service {
public:
gRPCSpeakerServiceImpl();
~gRPCSpeakerServiceImpl() override = default;
grpc::Status GetStatus(grpc::ServerContext* context, const api::GetSpeakerStateCommand_Request* request,api::GetSpeakerStateCommand_Feedback* response) override;
grpc::Status PlayAudio(grpc::ServerContext* context, const api::PlayAudioCommand_Request* request,api::PlayAudioCommand_Feedback* response) override;
grpc::Status StopPlayback(grpc::ServerContext* context, const api::StopSpeakerCommand_Request* request,api::StopSpeakerCommand_Feedback* response) override;
grpc::Status PausePlayback(grpc::ServerContext* context, const api::PauseSpeakerCommand_Request* request,api::PauseSpeakerCommand_Feedback* response) override;
grpc::Status ResumePlayback(grpc::ServerContext* context, const api::ResumeSpeakerCommand_Request* request,api::ResumeSpeakerCommand_Feedback* response) override;
grpc::Status SetVolume(grpc::ServerContext* context, const api::SetSpeakerVolumeCommand_Request* request,api::SetSpeakerVolumeCommand_Feedback* response) override;
grpc::Status GetVolume(grpc::ServerContext* context, const api::GetSpeakerVolumeCommand_Request* request,api::GetSpeakerVolumeCommand_Feedback* response) override;
private:
device::DeviceManager& dmgr_;
};
}
#endif //GRPC_SPEAKER_SERVICE_H

View File

@ -0,0 +1,26 @@
//
// Created by xtkuang on 2025/6/6.
//
#ifndef GRPC_SYSTEM_SERVICE_H
#define GRPC_SYSTEM_SERVICE_H
#include "cmvr/api/system_service.grpc.pb.h"
#include "../utils/base/grpc_utils.h"
#include "device_manager/device_manager.h"
namespace cmvr::service
{
class gRPCSystemServiceImpl: public api::SystemService::Service {
public:
gRPCSystemServiceImpl();
~gRPCSystemServiceImpl() override = default;
grpc::Status GetSystemInfo(grpc::ServerContext* context, const api::GetSystemInfoCommand_Request* request, api::GetSystemInfoCommand_Feedback* response) override;
grpc::Status GetSystemStatus(grpc::ServerContext* context, const api::GetSystemStatusCommand_Request* request, api::GetSystemStatusCommand_Feedback* response) override;
grpc::Status UpdateParams(grpc::ServerContext* context, const cmvr::api::UpdateParamsCommand_Request* request, cmvr::api::UpdateParamsCommand_Feedback* response) override;
private:
device::DeviceManager& dmgr_;
};
}
#endif //GRPC_SYSTEM_SERVICE_H

View File

@ -0,0 +1,72 @@
#ifndef INTERPOLATION_BASE_H
#define INTERPOLATION_BASE_H
#include "utils/math/geometry.h"
#include <vector>
#include <stdexcept>
namespace cmvr::math {
/**
* 姿
* 姿(Pose3d)姿(Pose2d)
*/
class AbstractInterpolation {
public:
// 构造函数
AbstractInterpolation(const std::vector<Pose3d>& waypoints);
AbstractInterpolation(const std::vector<Pose2d>& waypoints);
// 析构函数
virtual ~AbstractInterpolation() = default;
/**
*
* @param t [0, 1]01
* @return 姿
*/
virtual Pose3d interpolate_3d(double t) const = 0;
virtual Pose2d interpolate_2d(double t) const = 0;
/**
*
* @param num_points
* @return
*/
std::vector<Pose3d> generate_trajectory_3d(size_t num_points) const;
std::vector<Pose2d> generate_trajectory_2d(size_t num_points) const;
protected:
// 路径点存储
std::vector<Pose3d> waypoints_3d_;
std::vector<Pose2d> waypoints_2d_;
/**
* 线
* @param a
* @param b
* @param t [0,1]
* @return
*/
static double linear_interpolate(double a, double b, double t);
/**
* 线(slerp)
* @param q1
* @param q2
* @param t [0,1]
* @return
*/
static Quat slerp(const Quat& q1, const Quat& q2, double t);
/**
* t的范围并进行约束
* @param t
* @return [0,1]
*/
static double clamp_t(double t);
};
} // namespace cmvr::math
#endif // INTERPOLATION_BASE_H

View File

@ -0,0 +1,17 @@
//
// Created by xtkuang on 2025/6/1.
//
#ifndef GRPC_UTILS_H
#define GRPC_UTILS_H
#include <grpcpp/grpcpp.h>
inline void setCurrentTimestamp(google::protobuf::Timestamp* ts) {
auto now = std::chrono::system_clock::now();
auto duration = now.time_since_epoch();
ts->set_seconds(std::chrono::duration_cast<std::chrono::seconds>(duration).count());
ts->set_nanos(std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count() % 1000000000);
}
#endif //GRPC_UTILS_H

View File

@ -0,0 +1,53 @@
//
// Created by xtkuang on 2025/6/3.
//
#ifndef LOGGER_H
#define LOGGER_H
#include <sys/stat.h>
#include <unistd.h>
#include <glog/logging.h>
#include "rapidxml/xml_parser.h"
using namespace std;
inline bool initLogger(const XmlNode &cfg) {
google::InitGoogleLogging("cmvr_es");
std::string temp = cfg.getAttrString("dir");
if (temp.empty()) {
std::cerr << "Error: no directory specified" << std::endl;
return false;
} else {
// 判断目录是否存在
if (access(temp.c_str(), F_OK) != 0) {
// 创建目录
if (mkdir(temp.c_str(), 0755) != 0) {
std::cerr << "Failed to create directory: " << temp << std::endl;
return false;
}
}
FLAGS_log_dir = temp;
}
temp = cfg.getAttrDefault("level", "info");
if (temp == "info") {
FLAGS_minloglevel = google::INFO;
} else if (temp == "warn") {
FLAGS_minloglevel = google::WARNING;
} else if (temp == "error") {
FLAGS_minloglevel = google::ERROR;
} else if (temp == "fatal") {
FLAGS_minloglevel = google::FATAL;
}
FLAGS_logbufsecs = cfg.getAttrDefault("bufSize", 5);
FLAGS_max_log_size = cfg.getAttrDefault("logSize", 1024);
FLAGS_logtostderr = false;
FLAGS_alsologtostderr = true;
return true;
}
#endif //LOGGER_H

33
include/utils/base/os.h Normal file
View File

@ -0,0 +1,33 @@
//
// Created by xtkuang on 2025/6/11.
//
#ifndef OS_H
#define OS_H
#include <vector>
#include <iostream>
#include <sys/stat.h>
inline bool pathExists(const std::string& path) {
struct stat info;
return stat(path.c_str(), &info) == 0;
}
inline std::vector<std::string> splitString(const std::string& pattern, const std::string& delimiter) {
std::vector<std::string> result;
if (delimiter.empty()) {
result.push_back(pattern); // 若分隔符为空,则原样返回
return result;
}
size_t start = 0;
size_t end;
while ((end = pattern.find(delimiter, start)) != std::string::npos) {
result.push_back(pattern.substr(start, end - start));
start = end + delimiter.length();
}
result.push_back(pattern.substr(start));
return result;
}
#endif //OS_H

View File

@ -0,0 +1,136 @@
//
// Created by xtkuang on 2025/5/30.
//
#ifndef CMVR_ES_RING_BUFFER_H
#define CMVR_ES_RING_BUFFER_H
#pragma once
#include <deque>
#include <mutex>
#include <vector>
#include <atomic>
#include <optional>
template<typename T>
class RingBuffer {
public:
explicit RingBuffer(size_t capacity) : capacity_(capacity) {}
void push(const T& item) {
std::lock_guard<std::mutex> lock(mutex_);
if (buffer_.size() >= capacity_) {
buffer_.pop_front();
}
buffer_.push_back(item);
}
std::vector<T> getAll() const {
std::lock_guard<std::mutex> lock(mutex_);
return std::vector<T>(buffer_.begin(), buffer_.end());
}
void clear() {
std::lock_guard<std::mutex> lock(mutex_);
buffer_.clear();
}
size_t size() const {
std::lock_guard<std::mutex> lock(mutex_);
return buffer_.size();
}
private:
size_t capacity_;
std::deque<T> buffer_;
mutable std::mutex mutex_;
};
template<typename T>
class SPMCRingBuffer {
public:
explicit SPMCRingBuffer(size_t capacity)
: buffer_(capacity), capacity_(capacity),
head_(0), tail_(0) {}
// 写入操作(仅支持单个生产者)
void push(const T& item) {
size_t head = head_.load(std::memory_order_relaxed);
size_t tail = tail_.load(std::memory_order_acquire);
buffer_[head % capacity_] = item;
head = head + 1;
head_.store(head, std::memory_order_release);
if (head - tail >= capacity_) {
// 队列满,覆盖最旧的数据
tail_.store(tail + 1, std::memory_order_release);
}
}
// 单消费者使用(内部 tail_
std::optional<T> pop() {
size_t tail = tail_.load(std::memory_order_relaxed);
size_t head = head_.load(std::memory_order_acquire);
if (tail >= head) return std::nullopt;
T value = buffer_[tail % capacity_];
tail_.store(tail + 1, std::memory_order_release);
return value;
}
std::optional<T> getLast() {
size_t tail = tail_.load(std::memory_order_relaxed);
size_t head = head_.load(std::memory_order_acquire);
if (tail >= head) return std::nullopt;
T value = buffer_[head_ % capacity_];
return value;
}
// 多消费者使用(每个读者独立维护 reader_tail
std::optional<T> pop(size_t& reader_tail) const {
size_t head = head_.load(std::memory_order_acquire);
if (reader_tail >= head) return std::nullopt;
if (head > reader_tail + capacity_) {
// 数据已被覆盖,跳过无效读取区间
reader_tail = head - capacity_;
return std::nullopt;
}
T value = buffer_[reader_tail % capacity_];
reader_tail++;
return value;
}
size_t size() const {
return head_.load(std::memory_order_acquire) - tail_.load(std::memory_order_acquire);
}
size_t getHead() const {
return head_.load(std::memory_order_acquire);
}
size_t getTail() const {
return tail_.load(std::memory_order_acquire);
}
bool empty() const {
return size() == 0;
}
bool full() const {
return size() >= capacity_;
}
void clear() {
head_.store(0, std::memory_order_release);
tail_.store(0, std::memory_order_release);
}
private:
std::vector<T> buffer_;
const size_t capacity_;
std::atomic<size_t> head_; // 共享写指针
std::atomic<size_t> tail_; // 共享读指针(仅用于 SPSC 模式)
};
#endif //CMVR_ES_RING_BUFFER_H

View File

@ -0,0 +1,81 @@
//
// Created by xtkuang on 2025/5/13.
//
#ifndef CMVR_ES_THREAD_POOL_H
#define CMVR_ES_THREAD_POOL_H
#include <thread>
#include <vector>
#include <functional>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <memory>
#include <chrono>
#include <future>
#include <boost/lockfree/queue.hpp>
#pragma warning(disable:4996)
#define GLOG_USE_GLOG_EXPORT
#include <glog/logging.h>
class InterruptFlag {
public:
void request_stop();
[[nodiscard]] bool stop_requested() const;
private:
std::atomic<bool> flag_ {false};
};
// 提交任务(带 future 返回)
class TaskHandle {
public:
using TaskFuncType = std::function<void()>;
using ReturnType = void;
TaskHandle(std::shared_ptr<std::promise<ReturnType>> promise)
: future_(promise->get_future()) {}
std::future<ReturnType>& get_future() { return future_; }
private:
std::future<ReturnType> future_;
};
class ThreadPool {
public:
ThreadPool(size_t min_threads, size_t max_threads);
~ThreadPool();
// 提交任务(不带返回值)
void submit(std::function<void(InterruptFlag&)> task);
TaskHandle submit_with_future(std::function<TaskHandle::TaskFuncType()> f);
void shutdown();
private:
void worker_loop(size_t id);
void monitor_loop();
boost::lockfree::queue<std::function<void(InterruptFlag&)>*> task_queue_;
std::atomic<size_t> pending_tasks_;
std::vector<std::thread> threads_;
std::vector<std::unique_ptr<InterruptFlag>> flags_;
std::mutex control_mutex_;
std::condition_variable control_cv_;
std::atomic<bool> shutdown_requested_ = false;
const size_t min_threads_;
const size_t max_threads_;
std::thread monitor_thread_;
};
#endif //CMVR_ES_THREAD_POOL_H

View File

@ -0,0 +1,37 @@
//
// Created by xtkuang on 2025/5/14.
//
#ifndef CMVR_ES_TIMER_H
#define CMVR_ES_TIMER_H
#include <sys/timerfd.h>
#include <unistd.h>
#include <functional>
#include <thread>
#include <atomic>
#include <system_error>
#include <iostream>
#include <cstring>
#include <utility>
class FDTimer {
public:
using Callback = std::function<void()>;
FDTimer();
~FDTimer();
void start(std::chrono::nanoseconds interval, Callback callback);
void stop();
[[nodiscard]] bool is_running() const;
private:
static timespec toTimespec(std::chrono::nanoseconds ns);
int fd_;
std::atomic<bool> running_;
Callback callback_;
std::thread worker_thread_;
};
#endif //CMVR_ES_TIMER_H

View File

@ -0,0 +1,118 @@
//
// Created by xtkuang on 2025/7/21.
//
#ifndef CMVR_ES_CARTESIAN_CONTROLLER_H
#define CMVR_ES_CARTESIAN_CONTROLLER_H
#pragma once
#include <Eigen/Core>
#include <Eigen/Dense>
#include <vector>
#include <string>
#include <memory>
#include <cmath>
#include <fcl/fcl.h>
#include <optional>
#include <unordered_map>
#include "utils/math/se3.h"
#include "utils/math/qp_solver.h"
#include "utils/dynamics/robot.h"
namespace cmvr::ctrl{
using cmvr::math::SE3;
// -----------------------------------------------------------------------------
// Task & collision descriptions
// -----------------------------------------------------------------------------
struct PoseTarget {
std::string link_name; //!< link to be controlled
Eigen::Matrix4d T_target; //!< desired pose w.r.t *base_link*
double w_posrot = 0.5; // [0→pure pos, 1→pure rot]
double weight = 1.0; // task weight (01 soft, 1 hard)
};
struct CollisionPair { std::string link_A, link_B; };
// -----------------------------------------------------------------------------
// CartesianController declaration (implementation in .cpp)
// -----------------------------------------------------------------------------
template<int DOF>
class CartesianController {
public:
using RobotT = cmvr::dyn::Robot<DOF>;
using VecD = Eigen::Vector<double, DOF>;
using Mat6D = Eigen::Matrix<double, 6, DOF>;
enum class Mode { Position, Velocity, Torque };
CartesianController(std::shared_ptr<RobotT> robot, double dsafe = 0.05, double lambda = 1e-2);
/* ------------------------- configuration ----------------------------- */
void setCollisionPairs(const std::vector<CollisionPair>& pairs);
// Joint limits (size = DOF). Any value = std::nullopt → no limit.
void setPositionLimits(const std::vector<std::optional<double>>& q_min, const std::vector<std::optional<double>>& q_max);
void setVelocityLimits(const std::vector<std::optional<double>>& qd_max);
void setAccelerationLimits(const std::vector<std::optional<double>>& qdd_max);
/* --------------------------- main API -------------------------------- */
/**
* Compute joint command given Cartesian objectives.
* @param state current (mutable) robot state
* @param base reference frame (string)
* @param targets list of PoseTarget
* @param dt controller step [s]
* @param mode desired output type
* @param out_cmd filled with q / / τ
* @return true if IK converged (position) or soft OK (others)
*/
bool compute(
std::shared_ptr<cmvr::dyn::State<DOF>>& state,
const std::string& base_link,
const std::vector<PoseTarget>& targets,
double dt,
Mode mode,
VecD& out_cmd,
int max_iters = 60,
double tol = 1e-3,
double alpha_h = 10.0);
private:
/* -------- internal helpers (implemented in .cpp) --------------------- */
bool solveIK(std::shared_ptr<cmvr::dyn::State<DOF>>& state, const std::string& base, const std::vector<PoseTarget>& targets,
const VecD& q_init, VecD& q_out, int max_iters, double tol, double alpha_h) const;
bool distanceConstraint(const CollisionPair& cp, std::shared_ptr<cmvr::dyn::State<DOF>>& state,
const std::vector<std::shared_ptr<fcl::CollisionObjectd>>& objs,
double& h_out, Eigen::RowVectorXd& J_out) const;
inline void clampVec(VecD& v, const std::vector<std::optional<double>>& lo, const std::vector<std::optional<double>>& hi) const;
/* -------------------------- data ------------------------------------ */
std::shared_ptr<RobotT> robot_;
std::vector<CollisionPair> pairs_;
double d_safe_ = 0.05;
double lambda_ = 1e-2;
mutable math::QPSolver solver_;
// joint limits (optional)
std::vector<std::optional<double>> q_min_ = std::vector<std::optional<double>>(DOF);
std::vector<std::optional<double>> q_max_ = std::vector<std::optional<double>>(DOF);
std::vector<std::optional<double>> qd_max_ = std::vector<std::optional<double>>(DOF);
std::vector<std::optional<double>> qdd_max_= std::vector<std::optional<double>>(DOF);
// FCL reusable buffers
mutable fcl::DistanceRequestd dist_req_{};
mutable fcl::DistanceResultd dist_res_{};
};
}
// ------------------------------ explicit instantiation -----------------------
extern template class cmvr::ctrl::CartesianController<7>;
extern template class cmvr::ctrl::CartesianController<14>;
extern template class cmvr::ctrl::CartesianController<20>;
#endif //CMVR_ES_CARTESIAN_CONTROLLER_H

View File

@ -0,0 +1,54 @@
//
// Created by xtkuang on 2025/7/8.
//
#ifndef INERTIAL_H
#define INERTIAL_H
#pragma once
#include <eigen3/Eigen/Core>
#include "utils/math/se3.h"
namespace cmvr::dyn {
class Inertial;
class Inertial {
public:
using MatrixType = Eigen::Matrix<double, 6, 6>;
static MatrixType I(double mass);
static MatrixType I(double mass, double ixx, double iyy, double izz,
const math::SE3::MatrixType& T = math::SE3::Identity());
static MatrixType I(double mass, double ixx, double iyy, double izz,
const Eigen::Vector3d& com);
static MatrixType I(double mass, double ixx, double iyy, double izz, double ixy, double ixz, double iyz,
const math::SE3::MatrixType& T = math::SE3::Identity());
static MatrixType I(double mass, double ixx, double iyy, double izz, double ixy, double ixz, double iyz,
const Eigen::Vector3d& com);
static MatrixType I(double mass, const Eigen::Vector3d& inertia,
const math::SE3::MatrixType& T = math::SE3::Identity());
static MatrixType I(double mass, const Eigen::Matrix<double, 6, 1>& inertia,
const math::SE3::MatrixType& T = math::SE3::Identity());
static MatrixType Transform(const math::SE3::MatrixType& T, const MatrixType& I);
static Eigen::Vector3d GetCOM(const MatrixType& I);
static double GetMass(const MatrixType& I);
// [I_{xx}, I_{yy}, I_{zz}, I_{xy}, I_{xz}, I_{yz}]^T
static Eigen::Vector<double, 6> GetInertia(const MatrixType& I);
};
}
#endif //INERTIAL_H

View File

@ -0,0 +1,108 @@
//
// Created by xtkuang on 2025/7/7.
//
#ifndef JOINT_H
#define JOINT_H
#include <eigen3/Eigen/Core>
#include <memory>
#include "utils/math/constants.h"
#include "utils/math/liegroup.h"
#include "utils/dynamics/link.h"
namespace cmvr::dyn {
class Joint : public std::enable_shared_from_this<Joint> {
public:
template<int DOF>
friend class Robot;
static std::shared_ptr<Joint> Make(std::string name, math::se3v::MatrixType S);
static std::shared_ptr<Joint> MakeRevoluteJoint(std::string name,
const math::SE3::MatrixType &T = math::SE3::Identity(),
const Eigen::Vector3d &axis = {0, 0, 1});
static std::shared_ptr<Joint> MakePrismaticJoint(std::string name,
const math::SE3::MatrixType &T = math::SE3::Identity(),
const Eigen::Vector3d &axis = {0, 0, 1});
static std::shared_ptr<Joint> MakeFixedJoint(std::string name);
std::string GetName() const;
void ConnectLinks(const std::shared_ptr<Link> &parent_link, const std::shared_ptr<Link> &child_link,
const math::SE3::MatrixType &T_pj = math::SE3::Identity(),
const math::SE3::MatrixType &T_jc = math::SE3::Identity());
void Disconnect();
void SetLimitQ(double lower, double upper);
void SetLimitQdot(double lower, double upper);
void SetLimitQddot(double lower, double upper);
void SetLimitTorque(double value);
double GetLimitQLower() const;
double GetLimitQUpper() const;
double GetLimitQdotLower() const;
double GetLimitQdotUpper() const;
double GetLimitQddotLower() const;
double GetLimitQddotUpper() const;
double GetLimitTorque() const;
void SetLimitQLower(double val);
void SetLimitQUpper(double val);
void SetLimitQdotLower(double val);
void SetLimitQdotUpper(double val);
void SetLimitQddotLower(double val);
void SetLimitQddotUpper(double val);
std::weak_ptr<Link> GetParentLink();
std::shared_ptr<Link> GetChildLink();
std::shared_ptr<const Link> GetChildLink() const;
bool IsFixed() const;
private:
explicit Joint(std::string name);
Joint(std::string name, math::se3v::MatrixType S);
private:
std::string name_{};
bool fixed_;
math::se3v::MatrixType S_;
double limit_torque_{(std::numeric_limits<double>::max)()};
double limit_q_lower_{-(std::numeric_limits<double>::max)()};
double limit_q_upper_{(std::numeric_limits<double>::max)()};
double limit_qdot_lower_{-(std::numeric_limits<double>::max)()};
double limit_qdot_upper_{(std::numeric_limits<double>::max)()};
// double limit_qddot_lower_{-(std::numeric_limits<double>::max)()};
// double limit_qddot_upper_{(std::numeric_limits<double>::max)()};
double limit_qddot_lower_{-10.};
double limit_qddot_upper_{10.}; // (rad/s^2)
std::weak_ptr<Link> parent_link_;
std::shared_ptr<Link> child_link_{nullptr};
math::SE3::MatrixType T_pj_, T_jc_;
};
}
#endif //JOINT_H

View File

@ -0,0 +1,143 @@
//
// Created by xtkuang on 2025/7/8.
//
#ifndef LINK_H
#define LINK_H
#pragma once
#include <eigen3/Eigen/Core>
#include <memory>
#include "utils/dynamics/inertial.h"
#include "utils/math/liegroup.h"
namespace cmvr::dyn {
template<int DOF>
class Robot;
class Link;
class Joint;
class Collision;
struct CollisionResult;
class Geom;
class GeomCapsule;
enum class GeomType { kCapsule = 0 };
class Link : public std::enable_shared_from_this<Link> {
public:
template<int DOF>
friend class Robot;
friend class Joint;
static std::shared_ptr<Link> Make(std::string name, Inertial::MatrixType I = Inertial::I(1.));
std::string GetName() const;
std::weak_ptr<Joint> GetParentJoint();
std::vector<std::shared_ptr<Joint> > GetChildJointList();
const std::vector<std::shared_ptr<Joint> > &GetChildJointList() const;
void AddCollision(const std::shared_ptr<Collision> &collision);
std::vector<std::shared_ptr<Collision> > GetCollisions();
const std::vector<std::shared_ptr<Collision> > &GetCollisions() const;
private:
Link(std::string name, Inertial::MatrixType I);
private:
std::string name_{};
Inertial::MatrixType I_{};
std::weak_ptr<Joint> parent_joint_;
std::vector<std::shared_ptr<Joint> > child_joints_;
std::vector<std::shared_ptr<Collision> > collisions_;
};
class Collision : public std::enable_shared_from_this<Collision> {
public:
explicit Collision(std::string name);
void SetOrigin(const math::SE3::MatrixType &T);
math::SE3::MatrixType GetOrigin() const;
void AddGeom(const std::shared_ptr<Geom> &geom);
std::vector<std::shared_ptr<Geom> > GetGeoms();
const std::vector<std::shared_ptr<Geom> > &GetGeoms() const;
private:
std::string name_;
math::SE3::MatrixType T_{math::SE3::Identity()};
std::vector<std::shared_ptr<Geom> > geoms_;
};
class Geom : public std::enable_shared_from_this<Geom> {
public:
Geom(unsigned int coltype = 0, unsigned int colaffinity = 0) : coltype_(coltype), colaffinity_(colaffinity) {
}
virtual ~Geom() = default;
virtual GeomType GetType() const = 0;
unsigned int GetColtype() const { return coltype_; }
unsigned int GetColaffinity() const { return colaffinity_; }
virtual std::optional<CollisionResult> ComputeMinimumDistance(const math::SE3::MatrixType &T,
const Geom &other_geom,
const math::SE3::MatrixType &other_T) const = 0;
bool Filter(const Geom &other_geom) const {
return (coltype_ & other_geom.colaffinity_) || (other_geom.coltype_ & colaffinity_);
}
protected:
unsigned int coltype_;
unsigned int colaffinity_;
};
class GeomCapsule : public Geom {
public:
GeomCapsule(double length, double radius, unsigned int coltype = 0, unsigned int colaffinity = 0);
GeomCapsule(Eigen::Vector3d sp, Eigen::Vector3d ep, double radius, unsigned int coltype = 0,
unsigned int colaffinity = 0);
GeomType GetType() const override;
std::optional<CollisionResult> ComputeMinimumDistance(const math::SE3::MatrixType &T, const Geom &other_geom,
const math::SE3::MatrixType &other_T) const override;
Eigen::Vector3d GetStartPoint() const;
Eigen::Vector3d GetEndPoint() const;
double GetRadius() const;
private:
Eigen::Vector3d sp_;
Eigen::Vector3d ep_;
double radius_;
};
struct CollisionResult {
std::string link1;
std::string link2;
Eigen::Vector3d position1;
Eigen::Vector3d position2;
double distance;
};
}
#endif //LINK_H

View File

@ -0,0 +1,288 @@
//
// Created by xtkuang on 2025/7/8.
//
#ifndef ROBOT_H
#define ROBOT_H
#pragma once
#include <Eigen/Core>
#include <iostream>
#include <memory>
#include <queue>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include <iomanip>
#include <limits>
#include "inertial.h"
#include "joint.h"
#include "link.h"
#include "state.h"
#include "utils/math/liegroup.h"
#include "utils/math/qp_solver.h"
namespace cmvr::dyn {
/**********************************************************
* FORWARD DECLARATION
**********************************************************/
//
template<int DOF>
class Robot;
class Link;
class Joint;
/**********************************************************
* MOBILE BASE
**********************************************************/
enum class MobileBaseType {
None, //
Differential, //
Mecanum //
};
struct MobileBase {
MobileBaseType type{MobileBaseType::None};
math::SE3::MatrixType T; // front = x-axis
std::vector<std::string> joints;
std::vector<double> params;
};
struct MobileBaseDifferential : public MobileBase {
unsigned int right_wheel_idx{};
unsigned int left_wheel_idx{};
double wheel_base{0.};
double wheel_radius{0.};
};
struct MobileBaseMecanum : public MobileBase {
unsigned int fr_wheel_idx{};
unsigned int fl_wheel_idx{};
unsigned int rr_wheel_idx{};
unsigned int rl_wheel_idx{};
double L_x{0.};
double L_y{0.};
double wheel_radius{0.};
};
/**********************************************************
* ROBOT
**********************************************************/
struct RobotConfiguration {
std::string name;
std::shared_ptr<Link> base_link;
std::shared_ptr<MobileBase> mobile_base;
};
template<int DOF>
class Robot {
public:
template<typename T, int N>
using ContainerType = typename std::conditional_t<(N > 0), std::array<T, (unsigned int) N>, std::vector<T> >;
struct Link_ {
struct SubLink_ {
std::shared_ptr<Link> link;
Inertial::MatrixType J_wrt_p;
math::SE3::MatrixType M_wrt_p;
math::SE3::MatrixType M_wrt_base;
};
std::vector<SubLink_> links;
Inertial::MatrixType J{Inertial::MatrixType::Zero()}; // Link_ inertial wrt base link
math::SE3::MatrixType M{math::SE3::Identity()}; // Base link to Link_ frame
Inertial::MatrixType I{Inertial::MatrixType::Zero()}; // Link_ inertial wrt Link_ frame
int depth{0};
int parent_joint_idx{-1};
std::vector<int> child_joint_idx{};
void SetBaseLink(const std::shared_ptr<Link> &link, const math::SE3::MatrixType &T) {
// Rest link information
links.clear();
J = Inertial::MatrixType::Zero();
M = T;
AddLink(link, math::SE3::Identity());
}
int AddLink(const std::shared_ptr<Link> &link, const math::SE3::MatrixType &M_wrt_p) {
Inertial::MatrixType J_wrt_p = Inertial::Transform(M_wrt_p, link->I_);
int idx = links.size();
SubLink_ l;
l.link = link;
l.J_wrt_p = J_wrt_p;
l.M_wrt_p = M_wrt_p;
l.M_wrt_base = M * M_wrt_p;
links.push_back(l);
I += J_wrt_p;
J += Inertial::Transform(M, J_wrt_p);
return idx;
}
};
struct Joint_ {
std::shared_ptr<Joint> joint{nullptr};
math::se3v::MatrixType S{math::se3v::MatrixType::Zero()}; // zero pose
int parent_link_idx{};
int child_link_idx{};
};
struct LinkIdx_ {
int link_idx;
int sub_link_idx;
};
explicit Robot(const RobotConfiguration &robot_configuration);
std::shared_ptr<Link> GetBase();
std::vector<std::string> GetLinkNames() const;
std::vector<std::string> GetJointNames() const;
std::shared_ptr<Link> GetLink(const std::string &name) const;
std::shared_ptr<Link> GetLink(std::shared_ptr<State<DOF>> state, int index) const;
LinkIdx_ GetLinkIdx(const std::string& name) const;
template<typename LinkContainer = std::vector<std::string>, typename JointContainer = std::vector<std::string> >
std::shared_ptr<State<DOF>> MakeState(const LinkContainer &link_names, const JointContainer &joint_names);
int GetDOF() const;
int GetNumberOfJoints() const;
void ComputeForwardKinematics(std::shared_ptr<State<DOF>> state);
void ComputeDiffForwardKinematics(std::shared_ptr<State<DOF>> state);
void Compute2ndDiffForwardKinematics(std::shared_ptr<State<DOF>> state);
void ComputeInverseDynamics(std::shared_ptr<State<DOF>> state);
Eigen::Vector<double, DOF> ComputeGravityTerm(std::shared_ptr<State<DOF>> state);
Eigen::Matrix<double, DOF, DOF> ComputeMassMatrix(std::shared_ptr<State<DOF>> state);
Eigen::Matrix<double, 6, 6> ComputeReflectiveInertia(std::shared_ptr<State<DOF>> state, unsigned int from, unsigned int to);
math::SE3::MatrixType ComputeTransformation(std::shared_ptr<State<DOF>> state, unsigned int from, unsigned int to);
math::se3v::MatrixType ComputeBodyVelocity(std::shared_ptr<State<DOF>> state, unsigned int from, unsigned int to);
Eigen::Matrix<double, 6, DOF> ComputeSpaceJacobian(std::shared_ptr<State<DOF>> state, unsigned int from, unsigned int to);
Eigen::Matrix<double, 6, DOF> ComputeBodyJacobian(std::shared_ptr<State<DOF>> state, unsigned int from, unsigned int to);
double ComputeMass(std::shared_ptr<State<DOF>> state, unsigned int target_link);
Eigen::Vector3d ComputeCenterOfMass(std::shared_ptr<State<DOF>> state, unsigned int ref_link, unsigned int target_link);
Eigen::Vector3d ComputeCenterOfMass(std::shared_ptr<State<DOF>> state, unsigned int ref_link, const std::vector<unsigned int> &target_links);
Eigen::Matrix<double, 3, DOF> ComputeCenterOfMassJacobian(std::shared_ptr<State<DOF>> state, unsigned int ref_link, unsigned int target_link);
Inertial::MatrixType ComputeTotalInertial(std::shared_ptr<State<DOF>> state, unsigned int ref_link);
Eigen::Vector3d ComputeCenterOfMass(std::shared_ptr<State<DOF>> state, unsigned int ref_link);
Eigen::Matrix<double, 3, DOF> ComputeCenterOfMassJacobian(std::shared_ptr<State<DOF>> state, unsigned int ref_link);
std::vector<CollisionResult> DetectCollisionsOrNearestLinks(std::shared_ptr<State<DOF>> state, int collision_threshold = 0);
// TODO: ComputeBodyJacobianDot
// TODO: ComputeBodyAcceleration
// TODO: InverseDiffDynamics
Eigen::Vector<double, DOF> GetLimitQLower(const std::shared_ptr<State<DOF>> &state);
Eigen::Vector<double, DOF> GetLimitQUpper(const std::shared_ptr<State<DOF>> &state);
Eigen::Vector<double, DOF> GetLimitQdotLower(const std::shared_ptr<State<DOF>> &state);
Eigen::Vector<double, DOF> GetLimitQdotUpper(const std::shared_ptr<State<DOF>> &state);
Eigen::Vector<double, DOF> GetLimitQddotLower(const std::shared_ptr<State<DOF>> &state);
Eigen::Vector<double, DOF> GetLimitQddotUpper(const std::shared_ptr<State<DOF>> &state);
Eigen::Vector<double, DOF> GetLimitTorque(const std::shared_ptr<State<DOF>> &state);
Eigen::Vector<double, DOF> GetJointProperty(const std::shared_ptr<State<DOF>> &state, const std::function<double(std::shared_ptr<Joint>)> &getter);
void ComputeMobilityInverseDiffKinematics(std::shared_ptr<State<DOF>> state, //
const Eigen::Vector2d &linear_velocity, // (m/s)
double angular_velocity // (rad/s)
);
void ComputeMobilityInverseDiffKinematics(std::shared_ptr<State<DOF>> state, //
const math::se2v::MatrixType &body_velocity // w, x, y
);
math::se2v::MatrixType ComputeMobilityDiffKinematics( //
std::shared_ptr<State<DOF>> state //
);
static int CountJoints(const std::shared_ptr<Link> &base_link, bool include_fixed=false);
math::SE3::MatrixType GetLinkT(std::shared_ptr<State<DOF>> state, const LinkIdx_ &idx);
math::se3v::MatrixType GetLinkV(std::shared_ptr<State<DOF>> state, const LinkIdx_ &idx);
math::SE3::MatrixType GetJointT(std::shared_ptr<State<DOF>> state, int joint_idx);
math::se3v::MatrixType GetJointV(std::shared_ptr<State<DOF>> state, int joint_idx);
math::se3v::MatrixType GetJointVdot(std::shared_ptr<State<DOF>> state, int joint_idx);
math::SE3::MatrixType GetTransformation(std::shared_ptr<State<DOF>> state, const LinkIdx_ &from, const LinkIdx_ &to);
Eigen::Matrix<double, 6, DOF> GetSpaceJacobian(std::shared_ptr<State<DOF>> state, const LinkIdx_ &from, const LinkIdx_ &to);
Eigen::Matrix<double, 6, DOF> GetBodyJacobian(std::shared_ptr<State<DOF>> state, const LinkIdx_ &from, const LinkIdx_ &to);
protected:
Robot() = default;
void Build(const RobotConfiguration &rc);
private:
ContainerType<Link_, DOF + 1> links_;
ContainerType<Joint_, DOF> joints_;
std::unordered_map<std::string, LinkIdx_> link_idx_; // link name to (parent idx, sub link idx)
std::unordered_map<std::string, unsigned int> joint_idx_; // joint name to joint idx
size_t n_links_{};
size_t n_joints_{};
/**
* MOBILE BASE
*/
std::shared_ptr<MobileBase> mobile_base_;
};
RobotConfiguration LoadRobotFromURDFData(const std::string &model, const std::string &base_link_name);
RobotConfiguration LoadRobotFromURDF(const std::string &path, const std::string &base_link_name);
inline std::string to_string(GeomType type) {
switch (type) {
case GeomType::kCapsule:
return "capsule";
}
return "unknown";
}
}
#include "robot.tpp"
#endif //ROBOT_H

View File

@ -0,0 +1,828 @@
#pragma once
#include "robot.h"
using namespace cmvr::dyn;
template<int DOF>
Robot<DOF>::Robot(const RobotConfiguration &robot_configuration) {
Build(robot_configuration);
}
template<int DOF>
std::shared_ptr<Link> Robot<DOF>::GetBase() {
return links_[0].links[0].link;
}
template<int DOF>
std::vector<std::string> Robot<DOF>::GetLinkNames() const {
std::vector<std::string> names;
for (const auto &[n, idx]: link_idx_) {
names.push_back(n);
}
return names;
}
template<int DOF>
std::vector<std::string> Robot<DOF>::GetJointNames() const {
std::vector<std::string> names;
for (const auto &[n, idx]: joint_idx_) {
names.push_back(n);
}
return names;
}
template<int DOF>
std::shared_ptr<Link> Robot<DOF>::GetLink(const std::string &name) const {
if (link_idx_.find(name) == link_idx_.end()) {
return nullptr;
}
const auto &idx = link_idx_.at(name);
return links_[idx.link_idx].links[idx.sub_link_idx].link;
}
template<int DOF>
std::shared_ptr<Link> Robot<DOF>::GetLink(std::shared_ptr<State<DOF> > state, int index) const {
if (index >= static_cast<int>(state->utr_link_map.size())) {
return nullptr;
}
const auto &idx = state->utr_link_map[index];
return links_[idx.link_idx].links[idx.sub_link_idx].link;
}
template<int DOF>
typename Robot<DOF>::LinkIdx_ Robot<DOF>::GetLinkIdx(const std::string& name) const {
auto it = link_idx_.find(name);
if (it == link_idx_.end()) {
throw std::runtime_error("Link name not found: " + name);
}
return it->second;
}
template<int DOF>
template<typename LinkContainer, typename JointContainer>
std::shared_ptr<State<DOF>> Robot<DOF>::MakeState(const LinkContainer &link_names, const JointContainer &joint_names) {
static_assert(std::is_same_v<typename LinkContainer::value_type, std::string> ||
std::is_same_v<typename LinkContainer::value_type, std::string_view>,
"LinkContainer value_type must be std::string");
static_assert(std::is_same_v<typename JointContainer::value_type, std::string> ||
std::is_same_v<typename JointContainer::value_type, std::string_view>,
"JointContainer value_type must be std::string");
std::vector<bool> flag;
flag.resize(n_joints_);
std::fill(flag.begin(), flag.end(), false);
auto state = std::shared_ptr<State<DOF>>(new State < DOF > (n_joints_));
for (int i = 0; i < static_cast<int>(joint_names.size()); i++) {
const auto &name = joint_names[i];
auto it = std::find_if(joints_.begin(), joints_.end(),
[name](const auto &j) { return j.joint->name_ == name; });
if (it == joints_.end()) {
throw std::runtime_error("Cannot find the joint with name");
}
state->utr_joint_map[i] = it - joints_.begin();
state->joint_names[i] = it->joint->name_;
flag[state->utr_joint_map[i]] = true;
}
for (unsigned int i = joint_names.size(); i < n_joints_; i++) {
auto it = std::find(flag.begin(), flag.end(), false);
state->utr_joint_map[i] = it - flag.begin();
state->joint_names[i] = (joints_.begin() + (it - flag.begin()))->joint->name_;
*it = true;
}
for (int i = 0; i < state->utr_joint_map.size(); i++) {
state->rtu_joint_map[state->utr_joint_map[i]] = i;
}
std::unordered_map<std::string, bool> name_flag;
state->link_names.clear();
state->utr_link_map.clear();
for (const auto &name: link_names) {
auto it = link_idx_.find(name);
if (it == link_idx_.end()) {
throw std::runtime_error("The link with the given name does not exist");
}
state->utr_link_map.push_back(it->second);
state->link_names.push_back(name);
name_flag[name] = true;
}
for (const auto &[k, v]: link_idx_) {
if (name_flag.find(k) == name_flag.end()) {
state->utr_link_map.push_back(v);
state->link_names.push_back(k);
}
}
for (auto i = 0; i < state->link_names.size(); i++) {
const auto &n = state->link_names[i];
auto it = link_idx_.find(n);
if (it == link_idx_.end()) {
throw std::runtime_error("Fatal error; link names in state should be found in link idx");
}
if (it->second.link_idx == 0 && it->second.sub_link_idx == 0) {
state->base_link_user_idx = i;
}
}
return state;
}
template<int DOF>
int Robot<DOF>::GetDOF() const {
return n_joints_;
}
template<int DOF>
int Robot<DOF>::GetNumberOfJoints() const {
return n_joints_;
}
template<int DOF>
void Robot<DOF>::ComputeForwardKinematics(std::shared_ptr<State<DOF>> state) {
for (auto i = 0; i < n_joints_; i++) {
state->E[i] = math::SE3::Exp(joints_[i].S, state->q(i));
int parent_joint_idx = links_[joints_[i].parent_link_idx].parent_joint_idx;
state->T[i] = GetJointT(state, parent_joint_idx) * state->E[i];
state->S.col(i) = math::SE3::Ad(GetJointT(state, parent_joint_idx), joints_[i].S);
}
}
template<int DOF>
void Robot<DOF>::ComputeDiffForwardKinematics(std::shared_ptr<State<DOF>> state) {
// In Body Frame
for (auto i = 0; i < n_joints_; i++) {
state->V.col(i) = joints_[i].S * state->qdot(i);
int parent_joint_idx = links_[joints_[i].parent_link_idx].parent_joint_idx;
state->V.col(i) += math::SE3::InvAd(state->E[i], GetJointV(state, parent_joint_idx));
}
}
template<int DOF>
void Robot<DOF>::Compute2ndDiffForwardKinematics(std::shared_ptr<State<DOF>> state) {
for (auto i = 0; i < n_joints_; i++) {
state->Vdot.col(i) = joints_[i].S * state->qddot(i);
int parent_joint_idx = links_[joints_[i].parent_link_idx].parent_joint_idx;
state->Vdot.col(i) += math::SE3::InvAd(state->E[i], GetJointVdot(state, parent_joint_idx)) +
math::SE3::ad(state->V.col(i), joints_[i].S * state->qdot(i));
}
}
template<int DOF>
void Robot<DOF>::ComputeInverseDynamics(std::shared_ptr<State<DOF>> state) {
for (int i = n_joints_ - 1; i >= 0; i--) {
Eigen::Vector<double, 6> F;
F.setZero();
for (const auto &child_joint_idx: links_[joints_[i].child_link_idx].child_joint_idx) {
F += math::SE3::InvAd(state->E[child_joint_idx]).transpose() * state->F.col(child_joint_idx);
}
F += links_[joints_[i].child_link_idx].J * state->Vdot.col(i) -
math::SE3::adTranspose(state->V.col(i), links_[joints_[i].child_link_idx].J * state->V.col(i));
state->F.col(i) = F;
state->tau(i) = joints_[i].S.dot(F);
}
}
template<int DOF>
Eigen::Vector<double, DOF> Robot<DOF>::ComputeGravityTerm(std::shared_ptr<State<DOF>> state) {
Eigen::Vector<double, DOF> gravity_term;
gravity_term.resize(n_joints_);
std::vector<Eigen::Vector<double, 6> > Vdot{}, Fs{};
Vdot.resize(n_joints_);
Fs.resize(n_joints_);
// Calculate Vdot
for (auto i = 0; i < n_joints_; i++) {
int parent_joint_idx = links_[joints_[i].parent_link_idx].parent_joint_idx;
if (parent_joint_idx < 0) {
Vdot[i] = math::SE3::InvAd(state->E[i], state->Vdot0);
} else {
Vdot[i] = math::SE3::InvAd(state->E[i], Vdot[parent_joint_idx]);
}
}
//
for (int i = n_joints_ - 1; i >= 0; i--) {
Eigen::Vector<double, 6> F;
F.setZero();
for (const auto &child_joint_idx: links_[joints_[i].child_link_idx].child_joint_idx) {
F += math::SE3::InvAd(state->E[child_joint_idx]).transpose() * Fs[child_joint_idx];
}
F += links_[joints_[i].child_link_idx].J * Vdot[i];
Fs[i] = F;
gravity_term(state->rtu_joint_map[i]) = joints_[i].S.dot(F);
}
return gravity_term;
}
template<int DOF>
Eigen::Matrix<double, DOF, DOF> Robot<DOF>::ComputeMassMatrix(std::shared_ptr<State<DOF>> state) {
Eigen::Matrix<double, DOF, DOF> M(n_joints_, n_joints_);
M.setZero();
std::vector<Eigen::Matrix<double, 6, DOF> > J;
J.resize(n_joints_);
for (auto i = 0; i < n_joints_; i++) {
int parent_joint_idx = links_[joints_[i].parent_link_idx].parent_joint_idx;
if (parent_joint_idx < 0) {
J[i].setZero();
J[i].col(state->rtu_joint_map[i]) = joints_[i].S;
} else {
J[i] = math::SE3::Ad(state->E[i].inverse()) * J[parent_joint_idx];
J[i].col(state->rtu_joint_map[i]) = joints_[i].S;
}
}
for (auto i = 0; i < n_joints_; i++) {
M += J[i].transpose() * links_[joints_[i].child_link_idx].J * J[i];
}
return M;
}
template<int DOF>
Eigen::Matrix<double, 6, 6> Robot<DOF>::ComputeReflectiveInertia(std::shared_ptr<State<DOF>> state, unsigned int from, unsigned int to) {
if (from >= state->utr_link_map.size() || to >= state->utr_link_map.size()) {
throw std::runtime_error("Out of range state link");
}
const auto &J = ComputeBodyJacobian(state, from, to);
Eigen::Matrix<double, DOF, DOF> m_inv = ComputeMassMatrix(state).completeOrthogonalDecomposition().
pseudoInverse();
return (J * m_inv * J.transpose()).completeOrthogonalDecomposition().pseudoInverse();
}
template<int DOF>
cmvr::math::SE3::MatrixType Robot<DOF>::ComputeTransformation(std::shared_ptr<State<DOF>> state, unsigned int from, unsigned int to) {
if (from >= state->utr_link_map.size() || to >= state->utr_link_map.size()) {
throw std::runtime_error("Out of range state link");
}
return GetTransformation(state, state->utr_link_map[from], state->utr_link_map[to]);
}
template<int DOF>
cmvr::math::se3v::MatrixType Robot<DOF>::ComputeBodyVelocity(std::shared_ptr<State<DOF>> state, unsigned int from, unsigned int to) {
if (from >= state->utr_link_map.size() || to >= state->utr_link_map.size()) {
throw std::runtime_error("Out of range state link");
}
math::SE3::MatrixType T_from_to = ComputeTransformation(state, from, to);
math::se3v::MatrixType V_from = GetLinkV(state, state->utr_link_map[from]);
math::se3v::MatrixType V_to = GetLinkV(state, state->utr_link_map[to]);
return V_to - math::SE3::InvAd(T_from_to, V_from);
}
template<int DOF>
Eigen::Matrix<double, 6, DOF> Robot<DOF>::ComputeSpaceJacobian(std::shared_ptr<State<DOF>> state, unsigned int from, unsigned int to) {
return GetSpaceJacobian(state, state->utr_link_map[from], state->utr_link_map[to]);
}
template<int DOF>
Eigen::Matrix<double, 6, DOF> Robot<DOF>::ComputeBodyJacobian(std::shared_ptr<State<DOF>> state, unsigned int from, unsigned int to) {
math::SE3::MatrixType T = ComputeTransformation(state, from, to);
return math::SE3::InvAd(T) * ComputeSpaceJacobian(state, from, to);
}
template<int DOF>
double Robot<DOF>::ComputeMass(std::shared_ptr<State<DOF>> state, unsigned int target_link) {
const auto &idx = state->utr_link_map[target_link];
return Inertial::GetMass(links_[idx.link_idx].links[idx.sub_link_idx].link->I_);
}
template<int DOF>
Eigen::Vector3d Robot<DOF>::ComputeCenterOfMass(std::shared_ptr<State<DOF>> state, unsigned int ref_link, unsigned int target_link) {
const auto &idx = state->utr_link_map[target_link];
return math::SE3::Multiply(ComputeTransformation(state, ref_link, target_link),
Inertial::GetCOM(links_[idx.link_idx].links[idx.sub_link_idx].link->I_));
}
template<int DOF>
Eigen::Vector3d Robot<DOF>::ComputeCenterOfMass(std::shared_ptr<State<DOF>> state, unsigned int ref_link, const std::vector<unsigned int> &target_links) {
Eigen::Vector3d com{Eigen::Vector3d::Zero()};
double mass = 0;
for (auto target_link: target_links) {
const auto &idx = state->utr_link_map[target_link];
const auto &p = Inertial::GetCOM(links_[idx.link_idx].links[idx.sub_link_idx].link->I_);
double m = Inertial::GetMass(links_[idx.link_idx].links[idx.sub_link_idx].link->I_);
com += math::SE3::Multiply(ComputeTransformation(state, ref_link, target_link), p) * m;
mass += m;
}
return com / mass;
}
template<int DOF>
Eigen::Matrix<double, 3, DOF> Robot<DOF>::ComputeCenterOfMassJacobian(std::shared_ptr<State<DOF>> state,
unsigned int ref_link,
unsigned int target_link) {
using namespace math;
const auto &idx = state->utr_link_map[target_link];
return SE3::GetRotation(ComputeTransformation(state, ref_link, target_link)) *
(SE3::InvAd(SE3::T(Inertial::GetCOM(links_[idx.link_idx].links[idx.sub_link_idx].link->I_))) *
ComputeBodyJacobian(state, ref_link, target_link))
.block(3, 0, 3, n_joints_);
}
template<int DOF>
Inertial::MatrixType Robot<DOF>::ComputeTotalInertial(std::shared_ptr<State<DOF>> state, unsigned int ref_link) {
Inertial::MatrixType I{Inertial::MatrixType::Zero()};
for (const auto &link: links_) {
I += Inertial::Transform(GetJointT(state, link.parent_joint_idx), link.J);
}
return Inertial::Transform(math::SE3::Inverse(GetLinkT(state, state->utr_link_map[ref_link])), I);
}
template<int DOF>
Eigen::Vector3d Robot<DOF>::ComputeCenterOfMass(std::shared_ptr<State<DOF>> state, unsigned int ref_link) {
Eigen::Vector3d sum{Eigen::Vector3d::Zero()};
double mass = 0;
for (const auto &link: links_) {
sum += Inertial::GetMass(link.J) *
math::SE3::Multiply(GetJointT(state, link.parent_joint_idx), Inertial::GetCOM(link.J));
mass += Inertial::GetMass(link.J);
}
return math::SE3::Multiply(math::SE3::Inverse(GetLinkT(state, state->utr_link_map[ref_link])), sum / mass);
}
template<int DOF>
Eigen::Matrix<double, 3, DOF> Robot<DOF>::ComputeCenterOfMassJacobian(std::shared_ptr<State<DOF>> state,
unsigned int ref_link) {
using namespace math;
Eigen::Matrix<double, 3, DOF> J;
J.resize(3, n_joints_);
J.setZero();
double mass = 0;
for (auto i = 0; i < links_.size(); i++) {
// const auto& link = links_[i];
double m = Inertial::GetMass(links_[i].I);
J += m * SE3::GetRotation(GetTransformation(state, state->utr_link_map[ref_link], {i, 0})) *
(SE3::InvAd(SE3::T(Inertial::GetCOM(links_[i].I))) *
GetBodyJacobian(state, state->utr_link_map[ref_link], {i, 0}))
.block(3, 0, 3, n_joints_);
mass += m;
}
return J / mass;
}
template<int DOF>
std::vector<CollisionResult> Robot<DOF>::DetectCollisionsOrNearestLinks(std::shared_ptr<State<DOF>> state, int collision_threshold) {
std::vector<CollisionResult> dis;
int n = state->GetLinkNames().size();
for (int i = 0; i < n; i++) {
auto link1 = GetLink(state, i);
if (!link1) {
throw std::runtime_error("Index error");
}
auto link1_T = ComputeTransformation(state, 0, i);
for (int j = i + 1; j < n; j++) {
auto link2 = GetLink(state, j);
if (!link2) {
throw std::runtime_error("Index error");
}
auto link2_T = ComputeTransformation(state, 0, j);
for (auto link1_col: link1->GetCollisions()) {
for (auto link2_col: link2->GetCollisions()) {
for (auto link1_geom: link1_col->GetGeoms()) {
for (auto link2_geom: link2_col->GetGeoms()) {
if (link1_geom->GetType() == GeomType::kCapsule && //
link2_geom->GetType() == GeomType::kCapsule && //
link1_geom->Filter(*link2_geom)) {
auto collision_result =
link1_geom->ComputeMinimumDistance(
link1_T * link1_col->GetOrigin(), *link2_geom, //
link2_T * link2_col->GetOrigin());
if (collision_result.has_value()) {
auto v = collision_result.value();
v.link1 = link1->GetName();
v.link2 = link2->GetName();
dis.push_back(v);
}
}
}
}
}
}
}
}
std::sort(dis.begin(), dis.end(),
[](const CollisionResult &r1, const CollisionResult &r2) { return r1.distance < r2.distance; });
std::vector<CollisionResult> rv;
for (const auto &d: dis) {
if (d.distance > 0 && static_cast<int>(rv.size()) >= collision_threshold) {
break;
}
rv.push_back(d);
}
return rv;
}
// TODO: ComputeBodyJacobianDot
// TODO: ComputeBodyAcceleration
// TODO: InverseDiffDynamics
template<int DOF>
Eigen::Vector<double, DOF> Robot<DOF>::GetLimitQLower(const std::shared_ptr<State<DOF>> &state) {
return GetJointProperty(state, [](auto j) { return j->GetLimitQLower(); });
}
template<int DOF>
Eigen::Vector<double, DOF> Robot<DOF>::GetLimitQUpper(const std::shared_ptr<State<DOF>> &state) {
return GetJointProperty(state, [](auto j) { return j->GetLimitQUpper(); });
}
template<int DOF>
Eigen::Vector<double, DOF> Robot<DOF>::GetLimitQdotLower(const std::shared_ptr<State<DOF>> &state) {
return GetJointProperty(state, [](auto j) { return j->GetLimitQdotLower(); });
}
template<int DOF>
Eigen::Vector<double, DOF> Robot<DOF>::GetLimitQdotUpper(const std::shared_ptr<State<DOF>> &state) {
return GetJointProperty(state, [](auto j) { return j->GetLimitQdotUpper(); });
}
template<int DOF>
Eigen::Vector<double, DOF> Robot<DOF>::GetLimitQddotLower(const std::shared_ptr<State<DOF>> &state) {
return GetJointProperty(state, [](auto j) { return j->GetLimitQddotLower(); });
}
template<int DOF>
Eigen::Vector<double, DOF> Robot<DOF>::GetLimitQddotUpper(const std::shared_ptr<State<DOF>> &state) {
return GetJointProperty(state, [](auto j) { return j->GetLimitQddotUpper(); });
}
template<int DOF>
Eigen::Vector<double, DOF> Robot<DOF>::GetLimitTorque(const std::shared_ptr<State<DOF>> &state) {
return GetJointProperty(state, [](auto j) { return j->GetLimitTorque(); });
}
template<int DOF>
Eigen::Vector<double, DOF> Robot<DOF>::GetJointProperty(const std::shared_ptr<State<DOF>> &state,
const std::function<double(std::shared_ptr<Joint>)> &getter) {
Eigen::Vector<double, DOF> prop;
prop.resize(n_joints_);
for (auto i = 0; i < n_joints_; i++) {
prop(state->rtu_joint_map[i]) = getter(joints_[i].joint);
}
return prop;
}
template<int DOF>
void Robot<DOF>::ComputeMobilityInverseDiffKinematics(std::shared_ptr<State<DOF>> state, //
const Eigen::Vector2d &linear_velocity, // (m/s)
double angular_velocity // (rad/s)
) {
math::se2v::MatrixType S;
S(0) = angular_velocity;
S.tail<2>() = linear_velocity;
ComputeMobilityInverseDiffKinematics(state, S);
}
template<int DOF>
void Robot<DOF>::ComputeMobilityInverseDiffKinematics(std::shared_ptr<State<DOF>> state, //
const math::se2v::MatrixType &body_velocity // w, x, y
) {
math::se3v::MatrixType S{math::se3v::MatrixType::Zero()};
S.block<3, 1>(2, 0) = body_velocity;
S = math::SE3::InvAd(mobile_base_->T, S);
switch (mobile_base_->type) {
case MobileBaseType::None: {
break;
}
case MobileBaseType::Differential: {
auto mb = std::static_pointer_cast<MobileBaseDifferential>(mobile_base_);
double v_right = S(3) + mb->wheel_base / 2 * S(2);
double v_left = S(3) - mb->wheel_base / 2 * S(2);
state->qdot(mb->right_wheel_idx) = -v_right / mb->wheel_radius;
state->qdot(mb->left_wheel_idx) = -v_left / mb->wheel_radius;
break;
}
case MobileBaseType::Mecanum: {
double v_x = S(3);
double v_y = S(4);
double w = S(2);
// std::cout<<"V_x: "<< v_x<<std::endl;
// std::cout<<"V_y: "<< v_y<<std::endl;
// std::cout<<"w: "<< w<<std::endl;
auto mb = std::static_pointer_cast<MobileBaseMecanum>(mobile_base_);
double w_1 = 1 / mb->wheel_radius * (v_x - v_y - (mb->L_x + mb->L_y) * w);
double w_2 = 1 / mb->wheel_radius * (v_x + v_y + (mb->L_x + mb->L_y) * w);
double w_3 = 1 / mb->wheel_radius * (v_x + v_y - (mb->L_x + mb->L_y) * w);
double w_4 = 1 / mb->wheel_radius * (v_x - v_y + (mb->L_x + mb->L_y) * w);
state->qdot(mb->fl_wheel_idx) = w_1;
state->qdot(mb->fr_wheel_idx) = w_2;
state->qdot(mb->rl_wheel_idx) = w_3;
state->qdot(mb->rr_wheel_idx) = w_4;
// std::cout<<"mb->fl_wheel_idx: "<<mb->fl_wheel_idx<<std::endl;
// std::cout<<"mb->fr_wheel_idx: "<<mb->fr_wheel_idx<<std::endl;
// std::cout<<"mb->rl_wheel_idx: "<<mb->rl_wheel_idx<<std::endl;
// std::cout<<"mb->rr_wheel_idx: "<<mb->rr_wheel_idx<<std::endl;
break;
}
}
}
template<int DOF>
cmvr::math::se2v::MatrixType Robot<DOF>::ComputeMobilityDiffKinematics( //
std::shared_ptr<State<DOF>> state //
) {
math::se3v::MatrixType S{math::se3v::MatrixType::Zero()};
switch (mobile_base_->type) {
case MobileBaseType::None: {
break;
}
case MobileBaseType::Differential: {
auto mb = std::static_pointer_cast<MobileBaseDifferential>(mobile_base_);
double w_r = -state->qdot(mb->right_wheel_idx);
double w_l = -state->qdot(mb->left_wheel_idx);
S.block<3, 1>(2, 0) = math::se2v::MatrixType{
(w_r - w_l) * mb->wheel_radius / mb->wheel_base,
(w_r + w_l) * mb->wheel_radius / 2, 0
};
break;
}
case MobileBaseType::Mecanum: {
auto mb = std::static_pointer_cast<MobileBaseMecanum>(mobile_base_);
double w_1 = state->qdot(mb->fl_wheel_idx);
double w_2 = state->qdot(mb->fr_wheel_idx);
double w_3 = state->qdot(mb->rl_wheel_idx);
double w_4 = state->qdot(mb->rr_wheel_idx);
double v_x = mb->wheel_radius / 4 * (w_1 + w_2 + w_3 + w_4);
double v_y = mb->wheel_radius / 4 * (-w_1 + w_2 + w_3 - w_4);
double w = mb->wheel_radius / (4 * (mb->L_x + mb->L_y)) * (-w_1 + w_2 - w_3 + w_4);
S.block<3, 1>(2, 0) = math::se2v::MatrixType{w, v_x, v_y};
break;
}
}
S = math::SE3::Ad(mobile_base_->T, S);
return S.block<3, 1>(2, 0);
}
template<int DOF>
int Robot<DOF>::CountJoints(const std::shared_ptr<Link> &base_link, bool include_fixed) {
int n_joints = 0;
std::queue<std::shared_ptr<Link> > que;
que.push(base_link);
while (!que.empty()) {
std::shared_ptr<Link> link = que.front();
que.pop();
for (const auto &joint: link->GetChildJointList()) {
que.push(joint->GetChildLink());
if (joint->IsFixed() && !include_fixed);
else {
n_joints++;
}
}
}
return n_joints;
}
template<int DOF>
void Robot<DOF>::Build(const RobotConfiguration &rc) {
const auto &base = rc.base_link;
int n_joints = CountJoints(base);
if constexpr (DOF < 0) {
n_links_ = n_joints + 1;
n_joints_ = n_joints;
links_.resize(n_links_);
joints_.resize(n_joints_);
} else {
if (n_joints != DOF) {
throw std::runtime_error("DOF does not match the number of joints");
}
n_links_ = DOF + 1;
n_joints_ = DOF;
}
struct QueueItem {
int parent_joint_idx{};
int parent_link_idx{};
std::shared_ptr<Link> link;
int depth{};
bool merge_parent_link{};
math::SE3::MatrixType M_wrt_base;
math::SE3::MatrixType M_wrt_p;
};
std::queue<QueueItem> que;
int link_idx = 0;
int joint_idx = 0;
{
{
QueueItem item;
item.parent_joint_idx = -1;
item.parent_link_idx = link_idx++;
item.link = base;
item.depth = 0;
item.merge_parent_link = false;
item.M_wrt_base = math::SE3::Identity();
item.M_wrt_p = math::SE3::Identity();
que.push(item);
}
while (!que.empty()) {
auto e = que.front();
que.pop();
if (!e.merge_parent_link) {
links_[e.parent_link_idx].SetBaseLink(e.link, e.M_wrt_base);
links_[e.parent_link_idx].depth = e.depth;
links_[e.parent_link_idx].parent_joint_idx = e.parent_joint_idx;
link_idx_[e.link->name_] = {e.parent_link_idx, 0};
} else {
int sub_link_idx = links_[e.parent_link_idx].AddLink(e.link, e.M_wrt_p);
link_idx_[e.link->name_] = {e.parent_link_idx, sub_link_idx};
}
for (const auto &joint: e.link->child_joints_) {
if (!joint->fixed_) {
math::SE3::MatrixType M_wrt_base = e.M_wrt_base * joint->T_pj_;
{
Joint_ j;
j.joint = joint;
j.S = math::SE3::Ad(M_wrt_base, joint->S_);
j.parent_link_idx = e.parent_link_idx;
j.child_link_idx = link_idx;
joints_[joint_idx] = j;
}
joint_idx_[joint->name_] = joint_idx;
links_[e.parent_link_idx].child_joint_idx.push_back(joint_idx);
{
QueueItem item;
item.parent_joint_idx = joint_idx++;
item.parent_link_idx = link_idx++;
item.link = joint->child_link_;
item.depth = e.depth + 1;
item.merge_parent_link = false;
item.M_wrt_base = M_wrt_base;
item.M_wrt_p = math::SE3::Identity();
que.push(item);
}
} else {
QueueItem item;
item.parent_joint_idx = e.parent_joint_idx;
item.parent_link_idx = e.parent_link_idx;
item.link = joint->child_link_;
item.depth = e.depth;
item.merge_parent_link = true;
item.M_wrt_base = e.M_wrt_base * joint->T_pj_ * joint->T_jc_;
item.M_wrt_p = e.M_wrt_p * joint->T_pj_ * joint->T_jc_;
que.push(item);
}
}
}
}
if (rc.mobile_base) {
switch (rc.mobile_base->type) {
case MobileBaseType::None: {
auto mb = std::make_shared<MobileBase>();
*std::static_pointer_cast<MobileBase>(mb) = *rc.mobile_base;
mobile_base_ = mb;
break;
}
case MobileBaseType::Differential: {
auto mb = std::make_shared<MobileBaseDifferential>();
*std::static_pointer_cast<MobileBase>(mb) = *rc.mobile_base;
if (rc.mobile_base->joints.size() != 2) {
throw std::runtime_error("Differential type mobile should have two joints.");
}
if (joint_idx_.find(rc.mobile_base->joints[0]) == joint_idx_.end()) {
throw std::runtime_error("Right wheel has invalid parameter.");
}
if (joint_idx_.find(rc.mobile_base->joints[1]) == joint_idx_.end()) {
throw std::runtime_error("Left wheel has invalid parameter.");
}
if (rc.mobile_base->params.size() != 2) {
throw std::runtime_error("Differential type mobile should have two parameters.");
}
mb->right_wheel_idx = joint_idx_[rc.mobile_base->joints[0]];
mb->left_wheel_idx = joint_idx_[rc.mobile_base->joints[1]];
mb->wheel_base = rc.mobile_base->params[0];
mb->wheel_radius = rc.mobile_base->params[1];
mobile_base_ = mb;
break;
}
case MobileBaseType::Mecanum:
auto mb = std::make_shared<MobileBaseMecanum>();
*std::static_pointer_cast<MobileBase>(mb) = *rc.mobile_base;
if (rc.mobile_base->joints.size() != 4) {
throw std::runtime_error(
"Mecanum type mobile should have four joints. (front-right, front-left, rear-right, rear-left)");
}
if (joint_idx_.find(rc.mobile_base->joints[0]) == joint_idx_.end()) {
throw std::runtime_error("Front-right wheel has invalid parameter.");
}
if (joint_idx_.find(rc.mobile_base->joints[1]) == joint_idx_.end()) {
throw std::runtime_error("Front-left wheel has invalid parameter.");
}
if (joint_idx_.find(rc.mobile_base->joints[2]) == joint_idx_.end()) {
throw std::runtime_error("Rear-right wheel has invalid parameter.");
}
if (joint_idx_.find(rc.mobile_base->joints[3]) == joint_idx_.end()) {
throw std::runtime_error("Rear-left wheel has invalid parameter.");
}
if (rc.mobile_base->params.size() != 3) {
throw std::runtime_error(
"Mecanum type mobile should have three parameters. (Lx, Ly, wheel radius)");
}
mb->fr_wheel_idx = joint_idx_[rc.mobile_base->joints[0]];
mb->fl_wheel_idx = joint_idx_[rc.mobile_base->joints[1]];
mb->rr_wheel_idx = joint_idx_[rc.mobile_base->joints[2]];
mb->rl_wheel_idx = joint_idx_[rc.mobile_base->joints[3]];
mb->L_x = rc.mobile_base->params[0];
mb->L_y = rc.mobile_base->params[1];
mb->wheel_radius = rc.mobile_base->params[2];
mobile_base_ = mb;
break;
}
}
}
template<int DOF>
cmvr::math::SE3::MatrixType Robot<DOF>::GetLinkT(std::shared_ptr<State<DOF>> state, const LinkIdx_ &idx) {
return GetJointT(state, links_[idx.link_idx].parent_joint_idx) *
links_[idx.link_idx].links[idx.sub_link_idx].M_wrt_base;
}
template<int DOF>
cmvr::math::se3v::MatrixType Robot<DOF>::GetLinkV(std::shared_ptr<State<DOF>> state, const LinkIdx_ &idx) {
return math::SE3::InvAd(links_[idx.link_idx].links[idx.sub_link_idx].M_wrt_base,
GetJointV(state, links_[idx.link_idx].parent_joint_idx));
}
template<int DOF>
cmvr::math::SE3::MatrixType Robot<DOF>::GetJointT(std::shared_ptr<State<DOF>> state, int joint_idx) {
if (joint_idx < 0)
return math::SE3::Identity();
return state->T[joint_idx];
}
template<int DOF>
cmvr::math::se3v::MatrixType Robot<DOF>::GetJointV(std::shared_ptr<State<DOF>> state, int joint_idx) {
if (joint_idx < 0)
return state->V0;
return state->V.col(joint_idx);
}
template<int DOF>
cmvr::math::se3v::MatrixType Robot<DOF>::GetJointVdot(std::shared_ptr<State<DOF>> state, int joint_idx) {
if (joint_idx < 0)
return state->Vdot0;
return state->Vdot.col(joint_idx);
}
template<int DOF>
cmvr::math::SE3::MatrixType Robot<DOF>::GetTransformation(std::shared_ptr<State<DOF>> state, const LinkIdx_ &from, const LinkIdx_ &to) {
return math::SE3::Inverse(GetLinkT(state, from)) * GetLinkT(state, to);
}
template<int DOF>
Eigen::Matrix<double, 6, DOF> Robot<DOF>::GetSpaceJacobian(std::shared_ptr<State<DOF>> state, const LinkIdx_ &from, const LinkIdx_ &to) {
Eigen::Matrix<double, 6, DOF> J;
J.resize(6, n_joints_);
J.setZero();
// TODO: Need to optimize
int from_link_idx = from.link_idx;
int to_link_idx = to.link_idx;
while (from_link_idx != to_link_idx) {
if (links_[from_link_idx].depth > links_[to_link_idx].depth) {
int pj = links_[from_link_idx].parent_joint_idx;
J.col(state->rtu_joint_map[pj]) = -state->S.col(pj);
from_link_idx = joints_[pj].parent_link_idx;
} else {
int pj = links_[to_link_idx].parent_joint_idx;
J.col(state->rtu_joint_map[pj]) = state->S.col(pj);
to_link_idx = joints_[pj].parent_link_idx;
}
}
return math::SE3::InvAd(GetLinkT(state, from)) * J;
}
template<int DOF>
Eigen::Matrix<double, 6, DOF> Robot<DOF>::GetBodyJacobian(std::shared_ptr<State<DOF>> state, const LinkIdx_ &from,
const LinkIdx_ &to) {
math::SE3::MatrixType T = GetTransformation(state, from, to);
return math::SE3::InvAd(T) * GetSpaceJacobian(state, from, to);
}

View File

@ -0,0 +1,141 @@
//
// Created by xtkuang on 2025/7/8.
//
#ifndef STATE_H
#define STATE_H
#pragma once
#include <eigen3/Eigen/Core>
#include "utils/math/se3.h"
namespace cmvr::dyn {
template<int DOF>
class Robot;
template<int DOF>
class State {
public:
template<int>
friend class Robot;
template<typename T, int N>
using ContainerType = typename std::conditional_t<(N > 0), std::array<T, (unsigned int) N>, std::vector<T> >;
unsigned int GetBaseLinkIdx() const { // NOLINT
return base_link_user_idx;
}
template<typename Derived>
void SetQ(const Eigen::MatrixBase<Derived> &new_q) {
Set<Derived::RowsAtCompileTime>(q, new_q.eval());
}
Eigen::Vector<double, DOF> GetQ() { return q(utr_joint_map); }
template<typename Derived>
void SetQdot(const Eigen::MatrixBase<Derived> &new_qdot) {
Set<Derived::RowsAtCompileTime>(qdot, new_qdot.eval());
}
Eigen::Vector<double, DOF> GetQdot() { return qdot(utr_joint_map); }
template<typename Derived>
void SetQddot(const Eigen::MatrixBase<Derived> &new_qddot) {
Set<Derived::RowsAtCompileTime>(qddot, new_qddot.eval());
}
Eigen::Vector<double, DOF> GetQddot() { return qddot(utr_joint_map); }
template<typename Derived>
void SetTau(const Eigen::MatrixBase<Derived> &new_tau) {
Set<Derived::RowsAtCompileTime>(tau, new_tau.eval());
}
Eigen::Vector<double, DOF> GetTau() { return tau(utr_joint_map); }
void SetV0(const math::se3v::MatrixType &new_V0) { V0 = new_V0; }
// Vdot of root link in root frame
void SetVdot0(const math::se3v::MatrixType &new_Vdot0) { Vdot0 = new_Vdot0; }
void SetGravity(const math::se3v::MatrixType &gravity) { Vdot0 = -gravity; }
ContainerType<std::string, DOF> GetJointNames() const { return joint_names; }
[[nodiscard]] std::vector<std::string> GetLinkNames() const { return link_names; }
private:
explicit State(int dof) {
if (!(DOF < 0 || dof == DOF)) {
throw std::runtime_error("State initialization failed");
}
if constexpr (DOF < 0) {
q.resize(dof);
qdot.resize(dof);
qddot.resize(dof);
tau.resize(dof);
E.resize(dof + 1, math::SE3::Identity());
S.resize(6, dof);
T.resize(dof + 1, math::SE3::Identity());
V.resize(6, dof);
Vdot.resize(6, dof);
F.resize(6, dof);
joint_names.resize(dof);
utr_joint_map.resize(dof);
rtu_joint_map.resize(dof);
} else {
E.fill(math::SE3::Identity());
T.fill(math::SE3::Identity());
}
q.setZero();
qdot.setZero();
qddot.setZero();
S.setZero();
V.setZero();
Vdot0.setZero();
F.setZero();
}
template<int N>
void Set(Eigen::Vector<double, DOF> &s, const Eigen::Vector<double, N> &i) {
if (s.size() == i.size()) {
s = i(rtu_joint_map);
} else if (s.size() > i.size()) {
s.template head<>(i.size()) = i(rtu_joint_map.template head<>(i.size()));
} else {
throw std::runtime_error("i.size cannot be greater than s.size");
}
}
ContainerType<std::string, DOF> joint_names;
Eigen::Vector<unsigned int, DOF> utr_joint_map; // user joint idx -> robot joint idx
Eigen::Vector<unsigned int, DOF> rtu_joint_map; // robot joint idx -> user joint idx
unsigned int base_link_user_idx;
std::vector<std::string> link_names;
std::vector<typename Robot<DOF>::LinkIdx_> utr_link_map; // user link idx -> robot dummy/sub link idx
public:
Eigen::Vector<double, DOF> q;
Eigen::Vector<double, DOF> qdot;
Eigen::Vector<double, DOF> qddot;
Eigen::Vector<double, DOF> tau;
math::se3v::MatrixType V0{math::se3v::MatrixType::Zero()};
math::se3v::MatrixType Vdot0{math::se3v::MatrixType::Zero()};
ContainerType<math::SE3::MatrixType, DOF> E{}; // exponential mapping
Eigen::Matrix<double, 6, DOF> S; // S(q_0,...q_i) in root frame
ContainerType<math::SE3::MatrixType, DOF> T{}; // product of exponential
Eigen::Matrix<double, 6, DOF> V;
Eigen::Matrix<double, 6, DOF> Vdot;
Eigen::Matrix<double, 6, DOF> F;
};
}
#endif //STATE_H

View File

@ -0,0 +1,52 @@
//
// Created by xtkuang on 2025/7/7.
//
#ifndef CONSTANCE_H
#define CONSTANCE_H
#pragma once
#include <eigen3/Eigen/Core>
namespace cmvr::math {
constexpr double kPi = 3.1415926535897932384626433832795; ///< \pi
constexpr double kPiHalf = 1.5707963267948966192313216916398; ///< \frac{\pi}{2}
constexpr double kPiDouble = 6.283185307179586476925286766559; ///< \pi*2
constexpr double kInvPiDouble = 0.15915494309189533576888376337251; ///< \frac{1}{\pi*2}
constexpr double kPiDividedBySqrt2 = 2.2214414690791831235079404950303; ///< \frac{\pi}{\sqrt{2}}
constexpr double kPiSquare = 9.8696044010893586188344909998762; ///< \pi^2
constexpr double kRad2Deg = 57.295779513082320876798154814105; ///< \frac{180}{\pi}
constexpr double kDeg2Rad = 0.01745329251994329576923690768489; /// \frac{\pi}{180}
static const Eigen::Matrix<double, 1, 4> kAffineConstant = {0, 0, 0, 1};
static const double kDoubleEpsilon = std::numeric_limits<double>::epsilon();
/// Calculate sine and cosine simultaneously
inline void fsincos(double theta, ///< Angle in radians
double& sine, ///< Variable for storing a sine value
double& cosine ///< Variable for storing a sine value
) {
using std::sin;
using std::sqrt;
theta -= (int)(theta * kInvPiDouble) * kPiDouble;
if (theta < 0)
theta += kPiDouble;
sine = sin(theta);
if (theta < kPiHalf) {
cosine = sqrt(1 - sine * sine);
return;
} else if (theta < kPi + kPiHalf) {
cosine = -sqrt(1 - sine * sine);
return;
}
cosine = sqrt(1 - sine * sine);
}
}
#endif //CONSTANCE_H

View File

@ -0,0 +1,57 @@
//
// Created by xtkuang on 2025/7/7.
//
#ifndef GEOMETRY_H
#define GEOMETRY_H
namespace cmvr::math {
typedef struct {
double x;
double y;
} Vec2;
typedef struct {
double x;
double y;
double z;
} Vec3;
/// quat
typedef struct {
double w;
double x;
double y;
double z;
} Quat;
/// position 3d
typedef struct {
double x; //* unit: m
double y;
double z;
} Position;
/// euler angel
typedef struct {
double rx; //* unit: rad
double ry;
double rz;
} Euler;
/// pose 3d
typedef struct {
Position position; ///< 位置单位m
Quat quaternion; ///< 四元数
Euler euler; ///< 欧拉角单位rad
} Pose3d;
typedef struct {
double x; //* unit: m
double y;
double theta;
} Pose2d;
}
#endif //GEOMETRY_H

View File

@ -0,0 +1,15 @@
//
// Created by xtkuang on 2025/7/7.
//
#ifndef LIEGROUP_H
#define LIEGROUP_H
#pragma once
#include "se2.h"
#include "se3.h"
#include "so3.h"
#endif //LIEGROUP_H

View File

@ -0,0 +1,126 @@
//
// Created by xtkuang on 2025/7/7.
//
#ifndef QP_SOLVER_H
#define QP_SOLVER_H
#pragma once
#include <exception>
#include <memory>
#include <optional>
#include <eigen3/Eigen/Core>
#include <OsqpEigen/OsqpEigen.h>
namespace cmvr::math {
class QPSolverException : public std::exception {
public:
static constexpr unsigned int kStatusOffset = 100;
explicit QPSolverException(int error_code);
const char* what() const noexcept override;
int code() const noexcept;
static std::string GenerateMessage(int code);
private:
int error_code_;
std::string message_;
};
class QPSolverImpl {
public:
QPSolverImpl() = default;
~QPSolverImpl() = default;
void SetupImpl(int n_var, int n_const, double time_limit);
void InitFunctionImpl();
void AddCostFunctionImpl(const Eigen::MatrixXd &A, const Eigen::VectorXd &b);
void SetCostFunctionImpl(const Eigen::MatrixXd &A, const Eigen::VectorXd &b);
void SetConstraintsFunctionImpl(const Eigen::MatrixXd &A, const Eigen::VectorXd &lb, const Eigen::VectorXd &ub);
void SetPrimalVariableImpl(const Eigen::VectorXd &pv);
void ResetIsFirstImpl();
Eigen::VectorXd SolveImpl();
Eigen::MatrixXd GetACostImpl() const;
Eigen::VectorXd GetBCostImpl() const;
Eigen::MatrixXd GetAConstImpl() const;
Eigen::VectorXd GetLowerBoundImpl() const;
Eigen::VectorXd GetUpperBoundImpl() const;
private:
OsqpEigen::Solver solver_;
int n_var_{};
int n_const_{};
int err_code_{};
int is_first_{};
int n_hessian_element_{};
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> A_cost_;
Eigen::Matrix<double, Eigen::Dynamic, 1> b_cost_;
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> A_const_;
Eigen::Matrix<double, Eigen::Dynamic, 1> lb_;
Eigen::Matrix<double, Eigen::Dynamic, 1> ub_;
Eigen::SparseMatrix<double> hessian_;
Eigen::Matrix<double, Eigen::Dynamic, 1> gradient_;
Eigen::SparseMatrix<double> linearMatrix_;
Eigen::Matrix<double, Eigen::Dynamic, 1> lowerBound_;
Eigen::Matrix<double, Eigen::Dynamic, 1> upperBound_;
Eigen::Matrix<double, Eigen::Dynamic, 1> primal_variable_for_warmstart_;
};
class QPSolver {
public:
QPSolver();
~QPSolver();
void Setup(int n_var, int n_const, double time_limit = 2e-3);
void InitFunction();
void AddCostFunction(const Eigen::MatrixXd& A, const Eigen::VectorXd& b);
void SetCostFunction(const Eigen::MatrixXd& A, const Eigen::VectorXd& b);
void SetConstraintsFunction(const Eigen::MatrixXd& A, const Eigen::VectorXd& lb, const Eigen::VectorXd& ub);
void SetPrimalVariable(const Eigen::VectorXd& pv);
void ResetIsFirst();
/**
* Solve the QP problem
* @return Solution
* @throw QPSolverException
*/
Eigen::VectorXd Solve();
Eigen::MatrixXd GetACost() const; // NOLINT
Eigen::VectorXd GetBCost() const; // NOLINT
Eigen::MatrixXd GetAConst() const; // NOLINT
Eigen::VectorXd GetLowerBound() const; // NOLINT
Eigen::VectorXd GetUpperBound() const; // NOLINT
private:
std::unique_ptr<QPSolverImpl> impl_;
};
}
#endif //QP_SOLVER_H

42
include/utils/math/se2.h Normal file
View File

@ -0,0 +1,42 @@
//
// Created by xtkuang on 2025/7/7.
//
#ifndef SE2_H
#define SE2_H
#pragma once
#include <eigen3/Eigen/Core>
#include "utils/math/constants.h"
namespace cmvr::math {
class SE2;
class se2v;
class se2v {
public:
using MatrixType = Eigen::Vector3d;
private:
se2v() = default;
};
class SE2 {
public:
using MatrixType = Eigen::Matrix3d;
static MatrixType Identity();
static MatrixType T(double angle, const Eigen::Vector<double, 2>& translation = {0, 0});
static MatrixType Exp(const se2v::MatrixType& s, double angle = 1.0);
static se2v::MatrixType Log(const MatrixType& T);
};
} // namespace rb::math
#endif //SE2_H

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