├── doc
└── JY901使用说明书V4.3.pdf
├── src
├── ros
│ ├── CMakeLists.txt
│ └── wit_ros.cpp
├── CMakeLists.txt
├── test
│ ├── CMakeLists.txt
│ └── initialization.cpp
├── nodelet
│ ├── CMakeLists.txt
│ └── wit_nodelet.cpp
└── driver
│ ├── CMakeLists.txt
│ ├── wit_driver.cpp
│ ├── command.cpp
│ ├── packet_finder.cpp
│ └── data.cpp
├── plugins
└── nodelet_plugins.xml
├── include
└── wit_node
│ ├── parameter.hpp
│ ├── packet_handler
│ ├── payload_headers.hpp
│ ├── packet_finder.hpp
│ └── payload_base.hpp
│ ├── wit_ros.hpp
│ ├── data.hpp
│ ├── wit_driver.hpp
│ └── command.hpp
├── launch
└── wit.launch
├── msg
└── ImuGpsRaw.msg
├── CMakeLists.txt
├── README.md
└── package.xml
/doc/JY901使用说明书V4.3.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yowlings/wit_node/HEAD/doc/JY901使用说明书V4.3.pdf
--------------------------------------------------------------------------------
/src/ros/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_library(wit_ros wit_ros.cpp)
2 | target_link_libraries(wit_ros wit_driver ${catkin_LIBRARIES} )
3 |
--------------------------------------------------------------------------------
/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_subdirectory(driver)
2 | add_subdirectory(ros)
3 | add_subdirectory(nodelet)
4 | add_subdirectory(test)
5 |
--------------------------------------------------------------------------------
/src/test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_executable(initialization initialization.cpp)
2 | target_link_libraries(initialization wit_driver)
3 |
--------------------------------------------------------------------------------
/src/nodelet/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_library(wit_nodelet wit_nodelet.cpp)
2 | add_dependencies(wit_nodelet wit_ros)
3 | target_link_libraries(wit_nodelet wit_ros)
4 |
5 |
--------------------------------------------------------------------------------
/src/driver/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | file(GLOB SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp)
2 | add_library(wit_driver ${SOURCES})
3 | target_link_libraries(wit_driver ${catkin_LIBRARIES})
4 |
--------------------------------------------------------------------------------
/plugins/nodelet_plugins.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Nodelet version of the wit node
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/include/wit_node/parameter.hpp:
--------------------------------------------------------------------------------
1 | #include
2 | #ifndef PARAMETER_HPP
3 | #define PARAMETER_HPP
4 | using namespace std;
5 | namespace wit {
6 | class Parameter {
7 | public:
8 | Parameter() : port_("/dev/ttyUSB0"), baut_rate_(115200), ns("wit") {}
9 |
10 | string port_;
11 | int baut_rate_;
12 | string ns;
13 | };
14 | }
15 | #endif // PARAMETER_HPP
16 |
--------------------------------------------------------------------------------
/launch/wit.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/msg/ImuGpsRaw.msg:
--------------------------------------------------------------------------------
1 | Header header
2 | float64 time
3 | float64[] acc
4 | float64[] gyro
5 | float64[] rpy
6 | float64[] mag
7 | uint16[] ps #port state
8 | float64 temperature
9 | float64 altitude
10 | float64 ap #atmosphere pressure
11 | float64 latitude
12 | float64 longtitude
13 | float64 gpsh #gps height
14 | float64 gpsy #gps yaw
15 | float64 gpsv #gps velocity
16 | float64[] quarternion
17 | uint8 sn #satelites number
18 | float64[] dop
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/test/initialization.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include
4 | #include
5 | #include "../../include/wit_node/wit_driver.hpp"
6 | using namespace wit;
7 | class WitManager {
8 | public:
9 | WitManager() {
10 | wit::Parameter param;
11 | param.port_ = "/dev/ttyUSB0";
12 | param.ns = "wit";
13 | param.baut_rate_ = 115200;
14 | try {
15 | wd_.init(param);
16 | } catch (ecl::StandardException &e) {
17 | std::cout << e.what();
18 | }
19 | }
20 |
21 | private:
22 | WitDriver wd_;
23 | };
24 |
25 | int main() {
26 | WitManager wm;
27 | ecl::Sleep()(500);
28 | return 0;
29 | }
30 |
--------------------------------------------------------------------------------
/src/nodelet/wit_nodelet.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "../../include/wit_node/wit_ros.hpp"
5 |
6 | namespace wit {
7 |
8 | class WitNodelet : public nodelet::Nodelet {
9 | public:
10 | WitNodelet() : shutdown_requested_(false){};
11 | ~WitNodelet() {
12 | NODELET_DEBUG_STREAM("Wit : waiting for update thread to finish.");
13 | shutdown_requested_ = true;
14 | update_thread_.join();
15 | }
16 |
17 | virtual void onInit() {
18 | NODELET_DEBUG_STREAM("Wit: initialising nodelet...");
19 | string nodelet_name = this->getName();
20 | wit_.reset(new WitRos(nodelet_name));
21 | if (wit_->init(this->getPrivateNodeHandle())) {
22 | update_thread_.start(&WitNodelet::update, *this);
23 | NODELET_INFO_STREAM("Wit : initialised.");
24 |
25 | } else {
26 | NODELET_ERROR_STREAM("Wit : could not initialise! Please restart.");
27 | }
28 | }
29 |
30 | private:
31 | void update() {
32 | Rate spin_rate(10);
33 | while (!shutdown_requested_ && ok()) {
34 | wit_->update();
35 | spin_rate.sleep();
36 | }
37 | }
38 |
39 | boost::shared_ptr wit_;
40 | ecl::Thread update_thread_;
41 | bool shutdown_requested_;
42 | };
43 | }
44 | PLUGINLIB_EXPORT_CLASS(wit::WitNodelet, nodelet::Nodelet);
45 |
--------------------------------------------------------------------------------
/include/wit_node/packet_handler/payload_headers.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file include/xbot_arm_driver/packet_handler/payload_headers.hpp
3 | *
4 | * @brief Byte id's for the individual payload headers.
5 | *
6 | * Each part of a xbot packet carries one or more payload chunks. Each chunk
7 | * is id'd by one of the values here.
8 | *
9 | * License: BSD
10 | * https://raw.github.com/yujinrobot/xbot_core/hydro-devel/xbot_arm_driver/LICENSE
11 | **/
12 | /*****************************************************************************
13 | ** Ifdefs
14 | *****************************************************************************/
15 |
16 | #ifndef XBOT_PAYLOAD_HEADERS_HPP_
17 | #define XBOT_PAYLOAD_HEADERS_HPP_
18 |
19 | /*****************************************************************************
20 | ** Includes
21 | *****************************************************************************/
22 |
23 | /*****************************************************************************
24 | ** Namespaces
25 | *****************************************************************************/
26 |
27 | namespace wit {
28 |
29 | class Header {
30 | public:
31 | enum PayloadType {
32 | TIME = 0x50,
33 | ACCE = 0x51,
34 | GYRO = 0x52,
35 | YPR = 0x53,
36 | MAG = 0x54,
37 | STATE = 0x55,
38 | PALT = 0x56,
39 | LOLA = 0x57,
40 | GPSV = 0x58,
41 | QUAT = 0x59,
42 | SATE = 0x5a
43 | };
44 | };
45 |
46 | } // namespace xbot
47 |
48 | #endif /* XBOT_PAYLOAD_HEADERS_HPP_ */
49 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 | project(wit_node)
3 |
4 | ## Compile as C++11, supported in ROS Kinetic and newer
5 | add_compile_options(-std=c++11)
6 |
7 | set(CMAKE_BUILD_TYPE "Release")
8 | set(CMAKE_CXX_STANDARD 11)
9 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
10 | add_definitions(-D_GLIBCXX_USE_C99=1)
11 |
12 | find_package(catkin REQUIRED COMPONENTS
13 | ecl_build
14 | ecl_devices
15 | ecl_sigslots
16 | ecl_time
17 | ecl_geometry
18 | roscpp
19 | rospy
20 | sensor_msgs
21 | std_msgs
22 | nodelet
23 | pluginlib
24 | message_generation
25 | )
26 |
27 |
28 | ## Generate messages in the 'msg' folder
29 | add_message_files(
30 | FILES
31 | ImuGpsRaw.msg
32 | )
33 |
34 | ## Generate added messages and services with any dependencies listed here
35 | generate_messages(
36 | DEPENDENCIES
37 | std_msgs
38 | )
39 |
40 | catkin_package(
41 | INCLUDE_DIRS include
42 | LIBRARIES wit_nodelet
43 | CATKIN_DEPENDS
44 | ecl_build
45 | ecl_devices
46 | ecl_geometry
47 | ecl_sigslots
48 | ecl_time
49 | nodelet
50 | pluginlib
51 | roscpp
52 | rospy
53 | sensor_msgs
54 | std_msgs
55 | )
56 |
57 | ###########
58 | ## Build ##
59 | ###########
60 |
61 | ## Specify additional locations of header files
62 | ## Your package locations should be listed before other locations
63 | include_directories(
64 | include
65 | ${catkin_INCLUDE_DIRS}
66 | )
67 |
68 | add_subdirectory(src)
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/include/wit_node/wit_ros.hpp:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ifndef WIT_ROS_HPP
4 | #define WIT_ROS_HPP
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include "wit_driver.hpp"
20 |
21 | using namespace std;
22 | using namespace ros;
23 |
24 | namespace wit {
25 | class WitRos {
26 | public:
27 | WitRos(string &node_name);
28 | ~WitRos();
29 | bool init(NodeHandle &nh);
30 | bool update();
31 |
32 | private:
33 | /*********************
34 | ** Variables
35 | **********************/
36 | string name_;
37 | WitDriver wd_;
38 |
39 | /*********************
40 | ** Ros Publishers
41 | **********************/
42 | void advertiseTopics(NodeHandle &nh);
43 | Publisher imu_pub_;
44 | Publisher gps_pub_;
45 | Publisher raw_data_pub_;
46 | Publisher related_yaw_pub_;
47 |
48 | /*********************
49 | ** Ros Subscribers
50 | **********************/
51 | Subscriber reset_offset_sub_;
52 | void subscribeTopics(NodeHandle &nh);
53 |
54 | void subscribeResetOffset(const std_msgs::Empty msg);
55 |
56 | /*********************
57 | ** SigSlots
58 | **********************/
59 |
60 | ecl::Slot<> slot_stream_data_;
61 |
62 | /*********************
63 | ** Slot Callbacks
64 | **********************/
65 | void processStreamData();
66 | };
67 | }
68 |
69 | #endif
70 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # wit_node
2 |
3 | This is the ROS nodelet package for wit motion company imu and gps sensor. Providing driver, ros driver and nodelet intergrating program.
4 |
5 |
6 |
7 | ## Dependencies and Install
8 |
9 | 1. ROS
10 | 2. ros--ecl
11 |
12 | Install ecl by
13 |
14 | ```bash
15 | sudo apt install ros--ecl
16 | ```
17 |
18 |
19 |
20 | ## Usage
21 |
22 | Launch the only ROS launch file:
23 |
24 | ```bash
25 | roslaunch wit_node wit.launch
26 | ```
27 |
28 | About parameter:
29 |
30 | -port
31 |
32 | This is the port that device name in Linux system, for example the default port name is "/dev/ttyUSB0"
33 |
34 |
35 |
36 | ## Msg
37 |
38 | ### ImuGpsRaw
39 |
40 | > Header header
41 | >
42 | > float64 time
43 | >
44 | > float64[] acc
45 | >
46 | > float64[] gyro
47 | >
48 | > float64[] rpy
49 | >
50 | > float64[] mag
51 | >
52 | > uint16[] ps #port state
53 | >
54 | > float64 temperature
55 | >
56 | > float64 altitude
57 | >
58 | > float64 ap #atmosphere pressure
59 | >
60 | > float64 latitude
61 | >
62 | > float64 longtitude
63 | >
64 | > float64 gpsh #gps height
65 | >
66 | > float64 gpsy #gps yaw
67 | >
68 | > float64 gpsv #gps velocity
69 | >
70 | > float64[] quarternion
71 | >
72 | > uint8 sn #satelites number
73 | >
74 | > float64[] dop
75 |
76 | ## Published Topics
77 |
78 | ### /imu (sensor_msgs/Imu)
79 |
80 | The standard ROS imu sensor msg which include orientation by filtered RPY.
81 |
82 | ### /gps (sensor_msgs/NavSatFix)
83 |
84 | The standard ROS gps or navigation satellites msg.
85 |
86 | ### /wit/raw_data (wit_node/ImuGpsRaw)
87 |
88 | All raw data provided by the wit device, including nine axises data, atmosphere pressure, temperature, latitude,longitude, altitude, satellites number .etc
89 |
90 | ### /wit/related_yaw (std_msgs/Float64)
91 |
92 | The offseted imu yaw data, which means the zero direction is start direction.
93 |
94 |
95 |
96 | ## Subscribed Topics
97 |
98 | ### /wit/reset_offset (std_msgs/Empty)
99 |
100 | Reset the offset yaw angle to current yaw, so the zero direction is turned to current direction.
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/include/wit_node/packet_handler/packet_finder.hpp:
--------------------------------------------------------------------------------
1 | #ifndef PACKET_FINDER_HPP_
2 | #define PACKET_FINDER_HPP_
3 | #include
4 | #include
5 | #include
6 |
7 | namespace wit {
8 |
9 | class PacketFinderBase {
10 | public:
11 | typedef ecl::PushAndPop BufferType;
12 |
13 | enum packetFinderState {
14 | clearBuffer = 0,
15 | waitingForStx,
16 | waitingForFlag,
17 | waitingForPayloadSize,
18 | waitingForPayloadToEtx,
19 | waitingForEtx,
20 | };
21 | enum packetFinderState state;
22 |
23 | protected:
24 | unsigned int size_stx;
25 | unsigned int size_etx;
26 | unsigned int size_length_field;
27 | bool variable_size_payload;
28 | unsigned int size_max_payload;
29 | unsigned int size_payload;
30 | unsigned int size_checksum_field;
31 |
32 | BufferType STX;
33 | BufferType ETX;
34 | BufferType buffer;
35 |
36 | bool verbose;
37 |
38 | ecl::Signal sig_warn, sig_error;
39 |
40 | public:
41 | PacketFinderBase(); /**< Default constructor. Use with configure(). **/
42 |
43 | virtual ~PacketFinderBase(){};
44 |
45 | void configure(const std::string &sigslots_namespace,
46 | const BufferType &putStx, const BufferType &putEtx,
47 | unsigned int sizeLengthField, unsigned int sizeMaxPayload,
48 | unsigned int sizeChecksumField, bool variableSizePayload);
49 | void clear();
50 | void enableVerbose();
51 | virtual bool update(const unsigned char *incoming,
52 | unsigned int numberOfIncoming);
53 | virtual bool checkSum();
54 | unsigned int numberOfDataToRead();
55 | void getBuffer(BufferType &bufferRef);
56 | void getPayload(BufferType &bufferRef);
57 |
58 | protected:
59 | bool WaitForStx(const unsigned char datum);
60 | bool WaitForFlag(const unsigned char datum);
61 | bool waitForPayloadSize(const unsigned char *incoming,
62 | unsigned int numberOfIncoming);
63 | bool waitForEtx(const unsigned char incoming, bool &foundPacket);
64 | bool waitForPayloadAndEtx(const unsigned char *incoming,
65 | unsigned int numberOfIncoming, bool &foundPacket);
66 | };
67 | };
68 |
69 | #endif /* PACKET_FINDER_HPP_ */
70 |
--------------------------------------------------------------------------------
/include/wit_node/data.hpp:
--------------------------------------------------------------------------------
1 |
2 | #ifndef DATA_HPP__
3 | #define DATA_HPP__
4 |
5 | #include "packet_handler/payload_base.hpp"
6 |
7 | #include
8 |
9 | namespace wit {
10 |
11 | /*****************************************************************************
12 | ** Interface
13 | *****************************************************************************/
14 |
15 | class Data : public packet_handler::payloadBase {
16 | public:
17 | Data() : packet_handler::payloadBase(false, 30){};
18 |
19 | struct IMUGPS {
20 | double timestamp;
21 | double a[3];
22 | double temperature;
23 | double w[3];
24 | double rpy[3];
25 | double mag[3];
26 | uint16_t d[4];
27 | float pressure;
28 | float altitude;
29 | float longtitude;
30 | float latitude;
31 | float gpsv;
32 | double gpsh;
33 | double gpsy;
34 | double q[4];
35 | uint16_t satelites;
36 | double gpsa[3];
37 |
38 | } imugps_;
39 |
40 | struct Flags {
41 | static const uint8_t TIME = 0x50;
42 | static const uint8_t ACCE = 0x51;
43 | static const uint8_t GYRO = 0x52;
44 | static const uint8_t RPY = 0x53;
45 | static const uint8_t MAG = 0x54;
46 | static const uint8_t STATE = 0x55;
47 | static const uint8_t PALT = 0x56;
48 | static const uint8_t LOLA = 0x57;
49 | static const uint8_t GPSV = 0x58;
50 | static const uint8_t QUAT = 0x59;
51 | static const uint8_t SATE = 0x5a;
52 | };
53 |
54 | bool serialise(ecl::PushAndPop &byteStream);
55 | bool deserialise(ecl::PushAndPop &byteStream);
56 | bool desTime(ecl::PushAndPop &byteStream);
57 | bool desAcce(ecl::PushAndPop &byteStream);
58 | bool desGyro(ecl::PushAndPop &byteStream);
59 | bool desRpy(ecl::PushAndPop &byteStream);
60 | bool desMag(ecl::PushAndPop &byteStream);
61 | bool desState(ecl::PushAndPop &byteStream);
62 | bool desPalt(ecl::PushAndPop &byteStream);
63 | bool desLola(ecl::PushAndPop &byteStream);
64 | bool desGpsv(ecl::PushAndPop &byteStream);
65 | bool desQuat(ecl::PushAndPop &byteStream);
66 | bool desSate(ecl::PushAndPop &byteStream);
67 |
68 | void build_special_variable(float &variable,
69 | ecl::PushAndPop &byteStream);
70 | };
71 | }
72 |
73 | #endif /* DATA_HPP__ */
74 |
--------------------------------------------------------------------------------
/include/wit_node/wit_driver.hpp:
--------------------------------------------------------------------------------
1 |
2 | #ifndef WIT_DRIVER_HPP_
3 | #define WIT_DRIVER_HPP_
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | //#include "command.hpp"
15 | #include "data.hpp"
16 | #include "packet_handler/packet_finder.hpp"
17 | #include "parameter.hpp"
18 |
19 | using namespace std;
20 | using namespace ecl;
21 | namespace wit {
22 |
23 | /*****************************************************************************
24 | ** Parent Interface
25 | *****************************************************************************/
26 | // 串口数据解码程序,使用有限状态机原理
27 | class PacketFinder : public PacketFinderBase {
28 | public:
29 | virtual ~PacketFinder() {}
30 | //重定义校验函数
31 | bool checkSum();
32 | };
33 |
34 | /*****************************************************************************
35 | ** Interface [wit]
36 | *****************************************************************************/
37 | /**
38 | * @brief The core wit driver class.
39 | *
40 | * This connects to the outside world via sigslots and get accessors.
41 | **/
42 | class WitDriver {
43 | public:
44 | WitDriver();
45 | ~WitDriver();
46 |
47 | //初始化
48 | void init(Parameter ¶m);
49 | // 检查是否连接上通信串口
50 | bool isConnected() { return connected_; }
51 | // 关闭接口
52 | void shutdown() { shutdown_requested_ = true; }
53 | bool isShutdown() const { return shutdown_requested_; }
54 | double getRelatedYaw() const { return relate_yaw_; }
55 |
56 | bool isAlive() { return alive_; }
57 | void resetYawOffset() { yaw_offset_ = data_.imugps_.rpy[2]; }
58 | //底盘数据流控制程序,运行于thread线程中
59 | void spin();
60 |
61 | // 传感器数据锁
62 | void lockDataAccess();
63 | void unlockDataAccess();
64 |
65 | /******************************************
66 | ** Getters - Raw Data Api
67 | *******************************************/
68 | /* Be sure to lock/unlock the data access (lockDataAccess and
69 | * unlockDataAccess)
70 | * around any getXXX calls - see the doxygen notes for lockDataAccess. */
71 | // 舵机状态信息
72 | Data::IMUGPS getData() const { return data_.imugps_; }
73 |
74 | private:
75 | bool connected_;
76 | bool alive_;
77 |
78 | //读取返回数据线程
79 | ecl::Thread thread_spin_;
80 |
81 | bool shutdown_requested_;
82 | /*********************
83 | ** Driver Paramters
84 | **********************/
85 | Parameter param_;
86 |
87 | /*********************
88 | ** Packet Handling
89 | **********************/
90 | Data data_;
91 | double relate_yaw_, yaw_offset_;
92 |
93 | // 下位机串口与串口buffer
94 | ecl::Serial serial;
95 | PacketFinder packet_finder;
96 | PacketFinder::BufferType data_buffer;
97 | ecl::Mutex data_mutex_;
98 |
99 | /*********************
100 | ** Signals
101 | **********************/
102 | ecl::Signal<> sig_stream_data;
103 | };
104 | }
105 |
106 | #endif
107 |
--------------------------------------------------------------------------------
/include/wit_node/command.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file include/xbot_arm_driver/command.hpp
3 | *
4 | * @brief Command structure.
5 | *
6 | * License: BSD
7 | * https://raw.github.com/yujinrobot/xbot_core/hydro-devel/xbot_arm_driver/LICENSE
8 | **/
9 | /*****************************************************************************
10 | ** Preprocessor
11 | *****************************************************************************/
12 |
13 | #ifndef WIT_COMMAND_DATA_HPP__
14 | #define WIT_COMMAND_DATA_HPP__
15 |
16 | /*****************************************************************************
17 | ** Includes
18 | *****************************************************************************/
19 |
20 | #include
21 | #include "packet_handler/payload_base.hpp"
22 |
23 | /*****************************************************************************
24 | ** Namespace
25 | *****************************************************************************/
26 |
27 | //#define GRIP_SPEED 20
28 | //#define MOTOR_SPEED_BIG 1000
29 | //#define MOTOR_SPEED_TINY 20
30 |
31 | namespace wit {
32 |
33 | class Command : public packet_handler::payloadBase {
34 | public:
35 | typedef ecl::PushAndPop Buffer;
36 | typedef ecl::Stencil BufferStencil;
37 |
38 | /**
39 | * These values are used to detect the type of sub-payload that is ensuing.
40 | */
41 | enum Name {
42 | Ping = 1,
43 | Read = 2,
44 | Write = 3,
45 | RegWrite = 4,
46 | Action = 5,
47 | Reset = 6,
48 | LeftArm = 7,
49 | RightArm = 8,
50 | SycnWrite = 0x83
51 | };
52 |
53 | /**
54 | * @brief Data structure containing data for commands.
55 | *
56 | * It is important to keep this
57 | * state as it will have to retain knowledge of the last known command in
58 | * some instances - e.g. for gp_out commands, quite often the incoming command
59 | * is only to set the output for a single led while keeping the rest of the
60 | * current
61 | * gp_out values as is.
62 | *
63 | * For generating individual commands we modify the data here, then copy the
64 | * command
65 | * class (avoid doing mutexes) and spin it off for sending down to the device.
66 | */
67 | struct Data {
68 | Data()
69 | : command(Ping),
70 | index(0),
71 | location(2047),
72 | read_start(0x38),
73 | read_length(15) {
74 | for (int i = 0; i < 12; i++) {
75 | sycn_location[i] = 2047;
76 | }
77 | }
78 |
79 | Name command;
80 | uint8_t index;
81 | uint16_t location;
82 | uint8_t read_start;
83 | uint8_t read_length;
84 | uint16_t sycn_location[12];
85 | uint16_t left_arm_location[6];
86 | uint16_t right_arm_location[6];
87 | };
88 |
89 | virtual ~Command() {}
90 |
91 | // 读取某个舵机的ERROR信息
92 | static Command setSingleMotorErrorRead(const uint8_t &index);
93 |
94 | // 控制某个舵机运动
95 | static Command setSingleMotorControl(const uint8_t &index,
96 | const uint16_t &location);
97 |
98 | // 同步控制12个舵机运动
99 | static Command setSycnMotorControl(const uint16_t *sycn_location);
100 |
101 | // 同步控制6个左手舵机运动
102 | static Command setLeftArmControl(const uint16_t *left_arm_location);
103 |
104 | // 同步控制6个右手舵机运动
105 | static Command setRightArmControl(const uint16_t *right_arm_location);
106 |
107 | // 读取某个舵机的状态信息
108 | static Command setSingleMotorStatusRead(const uint8_t &index);
109 |
110 | Data data;
111 |
112 | void resetBuffer(Buffer &buffer);
113 | bool serialise(ecl::PushAndPop &byteStream);
114 | bool deserialise(ecl::PushAndPop &byteStream) {
115 | return true;
116 | } /**< Unused **/
117 |
118 | private:
119 | static const unsigned char header0;
120 | static const unsigned char header1;
121 | };
122 |
123 | } // namespace xbot
124 |
125 | #endif /* WIT_COMMAND_DATA_HPP__ */
126 |
--------------------------------------------------------------------------------
/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | wit_node
4 | 0.0.0
5 | The wit_node package is a ROS package for wit motion IMU and GPS sensor, including driver and ros nodelet.
6 |
7 |
8 |
9 |
10 | roc
11 |
12 |
13 |
14 |
15 |
16 | BSD
17 |
18 |
19 |
20 |
21 |
22 | http://wiki.ros.org/wit_node
23 |
24 |
25 |
26 |
27 |
28 | roc
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | catkin
52 | ecl_devices
53 | ecl_sigslots
54 | ecl_time
55 | ecl_build
56 | ecl_geometry
57 | roscpp
58 | rospy
59 | sensor_msgs
60 | std_msgs
61 | nodelet
62 | pluginlib
63 | message_generation
64 |
65 | ecl
66 | roscpp
67 | rospy
68 | sensor_msgs
69 | std_msgs
70 | ecl_devices
71 | ecl_build
72 | ecl_sigslots
73 | ecl_time
74 | ecl_geometry
75 | nodelet
76 | pluginlib
77 | roscpp
78 | rospy
79 | sensor_msgs
80 | std_msgs
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/src/driver/wit_driver.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "../../include/wit_node/wit_driver.hpp"
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | namespace wit {
15 |
16 | bool PacketFinder::checkSum() {
17 | unsigned int packet_size(buffer.size());
18 | unsigned char cs(0);
19 | for (unsigned int i = 0; i < packet_size - 1; i++) {
20 | cs += buffer[i];
21 | }
22 |
23 | return (cs == buffer[packet_size - 1]) ? true : false;
24 | }
25 |
26 | WitDriver::WitDriver()
27 | : shutdown_requested_(false),
28 | connected_(false),
29 | alive_(false),
30 | yaw_offset_(0.0 / 0.0) {}
31 |
32 | /**
33 | * Shutdown the driver - make sure we wait for the thread to finish.
34 | */
35 | WitDriver::~WitDriver() {
36 | shutdown_requested_ = true; // thread's spin() will catch this and terminate
37 | thread_spin_.join();
38 | }
39 |
40 | void WitDriver::init(Parameter ¶m) {
41 | this->param_ = param;
42 | std::string ns = param_.ns;
43 |
44 | // connect signals
45 | sig_stream_data.connect(ns + std::string("/stream_data"));
46 |
47 | try {
48 | serial.open(param_.port_, ecl::BaudRate_115200, ecl::DataBits_8,
49 | ecl::StopBits_1, ecl::NoParity);
50 | serial.block(4000); // blocks by default, but just to be clear!
51 | connected_ = true;
52 |
53 | } catch (const ecl::StandardException &e) {
54 | connected_ = false;
55 | if (e.flag() == ecl::NotFoundError) {
56 | } else {
57 | throw ecl::StandardException(LOC, e);
58 | }
59 | }
60 |
61 | ecl::PushAndPop stx(1, 0);
62 | ecl::PushAndPop etx(1);
63 | stx.push_back(0x55);
64 | packet_finder.configure(ns, stx, etx, 1, 256, 1, true);
65 | thread_spin_.start(&WitDriver::spin, *this);
66 | }
67 |
68 | void WitDriver::lockDataAccess() { data_mutex_.lock(); }
69 |
70 | /**
71 | * Unlock a previously locked data access privilege.
72 | * @sa lockDataAccess()
73 | */
74 | void WitDriver::unlockDataAccess() { data_mutex_.unlock(); }
75 |
76 | /**
77 | * @brief Performs a scan looking for incoming data packets.
78 | *
79 | * Sits on the device waiting for incoming and then parses it, and signals
80 | * that an update has occured.
81 | *
82 | * Or, if in simulation, just loopsback the motor devices.
83 | */
84 |
85 | void WitDriver::spin() {
86 | ecl::TimeStamp last_signal_time;
87 | ecl::Duration timeout(0.1);
88 | unsigned char buf[256];
89 |
90 | while (!shutdown_requested_) {
91 | /*********************
92 | ** Checking Connection
93 | **********************/
94 | if (!serial.open()) {
95 | try {
96 | serial.open(param_.port_, ecl::BaudRate_115200, ecl::DataBits_8,
97 | ecl::StopBits_1, ecl::NoParity);
98 | serial.block(4000); // blocks by default, but just to be clear!
99 | connected_ = true;
100 | } catch (const ecl::StandardException &e) {
101 | connected_ = false;
102 | alive_ = false;
103 | // windows throws OpenError if not connected
104 | if (e.flag() == ecl::NotFoundError) {
105 | std::cout
106 | << "device does not (yet) available on this port, waiting..."
107 | << std::endl;
108 | } else if (e.flag() == ecl::OpenError) {
109 | std::cout << "device failed to open, waiting... ["
110 | << std::string(e.what()) << "]" << std::endl;
111 | ;
112 | } else {
113 | throw ecl::StandardException(LOC, e);
114 | }
115 | ecl::Sleep(5)(); // five seconds
116 | continue;
117 | }
118 | }
119 |
120 | /*********************
121 | ** Read Incoming
122 | **********************/
123 | int n = serial.read((char *)buf, 1);
124 | // std::cout << int(buf[0]) << std::endl;
125 | if (n == 0) {
126 | continue;
127 | }
128 | bool find_packet = packet_finder.update(buf, n);
129 |
130 | if (find_packet) {
131 | PacketFinder::BufferType local_buffer;
132 | packet_finder.getBuffer(local_buffer);
133 | packet_finder.getPayload(data_buffer);
134 | lockDataAccess();
135 | unsigned short flag = data_buffer[0];
136 | while (data_buffer.size() > 0) {
137 | data_.deserialise(data_buffer);
138 | if (flag == Data::Flags::RPY) {
139 | if (isnan(yaw_offset_)) yaw_offset_ = data_.imugps_.rpy[2];
140 | relate_yaw_ = data_.imugps_.rpy[2] - yaw_offset_;
141 | }
142 | }
143 | unlockDataAccess();
144 | alive_ = true;
145 | if (flag == Data::Flags::ACCE) {
146 | sig_stream_data.emit();
147 | }
148 | last_signal_time.stamp();
149 |
150 | } else {
151 | if (alive_ && ((ecl::TimeStamp() - last_signal_time) > timeout)) {
152 | alive_ = false;
153 | }
154 | }
155 | }
156 | }
157 |
158 | } // namespace WitDriver
159 |
--------------------------------------------------------------------------------
/src/ros/wit_ros.cpp:
--------------------------------------------------------------------------------
1 | #include "../../include/wit_node/wit_ros.hpp"
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | namespace wit {
8 |
9 | WitRos::WitRos(string &node_name)
10 | : name_(node_name), slot_stream_data_(&WitRos::processStreamData, *this) {}
11 |
12 | WitRos::~WitRos() {
13 | ROS_INFO_STREAM("Wit: waiting for wd_ thread finish[" << name_ << " ].");
14 | }
15 |
16 | bool WitRos::init(NodeHandle &nh) {
17 | advertiseTopics(nh);
18 | subscribeTopics(nh);
19 | slot_stream_data_.connect(name_ + string("/stream_data"));
20 |
21 | Parameter parameter;
22 |
23 | parameter.ns = name_;
24 |
25 | if (!nh.getParam("port", parameter.port_)) {
26 | ROS_ERROR_STREAM(
27 | "Wit : no wit device port given on the parameter server (e.g. "
28 | "/dev/ttyUSB0)["
29 | << name_ << "].");
30 | return false;
31 | }
32 |
33 | /*********************
34 | ** Driver Init
35 | **********************/
36 | try {
37 | wd_.init(parameter);
38 | ros::Duration(0.1).sleep();
39 | } catch (const ecl::StandardException &e) {
40 | switch (e.flag()) {
41 | case (ecl::OpenError): {
42 | ROS_ERROR_STREAM("Wit : could not open connection ["
43 | << parameter.port_ << "][" << name_ << "].");
44 | break;
45 | }
46 | default: {
47 | ROS_ERROR_STREAM("Wit : initialisation failed [" << name_ << "].");
48 | ROS_DEBUG_STREAM(e.what());
49 | break;
50 | }
51 | }
52 | return false;
53 | }
54 |
55 | return true;
56 | }
57 |
58 | bool WitRos::update() {
59 | if (wd_.isShutdown()) {
60 | ROS_ERROR_STREAM("Wit : Driver has been shutdown. Stopping update loop. ["
61 | << name_ << "].");
62 | return false;
63 | }
64 | if (!wd_.isConnected()) {
65 | ROS_ERROR_STREAM(
66 | "Wit : arm serial port is not connetced, please connect the arm.");
67 | return false;
68 | }
69 | processStreamData();
70 | return true;
71 | }
72 |
73 | void WitRos::advertiseTopics(NodeHandle &nh) {
74 | imu_pub_ = nh.advertise("/imu", 1000);
75 | gps_pub_ = nh.advertise("/gps", 1000);
76 | raw_data_pub_ = nh.advertise("raw_data", 1000);
77 | related_yaw_pub_ = nh.advertise("related_yaw", 1000);
78 | }
79 |
80 | void WitRos::subscribeTopics(NodeHandle &nh) {
81 | reset_offset_sub_ = nh.subscribe(string("reset_offset"), 10,
82 | &WitRos::subscribeResetOffset, this);
83 | }
84 | void WitRos::subscribeResetOffset(const std_msgs::Empty msg) {
85 | wd_.resetYawOffset();
86 | }
87 |
88 | void WitRos::processStreamData() {
89 | if (ok()) {
90 | sensor_msgs::Imu imu_msg;
91 | sensor_msgs::NavSatFix gps_msg;
92 | wit_node::ImuGpsRaw raw_msg;
93 | std_msgs::Float64 yaw_msg;
94 | imu_msg.header.frame_id = "imu_link";
95 | imu_msg.header.stamp = ros::Time::now();
96 | gps_msg.header.stamp = ros::Time::now();
97 | raw_msg.header.stamp = ros::Time::now();
98 | Data::IMUGPS data = wd_.getData();
99 | imu_msg.angular_velocity.x = data.w[0];
100 | imu_msg.angular_velocity.y = data.w[1];
101 | imu_msg.angular_velocity.z = data.w[2];
102 |
103 | imu_msg.linear_acceleration.x = data.a[0];
104 | imu_msg.linear_acceleration.y = data.a[1];
105 | imu_msg.linear_acceleration.z = data.a[2];
106 |
107 | imu_msg.orientation = tf::createQuaternionMsgFromRollPitchYaw(
108 | data.rpy[0], data.rpy[1], data.rpy[2]);
109 |
110 | imu_msg.orientation_covariance =
111 | {0.001, 0.0, 0.0,
112 | 0.0, 0.001, 0.0,
113 | 0.0, 0.0, 0.001};
114 | imu_msg.angular_velocity_covariance =
115 | {0.00001, 0.0, 0.0,
116 | 0.0, 0.00001, 0.0,
117 | 0.0, 0.0, 0.00001};
118 | imu_msg.linear_acceleration_covariance =
119 | {0.01, 0.0, 0.0,
120 | 0.0, 0.01, 0.0,
121 | 0.0, 0.0, 0.01};
122 |
123 | gps_msg.altitude = data.altitude;
124 | gps_msg.latitude = data.latitude;
125 | gps_msg.longitude = data.longtitude;
126 | gps_msg.position_covariance_type =
127 | sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN;
128 | for (int i = 0; i < 3; i++) {
129 | raw_msg.acc.push_back(data.a[i]);
130 | raw_msg.gyro.push_back(data.w[i]);
131 | raw_msg.rpy.push_back(data.rpy[i]);
132 | raw_msg.mag.push_back(data.mag[i]);
133 | raw_msg.dop.push_back(data.gpsa[i]);
134 | }
135 | for (int i = 0; i < 4; i++) {
136 | raw_msg.ps.push_back(data.d[i]);
137 | raw_msg.quarternion.push_back(data.q[i]);
138 | }
139 | raw_msg.sn = data.satelites;
140 | raw_msg.gpsh = data.gpsh;
141 | raw_msg.gpsy = data.gpsy;
142 | raw_msg.gpsv = data.gpsv;
143 | raw_msg.ap = data.pressure;
144 | raw_msg.longtitude = data.longtitude;
145 | raw_msg.altitude = data.altitude;
146 | raw_msg.latitude = data.latitude;
147 | raw_msg.time = data.timestamp;
148 | raw_msg.temperature = data.temperature;
149 |
150 | yaw_msg.data = wd_.getRelatedYaw();
151 |
152 | imu_pub_.publish(imu_msg);
153 | gps_pub_.publish(gps_msg);
154 | raw_data_pub_.publish(raw_msg);
155 | related_yaw_pub_.publish(yaw_msg);
156 | }
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/include/wit_node/packet_handler/payload_base.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file include/xbot_arm_driver/packet_handler/payload_base.hpp
3 | *
4 | * @brief Base class for payloads.
5 | *
6 | * License: BSD
7 | * https://raw.github.com/yujinrobot/xbot_core/hydro-devel/xbot_arm_driver/LICENSE
8 | **/
9 | /*****************************************************************************
10 | ** Ifdefs
11 | *****************************************************************************/
12 |
13 | #ifndef ROBOT_DATA_HPP_
14 | #define ROBOT_DATA_HPP_
15 |
16 | /*****************************************************************************
17 | ** Includes
18 | *****************************************************************************/
19 |
20 | #include
21 | #include
22 |
23 | /*****************************************************************************
24 | ** Namespaces
25 | *****************************************************************************/
26 |
27 | namespace packet_handler
28 | {
29 |
30 | /*****************************************************************************
31 | ** Interface
32 | *****************************************************************************/
33 | /**
34 | * @brief
35 | * Provides base class for payloads.
36 | *
37 | */
38 | class payloadBase
39 | {
40 | public:
41 |
42 | /**
43 | * this is simple magic to write the flag, when we get the packet from the host or
44 | * when we want to send the data
45 | */
46 | bool yes;
47 |
48 | /**
49 | * it indicates the type of derived packet. if packet type is dynamic, length of
50 | * packet can be changed during communication session. Ohterwise can not.
51 | */
52 | const bool is_dynamic;
53 |
54 | /**
55 | * it indicates length of data part of packet, except header and length field.
56 | * if packet is fixed type, this value should be matched with length field.
57 | * if packet is dynamic type, this value indicates minimal value of length field.
58 | */
59 | const unsigned char length;
60 |
61 | /*
62 | * construct and destruct
63 | */
64 | payloadBase(const bool is_dynamic_ = false, const unsigned char length_ = 0 )
65 | : yes(false)
66 | , is_dynamic(is_dynamic_)
67 | , length(length_)
68 | {};
69 | virtual ~payloadBase() {};
70 |
71 | /*
72 | * serialisation
73 | */
74 | virtual bool serialise(ecl::PushAndPop & byteStream)=0;
75 | virtual bool deserialise(ecl::PushAndPop & byteStream)=0;
76 |
77 | // utilities
78 | // todo; let's put more useful converters here. Or we may use generic converters
79 | protected:
80 | // below funciton should be replaced wiht converter
81 | //###########################################################
82 | //#数据在计算机内存中存储是高位在前,低位在后,int型10存储为:00000000000000000000000000001010
83 | //#数据在串口传输过程中是低位在前,高位在后,因而10存储为00001010000000000000000000000000
84 | //###########################################################
85 | template
86 | void buildVariable(T & V, ecl::PushAndPop & buffer)
87 | {
88 | if (buffer.size() < sizeof(T))
89 | return;
90 | V = static_cast(buffer.pop_front());
91 |
92 | unsigned int size_value(sizeof(T));
93 | for (unsigned int i = 1; i < size_value; i++)
94 | {
95 | V |= ((static_cast(buffer.pop_front())) << (8 * i));
96 | }
97 | }
98 |
99 | template
100 | void buildBytes(const T & V, ecl::PushAndPop & buffer)
101 | {
102 | unsigned int size_value(sizeof(T));
103 | for (unsigned int i = 0; i < size_value; i++)
104 | {
105 | buffer.push_back(static_cast((V >> (i * 8)) & 0xff));
106 | }
107 | }
108 | };
109 |
110 | /**
111 | * Need to be very careful with this - it will only work across platforms if they
112 | * happen to be doing reinterpret_cast with the same float standard.
113 | * @param V
114 | * @param buffer
115 | */
116 | template<>
117 | inline void payloadBase::buildVariable(float & V, ecl::PushAndPop & buffer)
118 | {
119 | if (buffer.size() < 4)
120 | return;
121 | unsigned int ui;
122 | ui = static_cast(buffer.pop_front());
123 |
124 | unsigned int size_value(4);
125 | for (unsigned int i = 1; i < size_value; i++)
126 | {
127 | ui |= ((static_cast(buffer.pop_front())) << (8 * i));
128 | }
129 |
130 | V = reinterpret_cast(ui);
131 | }
132 |
133 | template<>
134 | inline void payloadBase::buildBytes(const float & V, ecl::PushAndPop & buffer)
135 | {
136 | if (buffer.size() < 4)
137 | return;
138 | unsigned int size_value(4);
139 | unsigned int ui(reinterpret_cast(V));
140 | for (unsigned int i = 0; i < size_value; i++)
141 | {
142 | buffer.push_back(static_cast((ui >> (i * 8)) & 0xff));
143 | }
144 | }
145 |
146 | //#define FRAC_MAX 9223372036854775807LL /* 2**63 - 1 */
147 | //
148 | //struct dbl_packed
149 | //{
150 | // int exp;
151 | // long long frac;
152 | //};
153 | //
154 | //void pack(double x, struct dbl_packed *r)
155 | //{
156 | // double xf = fabs(frexp(x, &r->exp)) - 0.5;
157 | //
158 | // if (xf < 0.0)
159 | // {
160 | // r->frac = 0;
161 | // return;
162 | // }
163 | //
164 | // r->frac = 1 + (long long)(xf * 2.0 * (FRAC_MAX - 1));
165 | //
166 | // if (x < 0.0)
167 | // r->frac = -r->frac;
168 | //}
169 | //
170 | //double unpack(const struct dbl_packed *p)
171 | //{
172 | // double xf, x;
173 | //
174 | // if (p->frac == 0)
175 | // return 0.0;
176 | //
177 | // xf = ((double)(llabs(p->frac) - 1) / (FRAC_MAX - 1)) / 2.0;
178 | //
179 | // x = ldexp(xf + 0.5, p->exp);
180 | //
181 | // if (p->frac < 0)
182 | // x = -x;
183 | //
184 | // return x;
185 | //}
186 |
187 | }
188 | ;
189 | // namespace packet_handler
190 |
191 | #endif /* ROBOT_DATA_HPP_ */
192 |
--------------------------------------------------------------------------------
/src/driver/command.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "../../include/wit_node/command.hpp"
3 |
4 | namespace wit {
5 |
6 | const unsigned char Command::header0 = 0xFF;
7 | const unsigned char Command::header1 = 0xFF;
8 | const uint16_t ALL_SPEED[14] = {10, 1000, 1000, 1000, 1000, 20, 20,
9 | 1000, 1000, 1000, 1000, 20, 20, 10};
10 |
11 | //读取单个舵机的错误状态信息指令发送
12 | Command Command::setSingleMotorErrorRead(const uint8_t &index) {
13 | Command outgoing;
14 | outgoing.data.index = index;
15 | outgoing.data.command = Command::Ping;
16 | return outgoing;
17 | }
18 |
19 | //控制单个舵机指令发送
20 | Command Command::setSingleMotorControl(const uint8_t &index,
21 | const uint16_t &location) {
22 | Command outgoing;
23 | outgoing.data.index = index;
24 | outgoing.data.location = location;
25 | outgoing.data.command = Command::Write;
26 | return outgoing;
27 | }
28 |
29 | //读取单个舵机的所有状态信息指令发送
30 | Command Command::setSingleMotorStatusRead(const uint8_t &index) {
31 | Command outgoing;
32 | outgoing.data.index = index;
33 | outgoing.data.read_start = 0x38;
34 | outgoing.data.read_length = 15;
35 | outgoing.data.command = Command::Read;
36 | return outgoing;
37 | }
38 |
39 | //编号为1~12的手臂关节舵机控制
40 | Command Command::setSycnMotorControl(const uint16_t *sycn_location) {
41 | Command outgoing;
42 | outgoing.data.index = 0xFE;
43 | for (int i = 0; i < 12; i++) {
44 | outgoing.data.sycn_location[i] = sycn_location[i];
45 | }
46 | outgoing.data.command = Command::SycnWrite;
47 | return outgoing;
48 | }
49 |
50 | //编号为7~12的左手关节舵机位置控制
51 | Command Command::setLeftArmControl(const uint16_t *left_arm_location) {
52 | Command outgoing;
53 | outgoing.data.index = 0xFE;
54 | for (int i = 0; i < 6; i++) {
55 | outgoing.data.left_arm_location[i] = left_arm_location[i];
56 | }
57 | outgoing.data.command = Command::LeftArm;
58 | return outgoing;
59 | }
60 |
61 | //编号为1~6的右手手臂关节舵机控制
62 | Command Command::setRightArmControl(const uint16_t *right_arm_location) {
63 | Command outgoing;
64 | outgoing.data.index = 0xFE;
65 | for (int i = 0; i < 6; i++) {
66 | outgoing.data.right_arm_location[i] = right_arm_location[i];
67 | }
68 | outgoing.data.command = Command::RightArm;
69 | return outgoing;
70 | }
71 |
72 | /*****************************************************************************
73 | ** Implementation [Serialisation]
74 | *****************************************************************************/
75 | /**
76 | * 重置缓存区
77 | */
78 | void Command::resetBuffer(Buffer &buffer) {
79 | buffer.clear();
80 | buffer.resize(256);
81 | buffer.push_back(Command::header0);
82 | buffer.push_back(Command::header1);
83 | }
84 |
85 | bool Command::serialise(ecl::PushAndPop &byteStream) {
86 | // need to be sure we don't pass through an emum to the Trans'd buildBytes
87 | // functions.
88 | unsigned char cmd = static_cast(data.command);
89 | uint8_t size_byte;
90 | uint8_t index;
91 | // uint16_t speed;
92 | uint16_t time;
93 | uint8_t address;
94 | uint8_t label1;
95 | uint8_t label2;
96 | uint8_t sycn_cmd(0x83);
97 | switch (data.command) {
98 | case Ping:
99 | buildBytes(data.index, byteStream);
100 | size_byte = 0x02;
101 | buildBytes(size_byte, byteStream);
102 | buildBytes(cmd, byteStream);
103 | break;
104 | case Read:
105 | buildBytes(data.index, byteStream);
106 | size_byte = 0x04;
107 | buildBytes(size_byte, byteStream);
108 | buildBytes(cmd, byteStream);
109 | buildBytes(data.read_start, byteStream);
110 | buildBytes(data.read_length, byteStream);
111 | break;
112 | case Write:
113 | buildBytes(data.index, byteStream);
114 | size_byte = 0x09;
115 | buildBytes(size_byte, byteStream);
116 | buildBytes(cmd, byteStream);
117 | address = 0x2A;
118 | buildBytes(address, byteStream);
119 | buildBytes(data.location, byteStream);
120 | time = 0;
121 | buildBytes(time, byteStream);
122 | buildBytes(ALL_SPEED[data.index], byteStream);
123 | break;
124 | case RegWrite:
125 | buildBytes(cmd, byteStream);
126 | break;
127 | case Action:
128 | index = 0xFE;
129 | buildBytes(index, byteStream);
130 | size_byte = 0x02;
131 | buildBytes(size_byte, byteStream);
132 | buildBytes(cmd, byteStream);
133 | break;
134 | case SycnWrite:
135 | buildBytes(data.index, byteStream);
136 | size_byte = 0x58;
137 | buildBytes(size_byte, byteStream);
138 | buildBytes(cmd, byteStream);
139 | label1 = 0x2A;
140 | buildBytes(label1, byteStream);
141 | label2 = 0x06;
142 | buildBytes(label2, byteStream);
143 | for (uint8_t i = 1; i < 13; i++) {
144 | buildBytes(i, byteStream);
145 | buildBytes(data.sycn_location[i - 1], byteStream);
146 | time = 0;
147 | buildBytes(time, byteStream);
148 | buildBytes(ALL_SPEED[i], byteStream);
149 | }
150 | break;
151 | case LeftArm:
152 | buildBytes(data.index, byteStream);
153 | size_byte = 0x2E;
154 | buildBytes(size_byte, byteStream);
155 | buildBytes(sycn_cmd, byteStream);
156 | label1 = 0x2A;
157 | buildBytes(label1, byteStream);
158 | label2 = 0x06;
159 | buildBytes(label2, byteStream);
160 | for (uint8_t i = 7; i < 13; i++) {
161 | buildBytes(i, byteStream);
162 | buildBytes(data.left_arm_location[i - 7], byteStream);
163 | time = 0;
164 | buildBytes(time, byteStream);
165 | buildBytes(ALL_SPEED[i], byteStream);
166 | }
167 | break;
168 | case RightArm:
169 | buildBytes(data.index, byteStream);
170 | size_byte = 0x2E;
171 | buildBytes(size_byte, byteStream);
172 | buildBytes(sycn_cmd, byteStream);
173 | label1 = 0x2A;
174 | buildBytes(label1, byteStream);
175 | label2 = 0x06;
176 | buildBytes(label2, byteStream);
177 | for (uint8_t i = 1; i < 7; i++) {
178 | buildBytes(i, byteStream);
179 | buildBytes(data.right_arm_location[i - 1], byteStream);
180 |
181 | time = 0;
182 | buildBytes(time, byteStream);
183 | buildBytes(ALL_SPEED[i], byteStream);
184 | }
185 | // std::cout<
16 | #include
17 | using namespace std;
18 | /*****************************************************************************
19 | ** Namespaces
20 | *****************************************************************************/
21 |
22 | namespace wit {
23 |
24 | /*****************************************************************************
25 | ** Implementation
26 | *****************************************************************************/
27 |
28 | PacketFinderBase::PacketFinderBase() : state(waitingForStx), verbose(false) {}
29 |
30 | /*****************************************************************************
31 | ** Public
32 | *****************************************************************************/
33 |
34 | void PacketFinderBase::configure(const std::string &sigslots_namespace,
35 | const BufferType &putStx,
36 | const BufferType &putEtx,
37 | unsigned int sizeLengthField,
38 | unsigned int sizeMaxPayload,
39 | unsigned int sizeChecksumField,
40 | bool variableSizePayload) {
41 | size_stx = putStx.size();
42 | size_etx = putEtx.size();
43 | size_length_field = sizeLengthField;
44 | variable_size_payload = variableSizePayload;
45 | size_max_payload = sizeMaxPayload;
46 | size_payload = variable_size_payload ? 0 : sizeMaxPayload;
47 | size_checksum_field = sizeChecksumField;
48 | STX = putStx;
49 | ETX = putEtx;
50 | buffer = BufferType(size_stx + size_length_field + size_max_payload +
51 | size_checksum_field + size_etx);
52 | state = waitingForStx;
53 |
54 | sig_warn.connect(sigslots_namespace + std::string("/ros_warn"));
55 | sig_error.connect(sigslots_namespace + std::string("/ros_error"));
56 |
57 | // todo; exception
58 | // Problem1: size_length_field = 1, vairable_size_payload = false
59 |
60 | clear();
61 | }
62 |
63 | void PacketFinderBase::clear() {
64 | state = waitingForStx;
65 | buffer.clear();
66 | }
67 |
68 | void PacketFinderBase::enableVerbose() { verbose = true; }
69 |
70 | bool PacketFinderBase::checkSum() { return true; }
71 |
72 | unsigned int PacketFinderBase::numberOfDataToRead() {
73 | unsigned int num(0);
74 |
75 | switch (state) {
76 | case waitingForEtx:
77 | num = 1;
78 | break;
79 |
80 | case waitingForPayloadToEtx:
81 | num = size_payload + size_etx + size_checksum_field;
82 | break;
83 |
84 | case waitingForPayloadSize:
85 | num = size_checksum_field;
86 | break;
87 |
88 | case waitingForStx:
89 | case clearBuffer:
90 | default:
91 | num = 1;
92 | break;
93 | }
94 |
95 | if (verbose) {
96 | printf("[state(%d):%02d]", state, num);
97 | }
98 | return num;
99 | }
100 |
101 | void PacketFinderBase::getBuffer(BufferType &bufferRef) { bufferRef = buffer; }
102 |
103 | void PacketFinderBase::getPayload(BufferType &bufferRef) {
104 | bufferRef.clear();
105 |
106 | bufferRef.resize(buffer.size() - size_stx - size_checksum_field);
107 | for (unsigned int i = size_stx; i < buffer.size() - size_checksum_field;
108 | i++) {
109 | bufferRef.push_back(buffer[i]);
110 | }
111 | }
112 |
113 | /**
114 | * Checks for incoming packets.
115 | *
116 | * @param incoming
117 | * @param numberOfIncoming
118 | * @return bool : true if a valid incoming packet has been found.
119 | */
120 | bool PacketFinderBase::update(const unsigned char *incoming,
121 | unsigned int numberOfIncoming) {
122 | // clearBuffer = 0, waitingForStx, waitingForPayloadSize,
123 | // waitingForPayloadToEtx, waitingForEtx,
124 | // std::cout << "update [" << numberOfIncoming << "][" << state << "]" <<
125 | // std::endl;
126 | if (!(numberOfIncoming > 0)) return false;
127 |
128 | bool found_packet(false);
129 |
130 | if (state == clearBuffer) {
131 | buffer.clear();
132 | state = waitingForStx;
133 | }
134 | switch (state) {
135 | case waitingForStx:
136 | if (WaitForStx(incoming[0])) {
137 | state = waitingForFlag;
138 | }
139 | break;
140 | case waitingForFlag:
141 | if (WaitForFlag(incoming[0])) {
142 | size_payload = 8;
143 | state = waitingForPayloadToEtx;
144 | }
145 |
146 | break;
147 | case waitingForPayloadToEtx:
148 | if (waitForPayloadAndEtx(incoming, numberOfIncoming, found_packet)) {
149 | state = clearBuffer;
150 | }
151 | break;
152 |
153 | default:
154 | state = waitingForStx;
155 | break;
156 | }
157 | if (found_packet) {
158 | return checkSum();
159 | } else {
160 | return false;
161 | }
162 | }
163 | /*****************************************************************************
164 | ** Protected
165 | *****************************************************************************/
166 |
167 | bool PacketFinderBase::WaitForStx(const unsigned char datum) {
168 | bool found_stx(true);
169 |
170 | // add incoming datum
171 | buffer.push_back(datum);
172 |
173 | // check whether we have STX
174 | for (unsigned int i = 0; i < buffer.size() && i < STX.size(); i++) {
175 | if (buffer[i] != STX[i]) {
176 | found_stx = false;
177 | buffer.pop_front();
178 | break;
179 | }
180 | }
181 |
182 | return (found_stx && buffer.size() == STX.size());
183 | }
184 |
185 | bool PacketFinderBase::WaitForFlag(const unsigned char datum) {
186 | bool found_id(true);
187 |
188 | buffer.push_back(datum);
189 |
190 | return found_id;
191 | }
192 |
193 | bool PacketFinderBase::waitForPayloadSize(const unsigned char *incoming,
194 | unsigned int numberOfIncoming) {
195 | // push data
196 | unsigned char first_byte;
197 | for (unsigned int i = 0; i < numberOfIncoming; i++) {
198 | first_byte = incoming[i];
199 | buffer.push_back(incoming[i]);
200 | }
201 |
202 | if (verbose) {
203 | for (unsigned int i = 0; i < buffer.size(); i++) printf("%02x ", buffer[i]);
204 | printf("\n");
205 | }
206 |
207 | // check when we need to wait for etx
208 | if (buffer.size() < size_stx + 1 + size_length_field) {
209 | return false;
210 | } else {
211 | size_payload = buffer[size_stx + 1];
212 | }
213 |
214 | if (verbose) {
215 | printf("[payloadSize: %d]\n", size_payload);
216 | }
217 |
218 | return true;
219 | }
220 |
221 | bool PacketFinderBase::waitForEtx(const unsigned char incoming,
222 | bool &foundPacket) {
223 | // push data
224 | buffer.push_back(incoming);
225 |
226 | // check when we need to wait for etx
227 | // if minimum payload size is 1
228 | if (buffer.size() < size_stx + size_etx + 1) {
229 | return false;
230 | } else {
231 | unsigned int number_of_match(0);
232 | for (unsigned int i = 0; i < ETX.size(); i++) {
233 | if (buffer[buffer.size() - ETX.size() + i] == ETX[i]) {
234 | number_of_match++;
235 | }
236 | }
237 |
238 | if (number_of_match == ETX.size()) {
239 | foundPacket = true;
240 | return true;
241 | }
242 |
243 | if (buffer.size() >= size_stx + size_max_payload + size_etx)
244 | return true;
245 | else
246 | return false;
247 | }
248 | }
249 |
250 | bool PacketFinderBase::waitForPayloadAndEtx(const unsigned char *incoming,
251 | unsigned int numberOfIncoming,
252 | bool &foundPacket) {
253 | // push data
254 | for (unsigned int i = 0; i < numberOfIncoming; i++) {
255 | buffer.push_back(incoming[i]);
256 | }
257 |
258 | if (size_payload > size_max_payload) {
259 | state = clearBuffer;
260 |
261 | return false;
262 | }
263 | // std::cout << buffer.size() << endl;
264 | // check when we need to wait for etx
265 | if (buffer.size() < size_stx + size_length_field + size_payload +
266 | size_checksum_field + size_etx) {
267 | return false;
268 | } else {
269 | foundPacket = true;
270 | return true;
271 | }
272 | }
273 | }
274 |
--------------------------------------------------------------------------------
/src/driver/data.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file /xbot_arm_driver/src/driver/core_sensors.cpp
3 | *
4 | * @brief Implementation of the core sensor packet data.
5 | *
6 | * License: BSD
7 | * https://raw.github.com/yujinrobot/xbot_core/hydro-devel/xbot_arm_driver/LICENSE
8 | **/
9 |
10 | /*****************************************************************************
11 | ** Includes
12 | *****************************************************************************/
13 |
14 | #include "../../include/wit_node/data.hpp"
15 | #include
16 | #include "../../include/wit_node/packet_handler/payload_headers.hpp"
17 | /*****************************************************************************
18 | ** Namespaces
19 | *****************************************************************************/
20 |
21 | namespace wit {
22 |
23 | /*****************************************************************************
24 | ** Implementation
25 | *****************************************************************************/
26 |
27 | bool Data::serialise(ecl::PushAndPop &byteStream) { return true; }
28 |
29 | bool Data::desTime(ecl::PushAndPop &byteStream) {
30 | uint8_t tmpL, tmpH;
31 | uint16_t tmp;
32 | buildVariable(tmpL, byteStream); // 20YY
33 | // std::cout << int(tmpL) << std::endl;
34 | buildVariable(tmpL, byteStream); // MM
35 | buildVariable(tmpL, byteStream); // DD
36 | imugps_.timestamp = tmpL * 24 * 60 * 60.0;
37 | buildVariable(tmpL, byteStream); // HH
38 | imugps_.timestamp += tmpL * 60 * 60.0;
39 | buildVariable(tmpL, byteStream); // MM
40 | imugps_.timestamp += tmpL * 60.0;
41 | buildVariable(tmpL, byteStream); // SS
42 | imugps_.timestamp += tmpL;
43 | buildVariable(tmp, byteStream); // MSL,MSH
44 | imugps_.timestamp += tmp / 1000.0;
45 | if (byteStream.size() == 0) {
46 | // std::cout << imugps_.timestamp << std::endl;
47 | return true;
48 | } else {
49 | return false;
50 | }
51 | }
52 |
53 | bool Data::desAcce(ecl::PushAndPop &byteStream) {
54 | int16_t tmp;
55 | buildVariable(tmp, byteStream); // accx
56 | imugps_.a[0] = tmp * 16 * 9.8 / 32768;
57 | buildVariable(tmp, byteStream); // accy
58 | imugps_.a[1] = tmp * 16 * 9.8 / 32768;
59 | buildVariable(tmp, byteStream); // accz
60 | imugps_.a[2] = tmp * 16 * 9.8 / 32768;
61 | buildVariable(tmp, byteStream);
62 | imugps_.temperature = tmp / 100.0;
63 | if (byteStream.size() == 0) {
64 | // std::cout << imugps_.a[2] << std::endl;
65 | return true;
66 | } else {
67 | return false;
68 | }
69 | }
70 | bool Data::desGyro(ecl::PushAndPop &byteStream) {
71 | int16_t tmp;
72 | buildVariable(tmp, byteStream); // wx
73 | imugps_.w[0] = tmp * 2000.0 * 3.1415926 / (32768 * 180.0);
74 | buildVariable(tmp, byteStream); // wy
75 | imugps_.w[1] = tmp * 2000.0 * 3.1415926 / (32768 * 180.0);
76 | buildVariable(tmp, byteStream); // wz
77 | imugps_.w[2] = tmp * 2000.0 * 3.1415926 / (32768 * 180.0);
78 | buildVariable(tmp, byteStream);
79 | imugps_.temperature = tmp / 100.0;
80 | if (byteStream.size() == 0) {
81 | // std::cout << imugps_.w[0] << std::endl;
82 | return true;
83 | } else {
84 | return false;
85 | }
86 | }
87 |
88 | // Given the measurement as a float (incorrectly), convert it to decimal degrees.
89 | static float fixBits(float measurement, const char *name) {
90 | static const float seven_zeros = 10000000;
91 |
92 | int int_measurement = reinterpret_cast(measurement);
93 | float degrees = int_measurement / seven_zeros;
94 | float minutes_and_seconds = (int_measurement % (int)seven_zeros) / seven_zeros;
95 | return degrees + minutes_and_seconds * 100 / 60;
96 | }
97 |
98 | bool Data::desLola(ecl::PushAndPop &byteStream) {
99 | buildVariable(imugps_.longtitude, byteStream);
100 | buildVariable(imugps_.latitude, byteStream);
101 |
102 | imugps_.latitude = fixBits(imugps_.latitude, "latitude");
103 | imugps_.longtitude = fixBits(imugps_.longtitude, "longitude");
104 | if (byteStream.size() == 0) {
105 | // std::cout << imugps_.pressure << std::endl;
106 | return true;
107 | } else {
108 | return false;
109 | }
110 | }
111 | bool Data::desMag(ecl::PushAndPop &byteStream) {
112 | int16_t tmp;
113 | buildVariable(tmp, byteStream); // magx
114 | imugps_.mag[0] = tmp;
115 | buildVariable(tmp, byteStream); // magy
116 | imugps_.mag[1] = tmp;
117 | buildVariable(tmp, byteStream); // magz
118 | imugps_.mag[2] = tmp;
119 | buildVariable(tmp, byteStream);
120 | imugps_.temperature = tmp / 100.0;
121 | if (byteStream.size() == 0) {
122 | // std::cout << imugps_.mag[0] << std::endl;
123 | return true;
124 | } else {
125 | return false;
126 | }
127 | }
128 | bool Data::desPalt(ecl::PushAndPop &byteStream) {
129 | buildVariable(imugps_.pressure, byteStream);
130 | buildVariable(imugps_.altitude, byteStream);
131 | if (byteStream.size() == 0) {
132 | // std::cout << imugps_.pressure << std::endl;
133 | return true;
134 | } else {
135 | return false;
136 | }
137 | }
138 | bool Data::desQuat(ecl::PushAndPop &byteStream) {
139 | int16_t tmp;
140 | buildVariable(tmp, byteStream);
141 | imugps_.q[0] = tmp / 32768.0;
142 | buildVariable(tmp, byteStream);
143 | imugps_.q[1] = tmp / 32768.0;
144 | buildVariable(tmp, byteStream);
145 | imugps_.q[2] = tmp / 32768.0;
146 | buildVariable(tmp, byteStream);
147 | imugps_.q[3] = tmp / 32768.0;
148 | if (byteStream.size() == 0) {
149 | // std::cout << imugps_.q[0] << std::endl;
150 | return true;
151 | } else {
152 | return false;
153 | }
154 | }
155 | bool Data::desSate(ecl::PushAndPop &byteStream) {
156 | buildVariable(imugps_.satelites, byteStream);
157 | uint16_t tmp;
158 | buildVariable(tmp, byteStream);
159 | imugps_.gpsa[0] = tmp / 100.0;
160 | buildVariable(tmp, byteStream);
161 | imugps_.gpsa[1] = tmp / 100.0;
162 | buildVariable(tmp, byteStream);
163 | imugps_.gpsa[2] = tmp / 100.0;
164 | if (byteStream.size() == 0) {
165 | // std::cout << imugps_.gpsa[0] << std::endl;
166 | return true;
167 | } else {
168 | return false;
169 | }
170 | }
171 | bool Data::desState(ecl::PushAndPop &byteStream) {
172 | int16_t tmp;
173 | buildVariable(tmp, byteStream); // D0
174 | imugps_.d[0] = tmp;
175 | buildVariable(tmp, byteStream); // D1
176 | imugps_.d[1] = tmp;
177 | buildVariable(tmp, byteStream); // D2
178 | imugps_.d[2] = tmp;
179 | buildVariable(tmp, byteStream); // D3
180 | imugps_.d[3] = tmp;
181 | if (byteStream.size() == 0) {
182 | // std::cout << imugps_.d[0] << std::endl;
183 | return true;
184 | } else {
185 | return false;
186 | }
187 | }
188 | bool Data::desRpy(ecl::PushAndPop &byteStream) {
189 | int16_t tmp;
190 | buildVariable(tmp, byteStream); // roll
191 | imugps_.rpy[0] = tmp * 3.1415926 / 32768;
192 | buildVariable(tmp, byteStream); // pitch
193 | imugps_.rpy[1] = tmp * 3.1415926 / 32768;
194 | buildVariable(tmp, byteStream); // yaw
195 | imugps_.rpy[2] = tmp * 3.1415926 / 32768;
196 | buildVariable(tmp, byteStream);
197 | imugps_.temperature = tmp / 100.0;
198 | if (byteStream.size() == 0) {
199 | // std::cout << imugps_.rpy[0] << std::endl;
200 | return true;
201 | } else {
202 | return false;
203 | }
204 | }
205 | bool Data::desGpsv(ecl::PushAndPop &byteStream) {
206 | int16_t tmp;
207 | buildVariable(tmp, byteStream); // gpsh
208 | imugps_.gpsh = tmp / 10.0;
209 | buildVariable(tmp, byteStream); // gpsy
210 | imugps_.gpsy = tmp / 10.0;
211 | buildVariable(imugps_.gpsv, byteStream); // accz
212 | imugps_.gpsv = imugps_.gpsv / 1000.0;
213 | if (byteStream.size() == 0) {
214 | // std::cout << imugps_.gpsv << std::endl;
215 | return true;
216 | } else {
217 | return false;
218 | }
219 | }
220 | bool Data::deserialise(ecl::PushAndPop &byteStream) {
221 | uint8_t flag;
222 | buildVariable(flag, byteStream);
223 | switch (flag) {
224 | case Flags::TIME:
225 | desTime(byteStream);
226 | break;
227 | case Flags::ACCE:
228 | desAcce(byteStream);
229 | break;
230 | case Flags::GYRO:
231 | desGyro(byteStream);
232 | break;
233 | case Flags::RPY:
234 | desRpy(byteStream);
235 | break;
236 | case Flags::MAG:
237 | desMag(byteStream);
238 | break;
239 | case Flags::STATE:
240 | desState(byteStream);
241 | break;
242 | case Flags::PALT:
243 | desPalt(byteStream);
244 | break;
245 | case Flags::LOLA:
246 | desLola(byteStream);
247 | break;
248 | case Flags::GPSV:
249 | desGpsv(byteStream);
250 | break;
251 | case Flags::QUAT:
252 | desQuat(byteStream);
253 | break;
254 | case Flags::SATE:
255 | desSate(byteStream);
256 | break;
257 | default:
258 | break;
259 | }
260 |
261 | return true;
262 | }
263 |
264 | void Data::build_special_variable(float &variable, ecl::PushAndPop &byteStream) {
265 | if (byteStream.size() < 2) return;
266 |
267 | unsigned char a, b;
268 | buildVariable(a, byteStream);
269 | buildVariable(b, byteStream);
270 | variable = ((unsigned int)(a & 0x0f)) / 100.0;
271 |
272 | variable += ((unsigned int)(a >> 4)) / 10.0;
273 |
274 | variable += (unsigned int)(b & 0x0f);
275 |
276 | variable += ((unsigned int)(b >> 4)) * 10;
277 | }
278 |
279 | } // namespace wit
280 |
--------------------------------------------------------------------------------