Controlling the MINI with OpenRB-150

1/14/2024
Presently, users of the MINI kit are likely “worried” about the availability of the OpenCM-904-C controller as ROBOTIS had previously announced its “retirement”.

Although the OpenRB-150 has the exact physical size as for the OpenCM-904-C, it is fairly obvious that just swapping out the 904 with the 150 is not feasible at all. So, my re-design approach hinges on this main assumption:

  • The 904 is no longer programmable, but its function as a Power Hub for the XL-320s is still operational.

The following picture shows the Hardware Redesign approach used:

Test_Setup_1_Annoted

  • The 2 LiPo batteries are still hooked up to the 904 as normal.

  • One of the DXL connector on the 904 needs to be diverted out into an X3P Hub via one Convertible Cable (XL-320 to X3P). Then from the X3P Hub a second Convertible Cable is used to bring DXL Power back to the right arm of the MINI. So, all 16 DXLs of the MINI are now powered. But how to control them from the 150?

  • A special X3P cable (with its Power Wire severed) is then connected between a DXL Connector on the 150 and the previous X3P Hub, thus isolating the Control Circuit of the XL-320s (i.e. from the 150) from their Power Circuit (i.e. from the 2 LiPo batteries via the 904).

  • The 150 is currently powered via USB from the PC, but it will be powered via VIN(DXL) with its own small battery at a later stage of the project.

So did this crazy mash-up work? My first test was to download the sketch usb_to_dynamixel.ino and tested to see if the Dynamixel Wizard could connect to all DXLs of the MINI? And it did:

DXLWIZ_MINI_1

Next, I created a sketch to do Sync Write/Read into the two shoulder joints (ID=1 and 2) with randomized Goal Positions. And this sketch worked fine also:

RandomGP_Mini

Below is a demo MP4 file:

Thus, so far, so good. The next step will be to translate ROBOTIS MOTION file into C/C++ Motion arrays and then use Sync Write to get the MINI to walk!

Until the next update!

3 Likes

Good morning
Your subject interests me a lot because I have Darwin mini with openCM9 HS card so I bought an openRB card and I’m getting into arduio. I also bought your book which I hope will help me understand how it works.
Sincerely

1/20/2024

I settled on the physical layout as shown below:

IMG_025990

