Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Ici, vous pouvez poster les photos & vidéos de vos modèles.
Bien lire les règles du sous-forum.
Répondre
sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 06 sept. 2015, 21:26

Bonjour :)

Pour que vous compreniez le sujet et mon intervention, je fait un bref récapitulatif de ma modeste expérience de l'électronique:

J'ai donc débuté l'électronique amateur il y a 1 an, au départ je ne savais pas à quoi servait un condensateur, je suis donc parti de zéro.
J'ai été comme un peu tout les amateurs qui ne savent pas par ou commencer au départ, j'ai téléchargé Arduino, puis au bout d'une semaine j'ai voulu savoir ce qu'il y avait derrière digitalWrite, et 2 ou 3 fonctions que j'avais utilisé au courant de cette semaine découverte. J'ai été voir la source et j'ai compris qu'il suffisait d'appliquer mes connaissances en programmation C++, de lire les 650 pages du datasheet du 328P (voir ici: http://www.atmel.com/images/Atmel-8271- ... mplete.pdf), pour créer ma propre bibliothèque et me passer finalement d'Arduino. Voila en gros le résumé.

Photos de quelques projets en électronique que j'ai réalisé durant l'année :)
http://sylvainmahe.xyz/forum/


Ceci étant dit, la bibliothèque étant maintenant terminée, je la met à disposition des internautes dans le but qu'ils puissent créer tout comme moi des projets assez complexes très facilement :)
Voici donc pour télécharger ma bibliothèque (qui n'a pas encore de nom): http://sylvainmahe.xyz/
(mon site dédié au projet est encore en construction)

J'estime le temps de développement de cette bibliothèque à entre 3000 à 4000 heures durant l'année.

Coté performances, ma bibliothèque est plus proche d'avr que d'arduino, par exemple, 1 million de pin toggling donne:
AVR: 651ms
ma bibliothèque: 753ms
Arduino: 4550ms



Le sujet ici présent: J'ai dernièrement construit un quadricoptère (chassis/carte pcb/électronique/programmation) en utilisant les fonctions de ma bibliothèque (voir lien ci-dessus), j'aimerais partager avec vous cette expérience car elle peut être intéressante pour ceux qui souhaitent se lancer dans le quadricoptère fait maison sans utiliser Arduino/Multiwii :)


Le premier test moteur avec hélices:
https://www.youtube.com/watch?v=rwDVVNhByQM[/video]

Les premiers tests en vol hier:
https://www.youtube.com/watch?v=lEjDbypSjDE[/video]

La puissance peut paraître légère (c'est censé être un quadricoptère de voltige), mais pour les premiers tests j'ai réglé la course des gaz à 50% max pour plus de sécurité, ceci explique cela :) Demain j'essayerais avec 100% de gaz.


Pour commencer, le code source sans ma bibliothèque (le main.cpp), fait seulement 326 lignes, donc sachez qu'un quadricoptère est en ordre de vol avec seulement 326 lignes dans le main avec ma bibliothèque qui tourne derrière, c'est très peu, ceci avec toutes les sécurités d'avant vol au branchement de la batterie lipo avec buzzer de signalement, à savoir:
-vérification que votre radiocommande est bien calibrée
-vérification de l'arrivée du pwm de toutes les voies du récepteur
-vérification de l'inter coupure moteur activé et du manche de gaz inférieur à 10%


Et également avec la musique au démarrage, ce qui n'est pas indispensable vous en conviendrez :)

Voila la photo du quadricoptère:
Image

La photo de la carte électronique:
Image
Image

Cette carte maison me sert à tous mes projets en électronique.Le plan de celle-ci se trouve en bas du sujet.

La machine pour réaliser le châssis, si vous le réalisez en tube aluminium le mieux est d'avoir une fraiseuse sous la main:
Image
Image

L'idée de ce topic est de comprendre qu'avec ma bibliothèque on peut en quelques lignes de programmation créer des choses plus ou moins complexes beaucoup plus facilement qu'Arduino et avec une plus grande vitesse d'execution et une quantité de mémoire moindre.

Exemple/Tuto - Potar + Servo avec ma bibliothèque (sans Arduino):

Vous devez déjà savoir programmer et linker une bibliothèque, avoir une petite idée de pourquoi se passer d'Arduino et qu'il faut AVR (l'architecture AVR de l'atmega328p), mais dans l'idéal, le processus est:

-télécharger la bibliothèque, décompresser les fichiers
-avoir une carte arduino uno ou équivalent
-avoir un programmateur (vous pouvez utiliser l'usbasp avec mes batchs windows ou linux inclus dans l'archive de la bibliothèque pour compiler)
-avoir avr c d'installé sur votre ordinateur
-avoir un servo-moteur et un potentiomètre sous la main

J'ai créé une vidéo qui vous montre très exactement la procédure:
https://www.youtube.com/watch?v=l6W0OJiucN0[/video]

Je recopie mon exemple ici (main.cpp):

Code : Tout sélectionner

#include "../library/Potentiometer.h"
#include "../library/Servo.h"

using namespace std;

int main()
{
	Servo myServo = Servo (1, 1100, 1900);
	Potentiometer myPotentiometer = Potentiometer (15);
	
	Servo::start (250);
	
	while (true)
	{
		myPotentiometer.state();
		
		myServo.pulse (myPotentiometer.curve (0, 1023, 1100, 1900, 0));
	}
	
	return 0;
}
En premier, remplacer "library" par le dossier dans l'archive qui contient la bibliothèque, encore une fois je ne suis pas encore sûr du nom que je vais lui donner.

A la déclaration de l'objet Servo, le premier paramètre est le numéro de la pin sur la carte (voir ma carte 328P en bas de ce sujet pour connaître la distribution des pins sur votre carte Arduino UNO par rapport à la mienne).
On indique également 1100, c'est le débattement min du servo, et 1900 le max, voyez le datasheet de votre servo-moteur pour connaître ces débattements, ou faites des tests.

A la déclaration de l'objet Potentiometer, on indique juste le numéro de la pin, ici la 15 c'est à dire PC0.
Ensuite on démarre le servo-moteur avec Servo::start et on indique en paramètre la fréquence du servo en Hz. Ici c'est un savox qui va jusqu'à 250Hz.

Dans la boucle principale on récupère l'état du potentiomètre avec state, sa correspond à connaître la tension en valeur 10 bit sur la pin PC0.

Ensuite on indique une position de palonnier de servo-moteur avec pulse, on lui injecte avec la fonction curve du potentiomètre la tension sous la forme d'une valeur de 10 bit (0 à 1023) interpolé de 1100 à 1900 (les débattements en us de notre servo-moteur) tout cela avec une courbe linéaire (le 0 à la fin).


Ensuite compilation avec le compilateur AVR et upload dans l'Atmega 328P avec le programmateur de votre choix, moi j'utilise l'usbasp, voir ici:
http://www.fischl.de/usbasp/

Et normalement ça fonctionne :)


Photos pour comprendre la distribution des pins sur ma carte 328P faite maison en relation avec la distribution des pins de ma bibliothèque:
Image
Image


Ma carte 328P et ma bibliothèque me servent à réaliser pleins de projets, cette carte n'est pas plus spécialisé dans le quadricoptère qu'autre chose, un exemple d'autre projet avec cette carte:
Un jeu PONG:
https://www.youtube.com/watch?v=x0699wl6ggg[/video]


Voila ce sera tout pour aujourd'hui, n'hésitez pas si vous avez des interrogations ou des commentaires :)

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 14 nov. 2015, 22:42

