by Miamicanes » Thu Dec 11, 2008 5:35 am
by Miamicanes
Thu Dec 11, 2008 5:35 am
Just to elaborate a bit on what I'm working towards and exploring...
My goal is to write replacement firmware for the CM5's Mega128 that enables it to efficiently and transparently serve as an application-level gateway between a host PC and Dynamixel bus.
The physical layer between the host PC and CM5's Mega128 might be a serial cable, or it might be a high-speed transparently error-correcting wireless link of some kind. I'm leaning heavily towards Zigbee (specifically, a pair of series 2.5 XBee modules),
At the PC end, it should be capable of dealing with a multithreaded Java control app whose threads have no idea what the others are doing, or when they themselves are communicating.
The theory:
AVR microcontrollers have a VERY cool feature: 9-bit serial. It's trivially easy to use... with 9-bit serial enabled, you simply read the ninth bit from the control register before reading the value of the most recently-received byte from the input register, or set the 9th bit's value before writing the next byte you plan to send to the output register. It's incredibly handy, because it gives you a "flag" bit that can be used WITHOUT having to escape, wrap, or otherwise encode 8-bit values being sent as data.
At the PC end, it's a little harder, since no USB-serial adapter I'm aware of directly supports 9-bit data (partly because the abstract Windows serial adapter interface has no concept of 9-bit data). HOWEVER, I've discovered by trial and error that it can be kludged with the SiLabs CP2103's driver. Basically, I determine whether the ninth bit needs to be 0 or 1 before sending each byte, and forcibly change the mode between PARITY_SPACE (all bytes sent with '0' for 9th bit) and PARITY_MARK (all bytes sent with '1' for 9th bit) if necessary. I've heard through the grapevine that at least one driver + Windows-version combination for another chipset (FTDI? Cypress?) has a memory leak, and at least one other insists on trying to do housekeeping every time you try switching between parity modes & kills your performance. In any case, the CP2103 with Vista32 and Gnu RXTX library seems to work fine.
The Workflow:
The gateway (my app running on the CM5's Mega128 that replaces its default firmware) waits until a byte is received via USART1.
The gateway examines the ninth bit of the byte it just received. If the bit is set, it means that the penultimate byte (currently sitting in the buffer) is the final (checksum) byte of a datagram, and upon sending it, it should switch into receive mode and wait to receive however many bytes is indicated by the most recently-received byte's value.
If the bit is clear, and there's no byte currently in the buffer, we just buffer that byte, and wait for the next one after making a note to remind ourselves that there IS a byte buffered.
If the bit is clear, and there IS a byte already in the buffer, we send the byte in the buffer to the Dynamixel bus at 1mbps, then buffer the byte we just received.
The advantage is that our latency and throughput is only slightly less than what we'd get by directly driving the Dynamixel bus from the host PC using a USB2Dynamixel. In fact, if whatever wireless layer we use is faster than 56kbit/sec, it's even faster than what we'd get by directly connecting the PC to the CM5 via serial in "Toss" mode. Since we delay sending each byte to the Dynamixel bus until we know for a fact that there's either one or more remaining data bytes to send after the one currently in the buffer, or until we know for a fact that the byte in the buffer IS the last byte of the datagram, and we know exactly how many bytes to expect in response, the Mega128 can send the byte in the buffer and IMMEDIATELY switch into 'receive' mode.
At the PC end, a singleton instance of a communication class has a synchronized method that takes a datagram as its argument, and returns the response datagram when it arrives. Because it's synchronized and singleton, invidiual Threads can hammer away at it to get their own requests over to the Robot and back without having to worry about what the other threads are up to. If at some point I realize that multiple threads are asking for the same information, I might abstract it a bit further and have proxy objects that make periodic requests (say, to read sensors on the Dynamixel bus), then use the responses to satisfy queries from one or more threads over the next few microseconds, until it makes another query to read the sensors again.
Ideally, I'd like to use something like the XBee series 2.5 at both the CM5 and PC ends, mainly because it seems as though the Zig100 is arbitrarily limited to 56kbit/sec (though that limit MIGHT simply be imposed by assumptions made by Toss mode, and have nothing whatsoever to do with the hardware capabilities of the Zig100 modules themselves... does anybody know?). However, I have to go take another look at someone's pics of the CM5's interior to see how much room I have, because it's been a while since I've directly peered inside
So... does anyone have any thoughts? See anything blatantly wrong, or that others have tried and already discovered won't work?
As far as I can tell by skimming over the past few months' worth of postings here, nobody has actually tried going as far as repurposing a CM5 to work in a way that should (in theory) be compatible with the hardware, but pretty different from how Robotis itself handles wireless communication between a PC and CM5 (via the USB2Dynamixel and Zig2serial... I just discovered the Zig2serial about 2 hours ago).
As noted in my previous post, however, the 800 pound elephant sitting in the room is the CM5's battery-charging method. If battery charging is NOT handled by the bootloader, and I can't find documentation on how to implement it myself, my plan of blowing the CM5's Mega128's main firmware away and replacing it with my own goes out the window.
Just to elaborate a bit on what I'm working towards and exploring...
My goal is to write replacement firmware for the CM5's Mega128 that enables it to efficiently and transparently serve as an application-level gateway between a host PC and Dynamixel bus.
The physical layer between the host PC and CM5's Mega128 might be a serial cable, or it might be a high-speed transparently error-correcting wireless link of some kind. I'm leaning heavily towards Zigbee (specifically, a pair of series 2.5 XBee modules),
At the PC end, it should be capable of dealing with a multithreaded Java control app whose threads have no idea what the others are doing, or when they themselves are communicating.
The theory:
AVR microcontrollers have a VERY cool feature: 9-bit serial. It's trivially easy to use... with 9-bit serial enabled, you simply read the ninth bit from the control register before reading the value of the most recently-received byte from the input register, or set the 9th bit's value before writing the next byte you plan to send to the output register. It's incredibly handy, because it gives you a "flag" bit that can be used WITHOUT having to escape, wrap, or otherwise encode 8-bit values being sent as data.
At the PC end, it's a little harder, since no USB-serial adapter I'm aware of directly supports 9-bit data (partly because the abstract Windows serial adapter interface has no concept of 9-bit data). HOWEVER, I've discovered by trial and error that it can be kludged with the SiLabs CP2103's driver. Basically, I determine whether the ninth bit needs to be 0 or 1 before sending each byte, and forcibly change the mode between PARITY_SPACE (all bytes sent with '0' for 9th bit) and PARITY_MARK (all bytes sent with '1' for 9th bit) if necessary. I've heard through the grapevine that at least one driver + Windows-version combination for another chipset (FTDI? Cypress?) has a memory leak, and at least one other insists on trying to do housekeeping every time you try switching between parity modes & kills your performance. In any case, the CP2103 with Vista32 and Gnu RXTX library seems to work fine.
The Workflow:
The gateway (my app running on the CM5's Mega128 that replaces its default firmware) waits until a byte is received via USART1.
The gateway examines the ninth bit of the byte it just received. If the bit is set, it means that the penultimate byte (currently sitting in the buffer) is the final (checksum) byte of a datagram, and upon sending it, it should switch into receive mode and wait to receive however many bytes is indicated by the most recently-received byte's value.
If the bit is clear, and there's no byte currently in the buffer, we just buffer that byte, and wait for the next one after making a note to remind ourselves that there IS a byte buffered.
If the bit is clear, and there IS a byte already in the buffer, we send the byte in the buffer to the Dynamixel bus at 1mbps, then buffer the byte we just received.
The advantage is that our latency and throughput is only slightly less than what we'd get by directly driving the Dynamixel bus from the host PC using a USB2Dynamixel. In fact, if whatever wireless layer we use is faster than 56kbit/sec, it's even faster than what we'd get by directly connecting the PC to the CM5 via serial in "Toss" mode. Since we delay sending each byte to the Dynamixel bus until we know for a fact that there's either one or more remaining data bytes to send after the one currently in the buffer, or until we know for a fact that the byte in the buffer IS the last byte of the datagram, and we know exactly how many bytes to expect in response, the Mega128 can send the byte in the buffer and IMMEDIATELY switch into 'receive' mode.
At the PC end, a singleton instance of a communication class has a synchronized method that takes a datagram as its argument, and returns the response datagram when it arrives. Because it's synchronized and singleton, invidiual Threads can hammer away at it to get their own requests over to the Robot and back without having to worry about what the other threads are up to. If at some point I realize that multiple threads are asking for the same information, I might abstract it a bit further and have proxy objects that make periodic requests (say, to read sensors on the Dynamixel bus), then use the responses to satisfy queries from one or more threads over the next few microseconds, until it makes another query to read the sensors again.
Ideally, I'd like to use something like the XBee series 2.5 at both the CM5 and PC ends, mainly because it seems as though the Zig100 is arbitrarily limited to 56kbit/sec (though that limit MIGHT simply be imposed by assumptions made by Toss mode, and have nothing whatsoever to do with the hardware capabilities of the Zig100 modules themselves... does anybody know?). However, I have to go take another look at someone's pics of the CM5's interior to see how much room I have, because it's been a while since I've directly peered inside
So... does anyone have any thoughts? See anything blatantly wrong, or that others have tried and already discovered won't work?
As far as I can tell by skimming over the past few months' worth of postings here, nobody has actually tried going as far as repurposing a CM5 to work in a way that should (in theory) be compatible with the hardware, but pretty different from how Robotis itself handles wireless communication between a PC and CM5 (via the USB2Dynamixel and Zig2serial... I just discovered the Zig2serial about 2 hours ago).
As noted in my previous post, however, the 800 pound elephant sitting in the room is the CM5's battery-charging method. If battery charging is NOT handled by the bootloader, and I can't find documentation on how to implement it myself, my plan of blowing the CM5's Mega128's main firmware away and replacing it with my own goes out the window.