Mr. Pearman you are obviously a very busy man and let me begin by thanking you for all that you do for this community.
I am experimenting with PID and TBH controllers so that I can teach my teams about them. I am using J Pearman’s code from this post https://vexforum.com/t/flywheel-velocity-control/29892/1 I am asking for conformation that my understanding is correct. I have never used structs before.
In pic one the struct is listed, in pic two is a definition that references the struct instantiated as “fw_controller”. It then uses “*fw” to be a pointer to the “fw_controller” or at least that is what I think. Then throughout the definition in pic 2 he is using the “->” operater as a short cut for assigning or calling the pointer. So what is happening is he is pointing to that inner variable of the struct and setting it equal to the things to the right in the code. For example fw-> target = velocity will make the target variable in the fw_controller = to the variable velocity. Am I correct about this?
Does leaving out the pointer and using "fw_controller.target = velocity " accomplish the same task? Is the “*fw” used as a shortcut so you don’t have to write it out each time?
The function in picture 2 accepts a struct of the type fw_controller, and then gives it a general name for use inside the function, just like when you make a function that takes an int, you give that int a name, which is then used in the function. The *fw is a pointer, and AFAIK it is necessary to pass a struct to a function. the arrow (->) instead of a period is necessary for use with a pointer.
fw_controller.target = velocity
will use a struct named fw_controller, but it doesn’t exist, so you will get an error. The *fw is the pointer name. You would use fwVelocitySet() like this:
fwVelocitySet(&flyControl, 1000, .8);
Those values are arbitrary, that’s just how the function would be called. The main thing is that you need a single & before the name of the struct, which tells the Cortex to access the address of the struct, rather than the contents of the struct itself. Also, the name that follows the ampersands (&) is the name of the particular struct to be used, not any particular variable inside that struct.
To elaborate on the answer given above, what you are seeing is an example of what is called passing a variable by reference. As stated in the previous post, you do in fact need to do this in this situation. The reason why is because the function is looking to mutate (or change, update) a value inside of the struct. If you just passed the struct without the pointer *, or by value, you would be working with what is effectively a copy of the struct used as a parameter in the function.
If a variable or struct is passed by value, mutated, and then evaluated outside that function where it was mutated, you would read the value before it was changed, since you only updated the copy, which you lose the reference for when the function exits. This is true in C for things as simple as variables of type int or float and for data structures.
Yes, this is why I struggle teaching structs to the kids. It takes a long time to get this. With what we do more global variables suffice. I know it won;t help you get a job better but pointer concepts are hard to teach.
A struct is a grouping of the collection of variables into one memory block and makes for nice logical grouping as well. If I need these multiple variables together every time I use them, then a struct allows me to create them all at once and reference them later.
Lets simplify the structure a bit…
typedef struct _my_structures_alias
So all these variables are right next to each other in memory and take up the size of two ints and a float all next to each other int he order of the struct definition.
So now when I go to use my structure I have to use one of two methods to access it. If I am accessing by value I use the . notation and if it is a pointer I use the -> notation.
The alias is used if I want to make more of these structures. But in here I am using just my_struct.
You can now access the structure members like a variable if it is directly in scope.
The second picture you showed is referencing the structure by reference. I am goign back to that for this explanation. You have the structure name passed in via the address it sits in into the call of the function. Then inside that function you have to use the arrow notation.
The pointer reference in the function call says look at this place of memory and play around with it like it was of this structure definition.
This means you gave me an address of a structure called fw_controller and I can access all those elements inside the structure.
The arrow notation says move on down that far in the memory struct to access that variable.
fw->first_cross = 1;
This code means start at the address fw gave you and go down a few sizes of variables from that initial memory pointer (9 floats and 7 longs worth of bytes). Then you can twiddle that memory for setting the value to 1.
Once you come out of the function the memory you passed in was manipulated for use with direct reference or give the address to a new function!