Salut à tous, j'ai acheté depuis peu une carte Arduino Mega 2560 R3 pour du prototypage. Je souhaite piloter un servomoteur à l'aide d'un GUI sur ordinateur. J'ai réussi ce projet, cependant lors de la phase de tests, après une dizaine de tests réussis, le servomoteur s'est emballé, a rejoint la position max: 180° et pouf de la fumée s'est échappée de ma carte: cramée. Je n'ai pas grande idée de pourquoi la carte a cramé et j'aimerais avoir vos avis et conseils svp.
Bon je travaille avec ce que j'ai sous la main alors voici le matériel utilisé:
un ServoMoteur ReadyToSky TD8325MG qui prend 4.8V-6.8V: https://fr.aliexpress.com/item/32298149426.html
La carte arduino Mega R3, reliée via USB au port Série du PC pour la communication avec le logiciel de commande que j'ai réalisé.
Et pour alimenter le tout... une alim de labo réglée sur environs 11.8V à 0.2 A
Le circuit est branché comme suit :
Schema servomotor controle.pdf (28,2 Ko)
voici le code qui tourne sur mon arduino:
#include <Arduino.h>
#include <Servo.h>
//PINS//
#define SERVO_PIN 11
//Providing parameters for motor control
enum etats{
Init,
ConnCheck,
DataWait,
DataDecode,
WaitStart,
RunServo,
Stop,
SendData,
Reset,
};
Servo monServo;
bool serialWriteDone,dataSent;
char data;
uint8_t c1,c2;
uint32_t value;
etats etat;
void writeReturnToSerial(String ret){
Serial.print('R');
Serial.print('<');
Serial.println(ret);
Serial.print('>');
}
void writeDataToSerial(char c1, char c2 )
{
Serial.print('!');
Serial.print('<');
Serial.print(c1);
Serial.print(c2);
Serial.print('>');
Serial.print('!');
}
void writeStrToSerial(String rtrnStr)//, char char2 )
{
Serial.print('!');
Serial.print('<');
Serial.println(rtrnStr);
Serial.print('>');
Serial.print('!');
}
void StopServo()
{
monServo.write(0);
delay(15);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
//pinMode(SERVO_PIN, OUTPUT);
monServo.attach(11);
etat=Init;
serialWriteDone=false;
serialWriteDone=false;
}
void loop() {
switch(etat){
case Init:
dataSent=false;
monServo.write(0);
PulseTime=0;
value=0;
c1=0;
c2=0;
serialWriteDone=false;
if(Serial.available()){
data=Serial.read();
if(data=='H'){
etat=ConnCheck;
}else{etat=Init;}
}
break;
case ConnCheck:
if(!serialWriteDone){
writeReturnToSerial("H_OK");
serialWriteDone=true;
}
if(Serial.available()){
data=Serial.read();
}
if (data=='S'){
serialWriteDone=false;
etat=DataWait;
}else{etat=ConnCheck;}
break;
case DataWait:
if(!serialWriteDone){
serialWriteDone=true;
writeReturnToSerial("LISTN_DATA");
}
if(Serial.available()>3){
data=Serial.read();
if(data=='<'){
c1=Serial.read();
data=Serial.read();
if (data==','){
c2=Serial.read();
data=Serial.read();
}
}
data=Serial.read();
if(data='>'){
serialWriteDone=false;
etat=DataDecode;
}
}else{etat=DataWait;}
break;
case DataDecode:
char c1_tmp;
if(!serialWriteDone){
writeReturnToSerial("D_DEC");
serialWriteDone=true;
}
value=int(c1);
value=value<<8;
value=value|int(c2);
serialWriteDone=false;
etat=WaitStart;
break;
case WaitStart:
if(!serialWriteDone){
writeReturnToSerial("WAIT_S");
serialWriteDone=true;
}
if(Serial.available()){data=Serial.read();}
if (data=='G'){
serialWriteDone=false;
etat=RunServo;
}else{etat=WaitStart;}
break;
case RunServo:
if(!serialWriteDone){
writeReturnToSerial("RUN_MOT");
serialWriteDone=true;
}
if (Serial.available()){data=Serial.read();}
if(data=='B'){
serialWriteDone=false;
StopServo();
etat=Stop;
}else{
monServo.write(value);
delay(15);
etat=RunServo;
}
break;
case Stop:
if (!serialWriteDone){
writeReturnToSerial("STOPPED");
serialWriteDone=true;
}
serialWriteDone=false;
etat=SendData;
break;
case SendData:
if(!serialWriteDone){
writeReturnToSerial("DATA_S");
serialWriteDone=true;
}
if(!dataSent){
/*c2=uint8_t(PulseTime);
c1=uint8_t(PulseTime>>8);*/
c2=uint8_t(value);
c1=0;
writeDataToSerial(c1,c2);
dataSent=true;
}
if (Serial.available()){
data=Serial.read();
}
if (data=='R'){
writeReturnToSerial("REIN_OK");
etat=Init;
}else{
etat=SendData;}
break;
}
}
Enfin, j'ai réalisé le GUI sur delphi, en pascal. En voici le code:
unit ServoMotor_Control_Unit;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, AdPacket, OoMisc, AdPort, AdSelCom, Vcl.StdCtrls;
type
TForm11 = class(TForm)
displayMemo: TMemo;
comCombo: TComboBox;
brCombo: TComboBox;
refreshBtn: TButton;
initBtn: TButton;
startBtn: TButton;
connectBtn: TButton;
sendBtn: TButton;
degreeEdit: TEdit;
portCom: TApdComPort;
commandReturn: TApdDataPacket;
dataReturn: TApdDataPacket;
procedure FormCreate(Sender: TObject);
procedure dataCreate();
procedure dataSend();
procedure refreshBtnClick(Sender: TObject);
procedure initBtnClick(Sender: TObject);
procedure connectBtnClick(Sender: TObject);
procedure sendBtnClick(Sender: TObject);
procedure startBtnClick(Sender: TObject);
procedure OnCommandString(Sender: TObject; Data: AnsiString);
procedure OnDataString(Sender: TObject; Data: AnsiString);
private
{ Déclarations privées }
public
{ Déclarations publiques }
end;
var
Form11: TForm11;
dataSent, motorIsRunning:boolean;
value, shiftVal, checkVal,retVal: integer;
byte2,byte1,retByte1,retByte2: byte;
implementation
{$R *.dfm}
//~~~~~~~~~~~~ CTOR & DTOR ~~~~~~~~~~\\
procedure TForm11.FormCreate(Sender: TObject);
var
i : Integer;
begin
displayMemo.Lines.Clear;
dataSent:=false;
motorIsRunning:=false;
sendBtn.Enabled:=false;
startBtn.Enabled:=false;
connectBtn.Enabled:=false;
comCombo.Items.Clear;
for i := 1 to 10 do
begin
if IsPortAvailable(i) then
begin
comCombo.Items.Add ('COM' + IntToStr (i));
end;
end;
brCombo.ItemIndex:=5;
end;
//~~~~~~~ Functions & Procs. ~~~~~~~~~\\
procedure TForm11.dataCreate();
begin
value:=0;
byte1:=0;
byte2:=0;
value:=value or ((StrToInt(degreeEdit.Text) and integer(511)));
if (value>180) then
begin
value:=180;
displayMemo.Lines.Add('Value dépasse 180°: Val set to 180°');
end;
byte2:=byte(value);
shiftVal:= value shr 8;
byte1:= byte1 or byte(shiftVal);
checkVal:= integer(byte1);
checkVal:= checkVal shl 8;
checkVal:= checkVal or integer(byte2);
end;
procedure TForm11.dataSend();
begin
displayMemo.Lines.Add('<' + IntToStr(byte1) +','+ IntToStr(byte2) + '>');
portCom.PutString('<' + Ansichar(byte1) +','+ Ansichar(byte2) + '>');
end;
//~~~~~~~~ Messages & Events ~~~~~~~~~~\\
procedure TForm11.refreshBtnClick(Sender: TObject);
begin
comCombo.Items.Clear;
TThread.CreateAnonymousThread(
procedure
var
i : Integer;
begin
for i := 1 to 64 do
begin
Application.ProcessMessages;
if IsPortAvailable(i) then
begin
comCombo.Items.Add ('COM' + IntToStr (i));
end;
end;
end).Start
end;
procedure TForm11.initBtnClick(Sender: TObject);
begin
if not(dataSent) then
begin
portCom.Baud:=StrToInt(brCombo.Text);
portCom.Parity:=TParity.pNone;
portCom.StopBits:=1;
portCom.ComNumber:=StrToInt(comCombo.Text[4]);
value:=0;
byte1:=0;
byte2:=0;
degreeEdit.Clear;
dataSent:=false;
commandReturn.StartString:='R<';
commandReturn.EndString:='>';
dataReturn.StartString:='!<';
dataReturn.EndString:='>!';
displayMemo.Lines.Add(' ');
displayMemo.Lines.Add('~~~ NEW SEQUENCE ~~~');
displayMemo.Lines.Add('Initialisation port COM' + IntToStr(portCom.ComNumber)+ ':Ok');
portCom.Open:=True;
portCom.FlushOutBuffer;
portCom.FlushInBuffer;
connectBtn.Enabled:=true;
end;
if(dataSent) then
begin
portCom.PutChar('R');
end;
end;
procedure TForm11.connectBtnClick(Sender: TObject);
begin
portCom.PutChar('H');
end;
procedure TForm11.sendBtnClick(Sender: TObject);
begin
dataCreate();
portCom.PutChar('S');
end;
procedure TForm11.startBtnClick(Sender: TObject);
begin
if not(motorIsRunning) then
begin
portCom.PutChar('G');
end;
if motorIsRunning then
begin
portCom.PutChar('B');
end;
end;
procedure TForm11.OnCommandString(Sender: TObject; Data: AnsiString);
begin
if Pos('H_OK',Data)>0 then
begin
displayMemo.Lines.Add('Handshake: OK');
sendBtn.Enabled:=true;
end;
if (Pos('LISTN_DATA', Data) > 0 ) then
begin
//displayMemo.Lines.Add('Wait for Data');
dataSend();
end;
if (Pos('D_DEC', Data) > 0 ) then
begin
//displayMemo.Lines.Add('dataDecode');
end;
if (Pos('WAIT_S', Data) > 0 ) then
begin
displayMemo.Lines.Add('Waiting Start');
startBtn.Enabled:=true;
end;
if (Pos('RUN_MOT', Data) > 0 ) then
begin
motorIsRunning:=true;
displayMemo.Lines.Add('Servo is running');
startBtn.Caption:='Stop';
end;
if (Pos('STOPPED', Data) > 0 ) then
begin
displayMemo.Lines.Add('Motor Stopped');
startBtn.Caption:='Start';
startBtn.Enabled:=false;
sendBtn.Enabled:=false;
connectBtn.Enabled:=false;
end;
if (Pos('DATA_S', Data) > 0 ) then
begin
//displayMemo.Lines.Add('Receiving Data');
dataSent:=true;
initBtn.Caption:='Reinit.';
end;
if (Pos('REIN_OK', Data) > 0 ) then
begin
displayMemo.Lines.Add('Reset: OK');
dataSent:=false;
initBtn.Caption:='Init.';
motorIsRunning:=false;
sendBtn.Caption:='Send';
sendBtn.Enabled:=false;
startBtn.Enabled:=false;
connectBtn.Enabled:=false;
degreeEdit.Clear;
end;
end;
procedure TForm11.OnDataString(Sender: TObject; Data: AnsiString);
begin
retByte1:=byte(Data[1]);
retByte2:=byte(Data[2]);
retVal:=integer(retByte1);
retVal:= retVal shl 8;
retVal:=retVal or integer(retByte2);
displayMemo.Lines.Add('Pulse width: '+ IntToStr(retVal)+'microS');
end;
end.
Voilà, j'espère que vous pourrez m'éclairer un peu. A noter, que l'alimentation est d'abord branchée sur une breadboard pour lier le condo. de découplage.
Je travaille dans un environnment avec de l'huile et j'ai découvert en revenant que pas maldh'uile avait coulé sous la breadboard (sous la partie alimentation). Cela a peut-être courtcircuité l'alim mais le condensateur semble intact.
Au plaisir de vous lire car j'ai peut-être fait une erreur bête qui m'échappe ou ai négligé une caractéristique de la carte ou du moteur et je ne compte pas cramer la future remplaçante de feu celle-ci.
Merci !






