/* * This file 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 file 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 . * * Author: Eugene Shamaev, Siddharth Bharat Purohit */ #include #include #if HAL_WITH_UAVCAN #include "AP_UAVCAN.h" #include #include //电机类 #include #include #include #include #include #include #include #include //#include //#include //#include //#include //#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LED_DELAY_US 50000 extern const AP_HAL::HAL& hal; #define debug_uavcan(level_debug, fmt, args...) do { if ((level_debug) <= AP::can().get_debug_level_driver(_driver_index)) { printf(fmt, ##args); }} while (0) // Translation of all messages from UAVCAN structures into AP structures is done // in AP_UAVCAN and not in corresponding drivers. // The overhead of including definitions of DSDL is very high and it is best to // concentrate in one place. // table of user settable CAN bus parameters const AP_Param::GroupInfo AP_UAVCAN::var_info[] = { // @Param: NODE // @DisplayName: UAVCAN node that is used for this network // @Description: UAVCAN node should be set implicitly // @Range: 1 250 // @User: Advanced AP_GROUPINFO("NODE", 1, AP_UAVCAN, _uavcan_node, 10), // @Param: SRV_BM // @DisplayName: RC Out channels to be transmitted as servo over UAVCAN // @Description: Bitmask with one set for channel to be transmitted as a servo command over UAVCAN // @Bitmask: 0: Servo 1, 1: Servo 2, 2: Servo 3, 3: Servo 4, 4: Servo 5, 5: Servo 6, 6: Servo 7, 7: Servo 8, 8: Servo 9, 9: Servo 10, 10: Servo 11, 11: Servo 12, 12: Servo 13, 13: Servo 14, 14: Servo 15 // @User: Advanced AP_GROUPINFO("SRV_BM", 2, AP_UAVCAN, _servo_bm, 0), // @Param: ESC_BM // @DisplayName: RC Out channels to be transmitted as ESC over UAVCAN // @Description: Bitmask with one set for channel to be transmitted as a ESC command over UAVCAN // @Bitmask: 0: ESC 1, 1: ESC 2, 2: ESC 3, 3: ESC 4, 4: ESC 5, 5: ESC 6, 6: ESC 7, 7: ESC 8, 8: ESC 9, 9: ESC 10, 10: ESC 11, 11: ESC 12, 12: ESC 13, 13: ESC 14, 14: ESC 15, 15: ESC 16 // @User: Advanced AP_GROUPINFO("ESC_BM", 3, AP_UAVCAN, _esc_bm, 0), // @Param: SRV_RT // @DisplayName: Servo output rate // @Description: Maximum transmit rate for servo outputs // @Range: 1 200 // @Units: Hz // @User: Advanced AP_GROUPINFO("SRV_RT", 4, AP_UAVCAN, _servo_rate_hz, 50), AP_GROUPEND }; // this is the timeout in milliseconds for periodic message types. We // set this to 1 to minimise resend of stale msgs #define CAN_PERIODIC_TX_TIMEOUT_MS 2 // publisher interfaces static uavcan::Publisher* vesc_rpm[MAX_NUMBER_OF_CAN_DRIVERS]; static uavcan::Publisher* act_out_array[MAX_NUMBER_OF_CAN_DRIVERS]; static uavcan::Publisher* esc_raw[MAX_NUMBER_OF_CAN_DRIVERS]; static uavcan::Publisher* rgb_led[MAX_NUMBER_OF_CAN_DRIVERS]; static uavcan::Publisher* buzzer[MAX_NUMBER_OF_CAN_DRIVERS]; static uavcan::Publisher* safety_state[MAX_NUMBER_OF_CAN_DRIVERS]; // subscribers // handler SafteyButton UC_REGISTRY_BINDER(ButtonCb, ardupilot::indication::Button); static uavcan::Subscriber *safety_button_listener[MAX_NUMBER_OF_CAN_DRIVERS]; struct ESCTelemetryData thruster_init = {0,0.0,0.0,0.0,0,0,0}; //struct ESCTelemetryData thruster[6]={thruster_init,thruster_init,thruster_init,thruster_init,thruster_init,thruster_init}; AP_UAVCAN::AP_UAVCAN() : _node_allocator() { AP_Param::setup_object_defaults(this, var_info); _singleton = this; for (uint8_t i = 0; i < UAVCAN_SRV_NUMBER; i++) { _SRV_conf[i].esc_pending = false; _SRV_conf[i].servo_pending = false; } for(uint8_t i = 0; i < 6; i++) { thruster[i]=thruster_init; } debug_uavcan(2, "AP_UAVCAN constructed\n\r"); } AP_UAVCAN::~AP_UAVCAN() { } static void esc_status_st_cb(const uavcan::ReceivedDataStructure&msg,uint8_t mgr ) {//接收到的数据在这里处理,打印出来 AP_UAVCAN &uavcan = AP::uavcan();//6自由度电机计算出来的PWM uint8_t i = msg.esc_index; uavcan.thruster[i].error_count = msg.error_count; uavcan.thruster[i].voltage = (float)msg.voltage; uavcan.thruster[i].current = (float)msg.current; uavcan.thruster[i].temperature = (float)msg.temperature-273.15; uavcan.thruster[i].rpm = (int32_t)msg.rpm; uavcan.thruster[i].power_rating_pct= (uint8_t)msg.power_rating_pct; static uint8_t cnt = 0; cnt++; if (cnt>50) { gcs().send_text(MAV_SEVERITY_INFO, "motor_index = %d %d %d %d .",(int)i,(int)uavcan.thruster[i].rpm,(int)uavcan.thruster[i].power_rating_pct,(int)uavcan.thruster[i].esc_index); gcs().send_text(MAV_SEVERITY_INFO, "motor %x %f %f %f.",(int)uavcan.thruster[i].error_count,(float)uavcan.thruster[i].voltage,(float)uavcan.thruster[i].current,(float)uavcan.thruster[i].temperature); cnt=0; } /*uint8_t i = msg.esc_index; thruster[i].error_count = msg.error_count; thruster[i].voltage = (float)msg.voltage; thruster[i].current = (float)msg.current; thruster[i].temperature = (float)msg.temperature; thruster[i].rpm = (int32_t)msg.rpm; thruster[i].power_rating_pct= (uint8_t)msg.power_rating_pct; static uint8_t cnt = 0; cnt++; if (cnt>50) { gcs().send_text(MAV_SEVERITY_WARNING, "motor %x %f %f %f.",(int)thruster[i].error_count,(float)thruster[i].voltage,(float)thruster[i].current,(float)thruster[i].temperature); gcs().send_text(MAV_SEVERITY_WARNING, "motor_index = 0 %d %d %d .",(int)thruster[i].rpm,(int)thruster[i].power_rating_pct,(int)thruster[i].esc_index); cnt=0; }*/ } static void esc_status_st_cb0(const uavcan::ReceivedDataStructure&msg ){ esc_status_st_cb(msg,0); } static void esc_status_st_cb1(const uavcan::ReceivedDataStructure&msg ){ esc_status_st_cb(msg,1); } static void (*esc_status_st_cb_arr[2])(const uavcan::ReceivedDataStructure&msg ) ={esc_status_st_cb0,esc_status_st_cb1}; AP_UAVCAN *AP_UAVCAN::get_uavcan(uint8_t driver_index) { if (driver_index >= AP::can().get_num_drivers() || AP::can().get_protocol_type(driver_index) != AP_BoardConfig_CAN::Protocol_Type_UAVCAN) { return nullptr; } return static_cast(AP::can().get_driver(driver_index)); } void AP_UAVCAN::init(uint8_t driver_index, bool enable_filters) { if (_initialized) { debug_uavcan(2, "UAVCAN: init called more than once\n\r"); return; } _driver_index = driver_index; AP_HAL::CANManager* can_mgr = hal.can_mgr[driver_index]; if (can_mgr == nullptr) { debug_uavcan(2, "UAVCAN: init called for inexisting CAN driver\n\r"); return; } if (!can_mgr->is_initialized()) { debug_uavcan(1, "UAVCAN: CAN driver not initialized\n\r"); return; } uavcan::ICanDriver* driver = can_mgr->get_driver(); if (driver == nullptr) { debug_uavcan(2, "UAVCAN: can't get UAVCAN interface driver\n\r"); return; } _node = new uavcan::Node<0>(*driver, SystemClock::instance(), _node_allocator); if (_node == nullptr) { debug_uavcan(1, "UAVCAN: couldn't allocate node\n\r"); return; } if (_node->isStarted()) { debug_uavcan(2, "UAVCAN: node was already started?\n\r"); return; } uavcan::NodeID self_node_id(_uavcan_node); _node->setNodeID(self_node_id); char ndname[20]; snprintf(ndname, sizeof(ndname), "org.ardupilot:%u", driver_index); uavcan::NodeStatusProvider::NodeName name(ndname); _node->setName(name); uavcan::protocol::SoftwareVersion sw_version; // Standard type uavcan.protocol.SoftwareVersion sw_version.major = AP_UAVCAN_SW_VERS_MAJOR; sw_version.minor = AP_UAVCAN_SW_VERS_MINOR; _node->setSoftwareVersion(sw_version); uavcan::protocol::HardwareVersion hw_version; // Standard type uavcan.protocol.HardwareVersion hw_version.major = AP_UAVCAN_HW_VERS_MAJOR; hw_version.minor = AP_UAVCAN_HW_VERS_MINOR; const uint8_t uid_buf_len = hw_version.unique_id.capacity(); uint8_t uid_len = uid_buf_len; uint8_t unique_id[uid_buf_len]; if (hal.util->get_system_id_unformatted(unique_id, uid_len)) { uavcan::copy(unique_id, unique_id + uid_len, hw_version.unique_id.begin()); } _node->setHardwareVersion(hw_version); int start_res = _node->start(); if (start_res < 0) { debug_uavcan(1, "UAVCAN: node start problem, error %d\n\r", start_res); return; } //Start Servers #ifdef HAS_UAVCAN_SERVERS _servers.init(*_node); #endif // Roundup all subscribers from supported drivers AP_GPS_UAVCAN::subscribe_msgs(this); AP_Compass_UAVCAN::subscribe_msgs(this); AP_Baro_UAVCAN::subscribe_msgs(this); AP_BattMonitor_UAVCAN::subscribe_msgs(this); AP_Airspeed_UAVCAN::subscribe_msgs(this); AP_OpticalFlow_HereFlow::subscribe_msgs(this); AP_RangeFinder_UAVCAN::subscribe_msgs(this); auto *node= get_node(); uavcan::Subscriber* esc_status; esc_status = new uavcan::Subscriber(*node); const int esc_status_res = esc_status->start(esc_status_st_cb_arr[_driver_index]);//定义回调函数用于接收 if (esc_status_res<0) { return; } vesc_rpm[driver_index] = new uavcan::Publisher(*_node); vesc_rpm[driver_index]->setTxTimeout(uavcan::MonotonicDuration::fromMSec(2)); vesc_rpm[driver_index]->setPriority(uavcan::TransferPriority::OneLowerThanHighest); act_out_array[driver_index] = new uavcan::Publisher(*_node); act_out_array[driver_index]->setTxTimeout(uavcan::MonotonicDuration::fromMSec(2)); act_out_array[driver_index]->setPriority(uavcan::TransferPriority::OneLowerThanHighest); esc_raw[driver_index] = new uavcan::Publisher(*_node); esc_raw[driver_index]->setTxTimeout(uavcan::MonotonicDuration::fromMSec(2)); esc_raw[driver_index]->setPriority(uavcan::TransferPriority::OneLowerThanHighest); rgb_led[driver_index] = new uavcan::Publisher(*_node); rgb_led[driver_index]->setTxTimeout(uavcan::MonotonicDuration::fromMSec(20)); rgb_led[driver_index]->setPriority(uavcan::TransferPriority::OneHigherThanLowest); buzzer[driver_index] = new uavcan::Publisher(*_node); buzzer[driver_index]->setTxTimeout(uavcan::MonotonicDuration::fromMSec(20)); buzzer[driver_index]->setPriority(uavcan::TransferPriority::OneHigherThanLowest); safety_state[driver_index] = new uavcan::Publisher(*_node); safety_state[driver_index]->setTxTimeout(uavcan::MonotonicDuration::fromMSec(20)); safety_state[driver_index]->setPriority(uavcan::TransferPriority::OneHigherThanLowest); safety_button_listener[driver_index] = new uavcan::Subscriber(*_node); if (safety_button_listener[driver_index]) { safety_button_listener[driver_index]->start(ButtonCb(this, &handle_button)); } _led_conf.devices_count = 0; if (enable_filters) { configureCanAcceptanceFilters(*_node); } /* * Informing other nodes that we're ready to work. * Default mode is INITIALIZING. */ _node->setModeOperational(); // Spin node for device discovery _node->spin(uavcan::MonotonicDuration::fromMSec(5000)); snprintf(_thread_name, sizeof(_thread_name), "uavcan_%u", driver_index); if (!hal.scheduler->thread_create(FUNCTOR_BIND_MEMBER(&AP_UAVCAN::loop, void), _thread_name, 4096, AP_HAL::Scheduler::PRIORITY_CAN, 0)) { _node->setModeOfflineAndPublish(); debug_uavcan(1, "UAVCAN: couldn't create thread\n\r"); return; } _initialized = true; debug_uavcan(2, "UAVCAN: init done\n\r"); } void AP_UAVCAN::loop(void) { while (true) { if (!_initialized) { hal.scheduler->delay_microseconds(1000); continue; } const int error = _node->spin(uavcan::MonotonicDuration::fromMSec(1)); if (error < 0) { hal.scheduler->delay_microseconds(100); continue; } uint32_t now = AP_HAL::micros(); uint32_t servo_period_us = 1000000UL / unsigned(_servo_rate_hz.get()); if (now - _SRV_last_send_us >= servo_period_us){ _SRV_last_send_us = now; const AP_Motors6DOF &motors6dof = AP::motors6dof();//6自由度电机计算出来的PWM uavcan::equipment::esc::RPMCommand msg; msg.rpm.push_back(motors6dof.motor_to_can[0]); msg.rpm.push_back(motors6dof.motor_to_can[1]); msg.rpm.push_back(motors6dof.motor_to_can[2]); msg.rpm.push_back(motors6dof.motor_to_can[3]); msg.rpm.push_back(motors6dof.motor_to_can[4]); msg.rpm.push_back(motors6dof.motor_to_can[5]); vesc_rpm[_driver_index]->broadcast(msg); } } } ///// SRV output ///// void AP_UAVCAN::SRV_send_actuator(void) { uint8_t starting_servo = 0; bool repeat_send; WITH_SEMAPHORE(SRV_sem); do { repeat_send = false; uavcan::equipment::actuator::ArrayCommand msg; uint8_t i; // UAVCAN can hold maximum of 15 commands in one frame for (i = 0; starting_servo < UAVCAN_SRV_NUMBER && i < 15; starting_servo++) { uavcan::equipment::actuator::Command cmd; /* * Servo output uses a range of 1000-2000 PWM for scaling. * This converts output PWM from [1000:2000] range to [-1:1] range that * is passed to servo as unitless type via UAVCAN. * This approach allows for MIN/TRIM/MAX values to be used fully on * autopilot side and for servo it should have the setup to provide maximum * physically possible throws at [-1:1] limits. */ if (_SRV_conf[starting_servo].servo_pending && ((((uint32_t) 1) << starting_servo) & _servo_bm)) { cmd.actuator_id = starting_servo + 1; // TODO: other types cmd.command_type = uavcan::equipment::actuator::Command::COMMAND_TYPE_UNITLESS; // TODO: failsafe, safety cmd.command_value = constrain_float(((float) _SRV_conf[starting_servo].pulse - 1000.0) / 500.0 - 1.0, -1.0, 1.0); msg.commands.push_back(cmd); i++; } } if (i > 0) { act_out_array[_driver_index]->broadcast(msg); if (i == 15) { repeat_send = true; } } } while (repeat_send); } void AP_UAVCAN::SRV_send_esc(void) { static const int cmd_max = uavcan::equipment::esc::RawCommand::FieldTypes::cmd::RawValueType::max(); uavcan::equipment::esc::RawCommand esc_msg; uint8_t active_esc_num = 0, max_esc_num = 0; uint8_t k = 0; WITH_SEMAPHORE(SRV_sem); // find out how many esc we have enabled and if they are active at all for (uint8_t i = 0; i < UAVCAN_SRV_NUMBER; i++) { if ((((uint32_t) 1) << i) & _esc_bm) { max_esc_num = i + 1; if (_SRV_conf[i].esc_pending) { active_esc_num++; } } } // if at least one is active (update) we need to send to all if (active_esc_num > 0) { k = 0; for (uint8_t i = 0; i < max_esc_num && k < 20; i++) { if ((((uint32_t) 1) << i) & _esc_bm) { // TODO: ESC negative scaling for reverse thrust and reverse rotation float scaled = cmd_max * (hal.rcout->scale_esc_to_unity(_SRV_conf[i].pulse) + 1.0) / 2.0; scaled = constrain_float(scaled, 0, cmd_max); esc_msg.cmd.push_back(static_cast(scaled)); } else { esc_msg.cmd.push_back(static_cast(0)); } k++; } esc_raw[_driver_index]->broadcast(esc_msg); } } void AP_UAVCAN::SRV_push_servos() { WITH_SEMAPHORE(SRV_sem); for (uint8_t i = 0; i < NUM_SERVO_CHANNELS; i++) { // Check if this channels has any function assigned if (SRV_Channels::channel_function(i)) { _SRV_conf[i].pulse = SRV_Channels::srv_channel(i)->get_output_pwm(); _SRV_conf[i].esc_pending = true; _SRV_conf[i].servo_pending = true; } } _SRV_armed = hal.util->safety_switch_state() != AP_HAL::Util::SAFETY_DISARMED; } ///// LED ///// void AP_UAVCAN::led_out_send() { uint64_t now = AP_HAL::micros64(); if ((now - _led_conf.last_update) < LED_DELAY_US) { return; } uavcan::equipment::indication::LightsCommand msg; { WITH_SEMAPHORE(_led_out_sem); if (_led_conf.devices_count == 0) { return; } uavcan::equipment::indication::SingleLightCommand cmd; for (uint8_t i = 0; i < _led_conf.devices_count; i++) { cmd.light_id =_led_conf.devices[i].led_index; cmd.color.red = _led_conf.devices[i].red >> 3; cmd.color.green = _led_conf.devices[i].green >> 2; cmd.color.blue = _led_conf.devices[i].blue >> 3; msg.commands.push_back(cmd); } } rgb_led[_driver_index]->broadcast(msg); _led_conf.last_update = now; } bool AP_UAVCAN::led_write(uint8_t led_index, uint8_t red, uint8_t green, uint8_t blue) { if (_led_conf.devices_count >= AP_UAVCAN_MAX_LED_DEVICES) { return false; } WITH_SEMAPHORE(_led_out_sem); // check if a device instance exists. if so, break so the instance index is remembered uint8_t instance = 0; for (; instance < _led_conf.devices_count; instance++) { if (_led_conf.devices[instance].led_index == led_index) { break; } } // load into the correct instance. // if an existing instance was found in above for loop search, // then instance value is < _led_conf.devices_count. // otherwise a new one was just found so we increment the count. // Either way, the correct instance is the current value of instance _led_conf.devices[instance].led_index = led_index; _led_conf.devices[instance].red = red; _led_conf.devices[instance].green = green; _led_conf.devices[instance].blue = blue; if (instance == _led_conf.devices_count) { _led_conf.devices_count++; } return true; } // buzzer send void AP_UAVCAN::buzzer_send() { uavcan::equipment::indication::BeepCommand msg; WITH_SEMAPHORE(_buzzer.sem); uint8_t mask = (1U << _driver_index); if ((_buzzer.pending_mask & mask) == 0) { return; } _buzzer.pending_mask &= ~mask; msg.frequency = _buzzer.frequency; msg.duration = _buzzer.duration; buzzer[_driver_index]->broadcast(msg); } // buzzer support void AP_UAVCAN::set_buzzer_tone(float frequency, float duration_s) { WITH_SEMAPHORE(_buzzer.sem); _buzzer.frequency = frequency; _buzzer.duration = duration_s; _buzzer.pending_mask = 0xFF; } // SafetyState send void AP_UAVCAN::safety_state_send() { ardupilot::indication::SafetyState msg; uint32_t now = AP_HAL::millis(); if (now - _last_safety_state_ms < 500) { // update at 2Hz return; } _last_safety_state_ms = now; switch (hal.util->safety_switch_state()) { case AP_HAL::Util::SAFETY_ARMED: msg.status = ardupilot::indication::SafetyState::STATUS_SAFETY_OFF; break; case AP_HAL::Util::SAFETY_DISARMED: msg.status = ardupilot::indication::SafetyState::STATUS_SAFETY_ON; break; default: // nothing to send return; } safety_state[_driver_index]->broadcast(msg); } /* handle Button message */ void AP_UAVCAN::handle_button(AP_UAVCAN* ap_uavcan, uint8_t node_id, const ButtonCb &cb) { switch (cb.msg->button) { case ardupilot::indication::Button::BUTTON_SAFETY: { AP_BoardConfig *brdconfig = AP_BoardConfig::get_singleton(); if (brdconfig && brdconfig->safety_button_handle_pressed(cb.msg->press_time)) { AP_HAL::Util::safety_state state = hal.util->safety_switch_state(); if (state == AP_HAL::Util::SAFETY_ARMED) { hal.rcout->force_safety_on(); } else { hal.rcout->force_safety_off(); } } break; } } } AP_UAVCAN *AP_UAVCAN::_singleton; namespace AP { AP_UAVCAN &uavcan() { return *AP_UAVCAN::get_singleton(); } }; #endif // HAL_WITH_UAVCAN