My software solution for the MINI is adapted from the one described in Section 2.13 of my Arduino Book (https://www.amazon.com/Using-ARDUINO-ROBOTIS-Systems-Ngoc/dp/0999391895), which was designed for a robot based on XL-430s set into Time-based Position Control. See picture of the A4WP-H robot below:

FrontTiltUp

The XL-320 of course does not have that Time-based mode, but the same data structure (numerical arrays) can still be used. So the Motion Data from the MINI Motion File is “transcribed” into a C/C++ array:

ReadyPose

float _READY_POSE[17] = { 390,0,0,-73.24,73.24,0,0,0,0,-26.37,26.37,29.3,-29.3,13.18,-13.18,0,0 };  // in ms & in degrees

Then it is only a matter of building a big Sync Write packet for all 16 XL-320s Goal Position values and then send it away into the DXL network. I used the Sync Time of 390 ms as a simple Time Delay (between Motion Frames - as shown in My Arduino book). Strictly speaking, this is not as “accurate” as the Time-based Control mode available with the XL-430, nor the Motion timing achieved when the OpenCM-904 (or CM-530/550) is operating in its ROBOTIS firmware (TASK+MOTION), but the demo video below showed that the MINI performance was good enough - I think.

This video showed that the gear back-lash on my aged Mini is getting very bad!

Also it showed that the mechanical aspects of where to put the extra hardware, so as to keep the overall CG of the MINI “near” where it was on the original Mini, will be the most challenging issue.

3 Likes

can you share your code ? thank you in advance

You will have to wait until the 2nd edition of my Mini book coming out towards year’s end. It is derived from codes from Section 2.13 of my Arduino book, so you already have the concepts and sample codes. Consider it as a challenge to figure things out on your own.

1 Like

THANKS
I’m still going to learn. Waiting for your book to come out
Sincerely

Good morning
Am I on track for the mini?
Do you have an example of code to control the arm movement in the loop with the keyboard because I don’t know how to do it. I thank you in advance.
Sincerely
`<// **** Paramètres globaux pour les DXL *********
#include <Dynamixel2Arduino.h>
#define DXL_SERIAL Serial1
#define DEBUG_SERIAL Serial

// **** Global Parameters for DXLs *********
const uint8_t BROADCAST_ID = 254;
const uint8_t DXL_ID1 = 1 ;
const uint8_t DXL_ID2 = 2 ;
const uint8_t DXL_ID3 = 3 ;
const uint8_t DXL_ID4 = 4 ;
const uint8_t DXL_ID5 = 5 ;
const uint8_t DXL_ID6 = 6 ;
const uint8_t DXL_ID7 = 7 ;
const uint8_t DXL_ID8 = 8 ;
const uint8_t DXL_ID9 = 9 ;
const uint8_t DXL_ID10 = 10 ;
const uint8_t DXL_ID11 = 11 ;
const uint8_t DXL_ID12 = 12 ;
const uint8_t DXL_ID13 = 13 ;
const uint8_t DXL_ID14 = 14 ;
const uint8_t DXL_ID15 = 15 ;
const uint8_t DXL_ID16 = 16 ;

const float DXL_PROTOCOL_VERSION = 2.0;
const uint8_t GP_DXL_CNT = 16; // nombre de DXL utilisés en mode Contrôle de position
const uint8_t GP_DXL_ID_LIST[GP_DXL_CNT] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}; //ID de servo définis en mode Contrôle de position
const uint16_t ADDR_X_PRESENT_POSITION = 37; // (XL-320)
const uint16_t LEN_X_PRESENT_POSITION = 2 ; // (XL-320)
const uint16_t ADDR_X_GOAL_POSITION = 30; // (XL-320)
const uint16_t LEN_X_GOAL_POSITION = 2; // (XL-320)
const uint16_t ADDR_X_MOVING_SPEED= 32; // (XL-320) adress 32 byt 2 0-2047
const uint16_t LEN_X_MOVING_SPEED= 2; // (XL-320)
const uint16_t ADDR_X_TORQUE_ENABLE= 24; // (XL-320) TORQUE_ENABLE adress 24 0 off 1 on
const uint16_t LEN_X_TORQUE_ENABLE= 1;
const uint8_t CONTROL_MODE = 2; // for XL320 adress 11 byt 1 mode 2 joint

Dynamixel2Arduino dxl_mini(DXL_SERIAL);

ParamForSyncWriteInst_t GP_sync_write_param; // Parameters structure for SW GP packet
ParamForSyncReadInst_t GP_sync_read_param; // Parameters structure for SR GP packet
RecvInfoFromStatusInst_t GP_read_result; // Structure for results of SR PP command

uint8_t dxl_error = 0; // Dynamixel error
int32_t dxl_present_position[GP_DXL_CNT] = { 0 }; // Tableau de position actuelle
int32_t dxl_goal_position[GP_DXL_CNT] = { 0 }; // Tableau de position d’objectif
bool read_present_positions_OK = false;

// Section MOUVEMENT
int _STEP_TIME_0 = millis();
int _STEP_TIME_1 = millis();
int _pose_init[17] ={390, 0, 0, -73.24, 73.24, 0, 0, 0, 0, -26.37, 26.37, 29.3, -29.3, 13.18, -13.18, 0, 0};

int salut_main [6][17] = { {100,-0.29, -150 ,-73.54 ,72.36, -0.29, 0.59 ,-0.29 ,-0.29, -26.66, 26.07 ,29, -29.59, 12.89, -13.48, -0.29, -0.29},
{0,-0.29 ,-149.71, -73.54, 51.27, -0.29, -33.69, -0.29, -0.29 ,-26.66, 26.07, 29 ,-29.59, 12.89, -13.48 ,-0.29 ,-0.29},
{0,-0.29 ,-150, -73.54, 91.7, -0.29, 32.81, -0.29 ,-0.29 ,-26.66 ,26.07 ,29 ,-29.59, 12.89, -13.48, -0.29, -0.29},
{0,-0.29 ,-149.71, -73.54, 51.27, -0.29, -33.69 ,-0.29, -0.29, -26.66 ,26.07 ,29 ,-29.59, 12.89, -13.48, -0.29, -0.29},
{0,-0.29 ,-150, -73.54, 91.7, -0.29, 32.81, -0.29, -0.29, -26.66, 26.07, 29 ,-29.59 ,12.89 ,-13.48, -0.29 ,-0.29},
{0,0 ,0 ,-73.24 ,73.24 ,0, 0, 0, 0 ,-26.37, 26.37, 29.3 ,-29.3 ,13.18 ,-13.18 ,0 ,0 } };

/*int salut_2 [6][17] = { {_STEP_TIME_1,-22.27 ,-44.24, -73.24, 73.24, 0, 0, 0, 0, -26.37, 26.07, 29.3, -29.3, 13.18, -13.48, 0, 0, },
{_STEP_TIME_1,-22.27,-44.24, -62.99, 92.58, -71.78, 58.59, 0, 0, -26.37, 26.07, 29.3, -29.3, 13.18, -13.48, 0, 0 },
{_STEP_TIME_1,-22.27, -69.73, -62.99, 92.58, -71.78, 58.59, 0, 0, -79.39, 82.91, 29.3, -29.3, -10.25, 10.55, 0, 0},
{_STEP_TIME_1,-22.27,-69.73, -62.99, 92.58, -71.78, 58.59, 0, 0, -79.39, 82.91, 29.3, -29.3, -10.25, 10.55, 0, 0},
{_STEP_TIME_1,-22.27, -44.24, -73.24, 73.24, 0, 0, 0, 0, -26.37, 26.07, 29.3, -29.3, 13.18, -13.48, 0, 0},
{_STEP_TIME_1,0, 0, -73.24, 73.24, 0, 0, 0, 0, -26.37, 26.37, 29.3, -29.3, 13.18, -13.18, 0, 0 } }; */

// ********** Function prototypes Prototypes de fonctions
int CalcAngle2Raw(int angle);

//bool check_motion();
int GP_time = _pose_init[0]; //c’est-à-dire _STEP_TIME_0
int CalcAngle2Raw(int angle)
{
return (int)(round((angle * 1023.0 / 300.0 + 512.0)));// return (int)(round((angle * 1023.0 / 300.0 + 512.0)));XL 320
} // fin de CalcAngle2Raw (angle int)

//**** Cet espace de noms est requis pour utiliser les noms d’éléments de la table de contrôle
using namespace ControlTableItem;

void setup()
{
int goal_position_raw = 0; // raw valeur brute de la position de l’objectif DXL
Serial.begin(115200);
while(!Serial); // attendez que l’opérateur ouvre Serial Monitor

//****** Configuration des Dynamixels pour mini ***pour XL320
dxl_mini.begin(1000000);
dxl_mini.setPortProtocolVersion(DXL_PROTOCOL_VERSION);
dxl_mini.scan();
Serial.println("Fin de la numérisation des DXL du robot ");

// Préparation du paquet GP SW

GP_sync_write_param.addr = ADDR_X_GOAL_POSITION;
GP_sync_write_param.length = LEN_X_GOAL_POSITION;
GP_sync_write_param.id_count = GP_DXL_CNT;
for(int i = 0; i < GP_DXL_CNT; i++){
GP_sync_write_param.xel[i].id = GP_DXL_ID_LIST[i];
}
Serial.println(“Fin de la préparation du paquet GP SW”);

// Préparation du paquet GP SR
GP_sync_read_param.addr = ADDR_X_PRESENT_POSITION; // Present Position of DYNAMIXEL-X series
GP_sync_read_param.length = LEN_X_PRESENT_POSITION;
GP_sync_read_param.id_count = GP_DXL_CNT; // Number of servos in Position Control Mode
for(int i = 0; i < GP_DXL_CNT; i++){
GP_sync_read_param.xel[i].id = GP_DXL_ID_LIST[i];
}
Serial.println(“Fin de la préparation du paquet GP SR”);

// Configuration des servos GP dans la zone EEPROM : mode contrôle contrôle de position
// et dans la zone RAM : accélération du profil, vitesse du profil
for(int i = 0; i < GP_DXL_CNT; i++){
dxl_mini.torqueOff(GP_DXL_ID_LIST[i]); // Torque OFF
//dxl_mini.writeControlTableItem( GP_DXL_ID_LIST[i],CONTROL_MODE); //
dxl_mini.setOperatingMode(GP_DXL_ID_LIST[i], OP_POSITION); // Position Control
dxl_mini.torqueOn(GP_DXL_ID_LIST[i]); // Torque ON
delay(100); // attendez un peu avant de travailler dans la zone RAM
}
Serial.println(“Fin de la configuration des servos GP”);

delay(3000);

Serial.println(“Mettre le robot dans la pose initiale”);
// Réglez le robot sur la pose _ via SyncWrite
// Allouez la valeur brute de chaque position d’objectif dans le paquet GP SW, un DXL à la fois en utilisant les valeurs du tableau global _[1] à _[17]
for (int i = 0; i < GP_DXL_CNT; i++) // DXL 1 à 16
{
goal_position_raw = CalcAngle2Raw(_pose_init[i+1]); // convertir l’angle de mouvement en position d’objectif brute [0-4096], _[0] n’est pas utilisé ici
memcpy(GP_sync_write_param.xel[i].data, &goal_position_raw, sizeof(goal_position_raw));
}
dxl_mini.syncWrite(GP_sync_write_param); // send GP SW Packet
delay(3000);

// fin de l’installation() et de la pose initiale"

Serial.println(“jouer mouvement bras”);
for (int frame_no = 0; frame_no < 6; frame_no++) // 4 images de mouvement ont été définies pour le mouvement vers l’avant
{
GP_time = (int)(round(salut_main[frame_no][0] )); //c’est-à-dire STEP TIME 1 modifié avec le facteur de vitesse
//(int)(round(forward[frame_no][0] )); //c’est-à-dire STEP TIME 1 modifié avec le facteur de vitesse

    for (int i = 0; i < GP_DXL_CNT; i++)  // Définition des valeurs GP brutes pour les Walking DXL 1 à 8
    {
      goal_position_raw = (CalcAngle2Raw(salut_main[frame_no][i + 1]) );  //convertir l'angle de mouvement avec Adj Offset en Raw GP 
      memcpy(GP_sync_write_param.xel[i].data, &goal_position_raw, sizeof(goal_position_raw));
    }
    if (dxl_mini.syncWrite(GP_sync_write_param) == false)  // envoyer le paquet GP SW
    {
      Serial.println("Sfin  mouvement");
        
    }
    delay(400); // en attendant que chaque image clé soit jouée en ms
  }  //   fin de pour (numéro de trame)

} // fin du mouvement bras

void loop()

// Réinitialisation du robot à la pose d’initialisation
{
int GP_time = _pose_init[0]; //c’est-à-dire _STEP_TIME_0
int goal_position_raw = 0; // valeur brute de la position de l’objectif DXL
for (int i = 0; i < GP_DXL_CNT; i++) // Définir GP pour les DXL 1 à 16
{
goal_position_raw = CalcAngle2Raw(pose_init[i+1]); //convertir l’angle de mouvement en position d’objectif brute [0-1023]
memcpy(GP_sync_write_param.xel[i].data, &goal_position_raw, sizeof(goal_position_raw));
}
if (dxl_mini.syncWrite(GP_sync_write_param) == false) // envoyer le paquet GP SW si faux
{
Serial.println(“Échec du logiciel”); //Échec du logiciel pour SW_TC
()
// return 0;
}
delay(3000); // en attente de la réinitialisation de la pose pour jouer en ms

} >`

I do not have specific codes to interface keyboard inputs to a Mini doing motion. You will have to figure out this issue on your own. Section 2.4 of the Arduino book covers UART Programming using the Remocon (RC100) protocol and the Debug tool of TASK 2 (i.e. keys U-D-L-R and 1-2-3-4-5-6). Section 2.12 of the Arduino book is about to using RC-100 keyboard inputs to control the Mobile Manipulator, specifically the Arm - this is very close to what you want to do. This Mobile Manipulator robot uses AX-12A which has a Control Table similar to the XL-320 on the Mini - so this robot code will be helpful too for your Mini project.

But let’s get back to your current code first:

  1. Let’s use a “do nothing” loop() for now so that you can just concentrate on making the Mini bow one time only via setup(). So use this statement void loop() { } // end of loop()

  2. In setup(), you did not specify MOVING_SPEED to yours XL-320, this means that all your XL-320s could be running at Maximum Speed of 1023. So you should slow them down (=200) like shown below:

dxl.writeControlTableItem(MOVING_SPEED, GP_DXL_ID_LIST[i], 200); // Setting Initial Moving Speeds

It may be handy to set a SW packet structure for MOVING_SPEED parameters also. That way you can slow down or speed up any Motion Frame as needed. Of course sending the MOVING_SPEED SW packets, BEFORE sending the corresponding GOAL_POSITION packets.

  1. You use an IF structure to “send out” a GP SW packet

if (dxl_mini.syncWrite(GP_sync_write_param) == false) // envoyer le paquet GP SW
{
Serial.println(“Sfin mouvement”);
}

Why do you need this?

  1. Right now you use a delay(400) for all motion frames (1 to 6) - which is fine for now.
    But eventually you need to set each motion frame with its own delay time as shown in the ROBOTIS Motion File for the Mini. You cannot leave them at 0, like you currently have

int salut_main [6][17] = { {100,-0.29, -150 ,-73.54 ,72.36, -0.29, 0.59 ,-0.29 ,-0.29, -26.66, 26.07 ,29, -29.59, 12.89, -13.48, -0.29, -0.29},
{0,-0.29 ,-149.71, -73.54, 51.27, -0.29, -33.69, -0.29, -0.29 ,-26.66, 26.07, 29 ,-29.59, 12.89, -13.48 ,-0.29 ,-0.29},
{0,-0.29 ,-150, -73.54, 91.7, -0.29, 32.81, -0.29 ,-0.29 ,-26.66 ,26.07 ,29 ,-29.59, 12.89, -13.48, -0.29, -0.29},
{0,-0.29 ,-149.71, -73.54, 51.27, -0.29, -33.69 ,-0.29, -0.29, -26.66 ,26.07 ,29 ,-29.59, 12.89, -13.48, -0.29, -0.29},
{0,-0.29 ,-150, -73.54, 91.7, -0.29, 32.81, -0.29, -0.29, -26.66, 26.07, 29 ,-29.59 ,12.89 ,-13.48, -0.29 ,-0.29},
{0,0 ,0 ,-73.24 ,73.24 ,0, 0, 0, 0 ,-26.37, 26.37, 29.3 ,-29.3 ,13.18 ,-13.18 ,0 ,0 } };

ALSO big syntax error with Array salut_main[ ], it is declared as an INTEGER ARRAY, but you feed it with FLOATING POINT numbers!!!

In my previous post, I clearly used a FLOAT array for my _READY_POSE[ ] array.

I thank you for all these answers. I will therefore redo my program following your explanations.
Sincerely

BTW, Sub-Section 2.13.4 also is an application of using keyboard inputs (via TASK 2 Debug Window). Just need to go through the presented materials “several” times until you “got” the concepts down.

Bonjour,

J’ai besoin d’aide.

Quand j’envoie une commande pour jouer un mouvement, certaine fois le mouvement est joué plusieurs fois de suite. Comment faire pour que le mouvement ne joue qu’une seul fois .je pense que mon programme a un problème mais je ne voie pas ou.

Merci de votre aide.

Cordialement

Good morning,

I need help.

When I send a command to play a movement, sometimes the movement is played several times in a row. How to make the movement only play once. I think my program has a problem but I can’t see where.

Thank you for your help.

Sincerely



#include <RC100.h>

// **** Global Parameters for DXLs *********
#include <Dynamixel2Arduino.h>
#define DXL_SERIAL_1 Serial1 //Serial1 is for DXL port on OpenRB-150
//#define DEBUG_SERIAL Serial

// **** Global Parameters for DXLs *********
const uint8_t BROADCAST_ID = 254;
const uint8_t DXL_ID1 = 1 ;
const uint8_t DXL_ID2 = 2 ;
const uint8_t DXL_ID3 = 3 ;
const uint8_t DXL_ID4 = 4 ;
const uint8_t DXL_ID5 = 5 ;
const uint8_t DXL_ID6 = 6 ;
const uint8_t DXL_ID7 = 7 ;
const uint8_t DXL_ID8 = 8 ;
const uint8_t DXL_ID9 = 9 ;
const uint8_t DXL_ID10 = 10 ;
const uint8_t DXL_ID11 = 11 ;
const uint8_t DXL_ID12 = 12 ;
const uint8_t DXL_ID13 = 13 ;
const uint8_t DXL_ID14 = 14 ;
const uint8_t DXL_ID15 = 15 ;
const uint8_t DXL_ID16 = 16 ;

Dynamixel2Arduino dxl_mini(DXL_SERIAL_1);

// Number of DXLs used in robot
const float DXL_PROTOCOL_VERSION = 2.0;
const uint8_t GP_DXL_CNT = 16;  // nombre de DXL utilisés en mode Contrôle de position
const uint8_t GP_DXL_ID_LIST[GP_DXL_CNT] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};  //ID de servo définis en mode Contrôle de position
const uint16_t ADDR_X_PRESENT_POSITION = 37;   // (XL-320)
const uint16_t LEN_X_PRESENT_POSITION = 2 ;    //  (XL-320) 
const uint16_t ADDR_X_GOAL_POSITION = 30;      // (XL-320)
const uint16_t LEN_X_GOAL_POSITION = 2;        // (XL-320)
const uint16_t ADDR_X_MOVING_SPEED= 32;       // (XL-320)       adress 32 byt 2   0-2047 
const uint16_t LEN_X_MOVING_SPEED= 2;         // (XL-320)
const uint16_t ADDR_X_TORQUE_ENABLE= 24;       // (XL-320)    TORQUE_ENABLE     adress 24   0  off      1 on
const uint16_t LEN_X_TORQUE_ENABLE= 1;        
const uint8_t CONTROL_MODE = 2;  //             for XL320  adress 11      byt 1  mode 2 =joint   