Voila après une 30ène de vols de tests le code source final sans horizon artificiel (pour l'instant):
Main.cpp

Code : Tout sélectionner

#include "../library/Timer.h"
#include "../library/Delay.h"
#include "../library/Random.h"
#include "../library/Math.h"
#include "../library/Buzzer.h"
#include "../library/Servo.h"
#include "../library/Cycle.h"
#include "../library/Gyroscope.h"

using namespace std;

int main()
{
	uint8_t n = 0;
	Gyroscope mpu6050 = Gyroscope (0);
	Cycle channelThrottle = Cycle (1, false);
	uint16_t slowChannelThrottle = 0;
	uint16_t centerChannelThrottle = 0;
	Cycle channelPitch = Cycle (2, false);
	uint16_t centerChannelPitch = 0;
	Cycle channelRoll = Cycle (3, false);
	uint16_t centerChannelRoll = 0;
	Cycle channelYaw = Cycle (4, false);
	uint16_t centerChannelYaw = 0;
	Cycle channelHold = Cycle (5, false);
	uint16_t centerChannelHold = 0;
	Cycle channelOption = Cycle (6, false);
	uint16_t centerChannelOption = 0;
	Servo motor1 = Servo (7, 0, 0, 0);
	Servo motor2 = Servo (8, 0, 0, 0);
	Servo motor3 = Servo (9, 0, 0, 0);
	Servo motor4 = Servo (10, 0, 0, 0);
	Delay delaySoundStartCondition = Delay (1000, false);
	uint16_t mixThrottle = 0;
	int16_t mixThrustPitchGain = 0;
	int16_t mixThrustRollGain = 0;
	int16_t mixInertiaYawGain = 0;
	int16_t mixMinClearancePitch = 0;
	int16_t mixMaxClearancePitch = 0;
	int16_t mixMinClearanceRoll = 0;
	int16_t mixMaxClearanceRoll = 0;
	int16_t mixMinClearanceYaw = 0;
	int16_t mixMaxClearanceYaw = 0;
	const uint16_t SPEED_GYRO = 1000;
	int16_t speedPitch = 0;
	int16_t speedRoll = 0;
	int16_t speedYaw = 0;
	int16_t mixPitchOffsetGyro = 0;
	int16_t mixRollOffsetGyro = 0;
	int16_t mixYawOffsetGyro = 0;
	uint8_t thrustGainPitch = 0;
	uint8_t thrustGainRoll = 0;
	uint8_t inertiaGainYaw = 0;
	uint16_t gainMinRxGyro = 0;
	uint16_t gainMaxRxGyro = 0;
	uint16_t gainMinRyGyro = 0;
	uint16_t gainMaxRyGyro = 0;
	uint16_t gainMinRzGyro = 0;
	uint16_t gainMaxRzGyro = 0;
	int16_t mixMinRxGyro = 0;
	int16_t mixMaxRxGyro = 0;
	int16_t mixMinRyGyro = 0;
	int16_t mixMaxRyGyro = 0;
	int16_t mixMinRzGyro = 0;
	int16_t mixMaxRzGyro = 0;
	uint16_t mixMotor1 = 0;
	uint16_t mixMotor2 = 0;
	uint16_t mixMotor3 = 0;
	uint16_t mixMotor4 = 0;
	const uint16_t SETUP_MIN_CHANNEL_THROTTLE = 1000;
	const uint16_t SETUP_MAX_CHANNEL_THROTTLE = 2000;
	const uint16_t SETUP_MIN_CHANNEL_PITCH = 1000;
	const uint16_t SETUP_MAX_CHANNEL_PITCH = 2000;
	const uint16_t SETUP_MIN_CHANNEL_ROLL = 1000;
	const uint16_t SETUP_MAX_CHANNEL_ROLL = 2000;
	const uint16_t SETUP_MIN_CHANNEL_YAW = 1000;
	const uint16_t SETUP_MAX_CHANNEL_YAW = 2000;
	const uint16_t SETUP_MIN_CHANNEL_HOLD = 1000;
	const uint16_t SETUP_MAX_CHANNEL_HOLD = 2000;
	const uint16_t SETUP_MIN_CHANNEL_OPTION = 1500;
	const uint16_t SETUP_MAX_CHANNEL_OPTION = 2000;
	const int16_t SETUP_ZERO_PITCH = 38;
	const int16_t SETUP_ZERO_ROLL = -11;
	const int16_t SETUP_ZERO_YAW = -46;
	const uint16_t SETUP_FREQUENCY_ESC = 100;
	const uint16_t SETUP_HOLD_ESC = 950;
	const uint16_t SETUP_MIN_ESC = 1050;
	const uint16_t SETUP_MAX_ESC = 1950;
	const uint16_t SETUP_TRAVEL_PITCH = 300;
	const uint16_t SETUP_TRAVEL_ROLL = 300;
	const uint16_t SETUP_TRAVEL_YAW = 300;
	const uint16_t SETUP_SPEED_PITCH = 300;
	const uint16_t SETUP_SPEED_ROLL = 300;
	const uint16_t SETUP_SPEED_YAW = 200;
	const uint8_t SETUP_GAIN_PITCH = 87;
	const uint8_t SETUP_GAIN_ROLL = 83;
	const uint8_t SETUP_GAIN_YAW = 92;
	const uint8_t SETUP_THRUST_PROPELLER = 60;
	const uint8_t SETUP_INERTIA_PROPELLER = 100;
	
	Timer::pause (1000);
	
	slowChannelThrottle = round (double (SETUP_MIN_CHANNEL_THROTTLE) + ((double (SETUP_MAX_CHANNEL_THROTTLE) - double (SETUP_MIN_CHANNEL_THROTTLE)) / double (10)));
	centerChannelThrottle = round (double (SETUP_MAX_CHANNEL_THROTTLE) - ((double (SETUP_MAX_CHANNEL_THROTTLE) - double (SETUP_MIN_CHANNEL_THROTTLE)) / double (2)));
	centerChannelPitch = round (double (SETUP_MAX_CHANNEL_PITCH) - ((double (SETUP_MAX_CHANNEL_PITCH) - double (SETUP_MIN_CHANNEL_PITCH)) / double (2)));
	centerChannelRoll = round (double (SETUP_MAX_CHANNEL_ROLL) - ((double (SETUP_MAX_CHANNEL_ROLL) - double (SETUP_MIN_CHANNEL_ROLL)) / double (2)));
	centerChannelYaw = round (double (SETUP_MAX_CHANNEL_YAW) - ((double (SETUP_MAX_CHANNEL_YAW) - double (SETUP_MIN_CHANNEL_YAW)) / double (2)));
	centerChannelHold = round (double (SETUP_MAX_CHANNEL_HOLD) - ((double (SETUP_MAX_CHANNEL_HOLD) - double (SETUP_MIN_CHANNEL_HOLD)) / double (2)));
	centerChannelOption = round (double (SETUP_MAX_CHANNEL_OPTION) - ((double (SETUP_MAX_CHANNEL_OPTION) - double (SETUP_MIN_CHANNEL_OPTION)) / double (2)));
	
	Buzzer::pin (11);
	
	while (centerChannelThrottle == 0 || centerChannelPitch == 0 || centerChannelRoll == 0 || centerChannelYaw == 0 || centerChannelHold == 0 || centerChannelOption == 0)
	{
		delaySoundStartCondition.state();
		
		if (delaySoundStartCondition.update == true)
		{
			Buzzer::play (200, 100);
		}
	}
	
	delaySoundStartCondition.reset();
	
	Cycle::start (100);
	
	while (channelThrottle.us == 0 || channelPitch.us == 0 || channelRoll.us == 0 || channelYaw.us == 0 || channelHold.us == 0 || channelHold.us == 0)
	{
		channelThrottle.state();
		channelPitch.state();
		channelRoll.state();
		channelYaw.state();
		channelHold.state();
		channelOption.state();
		
		delaySoundStartCondition.state();
		
		if (delaySoundStartCondition.update == true)
		{
			Buzzer::key (200, 100);
			Buzzer::key (0, 100);
			Buzzer::key (200, 100);
			Buzzer::playKey();
		}
	}
	
	delaySoundStartCondition.reset();
	
	while (channelThrottle.us > slowChannelThrottle || channelHold.us < centerChannelHold)
	{
		channelThrottle.state();
		channelHold.state();
		
		delaySoundStartCondition.state();
		
		if (delaySoundStartCondition.update == true)
		{
			Buzzer::key (200, 100);
			Buzzer::key (0, 100);
			Buzzer::key (200, 100);
			Buzzer::key (0, 100);
			Buzzer::key (200, 100);
			Buzzer::playKey();
		}
	}
	
	Random::seed (15);
	
	for (n = 0; n < 16; n++)
	{
		if (n != 0)
		{
			Buzzer::key (0, Random::integer (25, 75));
		}
		
		Buzzer::key (Random::integer (70, 3000), Random::integer (25, 75));
	}
	
	Buzzer::playKey();
	
	speedPitch = Math::curve (0, SETUP_SPEED_PITCH, SPEED_GYRO, 0, 32767, 0);
	speedRoll = Math::curve (0, SETUP_SPEED_ROLL, SPEED_GYRO, 0, 32767, 0);
	speedYaw = Math::curve (0, SETUP_SPEED_YAW, SPEED_GYRO, 0, 32767, 0);
	
	thrustGainPitch = Math::curve (0, SETUP_THRUST_PROPELLER, 100, 0, SETUP_GAIN_PITCH, 0);
	gainMinRxGyro = Math::curve (0, thrustGainPitch, 100, 32767, 0, 0);
	gainMaxRxGyro = Math::curve (0, SETUP_GAIN_PITCH, 100, 32767, 0, 0);
	
	thrustGainRoll = Math::curve (0, SETUP_THRUST_PROPELLER, 100, 0, SETUP_GAIN_ROLL, 0);
	gainMinRyGyro = Math::curve (0, thrustGainRoll, 100, 32767, 0, 0);
	gainMaxRyGyro = Math::curve (0, SETUP_GAIN_ROLL, 100, 32767, 0, 0);
	
	inertiaGainYaw = Math::curve (0, SETUP_INERTIA_PROPELLER, 100, 0, SETUP_GAIN_YAW, 0);
	gainMinRzGyro = Math::curve (0, inertiaGainYaw, 100, 32767, 0, 0);
	gainMaxRzGyro = Math::curve (0, SETUP_GAIN_YAW, 100, 32767, 0, 0);
	
	mpu6050.setZero (SETUP_ZERO_PITCH, SETUP_ZERO_ROLL, SETUP_ZERO_YAW);
	
	motor1.hold (SETUP_HOLD_ESC);
	motor1.min (SETUP_MIN_ESC);
	motor1.max (SETUP_MAX_ESC);
	motor2.hold (SETUP_HOLD_ESC);
	motor2.min (SETUP_MIN_ESC);
	motor2.max (SETUP_MAX_ESC);
	motor3.hold (SETUP_HOLD_ESC);
	motor3.min (SETUP_MIN_ESC);
	motor3.max (SETUP_MAX_ESC);
	motor4.hold (SETUP_HOLD_ESC);
	motor4.min (SETUP_MIN_ESC);
	motor4.max (SETUP_MAX_ESC);
	
	motor1.moveHold();
	motor2.moveHold();
	motor3.moveHold();
	motor4.moveHold();
	
	Servo::start (SETUP_FREQUENCY_ESC);
	
	while (true)
	{
		mpu6050.state();
		channelThrottle.state();
		channelPitch.state();
		channelRoll.state();
		channelYaw.state();
		channelHold.state();
		channelOption.state();
		
		if (channelHold.us > centerChannelHold)
		{
			motor1.moveHold();
			motor2.moveHold();
			motor3.moveHold();
			motor4.moveHold();
		}
		else
		{
			mixThrottle = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, SETUP_MIN_ESC, SETUP_MAX_ESC, 0);
			
			mixMotor1 = mixThrottle;
			mixMotor2 = mixThrottle;
			mixMotor3 = mixThrottle;
			mixMotor4 = mixThrottle;
			
			mixMinClearancePitch = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, 0, SETUP_TRAVEL_PITCH, 0);
			mixMaxClearancePitch = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, SETUP_TRAVEL_PITCH, 0, 0);
			mixPitchOffsetGyro = Math::curve (SETUP_MIN_CHANNEL_PITCH, channelPitch.us, SETUP_MAX_CHANNEL_PITCH, -speedPitch, speedPitch, 0);
			mixThrustPitchGain = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, gainMaxRxGyro, gainMinRxGyro, 0);
			mixMinRxGyro = Math::wurve (-mixThrustPitchGain, mpu6050.rx + mixPitchOffsetGyro, mixThrustPitchGain, -mixMaxClearancePitch, 0, mixMinClearancePitch, 0, 0);
			mixMaxRxGyro = Math::wurve (-mixThrustPitchGain, mpu6050.rx + mixPitchOffsetGyro, mixThrustPitchGain, -mixMinClearancePitch, 0, mixMaxClearancePitch, 0, 0);
			
			mixMotor1 -= mixMinRxGyro;
			mixMotor2 -= mixMinRxGyro;
			mixMotor3 += mixMaxRxGyro;
			mixMotor4 += mixMaxRxGyro;
			
			mixMinClearanceRoll = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, 0, SETUP_TRAVEL_ROLL, 0);
			mixMaxClearanceRoll = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, SETUP_TRAVEL_ROLL, 0, 0);
			mixRollOffsetGyro = Math::curve (SETUP_MIN_CHANNEL_ROLL, channelRoll.us, SETUP_MAX_CHANNEL_ROLL, -speedRoll, speedRoll, 0);
			mixThrustRollGain = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, gainMaxRyGyro, gainMinRyGyro, 0);
			mixMinRyGyro = Math::wurve (-mixThrustRollGain, mpu6050.ry - mixRollOffsetGyro, mixThrustRollGain, -mixMaxClearanceRoll, 0, mixMinClearanceRoll, 0, 0);
			mixMaxRyGyro = Math::wurve (-mixThrustRollGain, mpu6050.ry - mixRollOffsetGyro, mixThrustRollGain, -mixMinClearanceRoll, 0, mixMaxClearanceRoll, 0, 0);
			
			mixMotor1 -= mixMinRyGyro;
			mixMotor2 += mixMaxRyGyro;
			mixMotor3 -= mixMinRyGyro;
			mixMotor4 += mixMaxRyGyro;
			
			mixMinClearanceYaw = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, 0, SETUP_TRAVEL_YAW, 0);
			mixMaxClearanceYaw = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, SETUP_TRAVEL_YAW, 0, 0);
			mixYawOffsetGyro = Math::curve (SETUP_MIN_CHANNEL_YAW, channelYaw.us, SETUP_MAX_CHANNEL_YAW, -speedYaw, speedYaw, 0);
			mixInertiaYawGain = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, gainMaxRzGyro, gainMinRzGyro, 0);
			mixMinRzGyro = Math::wurve (-mixInertiaYawGain, mpu6050.rz + mixYawOffsetGyro, mixInertiaYawGain, -mixMaxClearanceYaw, 0, mixMinClearanceYaw, 0, 0);
			mixMaxRzGyro = Math::wurve (-mixInertiaYawGain, mpu6050.rz + mixYawOffsetGyro, mixInertiaYawGain, -mixMinClearanceYaw, 0, mixMaxClearanceYaw, 0, 0);
			
			mixMotor1 -= mixMinRzGyro;
			mixMotor2 += mixMaxRzGyro;
			mixMotor3 += mixMaxRzGyro;
			mixMotor4 -= mixMinRzGyro;
			
			motor1.pulse (mixMotor1);
			motor2.pulse (mixMotor2);
			motor3.pulse (mixMotor3);
			motor4.pulse (mixMotor4);
		}
	}
	
	return 0;
}
Pour quadricoptère avec:
Moteur1 = avant gauche
Moteur2 = avant droit
Moteur3 = arrière gauche
Moteur4 = arrière droit

