cvra / pid

A PID controller implementation
68 stars 27 forks source link

Synchronization #8

Closed Stapelzeiger closed 10 years ago

Stapelzeiger commented 10 years ago

Setters and getters are not synchronized with the PID control function. How should we handle synchronization of such functions?

One solution would be to restrict the code to processor architectures where float read & writes are atomic. This would reduce the problem to a few places where multiple floats must absolutely be written/read atomically. But after the discussion about stdints the general attitude seems to be in favor of portability.

Stapelzeiger commented 10 years ago

Not really, you still would have to check for each parameter separately, or have some kind of opcode in the message you're passing.

Stapelzeiger commented 10 years ago

Perhaps we could create a class pid_config that implements just synchronization. It would have setter functions for all parameters, and a function accepts a pid-struct pointer and updates the contens (via normal setters) if the parameters changed. This last function would be called on each iteration of the control loop. The advantage is that such a class could also implement the protocol to accept parameters via CAN for example. Edit: what I meant with the last phrase is not that I want to integrate CAN-interface code in the PID controller, but to have a protocol for some kind of remote parameter-set call which will be needed at some point.

antoinealb commented 10 years ago

So the pid_config class/module would talk to itself over message passing, with its setter called in one thread and the update function in another one ?

Stapelzeiger commented 10 years ago

exactly

antoinealb commented 10 years ago

Not bad. And it is caller responsibility to never call pid_process and the parameter update function at the same time ?

Stapelzeiger commented 10 years ago

Yes, but since you will be doing this only in the control loop, this should not be a problem.

pierluca commented 10 years ago

I have something in the pipeline. Busy in the next 36 hours but will post on Sunday, probably.

A question though. How do we link the git repos? I'll need some synchronization primitives and I'm not sure how we should integrate the platform-abstraction in the pid repo.

Stapelzeiger commented 10 years ago

For dependencies we normally used git-submodules. But I'm not sure this would be a good idea for this kind of small module because we might end up having a synchronization-submodule in almost every module. The problem is that you cannot link multiple versions of the same library (same function/variable names) to one executable in C. The only alternative I see is tracking the dependencies "manually" by listing them in the Readme and hope that the API doesn't break. Maybe @antoinealb has an idea how to solve this problem.

antoinealb commented 10 years ago

I think we should simply list dependencies in README and have all the gitsubmodules in the application directory. The other option is writing / reusing some kind of dependency / package manager, but it seems overkill.

hope that the API doesn't break.

Well this will probably happen and we will have to fix it by hand when it happens. Also don't change the API too often.

pierluca commented 10 years ago

The README file doesn't allow for automatic compilation and testing to happen.... which is why I was asking in the first place. Should we modify the travis thing to clone the platform abstraction?

We should also decide on the final directory hierarchy, in order for the includes to make sense and be relatively unchanged over time.

Stapelzeiger commented 10 years ago

For the include directories, I suggest that we use #include <modulename.h> and specify the include paths via the compiler flag -I./module/dir/.

antoinealb commented 10 years ago

Yes, Travis will be able to build the PID tests and link them against the platform abstraction. Where Travis is limited is that you cannot ask him to re-run the PID tests when the platform abstraction change.

Personally I would prefer using #include <pid/pid.h> and only have a single -I flag. Much easier build setup in my opinion.

Stapelzeiger commented 10 years ago

OK, I agree on the single -I flag, also having a folder prefix for the header files (pid/ in your example) might be a good idea if the module contains multiple header files.

antoinealb commented 10 years ago

So the code structure would look like this :

| main.c
| Makefile
| pid/
| -- pid.h
| platform/

And the -I flag would point to the root folder, which contains main.c, right ?

Stapelzeiger commented 10 years ago

I would put the application code in a src/ subdirectory. It's much easier to get an overview of the structure if all source files aren't in the top level.

antoinealb commented 10 years ago

Ok. Perhaps we should discuss this issue somewhere else.

pierluca commented 10 years ago