uint16_t Current_Pose[GP_DXL_CNT] = { 0 };
//uint16_t Step = 10;//   Étape


// ********** RC100 settings *************
#include <RC100.h>
RC100 RC_2;  // Instalation de la télécommande via Serial2
uint16_t RcvData_2 = 0;
bool UP = false;
bool DOWN = false;
bool LEFT = false;
bool RIGHT = false;

// ********** End of Global Parameters Definition
// Function prototype

//**** This namespace is required to use Control table item names
//using namespace ControlTableItem;

ParamForSyncWriteInst_t MS_sync_write_param;  // Parameters structure for MS packet
ParamForSyncWriteInst_t GP_sync_write_param; // Parameters structure for SW GP packet
ParamForSyncReadInst_t GP_sync_read_param;  // Parameters structure for SR GP packet
RecvInfoFromStatusInst_t GP_read_result;  // Structure for results of SR PP command

uint8_t dxl_error = 0;  // Dynamixel error
int32_t dxl_MOVING_SPEED[GP_DXL_CNT] = { 0 };  // Tableau de position vitesse
int32_t dxl_present_position[GP_DXL_CNT] = { 0 };  //  Tableau de position actuelle
int32_t dxl_goal_position[GP_DXL_CNT] = { 0 };  // Tableau de position d'objectif  