Les paramètres à adapter selon votre quad commencent par le préfixe SETUP.
La gestion des moteurs prends en compte le rendement des hélices (paramètre THRUST), cette gestion est asymétrique de sorte que vous avez votre plein ralenti et plein gaz avec 100% des ordres pitch/roll/yaw disponible même manche de gaz (THROTTLE) en butée mini ou maxi.

Le quad est très verrouillé sur ses axes, la voltige passe sans aucune difficulté, j'ai testé pleins de choses: plein gaz vers le bas, boucles carrés, etc...

Il y a bien-sûr les trois sécurités d'avant démarrage que j'ai cité dans ce sujet.

Ma config actuelle est:
tiger motors mn2206
kiss esc 18A
lipo 4s 2200mAh
hélices hq 6x4.5"


Le code est très robuste, vous pouvez-y aller sans problème :) N'hésitez pas si vous avez un soucis ou des questions.

Avatar du membre
Leviatan
Chancelier Suprême
Messages : 886
Enregistré le : 17 nov. 2014, 20:36

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par Leviatan » 16 nov. 2015, 18:37

Bonjour,

Tres impressionnant, bravo !

Je conte moi aussi créer mes propres module 3g/6g, et autre electroniquerie pour voilure tournante, mais a base d'arduino.

Question : Pourquoi vouloir "se passer" des biblios arduinos ??? L'on peut très bien codé bas niveau au sein de l'API arduino.
Mon plus bel exemple est un projecteur laser avec un PID cadencé a 800 kHz avec comme retour de capteur des signaux IR analogique converti a l'ADC 12bits en SPI. (Les miroir étaient contrôlés par des bras de disques dur)
Le code etait fait un peu a l'arache (je me concentré sur l’électro), le traitement des timers fait en bas niveau, avec les vecteurs ISR bas niveaux, le SPI en bas niveau aussi. Mais je profite de l'api Arduino, qui me permet l'affichage sur ecran TFT de l'image vectoriel tres facilement.

Il existe moultes exemples d'applications temps réel qui fonctionne au sein de l'Api Arduino. Si il y a un truc que j'ai appris c'est a ne pas réinventé la roue (Tkt je la réinvente encore tres souvent :p ).

Par exemple, j'arrive largement a ton résultat de 753ms sur le million de toggles en codant directement sur les port E/S au sein de l'API.

Attention, cela n’enlève en rien la beauté du travail accompli. c'est même d'autant plus respectable : tu as tous fait toi même.
Je vous pris de bien vouloir excuser le passage a tabac de notre chère langue. Je me soigne.

- ♥ Walkera DF36 - Futaba ♥ Je l'aime ma 2CV rouillé
- Walkera DF4#1 - Mini Titan E325 SE
- Walkera V200D01 FBL Le pas fixe Moyen pour le blaireau Moyen
- TRex 450 Pro DFC V2 - 3gx- FutabaTrès joli sur mon étagère
- Procopter hybride DF36 - 3gx - Futaba Haha ! il a encore crashé !
- MiniProtos - kbar - Futaba Mouai ça va, il est pas si mal que ça.

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 20 déc. 2015, 16:51

Bonjour et merci pour ton commentaire :)

Ton projet est intéressant :)

En effet tu as raison on peut écrire de l'avr c dans la gui arduino, mais je trouve cela super pas propre pour ma part parce que derrière il y a bien les classes d'arduino qui initialisent tout un tas de fonctions matérielles de l'atmega, il y a des defines et pleins de choses qu'on ne veut pas, il y a le bootloader, il y a énormément de code du coup qu'on ne va pas se servir mais qui est la par défaut si les gens veulent d'arduino, il y a des conflis par rapport aux timers, et j'en passe...

Je pense qu'arduino est super pour débuter (quoique il est très très incomplet même pour débuter à en voir les fonctions qui pour certaines sont des redondances de ce qu'on trouve en c pur: https://www.arduino.cc/en/Reference/HomePage), mais si on veut vraiment programmer un micro-controlleur dans les règles et comprendre comment il fonctionne, et surtout si on est passionné de comment il fonctionne, alors il faut le programmer soit en assembleur, soit en avr c, les deux langages que préconise atmel.

Pour se faire je ne peux que conseiller http://www.avrfreaks.net/ le forum officiel d'atmel.

Je pense que pour compléter ma réponse "pourquoi se passer d'arduino", parce que je bricole tout moi même depuis l'enfance donc ça ne change pas avec la programmation, je trouve cela infiniment plus passionnant de faire les choses soit même que de se contenter de ce qui est déjà fait, tout en sachant que ce qui est déjà fait est la plupart du temps en programmation très très sale niveau code, ceci je l'ai constaté dans pleins de langages...
...à vrai dire c'est ma 2ème bibliothèque, la 1ère était pour du web dans le langage action script 3, elle faisait 11500 lignes et m'avais demandé plus de 6 mois de travail, mais c'est pour dire la récurrence de trouver des bibliothèques sales sur le net et ceci dans moultes langages.

Aussi pour la concurrence, étant donné qu'un bricoleur du dimanche comme moi y est arrivé, je trouve que c'est une honte que multiwiicopter utilise arduino... C'est vraiment pas pro du tout.

Enfin voila c'est mon point de vue.


Sinon pour ton écran TFT j'ai préparé une classe TftDisplay.cpp/.h mais je ne sais pas quand je vais avoir le temps de programmer ça, c'est beaucoup de travail de créer les fonctions pour dessiner sur un simple écran, en gros c'est un moteur 2D qu'il faut créer qui permettra de dessiner des polygones simples, avec gestion du canal alpha, couleurs, lignes, remplissage, anticrénelage, etc... Peut être dans quelques mois... :)

my____

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par my____ » 20 déc. 2015, 23:21

On ne se connait pas mais au premier abord je sent beaucoup de prétention dans ton travail, SVP arrête de crasher sur Arduino ... Ce système a été créé justement pour les programmeurs du dimanche comme moi .
Simple exemple la programmation d'un écran TFT ca m'aura pris 10 minutes pour afficher mes données ...
On peut toujours réinventer la roue, si c'est ton kif tant mieux mais fait le dans le respect du travail des autres ...
je trouve que c'est une honte que multiwiicopter utilise arduino... C'est vraiment pas pro du tout.
ce genre de phrase à mon sens n'a pas de sens :lol:
Ça retire en rien la qualité de ton travail et je souhaite le même succès qu'Arduino :)

Avatar du membre
Leviatan
Chancelier Suprême
Messages : 886
Enregistré le : 17 nov. 2014, 20:36

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par Leviatan » 21 déc. 2015, 17:01

Le seul point ou je rejoin MyBlood c'est concernant le fait qu' Arduino et Multiwii sont des plateformes pour initier les gens a la programation AVR.

C'est justement la vocation de Multiwii d'etre porté sur Arduino. Pro ou pas on s'en fout, la n'est pas la question.

Pour ce qui est du reste (code crade, meme tres crade par moment, non optimisé AVR, redondance de fonction...) je ne suis on ne peut plus d'accord avec toi.

Je n'ai plus moi meme la patience de réécrire du code qui marche, il n'y a que si celui ci n'est pas assés optimisé que je le reecris (c'est le cas par exemple des librairies Servos) est c'est donc par fleme/manque de temps que je reprend l'API d'arduino.

Mais tu as totalement raison concernant l'apport d'une multitude de fonctionnalité inutile : 2Ko de .hex pour juste faire clignoté une LED est un non-sens complet en terme d'AVR.

Cependant, voila, Arduino est un excellent (et je pese mes mots) outils du partage de la connaissance et du partage Open-Source. Combien de gens ne se serait jamais intéresser aux microcontrôleurs sans lui ? un ENORME paquet de gens.

Rien que pour cela je lui tire mon chapeau.

Maintenant, pour les puristes, et moi aussi ne t'inquiette pas, un code arduino fait hurlé et nous font saigné les yeux. A titre d'exemple, je BANNIS l'utilisation de digitalWrite/Read et analogWrite/Read et autres attachInterrupt au profit de l'acces direct au registre et port AVR. De meme pour les timers, bus SPI...

ça ne m'empeche pas d'etre fainéant et de reprendre du code que je n'ai pas envis de reecrire (comme la TFT, etc)

Par contre , tes librairies m’intéressent énormément :D !
Je vous pris de bien vouloir excuser le passage a tabac de notre chère langue. Je me soigne.

- ♥ Walkera DF36 - Futaba ♥ Je l'aime ma 2CV rouillé
- Walkera DF4#1 - Mini Titan E325 SE
- Walkera V200D01 FBL Le pas fixe Moyen pour le blaireau Moyen
- TRex 450 Pro DFC V2 - 3gx- FutabaTrès joli sur mon étagère
- Procopter hybride DF36 - 3gx - Futaba Haha ! il a encore crashé !
- MiniProtos - kbar - Futaba Mouai ça va, il est pas si mal que ça.

Otatiaro
Chancelier Suprême
Messages : 721
Enregistré le : 21 janv. 2008, 11:46

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par Otatiaro » 21 déc. 2015, 17:28

Hello,

C'est l'éternel débat entre haut niveau et bas niveau ... tu peux prendre le truc dans tous les sens, plus ta bibliothèque aura d'options et de possibilités, plus elle embarquera de code mort (inutile pour une application donnée, mais pas pour une autre).

D'ailleurs ce n'est pas ou tout blanc, ou tout noir, il y a une multitude de phases intermédiaires, qui vont d'arduino (on pourrait même aller plus loin, genre .NET micro framework, voir machine virtuelle java, etc.) qui permettent de faire des choses très évoluées en très peu de temps, mais forcément moins optimisé, jusqu'à écrire tout en assembleur en tapant directement dans les registres hardware (ce qui est fait je crois pour SimonK, BLHeli et bien d'autres).

Chez EZNOV, on cumule les deux ... d'un côté on a tout réécrit, du code de boot, au scheduler temps réel multi tache préemptif, en passant par les drivers bas niveau, bootloader, etc. mais d'un autre côté une fois qu'on peut se reposer sur ce framework qui est optimisé pour NOS besoins, on peut sortir du code beaucoup plus propre, plus simple et plus efficace, plus rapidement.

Et on est pas dépendants de code externe que l'on ne maitrise pas (j'ai vu des projets qui utilisaient Linux, qui ont été annulés parce qu'il y avait un bug dans le noyau, impossible à corriger sans y passer des mois à s'approprier des millions de lignes de code pour débugger), s'il y a un bug c'est forcément dans notre code (puisqu'il n'y a pas une ligne de code qu'on ait pas écrite), donc on sait comment débugger.

Mais c'est un investissement colossal, qui ne se justifie que si c'est ton cœur de métier et que tu es CERTAIN de pouvoir réutiliser le même framework sur beaucoup de projets.

Mon principal reproche à Arduino est de ne pas embarquer de scheduler RT préemptif ... la vie est tellement plus simple quand on peut écrire des taches indépendantes, qu'on peut limiter les interruptions au strict minimum (une interruption ne fait pas de calcul, elle est une interface entre le périphérique et la tache qui fait les calculs), et ne pas s'embêter avec la gestion des priorités.

Thomas.

PS : et pour info on code tout en C++ ici ... ca parait aberrant en embarqué pour certains, mais si on ne fait pas n'importe quoi n'importe comment c'est au moins aussi efficace que du C. Pour bien coder en C++ il faut comprendre comment le compilo transforme du C++ en C, pour bien coder en C, il faut comprend comment le compilo transforme le C en assembleur, pour bien coder en assembleur (ce qu'on fait quand VRAIMENT on ne peut pas faire autrement ...) il faut bien comprendre comment fonctionne le proc (Cortex-M3 ou M4 en ce qui me concerne). Comprendre l'impact en terme de code et de performances du code qu'on écrit, c'est primordial. [EDIT] Et ce n'est pas toujours le code le plus performant qui est le meilleur !!! On n'optimise pas "parce que", on n'optimise quand on DOIT optimiser, sinon c'est la propreté et surtout la maintenabilité du code qui prime. Et là j'aurais quelques reproches à faire à certains projets open source ...
Support : contact@eznov.com

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 23 déc. 2015, 22:05

