Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ardupilot
GitHub Repository: Ardupilot/ardupilot
Path: blob/master/Tools/AP_Periph/actuator_telem.cpp
9424 views
1
/*
2
This program is free software: you can redistribute it and/or modify
3
it under the terms of the GNU General Public License as published by
4
the Free Software Foundation, either version 3 of the License, or
5
(at your option) any later version.
6
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
11
12
You should have received a copy of the GNU General Public License
13
along with this program. If not, see <http://www.gnu.org/licenses/>.
14
*/
15
16
#include "AP_Periph.h"
17
18
#if AP_PERIPH_ACTUATOR_TELEM_ENABLED
19
20
#include <dronecan_msgs.h>
21
22
extern const AP_HAL::HAL &hal;
23
24
#ifndef AP_PERIPH_ACTUATOR_TELEM_RATE_DEFAULT
25
#define AP_PERIPH_ACTUATOR_TELEM_RATE_DEFAULT 10
26
#endif
27
28
#ifndef AP_PERIPH_ACTUATOR_TELEM_NUM_CHANNELS_DEFAULT
29
#define AP_PERIPH_ACTUATOR_TELEM_NUM_CHANNELS_DEFAULT 0
30
#endif
31
32
#ifndef AP_PERIPH_ACTUATOR_TELEM_CURR_PIN_DEFAULT
33
#define AP_PERIPH_ACTUATOR_TELEM_CURR_PIN_DEFAULT -1
34
#endif
35
36
#ifndef AP_PERIPH_ACTUATOR_TELEM_CURR_AMP_OFFSET_DEFAULT
37
#define AP_PERIPH_ACTUATOR_TELEM_CURR_AMP_OFFSET_DEFAULT 0.0f
38
#endif
39
40
#ifndef AP_PERIPH_ACTUATOR_TELEM_CURR_AMP_PERVLT_DEFAULT
41
#define AP_PERIPH_ACTUATOR_TELEM_CURR_AMP_PERVLT_DEFAULT 10
42
#endif
43
44
#ifndef AP_PERIPH_ACTUATOR_TELEM_CURR_MAX_DEFAULT
45
#define AP_PERIPH_ACTUATOR_TELEM_CURR_MAX_DEFAULT 2.5f
46
#endif
47
48
const AP_Param::GroupInfo ActuatorTelem::var_info[] = {
49
// @Param: _TELEM_RATE
50
// @DisplayName: Actuator Telemetry rate
51
// @Description: Actuator Telemetry update rate in Hz. Set to 0 to disable.
52
// @Units: Hz
53
// @Range: 0 100
54
// @User: Standard
55
AP_GROUPINFO("_TELEM_RATE", 1, ActuatorTelem, rate, AP_PERIPH_ACTUATOR_TELEM_RATE_DEFAULT),
56
57
// @Param: _NUM_CHANS
58
// @DisplayName: Number of actuator channels
59
// @Description: Number of actuator channels to monitor for telemetry.
60
// @Range: 0 4
61
// @User: Standard
62
AP_GROUPINFO("_NUM_CHANS", 2, ActuatorTelem, num_chans, AP_PERIPH_ACTUATOR_TELEM_NUM_CHANNELS_DEFAULT),
63
64
// @Param: _CURR_PIN1
65
// @DisplayName: Current sensing pin 1
66
// @Description: Analog input pin number for current sensing on channel 1. Set to -1 to disable.
67
// @Values: -1:Disabled
68
// @Range: -1 127
69
// @User: Standard
70
// @RebootRequired: True
71
AP_GROUPINFO("_CURR_PIN1", 3, ActuatorTelem, curr_pin1, AP_PERIPH_ACTUATOR_TELEM_CURR_PIN_DEFAULT),
72
73
// @Param: _AMP_OFFSET
74
// @DisplayName: Current sensor offset
75
// @Description: Voltage offset at zero current on the current sensor.
76
// @Units: V
77
// @User: Standard
78
AP_GROUPINFO("AMP_OFFSET", 4, ActuatorTelem, curr_amp_offset, AP_PERIPH_ACTUATOR_TELEM_CURR_AMP_OFFSET_DEFAULT),
79
80
// @Param: _AMP_PERVLT
81
// @DisplayName: Amps per volt
82
// @Description: Current sensor scale factor.
83
// @Units: A/V
84
// @User: Standard
85
AP_GROUPINFO("AMP_PERVLT", 5, ActuatorTelem, curr_amp_per_volt, AP_PERIPH_ACTUATOR_TELEM_CURR_AMP_PERVLT_DEFAULT),
86
87
// @Param: _CURR_MAX
88
// @DisplayName: Maximum current
89
// @Description: Maximum expected current for this channel.
90
// @Units: A
91
// @User: Standard
92
AP_GROUPINFO("CURR_MAX", 6, ActuatorTelem, curr_max, AP_PERIPH_ACTUATOR_TELEM_CURR_MAX_DEFAULT),
93
94
AP_GROUPEND
95
};
96
97
ActuatorTelem::ActuatorTelem(void)
98
{
99
AP_Param::setup_object_defaults(this, var_info);
100
for (uint8_t i = 0; i < HAL_ACTUATOR_TELEM_CURR_MAX_CHANNELS; i++) {
101
analog_sources[i] = nullptr;
102
}
103
}
104
105
void ActuatorTelem::init(void)
106
{
107
const int8_t curr_pin1_val = curr_pin1.get();
108
const int8_t num_chans_val = num_chans.get();
109
110
if (curr_pin1_val >= 0 && num_chans_val > 0) {
111
for (uint8_t i = 0; i < MIN(HAL_ACTUATOR_TELEM_CURR_MAX_CHANNELS, num_chans_val); i++) {
112
const int8_t pin = curr_pin1_val + i;
113
if (pin >= 0) {
114
analog_sources[i] = hal.analogin->channel(pin);
115
}
116
}
117
}
118
}
119
120
void ActuatorTelem::send_telemetry(uint8_t channel_index, uint8_t actuator_id)
121
{
122
// Check if this channel is enabled
123
if (channel_index >= HAL_ACTUATOR_TELEM_CURR_MAX_CHANNELS) {
124
return;
125
}
126
127
AP_HAL::AnalogSource *source = analog_sources[channel_index];
128
if (source == nullptr) {
129
return;
130
}
131
// Read current from analog input
132
float current_amp = 0;
133
float adc_voltage = source->voltage_average();
134
current_amp = (adc_voltage - curr_amp_offset) * curr_amp_per_volt;
135
136
uavcan_equipment_actuator_Status pkt {};
137
138
pkt.actuator_id = actuator_id;
139
pkt.position = nanf(""); // Not available
140
pkt.force = nanf(""); // Not available
141
pkt.speed = nanf(""); // Not available
142
143
// Calculate power rating percentage from current
144
const float max_current = curr_max.get();
145
if (max_current > 0 && current_amp >= 0) {
146
pkt.power_rating_pct = constrain_int16(current_amp / max_current * 100.0f, 0, 100);
147
} else {
148
pkt.power_rating_pct = UAVCAN_EQUIPMENT_ACTUATOR_STATUS_POWER_RATING_PCT_UNKNOWN;
149
}
150
151
// encode and broadcast
152
uint8_t buffer[UAVCAN_EQUIPMENT_ACTUATOR_STATUS_MAX_SIZE];
153
uint16_t total_size = uavcan_equipment_actuator_Status_encode(&pkt, buffer, !periph.canfdout());
154
155
periph.canard_broadcast(UAVCAN_EQUIPMENT_ACTUATOR_STATUS_SIGNATURE,
156
UAVCAN_EQUIPMENT_ACTUATOR_STATUS_ID,
157
CANARD_TRANSFER_PRIORITY_LOW,
158
&buffer[0],
159
total_size);
160
}
161
162
void ActuatorTelem::update()
163
{
164
// Check global telemetry rate
165
const float telem_rate = rate.get();
166
if (telem_rate <= 0) {
167
return; // telemetry disabled
168
}
169
170
const uint32_t now = AP_HAL::millis();
171
if (now - last_telem_update_ms < 1000.0f / telem_rate) {
172
return;
173
}
174
last_telem_update_ms = now;
175
176
#if HAL_PWM_COUNT > 0
177
const int8_t num_chans_val = num_chans.get();
178
if (num_chans_val > 0) {
179
for (uint8_t i = 0; i < MIN(HAL_PWM_COUNT, num_chans_val); i++) {
180
const auto *srv_channel = periph.servo_channels.srv_channel(i);
181
if (srv_channel == nullptr) {
182
continue;
183
}
184
185
const SRV_Channel::Function function = srv_channel->get_function();
186
// Only send for configured actuator functions
187
if (function < SRV_Channel::k_rcin1 || function > SRV_Channel::k_rcin16) {
188
continue;
189
}
190
191
const uint8_t actuator_id = function - SRV_Channel::k_rcin1 + 1;
192
193
send_telemetry(i, actuator_id);
194
}
195
}
196
#endif
197
}
198
199
#endif // AP_PERIPH_ACTUATOR_TELEM_ENABLED
200
201