Line data Source code
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 : simulator connector for ardupilot version of CRRCSim
17 : */
18 :
19 : #include "SIM_config.h"
20 :
21 : #if AP_SIM_CRRCSIM_ENABLED
22 :
23 : #include "SIM_CRRCSim.h"
24 :
25 : #include <stdio.h>
26 :
27 : #include <AP_HAL/AP_HAL.h>
28 :
29 : extern const AP_HAL::HAL& hal;
30 :
31 : namespace SITL {
32 :
33 0 : CRRCSim::CRRCSim(const char *frame_str) :
34 : Aircraft(frame_str),
35 0 : last_timestamp(0),
36 0 : sock(true)
37 : {
38 : // try to bind to a specific port so that if we restart ArduPilot
39 : // CRRCSim keeps sending us packets. Not strictly necessary but
40 : // useful for debugging
41 0 : sock.bind("127.0.0.1", 9003);
42 :
43 0 : sock.reuseaddress();
44 0 : sock.set_blocking(false);
45 0 : heli_servos = (strstr(frame_str,"heli") != nullptr);
46 0 : }
47 :
48 : /*
49 : decode and send servos for heli
50 : */
51 0 : void CRRCSim::send_servos_heli(const struct sitl_input &input)
52 : {
53 0 : float swash1 = (input.servos[0]-1000) / 1000.0f;
54 0 : float swash2 = (input.servos[1]-1000) / 1000.0f;
55 0 : float swash3 = (input.servos[2]-1000) / 1000.0f;
56 0 : float tail_rotor = (input.servos[3]-1000) / 1000.0f;
57 0 : float rsc = (input.servos[7]-1000) / 1000.0f;
58 :
59 0 : float col_pitch = (swash1+swash2+swash3)/3.0 - 0.5f;
60 0 : float roll_rate = (swash1 - swash2)/2;
61 0 : float pitch_rate = -((swash1 + swash2)/2.0 - swash3)/2;
62 0 : float yaw_rate = -(tail_rotor - 0.5);
63 :
64 : servo_packet pkt;
65 0 : pkt.roll_rate = constrain_float(roll_rate, -0.5, 0.5);
66 0 : pkt.pitch_rate = constrain_float(pitch_rate, -0.5, 0.5);
67 0 : pkt.throttle = constrain_float(rsc, 0, 1);
68 0 : pkt.yaw_rate = constrain_float(yaw_rate, -0.5, 0.5);
69 0 : pkt.col_pitch = constrain_float(col_pitch, -0.5, 0.5);
70 :
71 0 : sock.sendto(&pkt, sizeof(pkt), "127.0.0.1", 9002);
72 0 : }
73 :
74 : /*
75 : decode and send servos for fixed wing
76 : */
77 0 : void CRRCSim::send_servos_fixed_wing(const struct sitl_input &input)
78 : {
79 0 : float roll_rate = ((input.servos[0]-1000)/1000.0) - 0.5;
80 0 : float pitch_rate = ((input.servos[1]-1000)/1000.0) - 0.5;
81 0 : float yaw_rate = ((input.servos[3]-1000)/1000.0) - 0.5;
82 0 : float throttle = ((input.servos[2]-1000)/1000.0);
83 :
84 : servo_packet pkt;
85 0 : pkt.roll_rate = constrain_float(roll_rate, -0.5, 0.5);
86 0 : pkt.pitch_rate = constrain_float(pitch_rate, -0.5, 0.5);
87 0 : pkt.throttle = constrain_float(throttle, 0, 1);
88 0 : pkt.yaw_rate = constrain_float(yaw_rate, -0.5, 0.5);
89 0 : pkt.col_pitch = 0;
90 :
91 0 : sock.sendto(&pkt, sizeof(pkt), "127.0.0.1", 9002);
92 0 : }
93 :
94 : /*
95 : decode and send servos
96 : */
97 0 : void CRRCSim::send_servos(const struct sitl_input &input)
98 : {
99 0 : if (heli_servos) {
100 0 : send_servos_heli(input);
101 : } else {
102 0 : send_servos_fixed_wing(input);
103 : }
104 0 : }
105 :
106 : /*
107 : receive an update from the FDM
108 : This is a blocking function
109 : */
110 0 : void CRRCSim::recv_fdm(const struct sitl_input &input)
111 : {
112 : fdm_packet pkt;
113 :
114 : /*
115 : we re-send the servo packet every 0.1 seconds until we get a
116 : reply. This allows us to cope with some packet loss to the FDM
117 : */
118 0 : while (sock.recv(&pkt, sizeof(pkt), 100) != sizeof(pkt)) {
119 0 : send_servos(input);
120 : }
121 :
122 0 : accel_body = Vector3f(pkt.xAccel, pkt.yAccel, pkt.zAccel);
123 0 : gyro = Vector3f(pkt.rollRate, pkt.pitchRate, pkt.yawRate);
124 0 : velocity_ef = Vector3f(pkt.speedN, pkt.speedE, pkt.speedD);
125 :
126 0 : origin.lat = pkt.latitude * 1.0e7;
127 0 : origin.lng = pkt.longitude * 1.0e7;
128 0 : position.xy().zero();
129 0 : position.z = -pkt.altitude;
130 :
131 0 : airspeed = pkt.airspeed;
132 0 : airspeed_pitot = pkt.airspeed;
133 :
134 0 : dcm.from_euler(pkt.roll, pkt.pitch, pkt.yaw);
135 :
136 : // auto-adjust to crrcsim frame rate
137 0 : double deltat = pkt.timestamp - last_timestamp;
138 0 : time_now_us += deltat * 1.0e6;
139 :
140 0 : if (deltat < 0.01 && deltat > 0) {
141 0 : adjust_frame_time(1.0/deltat);
142 : }
143 0 : last_timestamp = pkt.timestamp;
144 0 : }
145 :
146 : /*
147 : update the CRRCSim simulation by one time step
148 : */
149 0 : void CRRCSim::update(const struct sitl_input &input)
150 : {
151 0 : send_servos(input);
152 0 : recv_fdm(input);
153 0 : update_battery();
154 0 : update_position();
155 0 : time_advance();
156 :
157 : // update magnetic field
158 0 : update_mag_field_bf();
159 0 : }
160 :
161 : } // namespace SITL
162 :
163 : #endif // AP_SIM_CRRCSIM_ENABLED
|