With respect to this:

| main.c
| Makefile
| pid/
| -- pid.h
| platform/

I would encourage you to think more globally. Where would state machine go? Where would other libraries go? We might as well decide on this quickly before changes become too large to make.

| control/
| -- pid/
| -- -- pid.h
| -- state-machine/
| processing/
| -- filters/
| platform/
| -- thread/
| -- -- mutex.h
| -- -- semaphore.h
| -- network/
| -- -- can/
| -- -- ethernet/
Stapelzeiger commented 10 years ago

Changes in the project structure should not involve any changes in the source files. Only the build-system must be updated, which should be relatively simple.

pierluca commented 10 years ago

#include's change depending on project structure. Putting everything on a flat hierarchy (-I all the dirs) doesn't seem particularly reasonable to me.

Stapelzeiger commented 10 years ago

Only the -I flags would change, which isn't so much work for the ~20 modules we will have.

Stapelzeiger commented 10 years ago

Why wouldn't you put all the modules in a flat hierarchy?

pierluca commented 10 years ago

if we're only going to have 20 modules, it's reasonable.

But when there are several dozens of modules and multiple people working on them, I find it's easy to have naming conflicts and hierarchies help in both avoiding that and making the dependencies clearer. That's been my experience at least.

Still, you have a better idea than me on the final project size.

If you tell me the advantages of keeping a certain flexibility in the hierarchy outweigh the potential disadvantages, I'm okay with it :)

Stapelzeiger commented 10 years ago

Like I see it hierarchy doesn't help much with naming conflicts, since C has no namespaces anyway. The only limitation with the current design is that the module names must be different. (For exported symbols we should generally prefix them with the module name.)

For the dependencies: I'm not sure it's possible to represent them with a folder hierarchy unless you put the base modules (like the platform abstraction) at the top or the hierarchy.

antoinealb commented 10 years ago

The project should be relatively small in the end, so I think the best way to handle it is to think about it later, if problems arise instead of over-engineering the build system/dependency solver/organization. We can always make change to the organization when we got actual code to organize.

pierluca commented 10 years ago

Quick question, as I'm not quite familiar with the whole cmake / travis thing. How would I need to modify the files to include the platform-abstraction library at the same level?

I have two variants of the code ready for testing, I'm mainly doing changes based on interface considerations.

antoinealb commented 10 years ago

Well, I don't know what the best option is. Probably configuring Travis CI to clone the platform-abstraction at the same level as the PID library, then add the platform abstraction to the CMakeList.

But we should probably discuss the build process with everyone at a meeting. Will you be there on Wednesday ? @froj @Stapelzeiger ?

pierluca commented 10 years ago

I might not be there :-( I have an exam on Saturday, I can only prepare for it during the evenings and I'm reaaaaally late with the preparation.

Still, could I ask you for a quick hack for my own fork in the mean time? I'm working on this from a variety of machines during short breaks and I haven't gotten around to using the VM as opposed to git/text editor/travis-for-testing. (I know, lame...)

antoinealb commented 10 years ago

Sure, I will try to make something and send you a PR in your own fork. But I will do it after we discussed source code organization with the others probably, since there is no emergency.

pierluca commented 10 years ago

Reasonable solution found. Will push tomorrow once I have double checked with a fresh mind.

pierluca commented 10 years ago

Now that build system is more or less in place (pending your approval and some modifications), I'll integrate the frequency parameter and push everything.

In my current implementation, I have forced users to get/set all coefficients at the same time. This is intended to prevent the PID coefficients being out of sync, i.e. you update kp, ki and kd, but some iterations take place between updating kp and kd, for instance.

I considered frequency and ARW limits to be updatable separately (i.e. independently) from the coefficients. Same thing I guess for the low-pass filter. Is that correct?

Thanks in advance.

antoinealb commented 10 years ago

I still haven't reviewed your build system, but your assumptions about parameter atomicity are correct at least from my point of view.

antoinealb commented 10 years ago

Fixed in #14 .