/* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "AP_Proximity_config.h" #if AP_PROXIMITY_MR72_ENABLED #include #include #include "AP_Proximity_MR72_CAN.h" const AP_Param::GroupInfo AP_Proximity_MR72_CAN::var_info[] = { // @Param: RECV_ID // @DisplayName: CAN receive ID // @Description: The receive ID of the CAN frames. A value of zero means all IDs are accepted. // @Range: 0 65535 // @User: Advanced AP_GROUPINFO("RECV_ID", 1, AP_Proximity_MR72_CAN, receive_id, 0), AP_GROUPEND }; AP_Proximity_MR72_CAN::AP_Proximity_MR72_CAN(AP_Proximity &_frontend, AP_Proximity::Proximity_State &_state, AP_Proximity_Params& _params): AP_Proximity_Backend(_frontend, _state, _params) { multican_MR72 = NEW_NOTHROW MultiCAN{FUNCTOR_BIND_MEMBER(&AP_Proximity_MR72_CAN::handle_frame, bool, AP_HAL::CANFrame &), AP_CAN::Protocol::NanoRadar, "MR72 MultiCAN"}; if (multican_MR72 == nullptr) { AP_BoardConfig::allocation_error("Failed to create proximity multican"); } AP_Param::setup_object_defaults(this, var_info); state.var_info = var_info; } // update state void AP_Proximity_MR72_CAN::update(void) { WITH_SEMAPHORE(_sem); const uint32_t now = AP_HAL::millis(); if (now - last_update_ms > 500) { // no new data. set_status(AP_Proximity::Status::NoData); } else { set_status(AP_Proximity::Status::Good); } } // handler for incoming frames. These come in at 100Hz bool AP_Proximity_MR72_CAN::handle_frame(AP_HAL::CANFrame &frame) { WITH_SEMAPHORE(_sem); // check if message is coming from the right sensor ID const uint16_t id = frame.id; if (receive_id > 0 && (get_radar_id(frame.id) != uint32_t(receive_id))) { return false; } switch (id & 0xFU) { case 0xAU: // number of objects _object_count = frame.data[0]; _current_object_index = 0; _temp_boundary.update_3D_boundary(state.instance, frontend.boundary); _temp_boundary.reset(); last_update_ms = AP_HAL::millis(); break; case 0xBU: // obstacle data parse_distance_message(frame); break; default: break; } return true; } // parse a distance message from CAN frame bool AP_Proximity_MR72_CAN::parse_distance_message(AP_HAL::CANFrame &frame) { if (_current_object_index >= _object_count) { // should never happen return false; } _current_object_index++; Vector2f obstacle_fr; // This parsing comes from the NanoRadar MR72 datasheet obstacle_fr.x = ((frame.data[2] & 0x07U) * 256 + frame.data[3]) * 0.2 - 204.6; obstacle_fr.y = (frame.data[1] * 32 + (frame.data[2] >> 3)) * 0.2 - 500; const float yaw = correct_angle_for_orientation(wrap_360(degrees(atan2f(obstacle_fr.x, obstacle_fr.y)))); const float objects_dist = obstacle_fr.length(); if (ignore_reading(yaw, objects_dist)) { // obstacle is probably near ground or out of range return false; } const AP_Proximity_Boundary_3D::Face face = frontend.boundary.get_face(yaw); _temp_boundary.add_distance(face, yaw, objects_dist); database_push(yaw, objects_dist); return true; } #endif // HAL_PROXIMITY_ENABLED