bool read_present_positions_OK = false;

// Section MOUVEMENT
bool check_motion();

/*void myDelay (unsigned long combien_de_temps)
  {
  unsigned long start = millis ();
  if (millis () - start <= combien_de_temps)//
    { }  
  } */

int GP_time = dxl_MOVING_SPEED[200]; 

int _STEP_TIME_0 = millis();
int STEP_TIME_1 = millis();
//const int _STEP_TIME_1 = delay();

float pose_init[17] = { 390,0, 0, -73.24, 73.24, 0, 0, 0, 0, -26.37, 26.37, 29.3, -29.3, 13.18, -13.18, 0, 0};

float salut_main[6][17] = { {50,-0.29, -150 ,-73.54 ,72.36, -0.29, 0.59 ,-0.29 ,-0.29, -26.66, 26.07 ,29, -29.59, 12.89, -13.48, -0.29, -0.29},    // 50  75  100   125 150   275
                           {25,-0.29 ,-150, -73.54, 51.27, -0.29, -33.69, -0.29, -0.29 ,-26.66, 26.07, 29 ,-29.59, 12.89, -13.48 ,-0.29 ,-0.29},
                           {25,-0.29 ,-150, -73.54, 91.7, -0.29, 32.81, -0.29 ,-0.29 ,-26.66 ,26.07 ,29 ,-29.59, 12.89, -13.48, -0.29, -0.29},
                           {25,-0.29 ,-150, -73.54, 51.27, -0.29, -33.69 ,-0.29, -0.29, -26.66 ,26.07 ,29 ,-29.59, 12.89, -13.48, -0.29, -0.29},
                           {25,-0.29 ,-150, -73.54, 91.7, -0.29, 32.81, -0.29, -0.29, -26.66, 26.07, 29 ,-29.59 ,12.89 ,-13.48, -0.29 ,-0.29},
                           {125,0 ,0 ,-73.24 ,73.24 ,0, 0, 0, 0 ,-26.37, 26.37, 29.3 ,-29.3 ,13.18 ,-13.18 ,0 ,0  } };

