What is a struct?

A struct (structure) is a convenient programming tool used to group related variables together into a single location. This concept is applicable to most C-like programming languages including C and C++, commonly used for embedded microcontroller applications.

This engineering brief introduces the struct construct using the Arduino Braccio robot arm (Figure 1) as a case study. This struct encapsulate all data (members) required to control the RC servos. This includes:

  • Object pointer: Arduino myServo object
  • char[10]: Atring holding the common name of the servo, e.g. “SHOULDER”
  • uint16_t: Servo limit minimum
  • uint16_t: Servo limit maximum
  • uint16_t: Servo home position
  • uint16_t: Servo command value
  • float: Servo transition accumulator

Figure 1: Image of the Arduino Braccio robot arm featuring six RC servos. The struct encapsulates the data for each RC servo.

Tech Tip: A defining characteristic of a struct is its ability to accommodate different data types. In this example, the struct holds 16-bit integers, a floating-point number, the address of an Arduino servo object, and even an ASCII string describing the servo.

Relationship between objects in C and C++

The struct encapsulates the information associated with an individual RC servo. We can take some liberty and describe this struct as an “object-like” container for an individual servo.

We could use the “object” designation if we switched to a fully Object-Oriented Programming (OOP) language such as C++. This would require us to associate the struct along with methods to manipulate the data.

For clarity, simplicity, and maximum compatibility, we will stay with a C implementation. Consequently, we will use the term “object-like” and use a collection of setters and getters to manipulate the data contained within the struct.

Why should I use a struct?

The robot arm makes a good case study for a struct application, as the RC servos provide a concrete example of object-like encapsulation. The six independent RC servos represent a moderate level of complexity. There is a real need to coordinate the action of all servos to provide a smooth controlled arm motion.

The “why use struct” question is best answered by considering the code necessary to move all servos from waypoint A to waypoint B. We could write independent code to control each servo. However, there are distinct advantages to building functions that operate on the servo:

  • Single-purpose functions to handle multiple servos makes the program easier to debug.

  • Easy to implement limits such as minimum and maximum servo position.

  • Scalability as it is relatively easy to add additional servos.

  • Easy to implement controlled arm motions involving all servos.

How is a struct used?

There are two parts to a struct, including a definition and the various usage statements.
This is the definition for the robot arm:

// Define the ServoData struct (private to this file)
typedef struct {
  Servo servo;                 // The servo object (from the Servo library)
  char name[10];               // ASCII name for the servo
  uint16_t minPulse;           // Minimum allowed pulse width
  uint16_t maxPulse;           // Maximum allowed pulse width
  uint16_t home;               // Home (default) position
  uint16_t cmd;                // Active servo command pulse width
  float transitionAccumulator;  // Intermediate value used when transitioning from one step to another.
} ServoData;

Observe that the struct holds the data for a single RC servo. We can then group the servos into a single “array of structs” as seen here.

static ServoData servos[NUM_SERVOS];

From there we can access members using commands such as:

servos[servoID].cmd = 1000;

The real power of this technique becomes apparent when we want to send the robot arm to the home position. Since the members are highly ordered, we can use a simple FOR loop to copy the struct’s home positions into the struct’s active servo command position. This is followed by a call to the updateAllServos() function which conducts a smooth controlled move of all servos until the robot arm to its predefined home position.

void HomeAllServos() {
  for (int i = 0; i < NUM_SERVOS; i++) {
    servos[i].cmd = servos[i].home;
  }
  updateAllServos();
}

Tech Tip: Consider the simplicity captured in the HomeAllServos() and updateAllServos() functions. There is simplicity as both operate on the shared array of structs. For instance, a new servo can be added with minimal change to the code. Troubleshooting is greatly simplified as the various function perform simple operations on the struct’s members.

Parting thoughts

The robot arm provides a down-to-earth example showcasing the power and convenience of the struct. In the C programming language, we programmatically handle each RC servo as an object-like encapsulation with a number of getters and setters to handle the struct members. Depending on your application, you may want to shift to C++ and encapsulate the RC servo data into a proper object complete with methods to manipulate the struct members. Either way, the struct represents a key aspect of code simplification with clear application in the embedded world.

At this point the robot arm is still a work in progress. Anticipate follow-on articles describing the code techniques.

Please add to the conversation by sharing how you use structs in your embedded code. Feel free to weigh in on the age-old embedded C vs C++ conversation.

Best wishes,

APDahlen

Related information

Please follow these links to related and useful information:

About this author

Aaron Dahlen, LCDR USCG (Ret.), serves as an application engineer at DigiKey. He has a unique electronics and automation foundation built over a 27-year military career as a technician and engineer which was further enhanced by 12 years of teaching (interwoven). With an MSEE degree from Minnesota State University, Mankato, Dahlen has taught in an ABET-accredited EE program, served as the program coordinator for an EET program, and taught component-level repair to military electronics technicians. Dahlen has returned to his Northern Minnesota home and thoroughly enjoys researching and writing articles such as this.

1 Like