diff --git a/src/segway_msgs/CMakeLists.txt b/src/segway_msgs/CMakeLists.txt new file mode 100755 index 0000000..7dc8e36 --- /dev/null +++ b/src/segway_msgs/CMakeLists.txt @@ -0,0 +1,76 @@ +cmake_minimum_required(VERSION 3.5) +project(segway_msgs) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpic") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fpic") +# Default to C99 +if(NOT CMAKE_C_STANDARD) + set(CMAKE_C_STANDARD 99) +endif() + +# Default to C++14 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 14) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +# find dependencies +find_package(ament_cmake REQUIRED) +find_package(std_msgs REQUIRED) +####find_package(builtin_interface REQUIRED) +find_package(geometry_msgs REQUIRED) +find_package(rosidl_default_generators REQUIRED) +find_package(action_msgs REQUIRED) + +set(msg_files + "msg/BmsFb.msg" + "msg/ChassisCtrlSrcFb.msg" + "msg/ChassisMileageMeterFb.msg" + "msg/ChassisModeFb.msg" + "msg/ErrorCodeFb.msg" + "msg/MotorWorkModeFb.msg" + "msg/SpeedFb.msg" + "msg/TicksFb.msg" +) + +set(srv_files + "srv/ChassisSendEvent.srv" + "srv/RosGetChargeMosCtrlStatusCmd.srv" + "srv/RosGetLoadParamCmd.srv" + "srv/RosGetSwVersionCmd.srv" + "srv/RosGetVelMaxFeedbackCmd.srv" + "srv/RosSetChargeMosCtrlCmd.srv" + "srv/RosSetChassisEnableCmd.srv" + "srv/RosSetChassisPoweroffCmd.srv" + "srv/RosSetLoadParamCmd.srv" + "srv/RosSetRemovePushCmd.srv" + "srv/RosSetVelMaxCmd.srv") + +set(action_files + "action/RosSetIapCmd.action" +) +rosidl_generate_interfaces(${PROJECT_NAME} + ${msg_files} + ${srv_files} + ${action_files} + DEPENDENCIES geometry_msgs std_msgs ADD_LINTER_TESTS) + +# ament_export_dependencies(rosidl_default_generators) +# ament_export_dependencies(rosidl_default_runtime) +# ament_export_include_directories(include) + +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + # the following line skips the linter which checks for copyrights + # uncomment the line when a copyright and license is not present in all source files + #set(ament_cmake_copyright_FOUND TRUE) + # the following line skips cpplint (only works in a git repo) + # uncomment the line when this package is not in a git repo + #set(ament_cmake_cpplint_FOUND TRUE) + ament_lint_auto_find_test_dependencies() +endif() + +ament_package() diff --git a/src/segway_msgs/action/RosSetIapCmd.action b/src/segway_msgs/action/RosSetIapCmd.action new file mode 100644 index 0000000..5e7da2b --- /dev/null +++ b/src/segway_msgs/action/RosSetIapCmd.action @@ -0,0 +1,6 @@ +int16 iap_board #1:iap central board; 2:iap motor board +--- +int16 iap_result #3: iap_state_complete; 4: iap_state_fail; 5: iap_state_abort +int16 error_code #When iap_result value is 4, this value represents the error code +--- +int16 iap_percent \ No newline at end of file diff --git a/src/segway_msgs/msg/BmsFb.msg b/src/segway_msgs/msg/BmsFb.msg new file mode 100644 index 0000000..aa841bf --- /dev/null +++ b/src/segway_msgs/msg/BmsFb.msg @@ -0,0 +1,5 @@ +int16 bat_soc +int16 bat_charging +int32 bat_vol +int32 bat_current +int16 bat_temp diff --git a/src/segway_msgs/msg/ChassisCtrlSrcFb.msg b/src/segway_msgs/msg/ChassisCtrlSrcFb.msg new file mode 100644 index 0000000..d159dd7 --- /dev/null +++ b/src/segway_msgs/msg/ChassisCtrlSrcFb.msg @@ -0,0 +1 @@ +uint16 chassis_ctrl_cmd_src \ No newline at end of file diff --git a/src/segway_msgs/msg/ChassisMileageMeterFb.msg b/src/segway_msgs/msg/ChassisMileageMeterFb.msg new file mode 100644 index 0000000..71d1bec --- /dev/null +++ b/src/segway_msgs/msg/ChassisMileageMeterFb.msg @@ -0,0 +1 @@ +uint32 vehicle_meters \ No newline at end of file diff --git a/src/segway_msgs/msg/ChassisModeFb.msg b/src/segway_msgs/msg/ChassisModeFb.msg new file mode 100644 index 0000000..3745d2a --- /dev/null +++ b/src/segway_msgs/msg/ChassisModeFb.msg @@ -0,0 +1 @@ +uint16 chassis_mode \ No newline at end of file diff --git a/src/segway_msgs/msg/ErrorCodeFb.msg b/src/segway_msgs/msg/ErrorCodeFb.msg new file mode 100644 index 0000000..e2fa46b --- /dev/null +++ b/src/segway_msgs/msg/ErrorCodeFb.msg @@ -0,0 +1,5 @@ +uint32 host_error +uint32 central_error +uint16 left_motor_error +uint16 right_motor_error +uint32 bms_error \ No newline at end of file diff --git a/src/segway_msgs/msg/MotorWorkModeFb.msg b/src/segway_msgs/msg/MotorWorkModeFb.msg new file mode 100644 index 0000000..1ee2876 --- /dev/null +++ b/src/segway_msgs/msg/MotorWorkModeFb.msg @@ -0,0 +1 @@ +uint16 motor_work_mode #0: no output torque 1: output torque \ No newline at end of file diff --git a/src/segway_msgs/msg/SpeedFb.msg b/src/segway_msgs/msg/SpeedFb.msg new file mode 100644 index 0000000..e2c22b4 --- /dev/null +++ b/src/segway_msgs/msg/SpeedFb.msg @@ -0,0 +1,5 @@ +float32 car_speed +float32 turn_speed +float32 l_speed +float32 r_speed +uint64 speed_timestamp \ No newline at end of file diff --git a/src/segway_msgs/msg/TicksFb.msg b/src/segway_msgs/msg/TicksFb.msg new file mode 100644 index 0000000..49553f4 --- /dev/null +++ b/src/segway_msgs/msg/TicksFb.msg @@ -0,0 +1,3 @@ +int32 l_ticks +int32 r_ticks +uint64 ticks_timestamp \ No newline at end of file diff --git a/src/segway_msgs/package.xml b/src/segway_msgs/package.xml new file mode 100755 index 0000000..0de6505 --- /dev/null +++ b/src/segway_msgs/package.xml @@ -0,0 +1,26 @@ + + + + segway_msgs + 0.0.0 + TODO: Package description + ninebot + TODO: License declaration + + ament_cmake + + rosidl_default_generators + rosidl_default_runtime + rosidl_interface_packages + + std_msgs + geometry_msgs + action_msgs + + ament_lint_auto + ament_lint_common + + + ament_cmake + + diff --git a/src/segway_msgs/srv/ChassisSendEvent.srv b/src/segway_msgs/srv/ChassisSendEvent.srv new file mode 100644 index 0000000..1dd5276 --- /dev/null +++ b/src/segway_msgs/srv/ChassisSendEvent.srv @@ -0,0 +1,3 @@ +int16 chassis_send_event_id +--- +bool ros_is_received \ No newline at end of file diff --git a/src/segway_msgs/srv/RosGetChargeMosCtrlStatusCmd.srv b/src/segway_msgs/srv/RosGetChargeMosCtrlStatusCmd.srv new file mode 100644 index 0000000..a9eac33 --- /dev/null +++ b/src/segway_msgs/srv/RosGetChargeMosCtrlStatusCmd.srv @@ -0,0 +1,3 @@ +bool ros_get_chassis_charge_ctrl_status +--- +int16 chassis_charge_ctrl_status \ No newline at end of file diff --git a/src/segway_msgs/srv/RosGetLoadParamCmd.srv b/src/segway_msgs/srv/RosGetLoadParamCmd.srv new file mode 100644 index 0000000..5c5f212 --- /dev/null +++ b/src/segway_msgs/srv/RosGetLoadParamCmd.srv @@ -0,0 +1,3 @@ +bool ros_get_load_param +--- +int16 get_load_param #0:no_load, 1: full_load \ No newline at end of file diff --git a/src/segway_msgs/srv/RosGetSwVersionCmd.srv b/src/segway_msgs/srv/RosGetSwVersionCmd.srv new file mode 100644 index 0000000..8ea2df5 --- /dev/null +++ b/src/segway_msgs/srv/RosGetSwVersionCmd.srv @@ -0,0 +1,5 @@ +bool ros_get_sw_version_cmd +--- +uint16 host_version +uint16 central_version +uint16 motor_version \ No newline at end of file diff --git a/src/segway_msgs/srv/RosGetVelMaxFeedbackCmd.srv b/src/segway_msgs/srv/RosGetVelMaxFeedbackCmd.srv new file mode 100644 index 0000000..f1bf0d2 --- /dev/null +++ b/src/segway_msgs/srv/RosGetVelMaxFeedbackCmd.srv @@ -0,0 +1,5 @@ +bool ros_get_vel_max_fb_cmd +--- +uint16 forward_max_vel_fb +uint16 backward_max_vel_fb +uint16 angular_max_vel_fb \ No newline at end of file diff --git a/src/segway_msgs/srv/RosSetChargeMosCtrlCmd.srv b/src/segway_msgs/srv/RosSetChargeMosCtrlCmd.srv new file mode 100644 index 0000000..9c69946 --- /dev/null +++ b/src/segway_msgs/srv/RosSetChargeMosCtrlCmd.srv @@ -0,0 +1,3 @@ +bool ros_set_chassis_charge_ctrl +--- +uint8 chassis_set_charge_ctrl_result \ No newline at end of file diff --git a/src/segway_msgs/srv/RosSetChassisEnableCmd.srv b/src/segway_msgs/srv/RosSetChassisEnableCmd.srv new file mode 100644 index 0000000..b7a82c5 --- /dev/null +++ b/src/segway_msgs/srv/RosSetChassisEnableCmd.srv @@ -0,0 +1,3 @@ +bool ros_set_chassis_enable_cmd +--- +uint8 chassis_set_chassis_enable_result \ No newline at end of file diff --git a/src/segway_msgs/srv/RosSetChassisPoweroffCmd.srv b/src/segway_msgs/srv/RosSetChassisPoweroffCmd.srv new file mode 100644 index 0000000..df2e8dd --- /dev/null +++ b/src/segway_msgs/srv/RosSetChassisPoweroffCmd.srv @@ -0,0 +1,3 @@ +bool ros_set_chassis_poweroff_cmd +--- +uint8 chassis_set_poweroff_result \ No newline at end of file diff --git a/src/segway_msgs/srv/RosSetLoadParamCmd.srv b/src/segway_msgs/srv/RosSetLoadParamCmd.srv new file mode 100644 index 0000000..5d61f2e --- /dev/null +++ b/src/segway_msgs/srv/RosSetLoadParamCmd.srv @@ -0,0 +1,3 @@ +int16 ros_set_load_param #0:no_load, 1: full_load +--- +uint8 chassis_set_load_param_result \ No newline at end of file diff --git a/src/segway_msgs/srv/RosSetRemovePushCmd.srv b/src/segway_msgs/srv/RosSetRemovePushCmd.srv new file mode 100644 index 0000000..a13175f --- /dev/null +++ b/src/segway_msgs/srv/RosSetRemovePushCmd.srv @@ -0,0 +1,3 @@ +bool ros_set_remove_push_cmd +--- +uint8 chassis_set_revove_push_result \ No newline at end of file diff --git a/src/segway_msgs/srv/RosSetVelMaxCmd.srv b/src/segway_msgs/srv/RosSetVelMaxCmd.srv new file mode 100644 index 0000000..8a26de4 --- /dev/null +++ b/src/segway_msgs/srv/RosSetVelMaxCmd.srv @@ -0,0 +1,5 @@ +float64 ros_set_forward_max_vel +float64 ros_set_backward_max_vel +float64 ros_set_angular_max_vel +--- +uint8 chassis_set_max_vel_result \ No newline at end of file diff --git a/src/segwayrmp/CMakeLists.txt b/src/segwayrmp/CMakeLists.txt new file mode 100755 index 0000000..92797ab --- /dev/null +++ b/src/segwayrmp/CMakeLists.txt @@ -0,0 +1,81 @@ +cmake_minimum_required(VERSION 3.5) +project(segwayrmp) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpic -Wl,-R${PROJECT_SOURCE_DIR}/lib") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fpic") +# Default to C99 +if(NOT CMAKE_C_STANDARD) + set(CMAKE_C_STANDARD 99) +endif() + +# Default to C++14 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 14) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +# find dependencies +find_package(ament_cmake REQUIRED) +find_package(rclcpp REQUIRED) +find_package(rclpy REQUIRED) +find_package(std_msgs REQUIRED) +find_package(nav_msgs REQUIRED) +find_package(sensor_msgs REQUIRED) +find_package(geometry_msgs REQUIRED) +find_package(segway_msgs REQUIRED) +find_package(tf2 REQUIRED) +find_package(tf2_ros REQUIRED) +find_package(rclcpp_action REQUIRED) +find_package(rclcpp_components REQUIRED) + +add_executable(SmartCar + src/SmartCar.cpp + src/robot.cpp +) +target_include_directories(SmartCar PUBLIC + $ + $ +) +target_link_directories(SmartCar PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/lib +) +# message(WARNING ${PROJECT_SOURCE_DIR} + "!!" + ${CMAKE_CURRENT_SOURCE_DIR} + "!!" + ${PROJECT_NAME}) +ament_target_dependencies(SmartCar + "rclcpp" "std_msgs" "nav_msgs" "sensor_msgs" "geometry_msgs" "segway_msgs" "tf2" "tf2_ros" +) +target_link_libraries(SmartCar + ${PROJECT_SOURCE_DIR}/lib/libctrl_x86_64.so +) + +add_executable(drive_segway_sample + tools/drive_segway_sample.cpp +) +target_include_directories(drive_segway_sample PUBLIC + $ + $ +) +ament_target_dependencies(drive_segway_sample + "rclcpp" "std_msgs" "nav_msgs" "sensor_msgs" "geometry_msgs" "segway_msgs" "tf2" "tf2_ros" +) + +install(TARGETS + SmartCar + drive_segway_sample + DESTINATION + lib/${PROJECT_NAME}) + +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + # the following line skips the linter which checks for copyrights + # uncomment the line when a copyright and license is not present in all source files + #set(ament_cmake_copyright_FOUND TRUE) + # the following line skips cpplint (only works in a git repo) + # uncomment the line when this package is not in a git repo + #set(ament_cmake_cpplint_FOUND TRUE) + ament_lint_auto_find_test_dependencies() +endif() + +ament_package() diff --git a/src/segwayrmp/include/comm_ctrl.h b/src/segwayrmp/include/comm_ctrl.h new file mode 100644 index 0000000..71abc33 --- /dev/null +++ b/src/segwayrmp/include/comm_ctrl.h @@ -0,0 +1,109 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef COMM_CTRL_H +#define COMM_CTRL_H + +#include +#include +#include "comm_ctrl_navigation.h" + + +// Map table transmission value gain coefficient; +#define ERROR_LINE_LIMIT_VEL_VALUE (5 * LINE_SPEED_TRANS_GAIN_MPS) +#define ERROR_ANGULAR_LIMIT_VEL_VALUE (5 * ANGULAR_SPEED_TRANS_GAIN_RADPS) +#define ACC_VALUE_GAIN 100 + + +#define RMP_HOST_ERR_BIT_MCU_HEART_BEAT 0 //The heartbeat with the chassis was interrupted +#define RMP_HOST_ERR_BIT_SERIAL_PORT_LOST 1 //Serial port module unplugged + +void AprGxJniEventRegister(int32_t (*callback)(int32_t)); + +//-------------------Timestamp------------------------ + +//--------------------GX--API------------------ +int init_control(void); +void exit_control(void); + +int16_t get_forward_speed_limit(void); +int16_t get_backward_speed_limit(void); +int16_t get_angular_speed_limit(void); +uint16_t get_Stop_Bottom_Status(void); +uint8_t set_calib_chassis_imu_gyro(void);//Reserve for later versions +uint16_t get_Chassis_Imu_Calib_Result(void); //Reserve for later versions +void clear_Chassis_Imu_Calib_Result(void);//Reserve for later versions +uint8_t set_calib_chassis_current(void); +uint16_t get_chassis_current_calib_result(void); +void clear_chassis_current_calib_result(void); + + +//-----------------GX IAP-------------------- +void IapAllBoard(const char **file_paths, char **versions); +int32_t IapSingerBoard(char * path,char * boradname,char* version); +//int32_t getIapTotalProgress(void); +//------------------GX Host------------------- + +char* GetGxHardVersion(void); +void TracePrint_Switch(bool status); //true or false +void SetNavigationStatus(uint8_t status); +void setSaveRecordCmd(void); //开始保存log接口     ps:上层调用 +void clearRecordCmd(void); //清除保存log命令     ps:上层不需要调�?so每次保存完log后会自动调用 +uint8_t getSaveRecordCmd(void); //获取是否开始保存log   ps:so自动调用,上层不需要调�? +uint8_t GetNavigationStatus(void); + + +void set_gx_route_bat_voltage(uint16_t voltage); + + +int16_t get_cmd_speed_forward(void); +int16_t get_fbk_speed_forward(void); +int16_t get_encode_fbk_speed_forward(void); +int16_t get_cmd_w_forward(void); +int16_t get_fbk_w_forward(void); +int16_t get_rec_cmd_vx(void); +int16_t get_rec_cmd_w(void); +int16_t get_pid_target_vx(void); +int16_t get_pid_target_w(void); +int16_t get_encode_speed_L(void); +int16_t get_encode_speed_R(void); + +int16_t get_heart_beat_data(board_name_e board_type); + +void set_host_error(uint8_t offset, uint8_t err_bool_value); +uint32_t get_host_error(void); +uint32_t get_host_speed_cmd_cnt(void); +uint32_t get_chassis_reply_speed_cmd_cnt(void); +int32_t get_encoder_l_ticks(void); +int32_t get_encoder_r_ticks(void); +char * get_smart_car_serial(void); +uint8_t get_comu_interface_serial0_can1(); +void showHostBuildTime(void); +void showChassisCentralBuildTime(void); + +/* 暂时不开放此接口,由于map表只能发送整数,故此接口待修改:乘以10或�?00下发,电机板收到命令数据后再恢复数据 */ +uint8_t set_cmd_acc(double linear_x_acc, double linear_x_brake_acc, double angular_z_acc);//Set the linear and angular accelerated speed: m/s2 ; rad/s2. + +uint8_t set_chassis_no_load(void); +uint8_t set_chassis_full_load(void); + +void ackWriteCentralMapInit(); +uint8_t ctrlMapAckWrite( uint8_t dest_id, uint8_t map_start_index, uint32_t mem_len); + +void set_chassis_charge_status(int16_t chargestatus); +uint32_t get_chassis_central_Err_Status(void); +uint16_t get_chassis_l_motor_Err_Status(void); +uint16_t get_chassis_r_motor_Err_Status(void); +uint32_t get_chassis_bms_Err_Status(void); +char * show_host_version(void); + + +int16_t get_charge_mos_ctrl_cmd(void);// Get chassis charge_ctrl mos cmd; 1:turn on; 0: turn off + +#endif + +#ifdef __cplusplus +} +#endif + diff --git a/src/segwayrmp/include/comm_ctrl_navigation.h b/src/segwayrmp/include/comm_ctrl_navigation.h new file mode 100644 index 0000000..9a3d365 --- /dev/null +++ b/src/segwayrmp/include/comm_ctrl_navigation.h @@ -0,0 +1,180 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef COMM_CTRL_NAVIGATION_H +#define COMM_CTRL_NAVIGATION_H + +#include +#include + +#define TYPE_ID_NUM 10 //Number of callback functions +//--------------------------DATA CALL BACK INDEX-------------------------- +#define Chassis_Data_Speed 1 +#define Chassis_Data_Ticks 2 +#define Chassis_Data_Odom_Pose_xy 3 +#define Chassis_Data_Odom_Euler_xy 4 +#define Chassis_Data_Odom_Euler_z 5 +#define Chassis_Data_Odom_Linevel_xy 6 +#define Chassis_Data_Imu_Gyr 7 //IMU Gyroscope data 陀螺仪数据上报 +#define Chassis_Data_Imu_Acc 8 //IMU Accelerometer data 加速度计数据上�? + +//-----------------------Event--------------------------------------------- +#define ChassisBootReadyEvent 1 // Chassis central control boot OK +#define PadPowerOffEvent 2 // The chassis will power off +#define OnEmergeStopEvent 3 // The chassis emergency stop button is triggered +#define OutEmergeStopEvent 4 // The chassis emergency stop button recover +#define OnLockedRotorProtectEvent 5 // the chassis motor locked-rotor +#define OutLockedRotorProtectEvent 6 // the chassis motor no longer locked-rotor +#define OnLostCtrlProtectEvent 7 // the chassis motor lost control +#define OutLostCtrlProtectEvent 8 // the chassis motor no longer lost control +#define CalibrateGyroSuccess 9 // Chassis gyroscope calibration successful +#define CalibrateGyroFail 10 // Chassis gyroscope calibration failed +#define CalibratePasheCurrentSuccess 11 // Chassis gyroscope calibration successful +#define CalibratePasheCurrentFail 12 // Chassis gyroscope calibration failed + + +//---------The proportional coefficient of the callback gyro data------------------ +#define CHASSIS_IMU_GYR_VALUE_TRANS_SCALE 900 //900~~32768(MAX value for int16: map table ) * 57.3(degrees for 1 rad) /2000(Gyroscope range: 2000dps) +#define CHASSIS_IMU_ACC_VALUE_TRANS_SCALE 4000 //4000~~32768(MAX value for int16: map table )/8(Accelerometer range: 8g) + +#define LINE_SPEED_TRANS_GAIN_MPS 3600 //3600-->1m/s +#define ANGULAR_SPEED_TRANS_GAIN_RADPS 1000 //1000-->1rad/s + +#define NO_LOAD 0 // Set the chassis parameters as no-load parameters, The chassis defaults to no load +#define FULL_LOAD 1 // Set the chassis parameters as full load parameters + +//-----------------------Version V0.6 and above--------------------------- +#define LOCK_MODE 0 // Lock the car +#define CTRL_MODE 1 // Control the car +#define PUSH_MODE 2 // push the car +#define EMERG_MODE 3 // emergency +#define ERROR_MODE 4 // Internal error + + +//-------------------Timestamp------------------------ +#define MAX_BASIC_FRM_SZ 0x1F + +#pragma pack(1) +typedef struct StampedBasicFrame_{ + uint32_t type_id; //Data type number + uint64_t timestamp; //Linux timestamp + char data[MAX_BASIC_FRM_SZ]; //Chassis specific data +} StampedBasicFrame; +#pragma pack() +typedef void (*h_aprctrl_datastamped_t)(StampedBasicFrame* frm); +typedef void (*h_aprctrl_event_t)(int32_t event_num); + +typedef struct { + h_aprctrl_datastamped_t on_new_data; +}s_aprctrl_datastamped_t; + +typedef struct { + h_aprctrl_event_t event_callback; +}s_aprctrl_event_t; + +typedef enum { + Host = 1, + Central = 2, //底盘只连中控�? + Motor = 3, + BMS = 4 +}board_name_e; + +typedef enum { + comu_serial = 0, + comu_can = 1 +}comu_choice_e; + +typedef struct{ + int16_t l_speed;//Left wheel speed + int16_t r_speed;//Right wheel speed + int16_t car_speed;//Vehicle linear speed + int16_t turn_speed;//Turning speed +}chassis_speed_data_t; + +typedef struct{ + int32_t l_ticks;//Left wheel ticks + int32_t r_ticks;//Right wheel ticks +}motor_ticks_t; + +typedef struct{ + float pos_x; + float pos_y; +}odom_pos_xy_t; + +typedef struct{ + float euler_x; + float euler_y; +}odom_euler_xy_t; + +typedef struct{ + float euler_z; +}odom_euler_z_t; + +typedef struct{ + float vel_line_x; + float vel_line_y; +}odom_vel_line_xy_t; + +typedef struct{ + int16_t gyr[3]; +}imu_gyr_original_data_t; + +typedef struct{ + int16_t acc[3]; +}imu_acc_original_data_t; + + +void aprctrl_datastamped_jni_register(s_aprctrl_datastamped_t* f); //The callback registration function +void aprctrl_eventcallback_jni_register(s_aprctrl_event_t* f); //Event callback registration function + +uint32_t get_err_state(board_name_e board_name);//Gets the software error status +int16_t get_bat_soc(void);//Gets the percentage of battery left +int16_t get_bat_charging(void);//Gets the charging status of the battery +int32_t get_bat_mvol(void);//Gets battery voltage, mV +int32_t get_bat_mcurrent(void);//Gets battery current, mA +int16_t get_bat_temp(void);// Gets battery temperature +int16_t get_chassis_work_model(void);//Get the chassis working mode +uint8_t get_chassis_load_state(void);//Gets whether the chassis parameters are empty or full load, 0: no_load, 1: full_load +uint16_t get_chassis_mode(void);//Gets chassis mode +int16_t get_ctrl_cmd_src(void); // Get the source of the control command +int32_t get_vehicle_meter(void); //Get the total mileage meters of the chssis +uint16_t get_host_version(void); +uint16_t get_chassis_central_version(void); +uint16_t get_chassis_motor_version(void); +int16_t get_line_forward_max_vel_fb(void); +int16_t get_line_backward_max_vel_fb(void); +int16_t get_angular_max_vel_fb(void); +int32_t getIapTotalProgress(void); +void iapCentralBoard(void);//Operate on the Central board: IAP +void iapMotorBoard(void);//Operate on the Motor board: IAP +bool isHostIapOver(void);//Query whether a single IAP ends +int16_t getHostIapResult(void); +int16_t getHostIapErrorCode(void); +int16_t get_chassis_hang_mode(void);//Get chassis hang_mode; 1: in Hang_mode; 0: not in Hand_mode. +int16_t get_charge_mos_ctrl_status(void);//Get the status of switch for charging MOS on the central board, charging:1; no charge:0 + + + +void set_cmd_vel(double linear_x,double angular_z);//Set the linear and angular speeds of the vehicle: m/s ; rad/s. +uint8_t set_line_forward_max_vel(double linear_forward_max_x);//Set the maximum linear velocity in the direction of advance +uint8_t set_line_backward_max_vel(double linear_backward_max_x);//Set the maximum linear velocity in the backward direction +uint8_t set_angular_max_vel(double angular_max_z);//Set the maximum angular velocity +uint8_t set_enable_ctrl(uint16_t enable_flag);//Set chassis movement enable +int init_control_ctrl(void);//Chassis initialization +void exit_control_ctrl(void);//Chassis software finished running +void set_smart_car_serial(const char * serial_no);//Set the serial port name +void set_comu_interface(comu_choice_e comu_choice); //Set communication interface: 'comu_serial': serial port; 'comu_can': CAN port +uint8_t set_chassis_load_state(int16_t newLoadSet);//Sets whether the chassis parameters are empty or full load, 0: no_load, 1: full_load +uint8_t set_chassis_poweroff(void);//Set two - wheel differential chassis shutdown +uint8_t set_remove_push_cmd(void);//An order to remove the push status +void setHostIapCanceled(void); +void set_chassis_hang_mode(int16_t enterHand);//Set chassis hang_mode; 1: enter the Hang_mode; 0: exit the Hand_mode. +uint8_t set_charge_mos_ctrl(bool on);//Set the switch for charging MOS on the central board; charging:1, stop charging:0. + +extern int32_t IapSingerBoard(char * path,char * boradname,char* version); +#endif + +#ifdef __cplusplus +} +#endif diff --git a/src/segwayrmp/include/segwayrmp/robot.h b/src/segwayrmp/include/segwayrmp/robot.h new file mode 100755 index 0000000..e7fef60 --- /dev/null +++ b/src/segwayrmp/include/segwayrmp/robot.h @@ -0,0 +1,169 @@ +#ifndef _ROBOT_H +#define _ROBOT_H + +#include +#include +#include +#include +#include "stdint.h" +#include +#include + +#include +#include "rclcpp/rclcpp.hpp" +#include +#include +#include +#include +#include "tf2_ros/transform_broadcaster.h" +#include +#include "tf2/LinearMath/Quaternion.h" +#include "comm_ctrl_navigation.h" +#include "rclcpp_action/rclcpp_action.hpp" +#include "segway_msgs/msg/bms_fb.hpp" +#include "segway_msgs/msg/chassis_ctrl_src_fb.hpp" +#include "segway_msgs/msg/chassis_mileage_meter_fb.hpp" +#include "segway_msgs/msg/chassis_mode_fb.hpp" +#include "segway_msgs/msg/error_code_fb.hpp" +#include "segway_msgs/msg/motor_work_mode_fb.hpp" +#include "segway_msgs/msg/speed_fb.hpp" +#include "segway_msgs/msg/ticks_fb.hpp" +#include "segway_msgs/srv/chassis_send_event.hpp" +#include "segway_msgs/srv/ros_get_charge_mos_ctrl_status_cmd.hpp" +#include "segway_msgs/srv/ros_get_load_param_cmd.hpp" +#include "segway_msgs/srv/ros_get_sw_version_cmd.hpp" +#include "segway_msgs/srv/ros_get_vel_max_feedback_cmd.hpp" +#include "segway_msgs/srv/ros_set_charge_mos_ctrl_cmd.hpp" +#include "segway_msgs/srv/ros_set_chassis_enable_cmd.hpp" +#include "segway_msgs/srv/ros_set_chassis_poweroff_cmd.hpp" +#include "segway_msgs/srv/ros_set_load_param_cmd.hpp" +#include "segway_msgs/srv/ros_set_remove_push_cmd.hpp" +#include "segway_msgs/srv/ros_set_vel_max_cmd.hpp" +#include "segway_msgs/action/ros_set_iap_cmd.hpp" + +#define pi 3.141592654 +#define pi_2 6.283185308 + +namespace robot +{ + class Chassis + { + public: + using iapCmd = segway_msgs::action::RosSetIapCmd; + using goalHandaleIapCmd = rclcpp_action::ServerGoalHandle; + Chassis(rclcpp::Node::SharedPtr nh); + static void pub_event_callback(int event_no); + private: + std::shared_ptr node; + + std::string bins_directory; + std::string chassis_version; + std::string route_version; + std::string connect_version; + + tf2::Quaternion odom_quat; + std::shared_ptr odom_broadcaster; + + segway_msgs::msg::BmsFb bms_fb; + segway_msgs::msg::ChassisCtrlSrcFb chassis_ctrl_src_fb; + segway_msgs::msg::ChassisMileageMeterFb chassis_mileage_meter_fb; + segway_msgs::msg::ChassisModeFb chassis_mode_fb; + segway_msgs::msg::ErrorCodeFb error_code_fb; + segway_msgs::msg::MotorWorkModeFb motor_work_mode_fb; + segway_msgs::msg::SpeedFb speed_fb; + segway_msgs::msg::TicksFb ticks_fb; + geometry_msgs::msg::TransformStamped odom_trans; + nav_msgs::msg::Odometry odom_fb; + sensor_msgs::msg::Imu imu_fb; + + rclcpp::Subscription::SharedPtr velocity_sub; + + rclcpp::Publisher::SharedPtr bms_fb_pub; + rclcpp::Publisher::SharedPtr chassis_ctrl_src_fb_pub; + rclcpp::Publisher::SharedPtr chassis_mileage_meter_fb_pub; + rclcpp::Publisher::SharedPtr chassis_mode_fb_pub; + rclcpp::Publisher::SharedPtr error_code_fb_pub; + rclcpp::Publisher::SharedPtr motor_work_mode_fb_pub; + rclcpp::Publisher::SharedPtr speed_fb_pub; + rclcpp::Publisher::SharedPtr ticks_fb_pub; + rclcpp::Publisher::SharedPtr odom_pub; + rclcpp::Publisher::SharedPtr imu_pub; + + + rclcpp::Service::SharedPtr ros_get_charge_mos_ctrl_status_cmd_server; + rclcpp::Service::SharedPtr ros_get_load_param_cmd_server; + rclcpp::Service::SharedPtr ros_get_sw_version_cmd_server; + rclcpp::Service::SharedPtr ros_get_vel_max_feedback_cmd_server; + rclcpp::Service::SharedPtr ros_set_charge_mos_ctrl_cmd_server; + rclcpp::Service::SharedPtr ros_set_chassis_enable_cmd_server; + rclcpp::Service::SharedPtr ros_set_chassis_poweroff_cmd_server; + rclcpp::Service::SharedPtr ros_set_load_param_cmd_server; + rclcpp::Service::SharedPtr ros_set_remove_push_cmd_server; + rclcpp::Service::SharedPtr ros_set_vel_max_cmd_server; + + void ros_get_charge_mos_ctrl_status_cmd_callback(const std::shared_ptr request, + std::shared_ptr response); + void ros_get_load_param_cmd_callback(const std::shared_ptr request, + std::shared_ptr response); + void ros_get_sw_version_cmd_callback(const std::shared_ptr request, + std::shared_ptr response); + void ros_get_vel_max_feedback_cmd_callback(const std::shared_ptr request, + std::shared_ptr response); + void ros_set_charge_mos_ctrl_cmd_callback(const std::shared_ptr request, + std::shared_ptr response); + void ros_set_chassis_enable_cmd_callback(const std::shared_ptr request, + std::shared_ptr response); + void ros_set_chassis_poweroff_cmd_callback(const std::shared_ptr request, + std::shared_ptr response); + void ros_set_load_param_cmd_callback(const std::shared_ptr request, + std::shared_ptr response); + void ros_set_remove_push_cmd_callback(const std::shared_ptr request, + std::shared_ptr response); + void ros_set_vel_max_cmd_callback(const std::shared_ptr request, + std::shared_ptr response); + + rclcpp_action::Server::SharedPtr iap_action_server; + + rclcpp::TimerBase::SharedPtr timer_1hz; + rclcpp::TimerBase::SharedPtr timer_1000hz; + + s_aprctrl_datastamped_t timestamp_data; + s_aprctrl_event_t event_data; + + void timer_1000hz_callback(void); + void timer_1hz_callback(void); + void speed_pub_callback(void); + void ticks_pub_callback(void); + void imu_pub_callback(void); + void pub_odom_callback(void); + void cmd_vel_callback(const geometry_msgs::msg::Twist::SharedPtr msg) const; + + void iapCmdExecute(const std::shared_ptr goal_handle); + rclcpp_action::GoalResponse handle_iapCmdGoal( + const rclcpp_action::GoalUUID & uuid, + std::shared_ptr goal) + { + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "Receive goal request with iap_board %d", goal->iap_board); + (void)uuid; + return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE; + } + + rclcpp_action::CancelResponse handle_iapCmdCancel( + const std::shared_ptr goal_handle) + { + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "Received request to cancel goal"); + (void)goal_handle; + return rclcpp_action::CancelResponse::ACCEPT; + } + + void handle_iapCmdAccepted(const std::shared_ptr goal_handle) + { + using namespace std::placeholders; + (void)goal_handle; + std::thread{std::bind(&Chassis::iapCmdExecute, this, _1), goal_handle}.detach(); + } + }; + +} + +#endif diff --git a/src/segwayrmp/lib/ctrl_arm64-v8a b/src/segwayrmp/lib/ctrl_arm64-v8a new file mode 100755 index 0000000..34f71bc Binary files /dev/null and b/src/segwayrmp/lib/ctrl_arm64-v8a differ diff --git a/src/segwayrmp/lib/ctrl_x86_64 b/src/segwayrmp/lib/ctrl_x86_64 new file mode 100755 index 0000000..bcc4f16 Binary files /dev/null and b/src/segwayrmp/lib/ctrl_x86_64 differ diff --git a/src/segwayrmp/lib/libctrl_arm64-v8a.so b/src/segwayrmp/lib/libctrl_arm64-v8a.so new file mode 100755 index 0000000..dd6df59 Binary files /dev/null and b/src/segwayrmp/lib/libctrl_arm64-v8a.so differ diff --git a/src/segwayrmp/lib/libctrl_x86_64.so b/src/segwayrmp/lib/libctrl_x86_64.so new file mode 100755 index 0000000..5d6c3a3 Binary files /dev/null and b/src/segwayrmp/lib/libctrl_x86_64.so differ diff --git a/src/segwayrmp/package.xml b/src/segwayrmp/package.xml new file mode 100755 index 0000000..b4c9143 --- /dev/null +++ b/src/segwayrmp/package.xml @@ -0,0 +1,31 @@ + + + + segwayrmp + 0.0.0 + TODO: Package description + ninebot + TODO: License declaration + + ament_cmake + + rclcpp + rclpy + std_msgs + nav_msgs + geometry_msgs + + segway_msgs + tf2 + tf2_ros + rclcpp_action + rclcpp_components + + + ament_lint_auto + ament_lint_common + + + ament_cmake + + diff --git a/src/segwayrmp/src/SmartCar.cpp b/src/segwayrmp/src/SmartCar.cpp new file mode 100755 index 0000000..f54da0f --- /dev/null +++ b/src/segwayrmp/src/SmartCar.cpp @@ -0,0 +1,27 @@ +#include "rclcpp/rclcpp.hpp" +#include "segwayrmp/robot.h" + +int main(int argc, char * argv[]) +{ + rclcpp::init(argc, argv); + auto node = rclcpp::Node::make_shared("SmartCar"); + + node->declare_parameter("serial_full_name", "/dev/ttyUSB0"); + std::string serial_full_name; + node->get_parameter("serial_full_name", serial_full_name); + // init_control()parameter: Fill in the full path name of the actual serial port being used + + set_smart_car_serial((char*)serial_full_name.c_str());//If a serial port is used, set the serial port name. + set_comu_interface(comu_serial);//Before calling init_control_ctrl, need to call this function set whether the communication port is serial or CAN. + + if (init_control_ctrl() == -1) { + printf("init_control failed!\n"); + exit_control_ctrl(); + } else { + printf("init_control success!\n"); + } + robot::Chassis sbv(node); + rclcpp::spin(node); + rclcpp::shutdown(); + return 0; +} \ No newline at end of file diff --git a/src/segwayrmp/src/robot.cpp b/src/segwayrmp/src/robot.cpp new file mode 100755 index 0000000..8122a96 --- /dev/null +++ b/src/segwayrmp/src/robot.cpp @@ -0,0 +1,489 @@ +#include "segwayrmp/robot.h" +#include +#define VEL_DT 0.05 //50ms +#define RAD_DEGREE_CONVER 57.2958 +#define HOST_SPEED_UINIT 3600 // +#define HOST_ANGULAR_SPEED_UINIT 2271 + +typedef struct{ + uint32_t typeId; + uint8_t dataSize; + uint64_t *segwayTimeStamp; + uint8_t * updateFlag; + void * dataPtr; +}SegwayData; + +chassis_speed_data_t SpeedData; +uint64_t Speed_TimeStamp; +uint8_t Speed_update; + +motor_ticks_t TickData; +uint64_t Tick_TimeStamp; +uint8_t Tick_update; + +imu_gyr_original_data_t ImuGyroData; +uint64_t ImuGyro_TimeStamp; +uint8_t ImuGyro_update; + +imu_acc_original_data_t ImuAccData; +uint64_t ImuAcc_TimeStamp; +uint8_t ImuAcc_update; + +odom_pos_xy_t OdomPoseXy; +odom_euler_xy_t OdomEulerXy; +odom_euler_z_t OdomEulerZ; +odom_vel_line_xy_t OdomVelLineXy; +uint64_t Odom_TimeStamp; +uint8_t OdomPoseXy_update; +uint8_t OdomEulerXy_update; +uint8_t OdomEulerZ_update; +uint8_t OdomVelLineXy_update; + +static SegwayData segway_data_tbl[] = { + {Chassis_Data_Speed, sizeof(SpeedData), &Speed_TimeStamp, &Speed_update, &SpeedData}, + {Chassis_Data_Ticks, sizeof(TickData), &Tick_TimeStamp, &Tick_update, &TickData}, + {Chassis_Data_Imu_Gyr, sizeof(ImuGyroData), &ImuGyro_TimeStamp, &ImuGyro_update, &ImuGyroData}, + {Chassis_Data_Imu_Acc, sizeof(ImuAccData), &ImuAcc_TimeStamp, &ImuAcc_update, &ImuAccData}, + {Chassis_Data_Odom_Pose_xy, sizeof(OdomPoseXy), &Odom_TimeStamp, &OdomPoseXy_update, &OdomPoseXy}, + {Chassis_Data_Odom_Euler_xy, sizeof(OdomEulerXy), &Odom_TimeStamp, &OdomEulerXy_update, &OdomEulerXy}, + {Chassis_Data_Odom_Euler_z, sizeof(OdomEulerZ), &Odom_TimeStamp, &OdomEulerZ_update, &OdomEulerZ}, + {Chassis_Data_Odom_Linevel_xy, sizeof(OdomVelLineXy), &Odom_TimeStamp, &OdomVelLineXy_update, &OdomVelLineXy} +}; + +std::shared_ptr car_node; +rclcpp::Client::SharedPtr event_client; + +void PubData(StampedBasicFrame_ *frame) +{ + uint8_t i = 0; + for (; i < sizeof(segway_data_tbl)/sizeof(segway_data_tbl[0]); i++) + { + if (frame->type_id == segway_data_tbl[i].typeId) break; + } + if (i < sizeof(segway_data_tbl)/sizeof(segway_data_tbl[0])){ + *(segway_data_tbl[i].segwayTimeStamp) = frame->timestamp; + *(segway_data_tbl[i].updateFlag) =1; + memcpy( segway_data_tbl[i].dataPtr, frame->data, segway_data_tbl[i].dataSize); + } +} + +void EventPubData(int event_no) +{ + robot::Chassis::pub_event_callback(event_no); +} + +namespace robot +{ +void Chassis::pub_event_callback(int event_no) +{ + using eventServiceResponseFutrue = rclcpp::Client::SharedFuture; + auto event_request = std::make_shared(); + event_request->chassis_send_event_id = event_no; + auto event_response_receive_callback = [](eventServiceResponseFutrue futrue) { + (void)futrue; + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "event sended successfully"); + }; + auto event_future_result = event_client->async_send_request(event_request, event_response_receive_callback); +} + +Chassis::Chassis(rclcpp::Node::SharedPtr nh) : node(nh) +{ + using namespace std::placeholders; + car_node = nh; + + timestamp_data.on_new_data = PubData; + aprctrl_datastamped_jni_register(×tamp_data); + event_data.event_callback = EventPubData; + aprctrl_eventcallback_jni_register(&event_data); + + node->declare_parameter("bins_directory", "/sdcard/firmware/"); + node->declare_parameter("chassis_version", "1.01"); + node->declare_parameter("route_version", "1.01"); + node->declare_parameter("connect_version", "1.01"); + + bms_fb_pub = node->create_publisher("/bms_fb", 1); + chassis_ctrl_src_fb_pub = node->create_publisher("/chassis_ctrl_src_fb", 1); + chassis_mileage_meter_fb_pub = node->create_publisher("/chassis_mileage_meter_fb", 1); + chassis_mode_fb_pub = node->create_publisher("/chassis_mode_fb", 1); + error_code_fb_pub = node->create_publisher("/error_code_fb", 1); + motor_work_mode_fb_pub = node->create_publisher("/motor_work_mode_fb", 1); + speed_fb_pub = node->create_publisher("/speed_fb", 1); + ticks_fb_pub = node->create_publisher("/ticks_fb", 1); + odom_pub = node->create_publisher("/odom", 1); + imu_pub = node->create_publisher("/imu", 1); + + event_client = node->create_client("event_srv"); + + ros_get_charge_mos_ctrl_status_cmd_server = node->create_service( + "get_charge_mos_ctrl_status", std::bind(&Chassis::ros_get_charge_mos_ctrl_status_cmd_callback, this, _1, _2)); + ros_get_load_param_cmd_server = node->create_service( + "get_load_param", std::bind(&Chassis::ros_get_load_param_cmd_callback, this, _1, _2)); + ros_get_sw_version_cmd_server = node->create_service( + "get_sw_version", std::bind(&Chassis::ros_get_sw_version_cmd_callback, this, _1, _2)); + ros_get_vel_max_feedback_cmd_server = node->create_service( + "get_vel_max_feedback", std::bind(&Chassis::ros_get_vel_max_feedback_cmd_callback, this, _1, _2)); + ros_set_charge_mos_ctrl_cmd_server = node->create_service( + "set_charge_mos_ctrl", std::bind(&Chassis::ros_set_charge_mos_ctrl_cmd_callback, this, _1, _2)); + ros_set_chassis_enable_cmd_server = node->create_service( + "set_chassis_enable", std::bind(&Chassis::ros_set_chassis_enable_cmd_callback, this, _1, _2)); + ros_set_chassis_poweroff_cmd_server = node->create_service( + "set_chassis_poweroff", std::bind(&Chassis::ros_set_chassis_poweroff_cmd_callback, this, _1, _2)); + ros_set_load_param_cmd_server = node->create_service( + "set_load_param", std::bind(&Chassis::ros_set_load_param_cmd_callback, this, _1, _2)); + ros_set_remove_push_cmd_server = node->create_service( + "set_remove_push", std::bind(&Chassis::ros_set_remove_push_cmd_callback, this, _1, _2)); + ros_set_vel_max_cmd_server = node->create_service( + "set_vel_max", std::bind(&Chassis::ros_set_vel_max_cmd_callback, this, _1, _2)); + + velocity_sub = node->create_subscription( + "cmd_vel", 1, std::bind(&Chassis::cmd_vel_callback, this, std::placeholders::_1)); + + + + iap_action_server = rclcpp_action::create_server( + node, + "iapCmd", + std::bind(&Chassis::handle_iapCmdGoal, this, _1, _2), + std::bind(&Chassis::handle_iapCmdCancel, this, _1), + std::bind(&Chassis::handle_iapCmdAccepted, this, _1)); + + odom_broadcaster = std::make_shared(node); + timer_1000hz = node->create_wall_timer(std::chrono::milliseconds(1), std::bind(&Chassis::timer_1000hz_callback, this)); + timer_1hz = node->create_wall_timer(std::chrono::milliseconds(1000), std::bind(&Chassis::timer_1hz_callback, this)); +} + +void Chassis::ros_get_charge_mos_ctrl_status_cmd_callback(const std::shared_ptr request, + std::shared_ptr response) +{ + int16_t ret = 0; + if (request->ros_get_chassis_charge_ctrl_status == true){ + ret = get_charge_mos_ctrl_status(); + response->chassis_charge_ctrl_status = ret; + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "receive RosGetChargeMosCtrlStatusCmd cmd[%d], charge_ctrl_status[%d]", + 1, ret); + } + else { + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "ros_get_chassis_charge_ctrl_status false"); + } +} +void Chassis::ros_get_load_param_cmd_callback(const std::shared_ptr request, + std::shared_ptr response) +{ + if (request->ros_get_load_param == false) { + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "ros_get_load_param fasle"); + return ; + } + response->get_load_param = get_chassis_load_state(); + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "get_load_param[%d]", response->get_load_param ); +} +void Chassis::ros_get_sw_version_cmd_callback(const std::shared_ptr request, + std::shared_ptr response) +{ + if (request->ros_get_sw_version_cmd == false) { + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "ros_get_sw_version_cmd fasle"); + return; + } + response->host_version = get_host_version(); + response->central_version = get_chassis_central_version(); + response->motor_version = get_chassis_motor_version(); + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "ros_get_sw_version_cmd true"); + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "host_version:%d, central_version:%d, motor_version:%d", + response->host_version, response->central_version, response->motor_version); +} +void Chassis::ros_get_vel_max_feedback_cmd_callback(const std::shared_ptr request, + std::shared_ptr response) +{ + if (request->ros_get_vel_max_fb_cmd == false) { + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "ros_get_vel_max_fb_cmd fasle"); + return; + } + response->forward_max_vel_fb = get_line_forward_max_vel_fb(); + response->backward_max_vel_fb = get_line_backward_max_vel_fb(); + response->angular_max_vel_fb = get_angular_max_vel_fb(); + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "ros_get_vel_max_fb_cmd true"); + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "forward_max_vel_fb:%d, backward_max_vel_fb:%d, angular_max_vel_fb:%d", + response->forward_max_vel_fb, response->backward_max_vel_fb, response->angular_max_vel_fb); +} +void Chassis::ros_set_charge_mos_ctrl_cmd_callback(const std::shared_ptr request, + std::shared_ptr response) +{ + uint8_t ret; + if (request->ros_set_chassis_charge_ctrl == false) { + ret = set_charge_mos_ctrl(false); + } + else { + ret = set_charge_mos_ctrl(true); + } + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "ros_set_chassis_charge_ctrl cmd[%d]", request->ros_set_chassis_charge_ctrl); + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "chassis_set_charge_ctrl_result[%d]", ret); + response->chassis_set_charge_ctrl_result = ret; +} +void Chassis::ros_set_chassis_enable_cmd_callback(const std::shared_ptr request, + std::shared_ptr response) +{ + uint8_t ret; + if (request->ros_set_chassis_enable_cmd == false) { + ret = set_enable_ctrl(0); + } + else { + ret = set_enable_ctrl(1); + } + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "ros_set_chassis_enable_cmd cmd[%d]", request->ros_set_chassis_enable_cmd); + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "chassis_set_chassis_enable_result[%d]", ret); + response->chassis_set_chassis_enable_result = ret; +} +void Chassis::ros_set_chassis_poweroff_cmd_callback(const std::shared_ptr request, + std::shared_ptr response) +{ + if (request->ros_set_chassis_poweroff_cmd == false) { + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "ros_set_chassis_poweroff_cmd fasle"); + return; + } + uint8_t ret = set_chassis_poweroff(); + response->chassis_set_poweroff_result = ret; + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "chassis_set_poweroff_result[%d]", ret); +} +void Chassis::ros_set_load_param_cmd_callback(const std::shared_ptr request, + std::shared_ptr response) +{ + int16_t value = request->ros_set_load_param; + if (value != 0 && value != 1){ + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "ros_set_load_param[%d] out of normal range ", value); + return; + } + uint8_t ret = set_chassis_load_state(value); + response->chassis_set_load_param_result = ret; + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "chassis_set_load_param_result[%d]", ret); +} +void Chassis::ros_set_remove_push_cmd_callback(const std::shared_ptr request, + std::shared_ptr response) +{ + if (request->ros_set_remove_push_cmd == false) { + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "ros_set_remove_push_cmd fasle"); + return; + } + uint8_t ret = set_remove_push_cmd(); + response->chassis_set_revove_push_result = ret; + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "chassis_set_revove_push_result[%d]", ret); +} +void Chassis::ros_set_vel_max_cmd_callback(const std::shared_ptr request, + std::shared_ptr response) +{ + double forward = request->ros_set_forward_max_vel; + double backward = request->ros_set_backward_max_vel; + double angular = request->ros_set_angular_max_vel; + uint8_t ret_forw = set_line_forward_max_vel(forward); + uint8_t ret_back = set_line_backward_max_vel(backward); + uint8_t ret_angl = set_angular_max_vel(angular); + response->chassis_set_max_vel_result = ret_forw | ret_back | ret_angl; + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "ros_set_forward_max_vel[%lf], ros_set_backward_max_vel[%lf], ros_set_angular_max_vel[%lf]", + forward, backward, angular); + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "set_line_forward_max_vel result[%d], set_line_backward_max_vel result[%d], set_angular_max_vel result[%d]", + ret_forw, ret_back, ret_angl); +} + +void Chassis::iapCmdExecute(const std::shared_ptr goal_handle) +{ + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "Executing goal"); + rclcpp::Rate loop_rate(1); + const auto goal = goal_handle->get_goal(); + auto feedback = std::make_shared(); + auto result = std::make_shared(); + int32_t iap_percent_fb; + + node->get_parameter("bins_directory", bins_directory); + node->get_parameter("chassis_version", chassis_version); + node->get_parameter("route_version", route_version); + node->get_parameter("connect_version", connect_version); + char bin_dir[100] = {0}; + char ver[100] = {0}; + switch (goal->iap_board) + { + case 1: + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "iap central board"); + bins_directory = bins_directory + "/central.bin"; + bins_directory.copy(bin_dir, bins_directory.length(), 0); + chassis_version.copy(ver, chassis_version.length(), 0); + IapSingerBoard(bin_dir, (char*)"central", ver); + break; + case 2: + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "iap motor board"); + bins_directory = bins_directory + "/motor.bin"; + bins_directory.copy(bin_dir, bins_directory.length(), 0); + route_version.copy(ver, route_version.length(), 0); + IapSingerBoard(bin_dir, (char*)"motor", ver); + break; + default: + RCLCPP_ERROR(rclcpp::get_logger("SmartCar"), + "iap_board value error, out of [1 2]", goal->iap_board); + result->set__iap_result(5); + goal_handle->canceled(result); + return; + } + + while (rclcpp::ok()) + { + if (goal_handle->is_canceling()) { + result->set__iap_result(5); + goal_handle->canceled(result); + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "Goal canceled"); + return; + } + iap_percent_fb = getIapTotalProgress(); + feedback->set__iap_percent(iap_percent_fb); + goal_handle->publish_feedback(feedback); + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "iap percent: %d", iap_percent_fb); + loop_rate.sleep(); + if (iap_percent_fb == 100) { + RCLCPP_INFO_ONCE(rclcpp::get_logger("SmartCar"), "iap successful"); + break; + } else if (iap_percent_fb < 0) { + RCLCPP_INFO_ONCE(rclcpp::get_logger("SmartCar"), "iap failed"); + break; + } + } + + if (rclcpp::ok()) { + if (iap_percent_fb == 100) { + result->set__iap_result(3); + goal_handle->succeed(result); + RCLCPP_INFO(rclcpp::get_logger("SmartCar"), "goal succeeded, iap succeeded"); + } else { + result->set__iap_result(getHostIapResult()); + result->set__error_code(getHostIapErrorCode()); + goal_handle->succeed(result); + RCLCPP_ERROR(rclcpp::get_logger("SmartCar"), "goal failed, iap failed"); + } + } +} + +void Chassis::cmd_vel_callback(const geometry_msgs::msg::Twist::SharedPtr msg) const +{ + double angular_vel = msg->angular.z; + double linear_vel = msg->linear.x; + angular_vel = (angular_vel > 3.0 ? 3.0 : (angular_vel < -3.0 ? -3.0 : angular_vel)); + linear_vel = (linear_vel > 3.0 ? 3.0 : (linear_vel < -1.0 ? -1.0 : linear_vel)); + + set_cmd_vel(linear_vel, angular_vel); + // printf("vl:%lf, va:%lf\n", linear_vel, angular_vel); +} + +void Chassis::timer_1hz_callback(void) +{ + bms_fb.bat_soc = get_bat_soc(); + bms_fb.bat_charging = get_bat_charging(); + bms_fb.bat_vol = get_bat_mvol(); + bms_fb.bat_current = get_bat_mcurrent(); + bms_fb.bat_temp = get_bat_temp(); + bms_fb_pub->publish(bms_fb); + + chassis_ctrl_src_fb.chassis_ctrl_cmd_src = get_ctrl_cmd_src(); + chassis_ctrl_src_fb_pub->publish(chassis_ctrl_src_fb); + + chassis_mileage_meter_fb.vehicle_meters = get_vehicle_meter(); + chassis_mileage_meter_fb_pub->publish(chassis_mileage_meter_fb); + + chassis_mode_fb.chassis_mode = get_chassis_mode();//0-lock_mode; 1-ctrl_mode; 2-push_mode; 3-emergency_mode; 4-error_mode + chassis_mode_fb_pub->publish(chassis_mode_fb); + + error_code_fb.host_error = get_err_state(Host); + error_code_fb.central_error = get_err_state(Central); + error_code_fb.left_motor_error = get_err_state(Motor) & 0xffff; + error_code_fb.right_motor_error = (get_err_state(Motor) >> 16) & 0xffff; + error_code_fb.bms_error = get_err_state(BMS); + error_code_fb_pub->publish(error_code_fb); + + motor_work_mode_fb.motor_work_mode = get_chassis_work_model(); + motor_work_mode_fb_pub->publish(motor_work_mode_fb); +} + +void Chassis::timer_1000hz_callback(void) +{ + speed_pub_callback(); + ticks_pub_callback(); + imu_pub_callback(); + pub_odom_callback(); +} + +void Chassis::speed_pub_callback(void) +{ + if (Speed_update == 1) { + Speed_update = 0; + speed_fb.car_speed = SpeedData.car_speed; + speed_fb.car_speed /= LINE_SPEED_TRANS_GAIN_MPS; + speed_fb.turn_speed = SpeedData.turn_speed; + speed_fb.turn_speed /= ANGULAR_SPEED_TRANS_GAIN_RADPS; + speed_fb.l_speed = SpeedData.l_speed; + speed_fb.l_speed /= LINE_SPEED_TRANS_GAIN_MPS; + speed_fb.r_speed = SpeedData.r_speed; + speed_fb.r_speed /= LINE_SPEED_TRANS_GAIN_MPS; + speed_fb.speed_timestamp = Speed_TimeStamp; + speed_fb_pub->publish(speed_fb); + } +} + +void Chassis::ticks_pub_callback(void) +{ + if (Tick_update == 1) { + Tick_update = 0; + ticks_fb.l_ticks = TickData.l_ticks; + ticks_fb.r_ticks = TickData.r_ticks; + ticks_fb.ticks_timestamp = Tick_TimeStamp; + ticks_fb_pub->publish(ticks_fb); + } +} + +void Chassis::imu_pub_callback(void) +{ + if (ImuGyro_update == 1 && ImuAcc_update == 1){ + ImuGyro_update = 0; + ImuAcc_update = 0; + imu_fb.header.stamp = node->now(); + imu_fb.header.frame_id = "base_link"; + imu_fb.angular_velocity.x = (double)ImuGyroData.gyr[0] / 900.0; + imu_fb.angular_velocity.y = (double)ImuGyroData.gyr[1] / 900.0; + imu_fb.angular_velocity.z = (double)ImuGyroData.gyr[2] / 900.0; + imu_fb.linear_acceleration.x = (double)ImuAccData.acc[0] / 4000.0 * 9.8; + imu_fb.linear_acceleration.y = (double)ImuAccData.acc[1] / 4000.0 * 9.8; + imu_fb.linear_acceleration.z = (double)ImuAccData.acc[2] / 4000.0 * 9.8; + imu_pub->publish(imu_fb); + } +} + +void Chassis::pub_odom_callback(void) +{ + if ((OdomPoseXy_update & OdomEulerXy_update & OdomEulerZ_update & OdomVelLineXy_update) == 1) { + OdomPoseXy_update = 0, OdomEulerXy_update = 0, OdomEulerZ_update = 0, OdomVelLineXy_update = 0; + + odom_quat.setRPY(0, 0, OdomEulerZ.euler_z / RAD_DEGREE_CONVER); + odom_trans.header.stamp = node->now(); + odom_trans.header.frame_id = "odom"; + odom_trans.child_frame_id = "base_link"; + odom_trans.transform.translation.x = OdomPoseXy.pos_x; + odom_trans.transform.translation.y = OdomPoseXy.pos_y; + odom_trans.transform.translation.z = 0.0; + odom_trans.transform.rotation.x = odom_quat.x(); + odom_trans.transform.rotation.y = odom_quat.y(); + odom_trans.transform.rotation.z = odom_quat.z(); + odom_trans.transform.rotation.w = odom_quat.w(); + odom_broadcaster->sendTransform(odom_trans); + + odom_fb.header.stamp = node->now(); + odom_fb.header.frame_id = "odom"; + odom_fb.pose.pose.position.x = OdomPoseXy.pos_x; + odom_fb.pose.pose.position.y = OdomPoseXy.pos_y; + odom_fb.pose.pose.position.z = 0.0; + odom_fb.pose.pose.orientation.x = odom_quat.x(); + odom_fb.pose.pose.orientation.y = odom_quat.y(); + odom_fb.pose.pose.orientation.z = odom_quat.z(); + odom_fb.pose.pose.orientation.w = odom_quat.w(); + + odom_fb.child_frame_id = "base_link"; + odom_fb.twist.twist.linear.x = (double)SpeedData.car_speed / LINE_SPEED_TRANS_GAIN_MPS; + odom_fb.twist.twist.linear.y = 0; + odom_fb.twist.twist.angular.z = (double)SpeedData.turn_speed / ANGULAR_SPEED_TRANS_GAIN_RADPS;; + odom_pub->publish(odom_fb); + } +} + +} diff --git a/src/segwayrmp/tools/drive_segway_sample.cpp b/src/segwayrmp/tools/drive_segway_sample.cpp new file mode 100755 index 0000000..a9568e0 --- /dev/null +++ b/src/segwayrmp/tools/drive_segway_sample.cpp @@ -0,0 +1,364 @@ +#include "segwayrmp/robot.h" +#include +#include +#include +#include +#include +#include +#include + +#define PRINTHELP 'h' +#define ADDLINEVEL 'w' +#define DECLINEVEL 's' +#define ADDANGULARVEL 'a' +#define DECANGULARVEL 'd' +#define PRINTCURVEL 'f' +#define VELRESETZERO 'g' +#define ENABLECMD 'e' +#define CHASSISPAUSE 'q' +// #define CLEARSCRAM 'c' +// #define GETERROR 'x' +#define IAPCENTRAL 'v' +#define IAPMOTOR 'b' +#define PRINTERRSW 'r' + +using iapCmd = segway_msgs::action::RosSetIapCmd; +using goalHandleIapCmd = rclcpp_action::ClientGoalHandle; + +std::shared_ptr drive_node; +rclcpp::Publisher::SharedPtr velocity_pub; +rclcpp::Subscription::SharedPtr error_sub; + +rclcpp::Client::SharedPtr enable_client; +// rclcpp::Client::SharedPtr clear_scram_client; +// rclcpp::Client::SharedPtr get_err_client; +rclcpp::Service::SharedPtr event_server; + +rclcpp_action::Client::SharedPtr iap_client; +uint8_t print_error = 0; + +char const* print_help() { + char const* printHelp = + "\t h : Displays the required keys and their meaning\n" + "\t w : Increase forward speed by 0.1m/s\n" + "\t s : Decrease forward speed by 0.1m/s\n" + "\t a : Increase the angular velocity by 0.1rad/s\n" + "\t d : Decrease the angular velocity by 0.1rad/s\n" + "\t f : Displays current speed Settings\n" + "\t g : Speed reset to zero\n" + "\t e : Chassis enable switch\n" + "\t q : Running pause. Click 'q'key again to resume running by the previous speed. W/S/A/D keys can also restore chassis running\n" + "\t v : Iap the central board, please put the bin file in /sdcard/firmware/\n" + "\t b : Iap the motor board, please put the bin file in /sdcard/firmware/\n" + "\t r : Open or close the switch: printing error code\n" + "\t others : Do nothing\n"; + return printHelp; +} + +void changemode(int dir) +{ + static struct termios oldt, newt; + + if ( dir == 1 ) + { + tcgetattr( STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~( ICANON | ECHO ); + tcsetattr( STDIN_FILENO, TCSANOW, &newt); + } + else + tcsetattr( STDIN_FILENO, TCSANOW, &oldt); +} + +int kbhit (void) +{ + struct timeval tv; + fd_set rdfs; //一组fd集合 + + tv.tv_sec = 0; + tv.tv_usec = 0; //时间为0,非阻塞 + + FD_ZERO(&rdfs); //fd集合清空 + FD_SET (STDIN_FILENO, &rdfs); //增加新的fd + + select(STDIN_FILENO+1, &rdfs, NULL, NULL, &tv); //非阻塞检测fd为0的tty读取状态,rdfs特定位置1 + return FD_ISSET(STDIN_FILENO, &rdfs); //判断指定的标准输入fd是否在rdfs集合中 +} + +static int scanKeyboard() +{ + int input_char = 0; + struct termios new_settings; + struct termios stored_settings; + tcgetattr(0, &stored_settings); + new_settings = stored_settings; + new_settings.c_lflag &= (~ICANON); //非规范模式:每次返回单个字符 + new_settings.c_cc[VTIME] = 0; + tcgetattr(0,&stored_settings); + new_settings.c_cc[VMIN] = 1; //读取的最小字节数 + tcsetattr(0, TCSANOW, &new_settings); + + changemode(1); + if (kbhit()) { + input_char = getchar(); + printf("\n"); + } + changemode(0); + + tcsetattr(0, TCSANOW, &stored_settings); + return input_char; +} + +char get_keyboard() +{ + char keyvalue = scanKeyboard(); + return keyvalue; +} + +void goal_response_callback(std::shared_future future) +{ + auto goal_handle = future.get(); + if (!goal_handle) { + RCLCPP_ERROR(rclcpp::get_logger("drive_segway_sample"), "Goal was rejected by server"); + } else { + RCLCPP_INFO(rclcpp::get_logger("drive_segway_sample"), "Goal accepted by server, waiting for result"); + } +} + +void feedback_callback( + goalHandleIapCmd::SharedPtr, + const std::shared_ptr feedback) +{ + RCLCPP_INFO(rclcpp::get_logger("drive_segway_sample"), "IAP process percentage:[%d]", feedback->iap_percent); +} + +void result_callback(const goalHandleIapCmd::WrappedResult & result) +{ + switch (result.code) { + case rclcpp_action::ResultCode::SUCCEEDED: + break; + case rclcpp_action::ResultCode::ABORTED: + RCLCPP_ERROR(rclcpp::get_logger("drive_segway_sample"), "Goal was aborted"); + return; + case rclcpp_action::ResultCode::CANCELED: + RCLCPP_ERROR(rclcpp::get_logger("drive_segway_sample"), "Goal was canceled"); + return; + default: + RCLCPP_ERROR(rclcpp::get_logger("drive_segway_sample"), "Unknown result code"); + return; + } + if (result.result->iap_result == 3) { + RCLCPP_INFO(rclcpp::get_logger("drive_segway_sample"), "iap success!"); + } else { + RCLCPP_INFO(rclcpp::get_logger("drive_segway_sample"), "iap fail!, error_code[%#x]", result.result->error_code); + } +} + +void drive_chassis_test() +{ + static uint16_t set_enable_cmd = 1; + uint8_t enable_switch = 0; + static double set_line_speed; + static double set_angular_speed; + static double send_line_speed; + static double send_angular_speed; + static uint8_t chassis_pause = 0; + // uint8_t clear_scram_flag = 0; + // uint8_t get_err_flag = 0; + uint8_t iap_flag = 0; + + auto enable_request = std::make_shared(); + // auto clear_scram_requst = std::make_shared(); + // auto get_err_request = std::make_shared(); + + char keyvalue = get_keyboard(); + switch (keyvalue) + { + case PRINTHELP: + printf("%s\n", print_help()); + break; + case ADDLINEVEL : + set_line_speed += 0.1; + send_line_speed = set_line_speed; + send_angular_speed = set_angular_speed; + printf("current set_line_speed[%lf], set_angular_speed[%lf]\n", set_line_speed, set_angular_speed); + break; + case DECLINEVEL : + set_line_speed -= 0.1; + send_line_speed = set_line_speed; + send_angular_speed = set_angular_speed; + printf("current set_line_speed[%lf], set_angular_speed[%lf]\n", set_line_speed, set_angular_speed); + break; + case ADDANGULARVEL : + set_angular_speed += 0.1; + send_line_speed = set_line_speed; + send_angular_speed = set_angular_speed; + printf("current set_line_speed[%lf], set_angular_speed[%lf]\n", set_line_speed, set_angular_speed); + break; + case DECANGULARVEL : + set_angular_speed -= 0.1; + send_line_speed = set_line_speed; + send_angular_speed = set_angular_speed; + printf("current set_line_speed[%lf], set_angular_speed[%lf]\n", set_line_speed, set_angular_speed); + break; + case PRINTCURVEL : + printf("current set_line_speed[%lf], set_angular_speed[%lf]\n", set_line_speed, set_angular_speed); + break; + case VELRESETZERO : + set_line_speed = 0; + set_angular_speed = 0; + send_line_speed = 0; + send_angular_speed = 0; + printf("current set_line_speed[%lf], set_angular_speed[%lf]\n", set_line_speed, set_angular_speed); + break; + case ENABLECMD : + enable_switch = 1; + enable_request->ros_set_chassis_enable_cmd = set_enable_cmd; + ++set_enable_cmd; + set_enable_cmd %= 2; + RCLCPP_INFO(rclcpp::get_logger("drive_segway_sample"), + "enable chassis switch[%d]", enable_request->ros_set_chassis_enable_cmd); + printf("current set_line_speed[%lf], set_angular_speed[%lf]\n", set_line_speed, set_angular_speed); + break; + case CHASSISPAUSE : + ++chassis_pause; + chassis_pause %= 2; + if (chassis_pause) { + send_line_speed = 0; + send_angular_speed = 0; + printf("Stop the chassis temporarily\n"); + } else { + send_line_speed = set_line_speed; + send_angular_speed = set_angular_speed; + printf("current set_line_speed[%lf], set_angular_speed[%lf]\n", set_line_speed, set_angular_speed); + } + break; + // case CLEARSCRAM : + // // clear_scram_flag = 1; + // break; + // case GETERROR: + // // get_err_flag = 1; + // break; + case IAPCENTRAL: + RCLCPP_INFO(rclcpp::get_logger("drive_segway_sample"), "iap chassis"); + iap_flag = 1; + break; + case IAPMOTOR: + RCLCPP_INFO(rclcpp::get_logger("drive_segway_sample"), "iap route"); + iap_flag = 2; + break; + case PRINTERRSW: + print_error = ~print_error; + break; + default: + break; + } + + geometry_msgs::msg::Twist cmd_vel; + cmd_vel.linear.x = send_line_speed; + cmd_vel.angular.z = send_angular_speed; + velocity_pub->publish(cmd_vel); + + if (enable_switch){ + using enableServiceResponseFutrue = rclcpp::Client::SharedFuture; + auto enable_response_receive_callback = [](enableServiceResponseFutrue futrue) { + RCLCPP_INFO(rclcpp::get_logger("drive_segway_sample"), + "event sended successfully, result:%d", futrue.get()->chassis_set_chassis_enable_result); + }; + auto enable_future_result = enable_client->async_send_request(enable_request, enable_response_receive_callback); + } + + // if (clear_scram_flag) { + // using clearServiceResponseFuture = rclcpp::Client::SharedFuture; + // auto clear_response_receive_callback = [](clearServiceResponseFuture future) { + // RCLCPP_INFO(rclcpp::get_logger("drive_segway_sample"), + // "clear scram status successfully, result:%d", future.get()->clear_scram_result); + // }; + // auto clear_future_result = clear_scram_client->async_send_request(clear_scram_requst, clear_response_receive_callback); + // } + + // if (get_err_flag) { + // using errorServiceResponseFuture = rclcpp::Client::SharedFuture; + // auto error_response_receive_callback = [](errorServiceResponseFuture future) { + // RCLCPP_INFO(rclcpp::get_logger("drive_segway_sample"), + // "chassis_error_code[%d], route_error_code[%d], connect_error_code[%d]", + // future.get()->chassis_error_code, + // future.get()->route_error_code, + // future.get()->connect_error_code); + // }; + // auto error_future_result = get_err_client->async_send_request(get_err_request, error_response_receive_callback); + // } + + if (iap_flag & 3) { + auto goal_msg = iapCmd::Goal(); + goal_msg.iap_board = iap_flag; + RCLCPP_INFO(rclcpp::get_logger("drive_segway_sample"), "sending goal, iap cmd goal"); + auto send_goal_options = rclcpp_action::Client::SendGoalOptions(); + send_goal_options.goal_response_callback = std::bind(&goal_response_callback, std::placeholders::_1); + send_goal_options.feedback_callback = std::bind(&feedback_callback, std::placeholders::_1, std::placeholders::_2); + send_goal_options.result_callback = std::bind(&result_callback, std::placeholders::_1); + iap_client->async_send_goal(goal_msg, send_goal_options); + } +} + +void get_error_code_callback(const segway_msgs::msg::ErrorCodeFb::SharedPtr msg) +{ + if (print_error != 0) { + RCLCPP_INFO(rclcpp::get_logger("drive_segway_sample"), "host_error[%#x], central_error[%#x], \ + left_motor_error[%#x], right_motor_error[%#x], bms_err[%#x]", + msg->host_error, msg->central_error, msg->left_motor_error, msg->right_motor_error, msg->bms_error); + } +} + +void get_chassis_event_callback(const std::shared_ptr request, + std::shared_ptr response) +{ + (void)response; + switch (request->chassis_send_event_id) + { + case OnEmergeStopEvent: + RCLCPP_INFO(rclcpp::get_logger("drive_segway_sample"), "CHASSIS EVENT: The chassis emergency stop button is triggered"); + break; + case OutEmergeStopEvent: + RCLCPP_INFO(rclcpp::get_logger("drive_segway_sample"), "CHASSIS EVENT: OThe chassis emergency stop button recover"); + break; + case PadPowerOffEvent: + RCLCPP_INFO(rclcpp::get_logger("drive_segway_sample"), "CHASSIS EVENT: The chassis will power off"); + break; + case OnLockedRotorProtectEvent: + RCLCPP_INFO(rclcpp::get_logger("drive_segway_sample"), "CHASSIS EVENT: the chassis motor locked-rotor"); + break; + case OutLockedRotorProtectEvent: + RCLCPP_INFO(rclcpp::get_logger("drive_segway_sample"), "CHASSIS EVENT: the chassis motor no longer locked-rotor"); + break; + default: + break; + } +} + +int main(int argc, char * argv[]) +{ + rclcpp::init(argc, argv); + drive_node = rclcpp::Node::make_shared("drive_segway_sample"); + + velocity_pub = drive_node->create_publisher("cmd_vel", 1); + error_sub = drive_node->create_subscription( + "error_code_fb", 1, std::bind(&get_error_code_callback, std::placeholders::_1)); + + enable_client = drive_node->create_client("set_chassis_enable"); + // clear_scram_client = drive_node->create_client("clear_scram_status_srv"); + // get_err_client = drive_node->create_client("get_error_srv"); + event_server = drive_node->create_service( + "event_srv", std::bind(&get_chassis_event_callback, std::placeholders::_1, std::placeholders::_2)); + + iap_client = rclcpp_action::create_client(drive_node, "iapCmd"); + + rclcpp::TimerBase::SharedPtr timer_100hz = + drive_node->create_wall_timer(std::chrono::milliseconds(10), &drive_chassis_test); + + printf("%s\n", print_help()); + + rclcpp::spin(drive_node); + rclcpp::shutdown(); + return 0; +} \ No newline at end of file