float salut_2[6][17] = { {25,-22.27 ,-44.24, -73.24, 73.24, 0, 0, 0, 0, -26.37, 26.07, 29.3, -29.3, 13.18, -13.48, 0, 0, },     //25  75  150  275  350  400
                           {50,-22.27,-44.24, -62.99, 92.58, -71.78, 58.59, 0, 0, -26.37, 26.07, 29.3, -29.3, 13.18, -13.48, 0, 0 },
                           {75,-22.27, -69.73, -62.99, 92.58, -71.78, 58.59, 0, 0, -79.39, 82.91, 29.3, -29.3, -10.25, 10.55, 0, 0},
                           {125,-22.27,-69.73, -62.99, 92.58, -71.78, 58.59, 0, 0, -79.39, 82.91, 29.3, -29.3, -10.25, 10.55, 0, 0},
                           {75,-22.27, -44.24, -73.24, 73.24, 0, 0, 0, 0, -26.37, 26.07, 29.3, -29.3, 13.18, -13.48, 0, 0},
                           {50,0, 0, -73.24, 73.24, 0, 0, 0, 0, -26.37, 26.37, 29.3, -29.3, 13.18, -13.18, 0, 0 } };                               

// ********** Function prototypes     
//int GP_time = dxl_MOVING_SPEED[300]; //////////////////////////////////////
int CalcAngle2Raw(int angle)
{
  return (int)(round((angle * 1023.0 / 300.0 + 512.0)));// return (int)(round((angle * 1023.0 / 300.0 + 512.0)));XL 320
}  // fin de CalcAngle2Raw (angle int)
//int32_t x= 0;
int i=16;
int frame_no = 0 ;
int goal_position_raw = 0;