On ne se connait pas mais au premier abord je sent beaucoup de prétention dans ton travail, SVP arrête de crasher sur Arduino ...
*myblood effectivement tu fait erreur, tu ne me connais pas, il y a absolument aucune prétention de quoi que ce soit dans mon travail, sinon je ne partagerais rien, je ne passerais pas énormément de temps à faire de l'explication auprès des personnes intéressé par ma bibliothèque, et je ne passerais pas du temps à concevoir les cartes associés à ma bibliothèque pour des projets et applications qui ne me servirons jamais pour moi (inclinomètre digital, tracker de drone rssi, horizon artificiel pour un pilote ulm, etc...).

Je ne crache pas du tout sur arduino, il est ce qu'il est, je dis simplement qu'eux c'est une entreprise italienne composé de techniciens, de développeurs, d'ingénieurs même, et que moi je ne suis qu'un particulier, mais que ma bibliothèque est plus performante que la leurs... en réalité je ne dis rien de plus que ça, après libre au gens d'essayer ma bibliothèque, ou de rester sur arduino, ou bien de développer votre propre bibliothèque car c'est vraiment passionnant comme expérience :)


*Leviatan concernant la vitesse, j’oubliai dans mon poste précédent de préciser que le but était d'arriver à la vitesse ou quasiment à la vitesse de l'avr pur mais au sein d'une bibliothèque composée de classes et fonctions.
Effectivement si tu code en avr pur tu auras la vitesse de l'avr pur... ;)


Sinon je suis d'accord pour le reste, ce que vous dites est intéressant à souligner.
*Otatiaro également. A noter que c'est bien une bibliothèque C++, j'indique avr c mais j’approuve totalement l'avr c++ même si comme tu le dis certains crient à l'hérésie pour des raisons plus ou moins justifiées.


Si vous avez des questions n'hésitez pas.

*Leviatan j'aimerais bien si tu le souhaites regarder ton code "servo" pour voir les différences entre nos façons de programmer, ça peut être enrichissant je pense, merci d'avance :)

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 28 déc. 2015, 14:28

Pour les personnes intéressés je vous met un exemple pour faire fonctionner un servo avec l'axe x d'un gyro mpu6050:

Code : Tout sélectionner

#include "../mylibrary/Gyroscope.h"
#include "../mylibrary/Servo.h"
#include "../mylibrary/Math.h"

using namespace std;

int main()
{
	Gyroscope mpu6050 = Gyroscope (0);
	Servo savox = Servo (1, 0, 1100, 1900);
	
	Servo::start (250);
	
	while (true)
	{
		mpu6050.state();
		
		savox.pulse (Math::curve (-32768, mpu6050.rx, 32767, 1100, 1900, 0));
	}
	
	return 0;
}
Je détaille les créations des objets si ça ne vous parle pas:
Gyroscope mpu6050 = Gyroscope (0);
//création d'un objet de type Gyroscope (dans cette bibliothèque le mpu6050):
-le 1er et seul paramètre c'est l'adresse du périphérique sur le bus TWI (I2C), si on indique 0 ma classe cherche elle même l'adresse sur le bus, c'est pratique. Une fois ça fait le mpu6050 fonctionne, ensuite la seule chose à faire est de récupérer les valeurs avec la fonction .state de la classe Gyroscope et vous pourrez utiliser les valeurs: .rx/.ry/.rz/.tx/.ty/.tz/.pitch/.roll/.yaw/.temperature de la classe Gyroscope.

Servo savox = Servo (1, 0, 1100, 1900);
//création d'un objet de type Servo:
-le 1er paramètre c'est le numéro de la pin sur lequel est branché le servo soit le port PD0 (voir ma carte 328p pour connaître la distribution des pins par rapport au 328p)
-le 2ème paramètre est le duty cycle pwm en μs pour servo au repos (c'est pratique pour les esc pour avoir une valeur gaz coupé, voir fonction .moveHold, .moveMin, .moveMax, gaz coupé/gaz au ralenti/plein gaz de la classe Servo).
-le 3ème paramètre est le débattement min en μs
-le 4ème paramètre est le débattement max en μs
les débattements min et max sont pratique pour être sûr de ne jamais aller en butée servo si vous indiquez des valeurs erronés ou hors débattement min/max avec la fonction .pulse de la classe Servo.


N'hésitez pas si vous avez des questions :)

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 28 déc. 2015, 15:03

Exemple pour lire les voies (duty cycle pwm/ppm) en μs de vos récepteurs de modélisme:

Code : Tout sélectionner

#include "../mylibrary/Cycle.h"

using namespace std;

int main()
{
   Cycle throttle = Cycle (1, false);
   
   Cycle::start (100);
   
   while (true)
   {
      throttle.state();
      
      //vous pouvez maintenant utiliser la valeur stockée dans la variable us de l'objet throttle (throttle.us)
   }
   
   return 0;
}
Explications:
Cycle throttle = Cycle (1, false);
//création d'un objet de type Cycle (pour duty cycle mais faudrait que je change ce nom)
//paramètre 1 pour pin 1 (PD0 du 328p)
//paramètre false pour mesure de l'état haut du duty cycle pwm (et non pas mesure de l'état bas)

Cycle::start (100);
//démarrage de la lecture pwm
//100 (voir dernier post ici: http://www.france-helico.com/topic/2281 ... omultiwii/ , c'est une sécurité en cas de récepteur qui déconne, fils débranché, etc...)


A noter que le pwm lu peut être à n'importe quelle fréquence, je pense que pour mon r6008hs futaba c'est du 50hz.

J'ai fait de nombreux tests sinon avec cette classe, notamment avec génération de pwm avec ma classe servo, puis renvoi du pwm vers ma classe cycle, puis à nouveau génération via ma classe servo, puis relecture avec cycle, ceci à des fréquences multiples 1Hz à 500Hz.
Au final: pwm out>fil qui retourne vers la carte>pwm in>pwm out>fil qui retourne vers la carte>pwm in>pwm out>vers servo numérique
Pour un résultat nickel, le servo n'avait pas le moindre frétillement.

Voila n'hésitez pas également si vous avez des interrogations ;)

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 01 janv. 2016, 19:11

Nouvelle vidéo avec un peu de voltige ;)
(soyez indulgents c'est pas facile de piloter avec les pouces gelés :p)

https://www.youtube.com/watch?v=0M3INZuHvoc[/video]

Image
Image

N'hésitez pas si vous avez des interrogations coté réalisation ou autre.

Avatar du membre
Leviatan
Chancelier Suprême
Messages : 886
Enregistré le : 17 nov. 2014, 20:36

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par Leviatan » 03 janv. 2016, 11:10

Je ne t'ai pas oublié, bien sur je posterais mes trois methodes de gestion de servo.

dans les trois je me sert d'un timer bien sur,
- une ou je vais grace au flag timer géré les ports pour créer le signal dans ma boucle main,
- une qui est identique sauf que je fait cette gestion des ports dans une ISR (Interrupt Services Routine pour ceux qui lirons :p )
- l'autre ou je me sert directement des duty cycles des timers 16 bits pour creer le signal.

je poste des exemples des que j'ai le temps. La ou je pense pouvoir faire de gros effort d'optimisation c'est sur la lecture PPM du signal.
Je vous pris de bien vouloir excuser le passage a tabac de notre chère langue. Je me soigne.

- ♥ Walkera DF36 - Futaba ♥ Je l'aime ma 2CV rouillé
- Walkera DF4#1 - Mini Titan E325 SE
- Walkera V200D01 FBL Le pas fixe Moyen pour le blaireau Moyen
- TRex 450 Pro DFC V2 - 3gx- FutabaTrès joli sur mon étagère
- Procopter hybride DF36 - 3gx - Futaba Haha ! il a encore crashé !
- MiniProtos - kbar - Futaba Mouai ça va, il est pas si mal que ça.

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 03 janv. 2016, 18:09

Merci pour la réponse :)

Donc ça correspond à ce que j'avais testé, pour ma part j'avais retenu l'idée des 2 ISR, un qui compare, et l'autre sur le dépassement de registre (overflow):

Code : Tout sélectionner

ISR (TIMER1_COMPA_vect, ISR_BLOCK)
{}

ISR (TIMER1_OVF_vect, ISR_BLOCK)
{}
Du coup ça permet de mettre autant de servo qu'il y a de ports sur l'atmega tout en gardant la précision du duty cycle du pwm uniquement hardware grâce à l'overflow, j'imagine que c'est comme ça que tu vois les choses? :)

Avatar du membre
Leviatan
Chancelier Suprême
Messages : 886
Enregistré le : 17 nov. 2014, 20:36

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par Leviatan » 03 janv. 2016, 18:37

Tout a fait ! c'est exactement ma methode

Par contre si j'ai autant de sortie PWM 16bits disponible que de servo, je prefere directement utiliser les sortie PWM sans passer par les ISRs. On gagne en précisions, et l'on peu régler la mème fréquence pour tous les servo ainsi que la meme ligne d'asservissement (Les servo sont commandé "en meme temps" et non les uns a la suites des autres, pour un timer donné évidement).

On gagne aussi en temps processeur (Il n'est plus bloqué par l'appel des ISR).

Donc en général je choisis ta solution quand beaucoup de servo, et ma solution n°3 si besoin de réglé précieusement les fréquences et d'avoir les servos fonctionnant en parallèles.
Je vous pris de bien vouloir excuser le passage a tabac de notre chère langue. Je me soigne.

- ♥ Walkera DF36 - Futaba ♥ Je l'aime ma 2CV rouillé
- Walkera DF4#1 - Mini Titan E325 SE
- Walkera V200D01 FBL Le pas fixe Moyen pour le blaireau Moyen
- TRex 450 Pro DFC V2 - 3gx- FutabaTrès joli sur mon étagère
- Procopter hybride DF36 - 3gx - Futaba Haha ! il a encore crashé !
- MiniProtos - kbar - Futaba Mouai ça va, il est pas si mal que ça.

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 03 janv. 2016, 19:18

Oui je comprends tout à fait, je me suis longuement interrogé sur la question de la précision également.

...Et puis finalement après plusieurs semaines de tests avec des servos savox numérique, je n'arrivais pas à distinguer la différence entre pure hardware et semi hardware avec les ISR, du coup comme mon boulo était sous la forme d'une bibliothèque fallait bien que je choisisse.

