June 15, 2009

It compiled! It compiled!

Okay, it's not a gigantic achievement. But it is a significant milestone, and it took me a lot of work to get here (more than it ought to have taken, honestly...). I finally compiled my first C++ class. I mean, besides the little ten-line classes that I wrote in school when I was still learning what object-oriented programming was. This is the first real object-oriented code I've written, and although it's not finished, a firm groundwork has been laid.
What I've got now is a "DynamixelNetwork" class that controls a serial port with an arbitrary amount of Dynamixel servos on it (we're using RX-10's, but I believe the communication protocol for other Dynamixel models is very similar, if not fully compatible). The reason for having one "Network" class instead of individual objects for each servo is because they can be daisy-chained together, so the communications all have to share the same serial port. Plus, there's not a whole lot that an individual servo class would do. The main requirement is simply an interface to the communications protocol, and that can just as well be centralized and used for any arbitrary servo. I may uncover additional requirements as I finish up the class, but I'm doing my best to keep the code flexible.
What's been taking me so long is just figuring out how to write to and read from the serial port. It seems to me that it's one of those tasks that just seems to be harder than it needs to be. I'm using the termios.h interface, which is archaic, difficult, and fugly, to say the best, but at least it's a standard. Right now I've got a working "sendMessage" method, and the "getResponse" method is mostly working, but giving me some weird errors. I don't understand what's wrong just yet, but I've mostly isolated the problem, and once I get that solved I'll have just about all I need. After some little difficulty I rolled those into a working class, got the .h and .cpp files all nice and neat-looking, and poked it with a sharp stick until it compiled. Once that was working, adding additional functionality was almost as simple as just finding which registers to write to (in the servo), and sticking in a few more methods. I also took some time along the way to add some bounds checking, sprinkle in some custom exceptions, and put in a few routines to improve general performance (like one that instructs the servos to stop sending status packets back after each instruction, to save the time it takes to wait for each one).
It's not all a cakewalk from here, though. What I have to do now, and I hope to finish this before Thursday, is to finally get the getResponse method working, organize the inheritance of my exceptions into a more logical structure (right now they're all inherited from the base exception class), write a udev rule for the USB serial port adaptor, fully comment the code, and add in baud rate switching. This last one's the hardest, because if you make a mistake switching the baud rate, you could end up with a servo that refuses to listen to you. (Because of the way the baud rate is set within the servos, it might even be possible to switch it to a rate that the PC serial port isn't capable of using... I think that's my biggest fear right now.) I might also add in a few "scan for servos on network" methods, but that's on low priority for now, because we're going to be working with a known configuration for this project. Eventually I'd like to add it, though, so that this could become a good general-purpose C++ library for the Dynamixel servos. I searched pretty thoroughly before deciding to roll my own, but now that I'm putting all this work into it I'd like to make it a contribution to others who don't want to put in this much effort (and also don't want to use .NET).

Well, that was an unnecessary amount of detail. Hope you enjoyed it. It's good to get all my thoughts laid out in text, though.

No comments:

Post a Comment