// Cet espace de noms est requis pour utiliser les noms d'éléments de la table de contrôle
 using namespace ControlTableItem; 

void setup() 
{
  int goal_position_raw = 0;  // raw     valeur brute de la position de l'objectif DXL
  Serial.begin(115200);
  while(!Serial);   // attendez que l'opérateur ouvre Serial Monitor
  
   // *****Configuration des Dynamixels pour mini ***
 
  dxl_mini.begin(1000000);     // débit en bauds du port DXL sur 1 Mbps pour XL320
  dxl_mini.setPortProtocolVersion(DXL_PROTOCOL_VERSION);
  dxl_mini.scan();
  Serial.println("Fin de la numérisation des DXL du robot "); 

    // Préparation du paquet GP SW
  MS_sync_write_param.addr = ADDR_X_MOVING_SPEED; 
  MS_sync_write_param.length = LEN_X_MOVING_SPEED;
  MS_sync_write_param.id_count = GP_DXL_CNT;  
  for(int i = 0; i < GP_DXL_CNT; i++){
    MS_sync_write_param.xel[i].id = GP_DXL_ID_LIST[i];
  }
  Serial.println("Fin de la préparation du paquet MS SW");

  // Préparation du paquet GP SR
  GP_sync_read_param.addr = ADDR_X_PRESENT_POSITION; // Present Position of DYNAMIXEL-X series
  GP_sync_read_param.length = LEN_X_PRESENT_POSITION;
  GP_sync_read_param.id_count = GP_DXL_CNT;  // Number of servos in Position Control Mode
  for(int i = 0; i < GP_DXL_CNT; i++){
    GP_sync_read_param.xel[i].id = GP_DXL_ID_LIST[i];
  }
  Serial.println("Fin de la préparation du paquet GP SR"); 

            // Préparation du paquet GP SW
  GP_sync_write_param.addr = ADDR_X_GOAL_POSITION; 
  GP_sync_write_param.length = LEN_X_GOAL_POSITION;
  GP_sync_write_param.id_count = GP_DXL_CNT;  
  for(int i = 0; i < GP_DXL_CNT; i++){
    GP_sync_write_param.xel[i].id = GP_DXL_ID_LIST[i];
  }
  Serial.println("Fin de la préparation du paquet GP SW");

// Configuration des servos GP dans la zone EEPROM : mode contrôle contrôle de position
// et dans la zone RAM : vitesse  dxl  du profil
  for(int i = 0; i < GP_DXL_CNT; i++){
    dxl_mini.torqueOff(GP_DXL_ID_LIST[i]);  // Torque OFF
    dxl_mini.writeControlTableItem(MOVING_SPEED, GP_DXL_ID_LIST[i], 0); // Définition des vitesses de déplacement initiales
    dxl_mini.setOperatingMode(GP_DXL_ID_LIST[i], OP_POSITION); 
    dxl_mini.torqueOn(GP_DXL_ID_LIST[i]);   // Torque ON
    delay(100);  // attendez un peu avant de travailler dans la zone RAM
  }
  Serial.println("Fin de la configuration des servos GP");  
  
  delay(1000);

 Serial.begin(115200);
  RC_2.begin(2);  // RC_2 utilisant Serial2 - Port UART 4 ​​broches - débit en bauds 57 600 bps dans RC100.cpp
   dxl_mini.begin(1000000);  
  dxl_mini.setPortProtocolVersion(DXL_PROTOCOL_VERSION);
  for (int i = 0; i < GP_DXL_CNT; i++)
  {
    dxl_mini.ping(GP_DXL_ID_LIST[i]);
    dxl_mini.torqueOff(GP_DXL_ID_LIST[i]);
    //dxl_mini.writeControlTableItem(MOVING_SPEED, GP_DXL_ID_LIST[i], 200);
    dxl_mini.setOperatingMode(GP_DXL_ID_LIST[i], OP_POSITION);
    dxl_mini.torqueOn(GP_DXL_ID_LIST[i]);
    delay(100);  // attendez un peu avant de travailler dans la zone RAM
  }
  Serial.println("Mettre le robot dans la pose initiale"); 
  // Allouez la valeur brute de chaque position d'objectif dans le paquet GP SW, un DXL à la fois en utilisant les valeurs du tableau global _[1] à _[116]
  for (int i = 0; i < GP_DXL_CNT; i++)  // DXL 1 à 16
  {
    //  Réglez le robot sur la pose _ via SyncWrite
    goal_position_raw = CalcAngle2Raw(pose_init[i+1]);  // convertir l'angle de mouvement en position d'objectif brute [0-1023], _[0] n'est pas utilisé ici
    memcpy(GP_sync_write_param.xel[i].data, &goal_position_raw, sizeof(goal_position_raw));
    dxl_mini.writeControlTableItem(MOVING_SPEED, GP_DXL_ID_LIST[i], 200);
    dxl_mini.setOperatingMode(GP_DXL_ID_LIST[i], OP_POSITION);
   
  }
   dxl_mini.syncWrite(GP_sync_write_param);  // send GP SW Packet
  delay(1000);
  Serial.println("Fin de la configuration pose init");     
}  