J'ai également fait d'autres tests pour vraiment valider ma classe servo (j'ai fait ça avec toutes les classes), à savoir fonctionnement de la classe servo + classe buzzer + classe timer + classe interruptions + classe cycle + classe leddisplay (spi max7219/21), et ça marche nickel comme si les servos étaient branchés seuls sans tout le bazar qui tourne à coté, d’où mon choix :)

Question rapidité, un changement d'état sur une pin sur un uc à 16mhz tel le 328p dure 651 nano seconde, état haut ou état bas, ce qui fait que quand l'ISR se déclenche, c'est tellement rapide qu'à mon avis on est plus sujet aux variations de fréquence à cause de l’imprécision du quartz qu'autre chose !

Donc le temps processeur... :lol:
Il me semble que la boucle principale de mon quad s’exécute en 4ms à 6ms je ne sais plus, ceci en aillant 6 voies à lire, plusieurs 10ènes d'appels au mpu6050, des courbes quand même pas mal complexes avec un certains nombre de paramètres variables (pour prendre en compte notamment le rendement des hélices), et pas mal d'autres choses.

Il faut savoir que le pwm hardware n'est pas si isolé que cela quand on fait le con niveau programmation, il y a pas mal de mois quand je faisais mes premiers tests servo, j'avais réussi à avoir les mêmes "glitchs" sur le pwm sans et avec isr, je ne sais plus comment j'avais fait mais pour dire...

Ce qu'il faut c'est bien utiliser les attributs "volatile" des variables quand on est dans une interruption, et tout préparer en amont pour que dans l’interruption on va à l'essentiel immédiatement.


Je pense que mon travail a redonné la vérité à l'atmega328p, contre les atmega32u4 parce que papi veut du pwm entièrement hardware sur ses 4 esc branchés sur sa naze32 pour faire du stationnaire, et contre les 72mhz parce que le pauvre 328p qu'on nous dit n'est pas assez rapide... :D

Enfin bref c'est mon point de vue, mais j'ai des vidéos pour le prouver ^_^

Otatiaro
Chancelier Suprême
Messages : 721
Enregistré le : 21 janv. 2008, 11:46

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par Otatiaro » 04 janv. 2016, 10:14

Hello,
sylvainmahe a écrit :Il me semble que la boucle principale de mon quad s’exécute en 4ms à 6ms je ne sais plus
C'est pas mal c'est ca va rapidement te limiter, sur le Neuron avec la fusion 9 axes, etc., on est à moins de 0.2ms ...

Et c'est là que tu rentres dans la cour des grands, passer de 4ms à 0.2ms c'est 20x plus rapide, on ne parle pas d'optimiser de quelques % par-ci par là, mais de repenser entièrement ton architecture pour fluidifier les calculs.

De plus, tu dois prendre en considération 2 choses, d'une part ta fréquence de calcul (si tu est à 5ms, ta fréquence de calcul max est de 200Hz), qui est importante pour la précision (notamment des intégrales), mais aussi et surtout le temps de latence de ton système, c'est à dire le temps entre un mouvement du quad et la réaction du moteur (donc temps de réaction du capteur, temps de récupération des données, de traitement, d'envoi de la nouvelle consigne au moteur, et prise en compte de la nouvelle vitesse moteur). C'est ce temps de latence qui est de loin l'indicateur le plus important des performances de ton contrôleur.

Thomas.
Support : contact@eznov.com

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 08 janv. 2016, 20:29

Le Neuron est t'il également fait avec un atmega328P?

Si je met juste le nécessaire c'est à dire j'évite de faire une moyenne de 4 valeurs par axe du mpu6050 pour avoir des belles courbes la je vais sans doute monter largement plus en fréquence (je peux faire un essai), mais qu'est ce que cela va changer? Admettons, même si la vitesse est plus rapide... ...chipotage, car avec des esc ou servos même à 500Hz finalement le goulo se situera au niveau de la, si c'est pas la ce sera au niveau des ordres radio, et etc...

Au final je ne vois pas vraiment ce que j'obtiendrais comme vol, c'est déjà hyper réactif ! :)


Je veux revenir au parallélisme du pwm puisque ça a été évoqué, combien de récepteurs de modélisme ont un oscillateur par voie pwm? Tous les récepteurs que j'ai, peut être je suis pauvre, mais en tout cas ils en ont la plupart qu'1 seul, et 2 seulement en ont 2.

Regarde, sur mon quadri, je fait fonctionner les 4 esc à 100Hz parce que je trouve ça suffisant, chaque esc reçoit son ordre l'un à la suite de l'autre, j'ai des kiss esc + tiger motor mn2206 (3s), hélices 6 pouces, lipo 4s, quand je met plein gaz d'un coup le quadri monte bien droit ;)

Que vouloir de plus?

Tiens je vais faire un test en supprimant tout ce qui est inutile dans ma classe mpu6050, descendre en dessous de la ms et constater. Ensuite je reviendrais ici vous rendre compte de la différence. Je part objectivement et si je constate une différence je vais vous le notifier.

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 09 janv. 2016, 15:57

Je vous donne réponse par rapport au benchmark: :)

Avec ma bibliothèque complète avec toutes les possibilités offerte par celle ci (notamment possibilité de faire fonctionner jusqu'à 20 servos, et/ou jusqu'à 20 voies récepteur en entrées)(classe cycle.cpp et servo.cpp), la boucle principale du quadricoptère s’exécute en très exactement: 5.838 ms

J'ai décidé donc d'enlever l'inutile (l'inutilisé) pour ce projet quadricoptère, donc en d'autres termes d'enlever les possibilités quasi infinies de projets possibles à réaliser avec cette bibliothèque (modulable), c'est à dire de la rendre (en une demi heure, sans non plus y passer des plombes) dédiée au projet quadricoptère uniquement. Le résultat est la en peu de temps de recherche, la boucle principale s'exécute maintenant en: 0.446 ms


Autre commentaire, le module Neuron que tu cites *Thomas est équipé d'un µC STM32F4 cadencé de 84 à 180 Mhz à registres 32 bits, alors que moi mon projet est sur µC ATMEGA328P cadencé de 8 à 20Mhz équipé de registres 8 bits !! :rolleyes: Ça n'a absolument rien à voir... :lol:

De plus, pour faire une simple addition 16 bits avec des registres 8 bits, il faut passer 2 fois dans les registres, ou encore 4 fois pour des calculs 32 bits...

*Thomas il faut comparer ce qui est comparable ! ;)

Admettons que dans le Neuron le quartz cadence le STM32F4 à 84 Mhz, l'µC le moins rapide de la série STM32F4, comparativement:
STM32F4 32 bits 84 Mhz / ATMEGA328P 8 bits 16 Mhz
Si je fait fonctionner mon programme avec l'µC le moins rapide de la série STM32F4, la vitesse d’exécution de la boucle principale donnerait certainement quelque chose se rapprochant de:
0.446 ms / ((84 Mhz / 16 Mhz) * (32 bits / 8 bits)) = 0.021 ms
Avec la bibliothèque complète:
5.838 ms / ((84 Mhz / 16 Mhz) * (32 bits / 8 bits)) = 0.278 ms

Si les gens qui ont fabriqué le Neuron par contre ont utilisés le STM32F4 cadencé à 180 Mhz, cela donne:
0.446 ms / ((180 Mhz / 16 Mhz) * (32 bits / 8 bits)) = 0.01 ms
Avec la bibliothèque complète:
5.838 ms / ((180 Mhz / 16 Mhz) * (32 bits / 8 bits)) = 0.129 ms


Je me pose la question dans ce cas de ce que signifie la cour des grands effectivement si les gens comparent un moteur de petite voiture avec un moteur de voiture de course. Avec un moteur de voiture de course je serais x fois plus rapide que ceux de la cour des grands, mais ça ne m'intéresse pas puisque mon projet est basé sur un petit moteur, et que le but était de redonner tout l'intérêt à ce petit moteur qui marche pas si mal en fin de compte quand on programme comme il faut... :)

Avatar du membre
Yoy24
Armageddon
Messages : 23296
Enregistré le : 29 juin 2010, 15:33

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par Yoy24 » 09 janv. 2016, 16:19

Yop)

Je suis ce sujet avec intérêt...
Svp évitez de pref les petites piques, qui ne feraient que nuire au sujet lui même
et par la mème occase attiser les susceptibilités de chaque-uns...!



MERCI par Avance... -_-
¨¨¨¨¨¨ Image - Vaucluse - Image - Compy300 - Image - Atom 500 - ¨¨¨¨¨¨
----------------- Image Hitec Aurora 9X Mode2- Image -Héli-X 6.1-
----------------------------The Meeting Heli4 2013/14/15..., j'y étais!!! ------------------------------

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 09 janv. 2016, 17:40

Pas de soucis l'intention n'y est pas, l'avis et le travail de chacun est tout à fait intéressant, le but est de replacer les choses dans leurs contextes pour éviter bien-sur d'écrire des choses erronés, rien de plus que cela ;)

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 10 janv. 2016, 20:09

Après quelques mois de recherches infructueuses en ce qui concerne le nom et le logo de mon projet cartes+bibliothèque, j'ai finalement réussi à en dessiner un qui me convient:

Image

