2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
31 #include "common/maths.h"
33 #include "drivers/io.h"
34 #include "drivers/dma.h"
35 #include "drivers/motor.h"
36 #include "drivers/serial.h"
37 #include "drivers/serial_tcp.h"
38 #include "drivers/system.h"
39 #include "drivers/pwm_output.h"
40 #include "drivers/light_led.h"
42 #include "drivers/timer.h"
43 #include "timer_def.h"
45 #include "drivers/accgyro/accgyro_virtual.h"
46 #include "drivers/barometer/barometer_virtual.h"
47 #include "flight/imu.h"
49 #include "config/feature.h"
50 #include "config/config.h"
51 #include "scheduler/scheduler.h"
59 #include "target/SITL/udplink.h"
61 uint32_t SystemCoreClock
;
63 static fdm_packet fdmPkt
;
64 static rc_packet rcPkt
;
65 static servo_packet pwmPkt
;
66 static servo_packet_raw pwmRawPkt
;
68 static bool rc_received
= false;
69 static bool fdm_received
= false;
71 static struct timespec start_time
;
72 static double simRate
= 1.0;
73 static pthread_t tcpWorker
, udpWorker
, udpWorkerRC
;
74 static bool workerRunning
= true;
75 static udpLink_t stateLink
, pwmLink
, pwmRawLink
, rcLink
;
76 static pthread_mutex_t updateLock
;
77 static pthread_mutex_t mainLoopLock
;
78 static char simulator_ip
[32] = "127.0.0.1";
80 #define PORT_PWM_RAW 9001 // Out
81 #define PORT_PWM 9002 // Out
82 #define PORT_STATE 9003 // In
83 #define PORT_RC 9004 // In
85 int targetParseArgs(int argc
, char * argv
[])
87 //The first argument should be target IP.
89 strcpy(simulator_ip
, argv
[1]);
92 printf("[SITL] The SITL will output to IP %s:%d (Gazebo) and %s:%d (RealFlightBridge)\n",
93 simulator_ip
, PORT_PWM
, simulator_ip
, PORT_PWM_RAW
);
97 int timeval_sub(struct timespec
*result
, struct timespec
*x
, struct timespec
*y
);
101 return pthread_mutex_trylock(&mainLoopLock
);
104 #define RAD2DEG (180.0 / M_PI)
105 #define ACC_SCALE (256 / 9.80665)
106 #define GYRO_SCALE (16.4)
108 void sendMotorUpdate(void)
110 udpSend(&pwmLink
, &pwmPkt
, sizeof(servo_packet
));
113 void updateState(const fdm_packet
* pkt
)
115 static double last_timestamp
= 0; // in seconds
116 static uint64_t last_realtime
= 0; // in uS
117 static struct timespec last_ts
; // last packet
119 struct timespec now_ts
;
120 clock_gettime(CLOCK_MONOTONIC
, &now_ts
);
122 const uint64_t realtime_now
= micros64_real();
123 if (realtime_now
> last_realtime
+ 500*1e3
) { // 500ms timeout
124 last_timestamp
= pkt
->timestamp
;
125 last_realtime
= realtime_now
;
130 const double deltaSim
= pkt
->timestamp
- last_timestamp
; // in seconds
131 if (deltaSim
< 0) { // don't use old packet
136 x
= constrain(-pkt
->imu_linear_acceleration_xyz
[0] * ACC_SCALE
, -32767, 32767);
137 y
= constrain(-pkt
->imu_linear_acceleration_xyz
[1] * ACC_SCALE
, -32767, 32767);
138 z
= constrain(-pkt
->imu_linear_acceleration_xyz
[2] * ACC_SCALE
, -32767, 32767);
139 virtualAccSet(virtualAccDev
, x
, y
, z
);
140 // printf("[acc]%lf,%lf,%lf\n", pkt->imu_linear_acceleration_xyz[0], pkt->imu_linear_acceleration_xyz[1], pkt->imu_linear_acceleration_xyz[2]);
142 x
= constrain(pkt
->imu_angular_velocity_rpy
[0] * GYRO_SCALE
* RAD2DEG
, -32767, 32767);
143 y
= constrain(-pkt
->imu_angular_velocity_rpy
[1] * GYRO_SCALE
* RAD2DEG
, -32767, 32767);
144 z
= constrain(-pkt
->imu_angular_velocity_rpy
[2] * GYRO_SCALE
* RAD2DEG
, -32767, 32767);
145 virtualGyroSet(virtualGyroDev
, x
, y
, z
);
146 // printf("[gyr]%lf,%lf,%lf\n", pkt->imu_angular_velocity_rpy[0], pkt->imu_angular_velocity_rpy[1], pkt->imu_angular_velocity_rpy[2]);
148 // temperature in 0.01 C = 25 deg
149 virtualBaroSet(pkt
->pressure
, 2500);
150 #if !defined(USE_IMU_CALC)
151 #if defined(SET_IMU_FROM_EULER)
153 double qw
= pkt
->imu_orientation_quat
[0];
154 double qx
= pkt
->imu_orientation_quat
[1];
155 double qy
= pkt
->imu_orientation_quat
[2];
156 double qz
= pkt
->imu_orientation_quat
[3];
157 double ysqr
= qy
* qy
;
160 // roll (x-axis rotation)
161 double t0
= +2.0 * (qw
* qx
+ qy
* qz
);
162 double t1
= +1.0 - 2.0 * (qx
* qx
+ ysqr
);
163 xf
= atan2(t0
, t1
) * RAD2DEG
;
165 // pitch (y-axis rotation)
166 double t2
= +2.0 * (qw
* qy
- qz
* qx
);
167 t2
= t2
> 1.0 ? 1.0 : t2
;
168 t2
= t2
< -1.0 ? -1.0 : t2
;
169 yf
= asin(t2
) * RAD2DEG
; // from wiki
171 // yaw (z-axis rotation)
172 double t3
= +2.0 * (qw
* qz
+ qx
* qy
);
173 double t4
= +1.0 - 2.0 * (ysqr
+ qz
* qz
);
174 zf
= atan2(t3
, t4
) * RAD2DEG
;
175 imuSetAttitudeRPY(xf
, -yf
, zf
); // yes! pitch was inverted!!
177 imuSetAttitudeQuat(pkt
->imu_orientation_quat
[0], pkt
->imu_orientation_quat
[1], pkt
->imu_orientation_quat
[2], pkt
->imu_orientation_quat
[3]);
181 #if defined(SIMULATOR_IMU_SYNC)
182 imuSetHasNewData(deltaSim
*1e6
);
183 imuUpdateAttitude(micros());
187 if (deltaSim
< 0.02 && deltaSim
> 0) { // simulator should run faster than 50Hz
188 // simRate = simRate * 0.5 + (1e6 * deltaSim / (realtime_now - last_realtime)) * 0.5;
189 struct timespec out_ts
;
190 timeval_sub(&out_ts
, &now_ts
, &last_ts
);
191 simRate
= deltaSim
/ (out_ts
.tv_sec
+ 1e-9*out_ts
.tv_nsec
);
193 // printf("simRate = %lf, millis64 = %lu, millis64_real = %lu, deltaSim = %lf\n", simRate, millis64(), millis64_real(), deltaSim*1e6);
195 last_timestamp
= pkt
->timestamp
;
196 last_realtime
= micros64_real();
198 last_ts
.tv_sec
= now_ts
.tv_sec
;
199 last_ts
.tv_nsec
= now_ts
.tv_nsec
;
201 pthread_mutex_unlock(&updateLock
); // can send PWM output now
203 #if defined(SIMULATOR_GYROPID_SYNC)
204 pthread_mutex_unlock(&mainLoopLock
); // can run main loop
208 static void* udpThread(void* data
)
213 while (workerRunning
) {
214 n
= udpRecv(&stateLink
, &fdmPkt
, sizeof(fdm_packet
), 100);
215 if (n
== sizeof(fdm_packet
)) {
217 printf("[SITL] new fdm %d t:%f from %s:%d\n", n
, fdmPkt
.timestamp
, inet_ntoa(stateLink
.recv
.sin_addr
), stateLink
.recv
.sin_port
);
220 updateState(&fdmPkt
);
224 printf("udpThread end!!\n");
228 static float readRCSITL(const rxRuntimeState_t
*rxRuntimeState
, uint8_t channel
)
230 UNUSED(rxRuntimeState
);
231 return rcPkt
.channels
[channel
];
234 static uint8_t rxRCFrameStatus(rxRuntimeState_t
*rxRuntimeState
)
236 UNUSED(rxRuntimeState
);
237 return RX_FRAME_COMPLETE
;
240 static void *udpRCThread(void *data
)
245 while (workerRunning
) {
246 n
= udpRecv(&rcLink
, &rcPkt
, sizeof(rc_packet
), 100);
247 if (n
== sizeof(rc_packet
)) {
249 printf("[SITL] new rc %d: t:%f AETR: %d %d %d %d AUX1-4: %d %d %d %d\n", n
, rcPkt
.timestamp
,
250 rcPkt
.channels
[0], rcPkt
.channels
[1],rcPkt
.channels
[2],rcPkt
.channels
[3],
251 rcPkt
.channels
[4], rcPkt
.channels
[5],rcPkt
.channels
[6],rcPkt
.channels
[7]);
253 rxRuntimeState
.channelCount
= SIMULATOR_MAX_RC_CHANNELS
;
254 rxRuntimeState
.rcReadRawFn
= readRCSITL
;
255 rxRuntimeState
.rcFrameStatusFn
= rxRCFrameStatus
;
257 rxRuntimeState
.rxProvider
= RX_PROVIDER_UDP
;
263 printf("udpRCThread end!!\n");
267 static void* tcpThread(void* data
)
272 dyad_setTickInterval(0.2f
);
273 dyad_setUpdateTimeout(0.5f
);
275 while (workerRunning
) {
280 printf("tcpThread end!!\n");
285 void systemInit(void)
289 clock_gettime(CLOCK_MONOTONIC
, &start_time
);
290 printf("[system]Init...\n");
292 SystemCoreClock
= 500 * 1e6
; // virtual 500MHz
294 if (pthread_mutex_init(&updateLock
, NULL
) != 0) {
295 printf("Create updateLock error!\n");
299 if (pthread_mutex_init(&mainLoopLock
, NULL
) != 0) {
300 printf("Create mainLoopLock error!\n");
304 ret
= pthread_create(&tcpWorker
, NULL
, tcpThread
, NULL
);
306 printf("Create tcpWorker error!\n");
310 ret
= udpInit(&pwmLink
, simulator_ip
, PORT_PWM
, false);
311 printf("[SITL] init PwmOut UDP link to gazebo %s:%d...%d\n", simulator_ip
, PORT_PWM
, ret
);
313 ret
= udpInit(&pwmRawLink
, simulator_ip
, PORT_PWM_RAW
, false);
314 printf("[SITL] init PwmOut UDP link to RF9 %s:%d...%d\n", simulator_ip
, PORT_PWM_RAW
, ret
);
316 ret
= udpInit(&stateLink
, NULL
, PORT_STATE
, true);
317 printf("[SITL] start UDP server @%d...%d\n", PORT_STATE
, ret
);
319 ret
= udpInit(&rcLink
, NULL
, PORT_RC
, true);
320 printf("[SITL] start UDP server for RC input @%d...%d\n", PORT_RC
, ret
);
322 ret
= pthread_create(&udpWorker
, NULL
, udpThread
, NULL
);
324 printf("Create udpWorker error!\n");
328 ret
= pthread_create(&udpWorkerRC
, NULL
, udpRCThread
, NULL
);
330 printf("Create udpRCThread error!\n");
335 void systemReset(void)
337 printf("[system]Reset!\n");
338 workerRunning
= false;
339 pthread_join(tcpWorker
, NULL
);
340 pthread_join(udpWorker
, NULL
);
343 void systemResetToBootloader(bootloaderRequestType_e requestType
)
347 printf("[system]ResetToBootloader!\n");
348 workerRunning
= false;
349 pthread_join(tcpWorker
, NULL
);
350 pthread_join(udpWorker
, NULL
);
356 printf("[timer]Init...\n");
359 void failureMode(failureMode_e mode
)
361 printf("[failureMode]!!! %d\n", mode
);
365 void indicateFailure(failureMode_e mode
, int repeatCount
)
368 printf("Failure LED flash for: [failureMode]!!! %d\n", mode
);
373 uint64_t nanos64_real(void)
376 clock_gettime(CLOCK_MONOTONIC
, &ts
);
377 return (ts
.tv_sec
*1e9
+ ts
.tv_nsec
) - (start_time
.tv_sec
*1e9
+ start_time
.tv_nsec
);
380 uint64_t micros64_real(void)
383 clock_gettime(CLOCK_MONOTONIC
, &ts
);
384 return 1.0e6
*((ts
.tv_sec
+ (ts
.tv_nsec
*1.0e-9)) - (start_time
.tv_sec
+ (start_time
.tv_nsec
*1.0e-9)));
387 uint64_t millis64_real(void)
390 clock_gettime(CLOCK_MONOTONIC
, &ts
);
391 return 1.0e3
*((ts
.tv_sec
+ (ts
.tv_nsec
*1.0e-9)) - (start_time
.tv_sec
+ (start_time
.tv_nsec
*1.0e-9)));
394 uint64_t micros64(void)
396 static uint64_t last
= 0;
397 static uint64_t out
= 0;
398 uint64_t now
= nanos64_real();
400 out
+= (now
- last
) * simRate
;
404 // return micros64_real();
407 uint64_t millis64(void)
409 static uint64_t last
= 0;
410 static uint64_t out
= 0;
411 uint64_t now
= nanos64_real();
413 out
+= (now
- last
) * simRate
;
417 // return millis64_real();
420 uint32_t micros(void)
422 return micros64() & 0xFFFFFFFF;
425 uint32_t millis(void)
427 return millis64() & 0xFFFFFFFF;
430 int32_t clockCyclesToMicros(int32_t clockCycles
)
435 int32_t clockCyclesTo10thMicros(int32_t clockCycles
)
440 uint32_t clockMicrosToCycles(uint32_t micros
)
444 uint32_t getCycleCounter(void)
446 return (uint32_t) (micros64() & 0xFFFFFFFF);
449 void microsleep(uint32_t usec
)
453 ts
.tv_nsec
= usec
*1000UL;
454 while (nanosleep(&ts
, &ts
) == -1 && errno
== EINTR
) ;
457 void delayMicroseconds(uint32_t us
)
459 microsleep(us
/ simRate
);
462 void delayMicroseconds_real(uint32_t us
)
467 void delay(uint32_t ms
)
469 uint64_t start
= millis64();
471 while ((millis64() - start
) < ms
) {
476 // Subtract the ‘struct timespec’ values X and Y, storing the result in RESULT.
477 // Return 1 if the difference is negative, otherwise 0.
479 // from: http://www.gnu.org/software/libc/manual/html_node/Elapsed-Time.html
480 int timeval_sub(struct timespec
*result
, struct timespec
*x
, struct timespec
*y
)
482 unsigned int s_carry
= 0;
483 unsigned int ns_carry
= 0;
484 // Perform the carry for the later subtraction by updating y.
485 if (x
->tv_nsec
< y
->tv_nsec
) {
486 int nsec
= (y
->tv_nsec
- x
->tv_nsec
) / 1000000000 + 1;
487 ns_carry
+= 1000000000 * nsec
;
491 // Compute the time remaining to wait. tv_usec is certainly positive.
492 result
->tv_sec
= x
->tv_sec
- y
->tv_sec
- s_carry
;
493 result
->tv_nsec
= x
->tv_nsec
- y
->tv_nsec
+ ns_carry
;
495 // Return 1 if result is negative.
496 return x
->tv_sec
< y
->tv_sec
;
501 pwmOutputPort_t motors
[MAX_SUPPORTED_MOTORS
];
502 static pwmOutputPort_t servos
[MAX_SUPPORTED_SERVOS
];
504 // real value to send
505 static int16_t motorsPwm
[MAX_SUPPORTED_MOTORS
];
506 static int16_t servosPwm
[MAX_SUPPORTED_SERVOS
];
507 static int16_t idlePulse
;
509 void servoDevInit(const servoDevConfig_t
*servoConfig
)
511 printf("[SITL] Init servos num %d rate %d center %d\n", MAX_SUPPORTED_SERVOS
,
512 servoConfig
->servoPwmRate
, servoConfig
->servoCenterPulse
);
513 for (uint8_t servoIndex
= 0; servoIndex
< MAX_SUPPORTED_SERVOS
; servoIndex
++) {
514 servos
[servoIndex
].enabled
= true;
518 static motorDevice_t motorPwmDevice
; // Forward
520 pwmOutputPort_t
*pwmGetMotors(void)
525 static float pwmConvertFromExternal(uint16_t externalValue
)
527 return (float)externalValue
;
530 static uint16_t pwmConvertToExternal(float motorValue
)
532 return (uint16_t)motorValue
;
535 static void pwmDisableMotors(void)
537 motorPwmDevice
.enabled
= false;
540 static bool pwmEnableMotors(void)
542 motorPwmDevice
.enabled
= true;
547 static void pwmWriteMotor(uint8_t index
, float value
)
549 if (pthread_mutex_trylock(&updateLock
) != 0) return;
551 if (index
< MAX_SUPPORTED_MOTORS
) {
552 motorsPwm
[index
] = value
- idlePulse
;
555 if (index
< pwmRawPkt
.motorCount
) {
556 pwmRawPkt
.pwm_output_raw
[index
] = value
;
559 pthread_mutex_unlock(&updateLock
); // can send PWM output now
562 static void pwmWriteMotorInt(uint8_t index
, uint16_t value
)
564 pwmWriteMotor(index
, (float)value
);
567 static void pwmShutdownPulsesForAllMotors(void)
569 motorPwmDevice
.enabled
= false;
572 bool pwmIsMotorEnabled(uint8_t index
)
574 return motors
[index
].enabled
;
577 static void pwmCompleteMotorUpdate(void)
580 // for gazebo8 ArduCopterPlugin remap, normal range = [0.0, 1.0], 3D rang = [-1.0, 1.0]
582 double outScale
= 1000.0;
583 if (featureIsEnabled(FEATURE_3D
)) {
587 pwmPkt
.motor_speed
[3] = motorsPwm
[0] / outScale
;
588 pwmPkt
.motor_speed
[0] = motorsPwm
[1] / outScale
;
589 pwmPkt
.motor_speed
[1] = motorsPwm
[2] / outScale
;
590 pwmPkt
.motor_speed
[2] = motorsPwm
[3] / outScale
;
592 // get one "fdm_packet" can only send one "servo_packet"!!
593 if (pthread_mutex_trylock(&updateLock
) != 0) return;
594 udpSend(&pwmLink
, &pwmPkt
, sizeof(servo_packet
));
595 // printf("[pwm]%u:%u,%u,%u,%u\n", idlePulse, motorsPwm[0], motorsPwm[1], motorsPwm[2], motorsPwm[3]);
596 udpSend(&pwmRawLink
, &pwmRawPkt
, sizeof(servo_packet_raw
));
599 void pwmWriteServo(uint8_t index
, float value
)
601 servosPwm
[index
] = value
;
602 if (index
+ pwmRawPkt
.motorCount
< SIMULATOR_MAX_PWM_CHANNELS
) {
603 // In pwmRawPkt, we put servo right after the motors.
604 pwmRawPkt
.pwm_output_raw
[index
+ pwmRawPkt
.motorCount
] = value
;
608 static motorDevice_t motorPwmDevice
= {
610 .postInit
= motorPostInitNull
,
611 .convertExternalToMotor
= pwmConvertFromExternal
,
612 .convertMotorToExternal
= pwmConvertToExternal
,
613 .enable
= pwmEnableMotors
,
614 .disable
= pwmDisableMotors
,
615 .isMotorEnabled
= pwmIsMotorEnabled
,
616 .decodeTelemetry
= motorDecodeTelemetryNull
,
617 .write
= pwmWriteMotor
,
618 .writeInt
= pwmWriteMotorInt
,
619 .updateComplete
= pwmCompleteMotorUpdate
,
620 .shutdown
= pwmShutdownPulsesForAllMotors
,
624 motorDevice_t
*motorPwmDevInit(const motorDevConfig_t
*motorConfig
, uint16_t _idlePulse
, uint8_t motorCount
, bool useUnsyncedPwm
)
627 UNUSED(useUnsyncedPwm
);
629 printf("Initialized motor count %d\n", motorCount
);
630 pwmRawPkt
.motorCount
= motorCount
;
632 idlePulse
= _idlePulse
;
634 for (int motorIndex
= 0; motorIndex
< MAX_SUPPORTED_MOTORS
&& motorIndex
< motorCount
; motorIndex
++) {
635 motors
[motorIndex
].enabled
= true;
637 motorPwmDevice
.count
= motorCount
; // Never used, but seemingly a right thing to set it anyways.
638 motorPwmDevice
.initialized
= true;
639 motorPwmDevice
.enabled
= false;
641 return &motorPwmDevice
;
645 uint16_t adcGetChannel(uint8_t channel
)
653 char _Min_Stack_Size
;
656 static FILE *eepromFd
= NULL
;
658 void FLASH_Unlock(void)
660 if (eepromFd
!= NULL
) {
661 fprintf(stderr
, "[FLASH_Unlock] eepromFd != NULL\n");
666 eepromFd
= fopen(EEPROM_FILENAME
,"r+");
667 if (eepromFd
!= NULL
) {
669 fseek(eepromFd
, 0 , SEEK_END
);
670 size_t lSize
= ftell(eepromFd
);
673 size_t n
= fread(eepromData
, 1, sizeof(eepromData
), eepromFd
);
675 printf("[FLASH_Unlock] loaded '%s', size = %ld / %ld\n", EEPROM_FILENAME
, lSize
, sizeof(eepromData
));
677 fprintf(stderr
, "[FLASH_Unlock] failed to load '%s'\n", EEPROM_FILENAME
);
681 printf("[FLASH_Unlock] created '%s', size = %ld\n", EEPROM_FILENAME
, sizeof(eepromData
));
682 if ((eepromFd
= fopen(EEPROM_FILENAME
, "w+")) == NULL
) {
683 fprintf(stderr
, "[FLASH_Unlock] failed to create '%s'\n", EEPROM_FILENAME
);
686 if (fwrite(eepromData
, sizeof(eepromData
), 1, eepromFd
) != 1) {
687 fprintf(stderr
, "[FLASH_Unlock] write failed: %s\n", strerror(errno
));
692 void FLASH_Lock(void)
695 if (eepromFd
!= NULL
) {
696 fseek(eepromFd
, 0, SEEK_SET
);
697 fwrite(eepromData
, 1, sizeof(eepromData
), eepromFd
);
700 printf("[FLASH_Lock] saved '%s'\n", EEPROM_FILENAME
);
702 fprintf(stderr
, "[FLASH_Lock] eeprom is not unlocked\n");
706 FLASH_Status
FLASH_ErasePage(uintptr_t Page_Address
)
708 UNUSED(Page_Address
);
709 // printf("[FLASH_ErasePage]%x\n", Page_Address);
710 return FLASH_COMPLETE
;
713 FLASH_Status
FLASH_ProgramWord(uintptr_t addr
, uint32_t value
)
715 if ((addr
>= (uintptr_t)eepromData
) && (addr
< (uintptr_t)ARRAYEND(eepromData
))) {
716 *((uint32_t*)addr
) = value
;
717 printf("[FLASH_ProgramWord]%p = %08x\n", (void*)addr
, *((uint32_t*)addr
));
719 printf("[FLASH_ProgramWord]%p out of range!\n", (void*)addr
);
721 return FLASH_COMPLETE
;
724 void IOConfigGPIO(IO_t io
, ioConfig_t cfg
)
728 printf("IOConfigGPIO\n");
731 void spektrumBind(rxConfig_t
*rxConfig
)
734 printf("spektrumBind\n");
739 printf("debugInit\n");
742 void unusedPinsInit(void)
744 printf("unusedPinsInit\n");