void loop() 
{
  // récupérer les positions actuelles des actionneurs 
  for(int i = 0; i < GP_DXL_CNT; i++)
  {
    Current_Pose[i] = dxl_mini.getPresentPosition(GP_DXL_ID_LIST[i]);
  }
  // effacer toutes les commandes du robot de Serial2  
  UP = false;
  DOWN = false;
  LEFT = false;
  RIGHT = false;
  
  RcvData_2 = 0;
  // Traitement des nouveaux boutons RC-100
  if (RC_2.available()) 
  {
    RcvData_2 = RC_2.readData();
    if (RcvData_2 == 0)
    {
      Serial.println("Tous les boutons libérés via Serial2");
      
    }
    if ((RcvData_2 & RC100_BTN_U) > 0)
    {
       Serial.println("Button UP poussé via Serial2");
       UP = true;
    }
    if ((RcvData_2 & RC100_BTN_D) > 0)
    {
       Serial.println("Button DOWN poussé via Serial2");
       DOWN = true;
    }
    if ((RcvData_2 & RC100_BTN_L) > 0)
    {
      Serial.println("Button LEFT poussé via Serial2");
       LEFT = true;
    }
    if ((RcvData_2 & RC100_BTN_R) > 0)
    {
       Serial.println("Button RIGHT poussé via Serial2");
       RIGHT = true;
    }
 } 
// Faire fonctionner le robot selon les commandes de l'opérateur via Serial2
      if(UP == true)  
  {
       Serial.println("jouer salut main"); 
       
      for (int frame_no = 0; frame_no <6; frame_no++)   // 6 images de mouvement ont été définies pour le mouvement bras
      {
        STEP_TIME_1  = (int)(round(salut_main[frame_no][0] ));   //c'est-à-dire STEP TIME 1 = millis
        for (int i = 0; i < GP_DXL_CNT; i++)  // Définition des valeurs GP brutes pour les DXL 1 à 16
        { 
          goal_position_raw = (CalcAngle2Raw(salut_main[frame_no][i+1]) );  //convertir l'angle de mouvement en Raw GP 
          memcpy(GP_sync_write_param.xel[i].data, &goal_position_raw, sizeof(goal_position_raw));
          dxl_mini.writeControlTableItem(MOVING_SPEED, GP_DXL_ID_LIST[i], 200);
          //dxl_mini.setOperatingMode(GP_DXL_ID_LIST[i], OP_POSITION);
        }
        dxl_mini.syncWrite(GP_sync_write_param); 
        delay(390); // en attendant que chaque image clé soit jouée en ms
      } 
      RcvData_2 == 0;
      return ;     //(RcvData_2) ;  
   } 
        if(DOWN  == true)  
  {
       Serial.println("jouer salut 2");  
      for (int frame_no = 0; frame_no <6; frame_no++)   // 6 images de mouvement ont été définies pour le mouvement bras
      {
         STEP_TIME_1 = (int)(round(salut_2[frame_no][0] )); 
        for (int i = 0; i < GP_DXL_CNT; i++)  // Définition des valeurs GP brutes pour les DXL 1 à 16
        {
           //STEP_TIME_1  = (int)(round(salut_2[frame_no][0] )); 
          goal_position_raw = (CalcAngle2Raw(salut_2[frame_no][i+1]) );  //convertir l'angle de mouvement en Raw GP 
          memcpy(GP_sync_write_param.xel[i].data, &goal_position_raw, sizeof(goal_position_raw));
          dxl_mini.writeControlTableItem(MOVING_SPEED, GP_DXL_ID_LIST[i], 400);
         // dxl_mini.setOperatingMode(GP_DXL_ID_LIST[i], OP_POSITION);/////////////////////////
        }
         dxl_mini.syncWrite(GP_sync_write_param); 
       
        delay(390); // en attendant que chaque image clé soit jouée en ms
      }  // fin de pour (numéro de trame)
     RcvData_2 == 0;
     return ; 
   }  
}   

Why do you need to use these statements ?

RcvData_2 == 0;
return;

What are they supposed to do?

Good morning,
I put this command so that the movement would be played only once and the program would return to the start of the loop. Because I never have this print on the screen “Serial.println(“All buttons released via Serial2”); » but it doesn’t work.
Thank you for your help.
Sincerely

To do some tasks only once, it is best to put them in setup(). Try that first to troubleshoot your coding.

Also it is not a good idea to involve rc100 for doing something once because no matter how fast you can tap on the RC buttons there will be several button messages in the RC100 serial buffer. But this situation can be handled. You already have my Arduino book, so study Section 2.9. In there I wanted to use Button 2 to set up my “tracking_mode” for the video camera. I wanted to set “tracking_mode” only ONCE, but I knew that there would be a bunch of Button 2 data coming in, no matter how fast I tapped on the Physical Button 2, i.e. how to ignore the extra information. That is all that I am going to tell you, because you need to go beyond your “shallow-learner” mode on your own.

Good morning,
Thank you for your help. I’m going to check all that.
Sincerely