Module pour modulable, mais aussi pour génération de signal modulé (pulse width modulation), d’où la forme du logo (onde carrée). GPL pour General Public Licence (https://fr.wikipedia.org/wiki/Licence_p ... A9rale_GNU).

J'ai aussi travailler sur le site aujourd'hui pour que cela soit cohérent niveau formes et couleurs, mais il me faudra d'autres week-end pour finaliser ce site ;)
http://sylvainmahe.xyz/


Encore une fois n'hésitez pas pour les commentaires et si vous avez des questions pour le fonctionnement de la bibliothèque, et/ou idées que vous pouvez apporter :)
Modifié en dernier par sylvainmahe le 31 janv. 2016, 12:52, modifié 1 fois.

Avatar du membre
Leviatan
Chancelier Suprême
Messages : 886
Enregistré le : 17 nov. 2014, 20:36

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par Leviatan » 10 janv. 2016, 21:40

La plus part des recepteur de nos jours, use du paralellisme pour controler les servo/moduleFBL.

Les troies voie AIL/PIT/ELEV sont en general parralelisée.

De toute maniere on s'en contre fou du recepteur, parralelisé ou non ne change absolument rien. Car ce qui nous interresse dans la parralellisation c'est la possibilité pour le module FBL de géré les 3 servo (ou 4 esc) en meme temps, ce qui permet au controleur FBL de travailler en meilleur harmonie (latance beacoup plus reduite entre les 3 servos)

Mais c'est de la br*lette intelectuel, car une bonne boucle d'asservissement bien réglé travaillera certe plus (erreur direct et integrale d'erreur plus élevée) non parrallelisé, mais ce sera effectivement invisible pour le pilote.

Classe le logo sinon ! Vraiment simpa ! ça fait pro !

Ha... Et il me semble que.... Otatiario (Thomas) EST le concepteur du Neuron :D :D :D


EDIT : On peut tres bien grillé une BMW M3 dans un virage avec une Clio 1.4 RN, si c'est pépé au volant de la BMW et Sebastien Loeb au volant de la Clio :D

Je ne connais pas le neuron, mais vus les retour... C'est pas pépé au volant de la BMW
Je vous pris de bien vouloir excuser le passage a tabac de notre chère langue. Je me soigne.

- ♥ Walkera DF36 - Futaba ♥ Je l'aime ma 2CV rouillé
- Walkera DF4#1 - Mini Titan E325 SE
- Walkera V200D01 FBL Le pas fixe Moyen pour le blaireau Moyen
- TRex 450 Pro DFC V2 - 3gx- FutabaTrès joli sur mon étagère
- Procopter hybride DF36 - 3gx - Futaba Haha ! il a encore crashé !
- MiniProtos - kbar - Futaba Mouai ça va, il est pas si mal que ça.

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 15 janv. 2016, 21:40

C'est vrai :)

Merci pour le logo, les logos généralement c'est ma bête noire, j'ai beaucoup de difficulté à faire des logos simples et qui percutent à peu près, la je me situe ni trop beau ni trop moche, donc je pense que je vais plus y toucher.

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 08 mai 2016, 13:35

Mise à jour importante de ma bibliothèque pour l'ATmega328P: http://sylvainmahe.xyz/data/module.zip
Celle ci est maintenant indépendante au sens ou je n'utilise plus aucun include vers des fichiers avr, ou des fichiers couramment utilisés/admis en langage c/c++, à savoir:

Code : Tout sélectionner

#include <stdlib.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <math.h>
#include <string.h>
A noter que ces fichiers avaient eux aussi de multiples include...


Voila à quoi ressemble ma bibliothèque maintenant:

Code : Tout sélectionner

"../module/GpioRead.h"
"../module/GpioWrite.h"
"../module/AnalogRead.h"
"../module/InterruptRead.h"
"../module/PwmRead.h"
"../module/PwmWrite.h"
"../module/SoundWrite.h"

"../module/Timer.h"
"../module/Delay.h"

"../module/Math.h"
"../module/Iteration.h"
"../module/Average.h"
"../module/Random.h"

"../module/Max7219.h"
"../module/Mpu6050.h"

"../module/Network.h"

"../module/Memory.h"
"../module/Power.h"
"../module/Tool.h"
Vous avez à disposition 19 classes pour créer vos projets, et selon les composants que j'achète j'ajouterais des classes dédiées à ces composants. Normalement une classes Si4432 devrait bientôt voir le jour pour la communication sans fil.


Pour ceux intéressés par la programmation c/c++ pour l'ATmega328P, voici ma liste des déclaration de registre et vecteurs d'interruption pour l'ATmega328P (c'est dans l'ordre comme indiqué dans le datasheet):

Code : Tout sélectionner

#define _UDR0 (*(volatile unsigned char *)(0xc6))
#define _UBRR0H (*(volatile unsigned char *)(0xc5))
#define _UBRR0L (*(volatile unsigned char *)(0xc4))
#define _UBRR0HL (*(volatile unsigned int *)(0xc4))
#define _UCSR0C (*(volatile unsigned char *)(0xc2))
#define _UCSR0B (*(volatile unsigned char *)(0xc1))
#define _UCSR0A (*(volatile unsigned char *)(0xc0))
#define _TWAMR (*(volatile unsigned char *)(0xbd))
#define _TWCR (*(volatile unsigned char *)(0xbc))
#define _TWDR (*(volatile unsigned char *)(0xbb))
#define _TWAR (*(volatile unsigned char *)(0xba))
#define _TWSR (*(volatile unsigned char *)(0xb9))
#define _TWBR (*(volatile unsigned char *)(0xb8))
#define _ASSR (*(volatile unsigned char *)(0xb6))
#define _OCR2B (*(volatile unsigned char *)(0xb4))
#define _OCR2A (*(volatile unsigned char *)(0xb3))
#define _TCNT2 (*(volatile unsigned char *)(0xb2))
#define _TCCR2B (*(volatile unsigned char *)(0xb1))
#define _TCCR2A (*(volatile unsigned char *)(0xb0))
#define _OCR1BH (*(volatile unsigned char *)(0x8b))
#define _OCR1BL (*(volatile unsigned char *)(0x8a))
#define _OCR1BHL (*(volatile unsigned int *)(0x8a))
#define _OCR1AH (*(volatile unsigned char *)(0x89))
#define _OCR1AL (*(volatile unsigned char *)(0x88))
#define _OCR1AHL (*(volatile unsigned int *)(0x88))
#define _ICR1H (*(volatile unsigned char *)(0x87))
#define _ICR1L (*(volatile unsigned char *)(0x86))
#define _ICR1HL (*(volatile unsigned int *)(0x86))
#define _TCNT1H (*(volatile unsigned char *)(0x85))
#define _TCNT1L (*(volatile unsigned char *)(0x84))
#define _TCNT1HL (*(volatile unsigned int *)(0x84))
#define _TCCR1C (*(volatile unsigned char *)(0x82))
#define _TCCR1B (*(volatile unsigned char *)(0x81))
#define _TCCR1A (*(volatile unsigned char *)(0x80))
#define _DIDR1 (*(volatile unsigned char *)(0x7f))
#define _DIDR0 (*(volatile unsigned char *)(0x7e))
#define _ADMUX (*(volatile unsigned char *)(0x7c))
#define _ADCSRB (*(volatile unsigned char *)(0x7b))
#define _ADCSRA (*(volatile unsigned char *)(0x7a))
#define _ADCH (*(volatile unsigned char *)(0x79))
#define _ADCL (*(volatile unsigned char *)(0x78))
#define _ADCHL (*(volatile unsigned int *)(0x78))
#define _TIMSK2 (*(volatile unsigned char *)(0x70))
#define _TIMSK1 (*(volatile unsigned char *)(0x6f))
#define _TIMSK0 (*(volatile unsigned char *)(0x6e))
#define _PCMSK2 (*(volatile unsigned char *)(0x6d))
#define _PCMSK1 (*(volatile unsigned char *)(0x6c))
#define _PCMSK0 (*(volatile unsigned char *)(0x6b))
#define _EICRA (*(volatile unsigned char *)(0x69))
#define _PCICR (*(volatile unsigned char *)(0x68))
#define _OSCCAL (*(volatile unsigned char *)(0x66))
#define _PRR (*(volatile unsigned char *)(0x64))
#define _CLKPR (*(volatile unsigned char *)(0x61))
#define _WDTCSR (*(volatile unsigned char *)(0x60))
#define _SREG (*(volatile unsigned char *)(0x5f))
#define _SPH (*(volatile unsigned char *)(0x5e))
#define _SPL (*(volatile unsigned char *)(0x5d))
#define _SPHL (*(volatile unsigned int *)(0x5d))
#define _SPMCSR (*(volatile unsigned char *)(0x57))
#define _MCUCR (*(volatile unsigned char *)(0x55))
#define _MCUSR (*(volatile unsigned char *)(0x54))
#define _SMCR (*(volatile unsigned char *)(0x53))
#define _ACSR (*(volatile unsigned char *)(0x50))
#define _SPDR (*(volatile unsigned char *)(0x4e))
#define _SPSR (*(volatile unsigned char *)(0x4d))
#define _SPCR (*(volatile unsigned char *)(0x4c))
#define _GPIOR2 (*(volatile unsigned char *)(0x4b))
#define _GPIOR1 (*(volatile unsigned char *)(0x4a))
#define _OCR0B (*(volatile unsigned char *)(0x48))
#define _OCR0A (*(volatile unsigned char *)(0x47))
#define _TCNT0 (*(volatile unsigned char *)(0x46))
#define _TCCR0B (*(volatile unsigned char *)(0x45))
#define _TCCR0A (*(volatile unsigned char *)(0x44))
#define _GTCCR (*(volatile unsigned char *)(0x43))
#define _EEARH (*(volatile unsigned char *)(0x42))
#define _EEARL (*(volatile unsigned char *)(0x41))
#define _EEARHL (*(volatile unsigned int *)(0x41))
#define _EEDR (*(volatile unsigned char *)(0x40))
#define _EECR (*(volatile unsigned char *)(0x3f))
#define _GPIOR0 (*(volatile unsigned char *)(0x3e))
#define _EIMSK (*(volatile unsigned char *)(0x3d))
#define _EIFR (*(volatile unsigned char *)(0x3c))
#define _PCIFR (*(volatile unsigned char *)(0x3b))
#define _TIFR2 (*(volatile unsigned char *)(0x37))
#define _TIFR1 (*(volatile unsigned char *)(0x36))
#define _TIFR0 (*(volatile unsigned char *)(0x35))
#define _PORTD (*(volatile unsigned char *)(0x2b))
#define _DDRD (*(volatile unsigned char *)(0x2a))
#define _PIND (*(volatile unsigned char *)(0x29))
#define _PORTC (*(volatile unsigned char *)(0x28))
#define _DDRC (*(volatile unsigned char *)(0x27))
#define _PINC (*(volatile unsigned char *)(0x26))
#define _PORTB (*(volatile unsigned char *)(0x25))
#define _DDRB (*(volatile unsigned char *)(0x24))
#define _PINB (*(volatile unsigned char *)(0x23))

#define _RESET __vector_ ## 0
#define _INT0 __vector_ ## 1
#define _INT1 __vector_ ## 2
#define _PCINT0 __vector_ ## 3
#define _PCINT1 __vector_ ## 4
#define _PCINT2 __vector_ ## 5
#define _WDT __vector_ ## 6
#define _TIMER2_COMPA __vector_ ## 7
#define _TIMER2_COMPB __vector_ ## 8
#define _TIMER2_OVF __vector_ ## 9
#define _TIMER1_CAPT __vector_ ## 10
#define _TIMER1_COMPA __vector_ ## 11
#define _TIMER1_COMPB __vector_ ## 12
#define _TIMER1_OVF __vector_ ## 13
#define _TIMER0_COMPA __vector_ ## 14
#define _TIMER0_COMPB __vector_ ## 15
#define _TIMER0_OVF __vector_ ## 16
#define _SPI_STC __vector_ ## 17
#define _USART_RX __vector_ ## 18
#define _USART_UDRE __vector_ ## 19
#define _USART_TX __vector_ ## 20
#define _ADC __vector_ ## 21
#define _EE_READY __vector_ ## 22
#define _ANALOG_COMP __vector_ ## 23
#define _TWI __vector_ ## 24
#define _SPM_READY __vector_ ## 25

#define _INTERRUPT_JUMP(vector) extern "C" void vector() __attribute__ ((signal)); void vector()

Un petit rappel (et mise à jour du code) de ce qu'il faut pour faire voler un quadri-hélicoptère:

Code : Tout sélectionner

#include "../module/Timer.h"
#include "../module/Delay.h"
#include "../module/Random.h"
#include "../module/Math.h"
#include "../module/SoundWrite.h"
#include "../module/PwmWrite.h"
#include "../module/PwmRead.h"
#include "../module/Mpu6050.h"

int main()
{
	unsigned char n = 0;
	Mpu6050 gyroscope = Mpu6050 (0);
	PwmRead channelThrottle = PwmRead (1, false);
	unsigned int slowChannelThrottle = 0;
	unsigned int centerChannelThrottle = 0;
	PwmRead channelPitch = PwmRead (2, false);
	unsigned int centerChannelPitch = 0;
	PwmRead channelRoll = PwmRead (3, false);
	unsigned int centerChannelRoll = 0;
	PwmRead channelYaw = PwmRead (4, false);
	unsigned int centerChannelYaw = 0;
	PwmRead channelHold = PwmRead (5, false);
	unsigned int centerChannelHold = 0;
	PwmRead channelOption = PwmRead (6, false);
	unsigned int centerChannelOption = 0;
	PwmWrite motor1 = PwmWrite (8, 0, 0, 0);
	PwmWrite motor2 = PwmWrite (9, 0, 0, 0);
	PwmWrite motor3 = PwmWrite (10, 0, 0, 0);
	PwmWrite motor4 = PwmWrite (11, 0, 0, 0);
	Delay delaySoundStartCondition = Delay (1000, false);
	unsigned int mixThrottle = 0;
	signed int mixThrustPitchGain = 0;
	signed int mixThrustRollGain = 0;
	signed int mixInertiaYawGain = 0;
	signed int mixMinClearancePitch = 0;
	signed int mixMaxClearancePitch = 0;
	signed int mixMinClearanceRoll = 0;
	signed int mixMaxClearanceRoll = 0;
	signed int mixMinClearanceYaw = 0;
	signed int mixMaxClearanceYaw = 0;
	const unsigned int SPEED_GYRO = 1000;
	signed int speedPitch = 0;
	signed int speedRoll = 0;
	signed int speedYaw = 0;
	signed int mixPitchOffsetGyro = 0;
	signed int mixRollOffsetGyro = 0;
	signed int mixYawOffsetGyro = 0;
	unsigned char thrustGainPitch = 0;
	unsigned char thrustGainRoll = 0;
	unsigned char inertiaGainYaw = 0;
	unsigned int gainMinRxGyro = 0;
	unsigned int gainMaxRxGyro = 0;
	unsigned int gainMinRyGyro = 0;
	unsigned int gainMaxRyGyro = 0;
	unsigned int gainMinRzGyro = 0;
	unsigned int gainMaxRzGyro = 0;
	signed int mixMinRxGyro = 0;
	signed int mixMaxRxGyro = 0;
	signed int mixMinRyGyro = 0;
	signed int mixMaxRyGyro = 0;
	signed int mixMinRzGyro = 0;
	signed int mixMaxRzGyro = 0;
	unsigned int mixMotor1 = 0;
	unsigned int mixMotor2 = 0;
	unsigned int mixMotor3 = 0;
	unsigned int mixMotor4 = 0;
	const unsigned int SETUP_MIN_CHANNEL_THROTTLE = 1000;
	const unsigned int SETUP_MAX_CHANNEL_THROTTLE = 2000;
	const unsigned int SETUP_MIN_CHANNEL_PITCH = 1000;
	const unsigned int SETUP_MAX_CHANNEL_PITCH = 2000;
	const unsigned int SETUP_MIN_CHANNEL_ROLL = 1000;
	const unsigned int SETUP_MAX_CHANNEL_ROLL = 2000;
	const unsigned int SETUP_MIN_CHANNEL_YAW = 1000;
	const unsigned int SETUP_MAX_CHANNEL_YAW = 2000;
	const unsigned int SETUP_MIN_CHANNEL_HOLD = 1000;
	const unsigned int SETUP_MAX_CHANNEL_HOLD = 2000;
	const unsigned int SETUP_MIN_CHANNEL_OPTION = 1500;
	const unsigned int SETUP_MAX_CHANNEL_OPTION = 2000;
	const signed int SETUP_ZERO_PITCH = 38;
	const signed int SETUP_ZERO_ROLL = -11;
	const signed int SETUP_ZERO_YAW = -46;
	const unsigned int SETUP_FREQUENCY_ESC = 100;
	const unsigned int SETUP_HOLD_ESC = 950;
	const unsigned int SETUP_MIN_ESC = 1050;
	const unsigned int SETUP_MAX_ESC = 1950;
	const unsigned int SETUP_TRAVEL_PITCH = 250;
	const unsigned int SETUP_TRAVEL_ROLL = 250;
	const unsigned int SETUP_TRAVEL_YAW = 400;
	const unsigned int SETUP_SPEED_PITCH = 320;
	const unsigned int SETUP_SPEED_ROLL = 320;
	const unsigned int SETUP_SPEED_YAW = 320;
	const unsigned char SETUP_GAIN_PITCH = 93;
	const unsigned char SETUP_GAIN_ROLL = 88;
	const unsigned char SETUP_GAIN_YAW = 95;
	const unsigned char SETUP_THRUST_PROPELLER = 55;
	const unsigned char SETUP_INERTIA_PROPELLER = 100;
	
	Timer::pause (1000);
	
	slowChannelThrottle = Math::round (float (SETUP_MIN_CHANNEL_THROTTLE) + ((float (SETUP_MAX_CHANNEL_THROTTLE) - float (SETUP_MIN_CHANNEL_THROTTLE)) / float (10)));
	centerChannelThrottle = Math::round (float (SETUP_MAX_CHANNEL_THROTTLE) - ((float (SETUP_MAX_CHANNEL_THROTTLE) - float (SETUP_MIN_CHANNEL_THROTTLE)) / float (2)));
	centerChannelPitch = Math::round (float (SETUP_MAX_CHANNEL_PITCH) - ((float (SETUP_MAX_CHANNEL_PITCH) - float (SETUP_MIN_CHANNEL_PITCH)) / float (2)));
	centerChannelRoll = Math::round (float (SETUP_MAX_CHANNEL_ROLL) - ((float (SETUP_MAX_CHANNEL_ROLL) - float (SETUP_MIN_CHANNEL_ROLL)) / float (2)));
	centerChannelYaw = Math::round (float (SETUP_MAX_CHANNEL_YAW) - ((float (SETUP_MAX_CHANNEL_YAW) - float (SETUP_MIN_CHANNEL_YAW)) / float (2)));
	centerChannelHold = Math::round (float (SETUP_MAX_CHANNEL_HOLD) - ((float (SETUP_MAX_CHANNEL_HOLD) - float (SETUP_MIN_CHANNEL_HOLD)) / float (2)));
	centerChannelOption = Math::round (float (SETUP_MAX_CHANNEL_OPTION) - ((float (SETUP_MAX_CHANNEL_OPTION) - float (SETUP_MIN_CHANNEL_OPTION)) / float (2)));
	
	SoundWrite::pin (13);
	
	while (centerChannelThrottle == 0 || centerChannelPitch == 0 || centerChannelRoll == 0 || centerChannelYaw == 0 || centerChannelHold == 0 || centerChannelOption == 0)
	{
		delaySoundStartCondition.state();
		
		if (delaySoundStartCondition.update == true)
		{
			SoundWrite::play (200, 100);
		}
	}
	
	delaySoundStartCondition.reset();
	
	PwmRead::start (100);
	
	while (channelThrottle.us == 0 || channelPitch.us == 0 || channelRoll.us == 0 || channelYaw.us == 0 || channelHold.us == 0 || channelOption.us == 0)
	{
		channelThrottle.state();
		channelPitch.state();
		channelRoll.state();
		channelYaw.state();
		channelHold.state();
		channelOption.state();
		
		delaySoundStartCondition.state();
		
		if (delaySoundStartCondition.update == true)
		{
			SoundWrite::key (200, 100);
			SoundWrite::key (0, 100);
			SoundWrite::key (200, 100);
			SoundWrite::playKey();
		}
	}
	
	delaySoundStartCondition.reset();
	
	while (channelThrottle.us > slowChannelThrottle || channelHold.us < centerChannelHold)
	{
		channelThrottle.state();
		channelHold.state();
		
		delaySoundStartCondition.state();
		
		if (delaySoundStartCondition.update == true)
		{
			SoundWrite::key (200, 100);
			SoundWrite::key (0, 100);
			SoundWrite::key (200, 100);
			SoundWrite::key (0, 100);
			SoundWrite::key (200, 100);
			SoundWrite::playKey();
		}
	}
	
	Random::seed (15);
	
	for (n = 0; n < 16; n++)
	{
		if (n != 0)
		{
			SoundWrite::key (0, Random::integer (25, 75));
		}
		
		SoundWrite::key (Random::integer (70, 3000), Random::integer (25, 75));
	}
	
	SoundWrite::playKey();
	
	speedPitch = Math::curve (0, SETUP_SPEED_PITCH, SPEED_GYRO, 0, 32767, 0);
	speedRoll = Math::curve (0, SETUP_SPEED_ROLL, SPEED_GYRO, 0, 32767, 0);
	speedYaw = Math::curve (0, SETUP_SPEED_YAW, SPEED_GYRO, 0, 32767, 0);
	
	thrustGainPitch = Math::curve (0, SETUP_THRUST_PROPELLER, 100, 0, SETUP_GAIN_PITCH, 0);
	gainMinRxGyro = Math::curve (0, thrustGainPitch, 100, 32767, 0, 0);
	gainMaxRxGyro = Math::curve (0, SETUP_GAIN_PITCH, 100, 32767, 0, 0);
	
	thrustGainRoll = Math::curve (0, SETUP_THRUST_PROPELLER, 100, 0, SETUP_GAIN_ROLL, 0);
	gainMinRyGyro = Math::curve (0, thrustGainRoll, 100, 32767, 0, 0);
	gainMaxRyGyro = Math::curve (0, SETUP_GAIN_ROLL, 100, 32767, 0, 0);
	
	inertiaGainYaw = Math::curve (0, SETUP_INERTIA_PROPELLER, 100, 0, SETUP_GAIN_YAW, 0);
	gainMinRzGyro = Math::curve (0, inertiaGainYaw, 100, 32767, 0, 0);
	gainMaxRzGyro = Math::curve (0, SETUP_GAIN_YAW, 100, 32767, 0, 0);
	
	gyroscope.setZero (SETUP_ZERO_PITCH, SETUP_ZERO_ROLL, SETUP_ZERO_YAW);
	
	motor1.hold (SETUP_HOLD_ESC);
	motor1.min (SETUP_MIN_ESC);
	motor1.max (SETUP_MAX_ESC);
	motor2.hold (SETUP_HOLD_ESC);
	motor2.min (SETUP_MIN_ESC);
	motor2.max (SETUP_MAX_ESC);
	motor3.hold (SETUP_HOLD_ESC);
	motor3.min (SETUP_MIN_ESC);
	motor3.max (SETUP_MAX_ESC);
	motor4.hold (SETUP_HOLD_ESC);
	motor4.min (SETUP_MIN_ESC);
	motor4.max (SETUP_MAX_ESC);
	
	PwmWrite::start (SETUP_FREQUENCY_ESC);
	
	while (true)
	{
		gyroscope.state();
		channelThrottle.state();
		channelPitch.state();
		channelRoll.state();
		channelYaw.state();
		channelHold.state();
		channelOption.state();
		
		if (channelHold.us > centerChannelHold)
		{
			motor1.moveHold();
			motor2.moveHold();
			motor3.moveHold();
			motor4.moveHold();
		}
		else
		{
			mixThrottle = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, SETUP_MIN_ESC, SETUP_MAX_ESC, 0);
			
			mixMotor1 = mixThrottle;
			mixMotor2 = mixThrottle;
			mixMotor3 = mixThrottle;
			mixMotor4 = mixThrottle;
			
			mixMinClearancePitch = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, 0, SETUP_TRAVEL_PITCH, 0);
			mixMaxClearancePitch = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, SETUP_TRAVEL_PITCH, 0, 0);
			mixPitchOffsetGyro = Math::curve (SETUP_MIN_CHANNEL_PITCH, channelPitch.us, SETUP_MAX_CHANNEL_PITCH, -speedPitch, speedPitch, 0);
			mixThrustPitchGain = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, gainMaxRxGyro, gainMinRxGyro, 0);
			mixMinRxGyro = Math::wurve (-mixThrustPitchGain, gyroscope.rx + mixPitchOffsetGyro, mixThrustPitchGain, -mixMaxClearancePitch, 0, mixMinClearancePitch, 0, 0);
			mixMaxRxGyro = Math::wurve (-mixThrustPitchGain, gyroscope.rx + mixPitchOffsetGyro, mixThrustPitchGain, -mixMinClearancePitch, 0, mixMaxClearancePitch, 0, 0);
			
			mixMotor1 -= mixMinRxGyro;
			mixMotor2 -= mixMinRxGyro;
			mixMotor3 += mixMaxRxGyro;
			mixMotor4 += mixMaxRxGyro;
			
			mixMinClearanceRoll = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, 0, SETUP_TRAVEL_ROLL, 0);
			mixMaxClearanceRoll = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, SETUP_TRAVEL_ROLL, 0, 0);
			mixRollOffsetGyro = Math::curve (SETUP_MIN_CHANNEL_ROLL, channelRoll.us, SETUP_MAX_CHANNEL_ROLL, -speedRoll, speedRoll, 0);
			mixThrustRollGain = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, gainMaxRyGyro, gainMinRyGyro, 0);
			mixMinRyGyro = Math::wurve (-mixThrustRollGain, gyroscope.ry - mixRollOffsetGyro, mixThrustRollGain, -mixMaxClearanceRoll, 0, mixMinClearanceRoll, 0, 0);
			mixMaxRyGyro = Math::wurve (-mixThrustRollGain, gyroscope.ry - mixRollOffsetGyro, mixThrustRollGain, -mixMinClearanceRoll, 0, mixMaxClearanceRoll, 0, 0);
			
			mixMotor1 -= mixMinRyGyro;
			mixMotor2 += mixMaxRyGyro;
			mixMotor3 -= mixMinRyGyro;
			mixMotor4 += mixMaxRyGyro;
			
			mixMinClearanceYaw = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, 0, SETUP_TRAVEL_YAW, 0);
			mixMaxClearanceYaw = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, SETUP_TRAVEL_YAW, 0, 0);
			mixYawOffsetGyro = Math::curve (SETUP_MIN_CHANNEL_YAW, channelYaw.us, SETUP_MAX_CHANNEL_YAW, -speedYaw, speedYaw, 0);
			mixInertiaYawGain = Math::curve (SETUP_MIN_CHANNEL_THROTTLE, channelThrottle.us, SETUP_MAX_CHANNEL_THROTTLE, gainMaxRzGyro, gainMinRzGyro, 0);
			mixMinRzGyro = Math::wurve (-mixInertiaYawGain, gyroscope.rz + mixYawOffsetGyro, mixInertiaYawGain, -mixMaxClearanceYaw, 0, mixMinClearanceYaw, 0, 0);
			mixMaxRzGyro = Math::wurve (-mixInertiaYawGain, gyroscope.rz + mixYawOffsetGyro, mixInertiaYawGain, -mixMinClearanceYaw, 0, mixMaxClearanceYaw, 0, 0);
			
			mixMotor1 -= mixMinRzGyro;
			mixMotor2 += mixMaxRzGyro;
			mixMotor3 += mixMaxRzGyro;
			mixMotor4 -= mixMinRzGyro;
			
			motor1.pulse (mixMotor1);
			motor2.pulse (mixMotor2);
			motor3.pulse (mixMotor3);
			motor4.pulse (mixMotor4);
		}
	}
	
	return 0;
}
Vidéo: https://www.youtube.com/watch?v=0M3INZuHvoc


N'hésitez pas si vous avez des questions ou des idées :)

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 06 juin 2016, 21:21

Dans la nouvelle version de ma bibliothèque j'ai inclus la gestion de 2 nouveaux composants:
le gyroscope/magnétomètre BNO055
et le baromètre BMP180

J'ai créé avec ce gyro un mode auto pilote très robuste (horizon artificiel) pour débutant pour piloter le quadri-hélicoptère, je le publierais bientôt pour ceux qui veulent une fonction débutant ! :)

Je ferais également des tests en vol avec le baromètre pour mesurer l'altitude.

J'ai d'autres composants à inclure prochainement à la bibliothèque:
le NRF24L01P pour communiquer en 2.4Ghz ;)

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 16 juin 2016, 11:08

(toujours en pure c++)
BNO055 et BMP180 intégrés et fonctionnels :)
(j'ai fait plusieurs vols avec ce nouveau gyro)

Première communication 2.4Ghz réussie avec le NRF24L01P :)

Je vous tiendrai informés de la suite (projet de réaliser une radiocommande 2.4ghz).

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 23 juin 2016, 14:57

Exemple de radiocommande une voie avec ma bibliothèque et le composant nrf24l01p ! ^_^

Imaginons que vous voulez transmettre la valeur d'un potentiomètre à votre modèle, ça donne ceci:

Code : Tout sélectionner

#include "../module/Nrf24L01P.h"
#include "../module/AnalogRead.h"

int main()
{
	Nrf24L01P canal = Nrf24L01P (1);
	AnalogRead potar = AnalogRead (15);
	
	Nrf24L01P::start (1, 86400312, true);
	
	while (true)
	{
		potar.state();
		
		canal.transmit (potar.value);
	}
	
	return 0;
}
Et à l'autre bout, on fait bouger un servo avec la valeur du potentiomètre qu'on reçois par radio:

Code : Tout sélectionner

#include "../module/Nrf24L01P.h"
#include "../module/PwmWrite.h"

int main()
{
	Nrf24L01P canal = Nrf24L01P (1);
	PwmWrite servo = PwmWrite (1, 0, 500, 1000);
	
	Nrf24L01P::start (1, 86400312, true);
	PwmWrite::start (50);
	
	while (true)
	{
		canal.receive();
		
		servo.pulse (canal.value);
	}
	
	return 0;
}
C'est pas plus compliqué que ça, mais avec ce modeste code vous avez déjà une radiocommande 1 voie :)

A noter que "86400312" c'est un identifiant unique (une clé réseau si vous voulez), que vous choisissez à votre guise pour sécuriser la communication entre les deux nrf24l01p.

Les possibilités sont vraiment grandes, vous pouvez émettre, transmettre à la suite dans n'importe quel ordre, j'ai essayé par exemple des configurations un peu délicates à savoir:
incrément d'une valeur (par exemple le temps qui passe)
transmission de cette valeur d'un module 1 à un autre module 2
réception de la valeur depuis le module 2 puis émission vers le module 1
réémission de la valeur reçue du module 1 vers le module 2
réémission de la valeur du module 2 vers le module 1
affichage de la valeur sur un afficheur à leds via le module 1

Et ça marche vraiment impec sans bugs, avec une latence de l'ordre du millième de secondes, et avec une portée d'au moins 1km bien-sûr :)

A vous de jouer :)

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 28 juin 2016, 14:52

J'ai bien avancé dans mon histoire de quadri auto-stable sur l'horizon, j'ai testé hier un nouveau code qui utilise la rapidité du mpu6050 (le mode de vol normal c'est à dire acrobaties), et la fusion gyro+magnétomètre du bno055 pour avoir un pitch/roll verrouillé (le mode de vol horizon).

On passe de l'un a l'autre avec un inter sur la radio, ça permet de voler en mode débutant (horizon), c'est vraiment très très facile à piloter pour le coup, et quand on bascule l'inter on peut faire de la voltige (le roll et le pitch ne suivent plus l'horizon et ne sont plus bloqués a des angles min/max qu'on prédéfini).
Cet inter permet aussi de sauver le modèle si jamais on est perdu dans nos manches (ca remet le quadri a plat), j'ai pas encore testé ça en vol, mettre le quadri sur le dos et basculer l'inter horizon, mais ça ne serait tarder.

J'ai fait une vidéo pour vous montrer ce mode:

https://www.youtube.com/watch?v=3daBac7hJnM[/video]

Et une nouveauté sinon: à la "demande" d'un youtubeur, j'ai créé le bout de code qu'il faut pour faire fonctioner le magnétomètre Hmc5883L.
-> https://cdn-shop.adafruit.com/datasheet ... ass_IC.pdf

C'est maintenant inclus dans ma bibliothèque: http://sylvainmahe.xyz/data/module.zip
Cela retourne les valeurs en gauss (puisque le datasheet parle de gauss j'ai mi ça dans cette unité), à noter que 1 gauss = 100 micro tesla.

Voila pour l'instant (en presque 2 ans de travail en solo) tout ce qui est créé comme classes dans ma bibliothèque:

Code : Tout sélectionner

#include "../module/GpioRead.h"
#include "../module/GpioWrite.h"
#include "../module/AnalogRead.h"
#include "../module/InterruptRead.h"
#include "../module/PwmRead.h"
#include "../module/PwmWrite.h"
#include "../module/SoundWrite.h"

#include "../module/Timer.h"
#include "../module/Delay.h"

#include "../module/Math.h"
#include "../module/Iteration.h"
#include "../module/Average.h"
#include "../module/Hysteresis.h"
#include "../module/Random.h"

#include "../module/Max7219.h"
#include "../module/Mpu6050.h"
#include "../module/Bno055.h"
#include "../module/Hmc5883L.h"
#include "../module/Bmp180.h"
#include "../module/Nrf24L01P.h"

#include "../module/Network.h"

#include "../module/Memory.h"
#include "../module/Power.h"
#include "../module/Tool.h"
Vous pouvez faire beaucoup de projets avec ça et l'atmega328p-pu.

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 08 juil. 2016, 22:18

Bulle en alu:

Image
Image

A la niche:

Image

Avatar du membre
steph66
Armageddon
Messages : 15124
Enregistré le : 29 janv. 2010, 08:43

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par steph66 » 09 juil. 2016, 00:12

Joli travail Sylvain :wub:
Image
page FB steph66 - #KeepRCHelisAlive
- Beam AvantGarde - Miniature Aircraft XCell Spectra-G, Fury, Fury 55 - Trex500 - miniProtos - Protos - BeastX Power - hitec aurora 9
Photos et vidéos sur ma page perso - Guide de l'autorotation pour les nuls - Mes fiches conseils : montage - réglage - pilotage

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 09 juil. 2016, 20:32

Merci :)

J'ai testé ça aujourd'hui, pas d'effet aérodynamique indésirable (c'est ce que je craignais le plus). Dans le cas contraire, j'aurais ouvert encore plus la bulle avec ma scie-cloche :)

Niveau visibilité ça rajoute du volume du coup c'est beaucoup plus facile à piloter :)

J'ai fait un essai de peinture sur une chute d'alu que j'ai brossé, je vais voir si je rajoute quelques parties peintes (genre rouge piment).

Dans l'ensemble c'est positif ce petit test, j'ai juste un gain dans mon algorithme à légèrement baisser et c'est bon.

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 16 juil. 2016, 23:23


diazou
Bleuzaille
Messages : 2
Enregistré le : 11 nov. 2016, 10:43
Contact :

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par diazou » 11 nov. 2016, 10:46

Salut sylvainmahe, ça t'a pris combien de temps pour le programmer en c++ ?
Mon Hoverboard-Test.fr.
Modifié en dernier par diazou le 23 mai 2018, 11:55, modifié 1 fois.

sylvainmahe
Capitaine
Messages : 167
Enregistré le : 06 sept. 2015, 20:30

Re: Homemade Quadcopter/C++ Code sans ARDUINO/MULTIWII

Message par sylvainmahe » 24 janv. 2017, 17:57

Salut, ce quadri fait parti d'un projet global de cartes électroniques + bibliothèque c++ qui a pris en tout 2 ans de programmation.

Par contre en une après-midi j'avais écris la première approche du programme de vol qui a permis d'effectuer les premiers vols, mais il aura fallu 1 an de tests et de réécriture complète de la logique du vol pour arriver au résultat souhaité en voltige notamment (le code d'aujourd'hui n'a plus rien a voir avec celui des premier tests)

Répondre

Retourner vers « Photos & vidéos de vos modèles »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 1 invité