Multi-m3pi Communication with Wixel

Hello,

I’m currently investigating possible multi-agent m3pi applications. In order to facilitate (wireless) communication between the m3pis and a PC, I’ve been using Wixels running the wireless serial app (one Wixel on each m3pi and one for the PC via USB). Although I realize this app is meant for two-way communication only, I’ve thought that it might be possible for each m3pi to communicate with the others (in a one-to-many fashion) if they all take turns broadcasting so as to not interfere with each other. In this case I would define a protocol in which each m3pi would transmit data along with its unique ID number, so when it finishes transmitting, the next m3pi in the sequence (or the PC, if it reaches its turn) can start transmitting. Would this kind of use of the wireless serial app be possible? Or is there a better way to do this?

Thanks,
Geoff

Hello, Geoff.

Yes, it is possible for you to do this but it would require you to spend a lot of time developing the Wixel app. The Wireless Serial App establishes a lossless communication channel between two devices, which means that the sender has to wait for an acknowledgment of his previous data packet before it tries to send the next data packet. If the acknowledgment doesn’t come, the sender retries. You can see the details of how this is implemented in the Wixel’s radio_link library in the Wixel SDK.

This simple system works for two devices, but it can not easily be extended to 3 or more. You would probably have to write your own radio library from scratch, or if you are willing to lose packets then you could look into using the Wixel’s radio_queue library.

You might want to look into using the XBee socket on the m3pi; I believe the XBee supports some kind of many-to-many communication.

–David

I see. I hadn’t realized that the Wireless Serial App had packet acknowledgement protocols at all (this seems rather obvious to me now, after the fact, since the WSA gives lossless transmissions). The fact that the WSA does this (ie, waiting for a single ACK, when in reality I need one for each receiving robot) explains why I keep losing packets when I have more than two m3pis active.

It seems I have a couple of options. One would be to build the multi-agent ack protocols into the m3pi’s communication protocol logic itself, and use a Wixel app that simply broadcasts any serial data it receives from the m3pi, without worrying about whether or not it was wirelessly received by another Wixel. The second option would be to do as you say, which is write a Wixel app which handles the acknowledgement protocol between all the robots transparently for me. Which would be the better choice?

A third option occurred to me as well. Would it be possible to configure the WSA to dynamically change the channel with which it receives and transmits, in response to a signal from its I/O lines? Each Wixel could operate on its own channel, but the one attached to the computer could change to the appropriate channel to transmit and receive to/from the appropriate robot Wixel. From there it’s just a simple matter of receiving the data from the robots one at a time, and then distributing it to the robots in a similar fashion. That would require minimal changes to the WSA app. Would this work?

It might not be so simple: the serial data comes to the Wixel one byte at a time, and you would have to think carefully about how you are going to package that data up into packets for the radio. Each packet ideally would have more than one byte of data.

Yes, I think this might be the easiest option, and it’s something I wanted to implement at some point. You should be able to change the Wireless Serial App so that when the computer sets the baud rate on the virtual COM port to something between 0 and 255 the Wixel changes the radio’s channel number to equal that “baud rate”. The CC2511’s radio has a complicated state diagram and it might be tricky to cleanly switch it to a new channel and recalibrate the frequency synthesizer.

–David

In a previous post a year ago, you wrote:

After reading through some of the Wixel SDK source code, I understand these instructions, but I am unsure about what to look for; how can the Wixel tell if the computer has changed the baud rate? I was also wondering, would this sort of dynamic channel-changing be possible for Wixels running attached to an m3pi (ie, would an m3pi be able to instruct its attached Wixel to change the channel as well)?

The USB virtual COM port is handled by the usb_com library, so you should look for a feature of that library that tells you when the baud rate has changed. Here is the documentation for that library:
pololu.github.com/wixel-sdk/usb__com_8h.html

The usb_serial app needs to know the virtual baud rate so it can set the baud rate of the UART, so you can look at its source code to see how it does that:
github.com/pololu/wixel-sdk/blo … b_serial.c

If these hints are not enough, let me know.

Yes, dynamic channel changing is possible for any Wixel regardless of whether it is connected to USB or an m3pi; you would just have to figure out how exactly the m3pi sends that instruction to the Wixel.

–David

Thanks, that should give me enough to work with. :slight_smile: Unfortunately, I’m away from home for the next week or so, and I won’t be able to do any work on my robots until I come back. I’ll keep you posted once I return.

Thanks,
Geoff

I’ve succeeded in implementing the dynamic channel changing, although not quite in the way that we discussed. Rather than have the PC set the virtual baud rate, I have implemented a primitive message system, whereby the PC or the m3pi commands the Wixel (via UART or USB messages) to change the channel.

I’ve modifed the WSA’s usbToRadioService() function to look like the following (and the corresponding uartToRadioService() is similar):


while(usbComRxAvailable() && radioComTxAvailable())
{

	//radioComTxSendByte(usbComRxReceiveByte());

	receivedByte = usbComRxReceiveByte();

	// are we in a state which accepts a new channel byte?
	if(acceptChannelByte)
	{
		setRadioChannel(receivedByte);    // changes CHANNR as discussed
		acceptChannelByte = 0;
	}
	else
	{
	
		// change to a state which accepts a new channel
		if(receivedByte == CHANNEL_CHANGE_BYTE)
		{
			acceptChannelByte = 1;
		}
		else	// normal 'message' byte, subtract one and send it away
		{
			radioComTxSendByte(receivedByte - 1);
		}
		
	}

}

Since the channel changing relies on the PC or m3pi to send data serially, wrapper functions were necessary to ensure that the byte for channel-changing (0x00) was not accidentally sent. Wrapper functions increment all regular message bytes by 0x01 (which are then decremented in the WSA before wireless transmission). This means that the value 0xff is not ‘available’ for transmission, but for my purposes this is not a big limitation. Wrapper functions can either clamp or ignore these values.

Thanks again for your help!
Geoff

Well, the channel changing works, but I’m experiencing a problem. My multi-agent project requires that communications between the m3pis and the PC run fairly quickly, but it seems that I have to put quite a long delay (>150ms) into my .NET code after changing the channel on the Wixel attached to my PC, before writing to the serial port for radio transmission. Otherwise, packets are sometimes transmitted on the incorrect channel. The shorter the delay, the greater the chances are of this problem occurring.

By use of the red LED on the Wixel, I’ve determined that the channel change itself occurs quite quickly. I’m not sure what could be necessitating the delay I’ve written into my .NET code. According to the CC2511’s datasheet, the frequency calibration should be on the order of microseconds. Could someone please shed some light on this?

Below is the code I’m using to change the channel of the Wixel.

void setRadioChannel(uint8 channel)
{
	LED_RED(1);

	radioComInit();

	do
	{
		RFST = SIDLE;
	}
	while(MARCSTATE != 0x01);
	
	CHANNR = channel;
	RFST = STX;

	LED_RED(0);
}

Thanks,
Geoff

You’re using radio_link.lib and radio_com.lib at some level, right? You should be sure to wait for all the packets in radio_link’s buffers to finish being sent before calling setRadioChannel. I think maybe the problem is that there are a lot of packets queued up to be sent in radio_link’s buffers, but when your main loop receives the command to change the radio channel it does it immediately without waiting for the queued data to be sent and acknowledged. Perhaps your problem isn’t really solved by delaying after setting the channel, but solved by delaying (in Wixel firmware) before setting the channel?

–David

Done; that worked really nicely. The delay before changing channels is very brief, which is great. Thanks!

The only thing remaining is to clear the TX queue and change to the next requested channel if the TX queue doesn’t empty itself after a certain amount of time has passed (perhaps a robot has been powered down or is unresponsive). I’ll assume that adding the following function to the radio_link library will do the trick:

void radioLinkResetTxQueue()
{
    radioLinkTxInterruptIndex = radioLinkTxMainLoopIndex;
}

Hello, Geoff!

Would you mind posting your complete, working code here in case other people in the community want to do the same thing?

–David

Hi David,

If I recall correctly, this function should be all that is needed (in the radio_link library) to change a Wixel radio’s channel.

void radioLinkChangeChannel(uint8 channel)
{

	// ensure that the radio is in an idle state
	do
	{
		RFST = SIDLE;
	}
	while((MARCSTATE & 0x1f) != 1);

	// force the radio to recalibrate to the given frequency
	CHANNR = channel;

	do
	{
		RFST = STX;
	}
	while((MARCSTATE & 0x1f) != 0x13);

	// reset the sequence bits
	acceptAnySequenceBit = 1;
	rxSequenceBit = 1;
	txSequenceBit = 0;

	// reset TX and RX pointers
	radioLinkRxInterruptIndex = radioLinkRxMainLoopIndex;
	radioLinkTxInterruptIndex = radioLinkTxMainLoopIndex;
	radioLinkTxCurrentPacketTries = 0;

	// start trying to send a reset packet.
	sendingReset = 1;
	radioMacStrobe();

}

How this can be used is demonstrated in the Project Tabletop Multi-Agent Grid Nav project. All source code can be downloaded from here.

Geoff

Hi there,

I need to write a wixel application that allows one master wixel to talk to several wixels, and them to talk back. I don’t need to talk to several wixels at the same time, and the “slave” wixels do not need to talk to other slave wixels, just to the master.

I am thinking about adding a parameter in the app that would act like an address. Do you think it would be possible to modify the radio link library and the wireless serial app to have the ACK/NACK handshaking system working only when the first incoming bytes match that address. Then I guess I would have to use a byte combination at the end of each frame to clearly state that the transfer is over and that the wixel should not ACK or NACK any incoming data until that data matches its address again.

Or maybe that address could be the serial number of the wixel itself (to avoid any confusion that would be very likey to happen if the address was only only one byte long)?

Does that seem feasible to you?

Thanks a lot for any info you can provide me with!

Hi Kom,

While it should be possible to accomplish what you’re trying to achieve, it would require some pretty heavy modification of the Wixel libraries.

Your approach would also require that you know each of the Wixel’s ID numbers, which could either be simply (a) known in advance and hard-coded, or (b) broadcasted as each Wixel joins the network.

You might be better off using different hardware or relying on the channel-change model described in previous posts. I’ve been making some improvements to that approach recently that might suit your needs, with a little modification. Let me know if you’re interested.

Geoff

Hi Geoff,

Thanks a lot for your reply. I considered moving to another hardware but I want to investigate that wixel “mesh” network idea further. Since I am dealing with a certain amount of RF modules, there is a cost consideration here too. I have been using the wireless serial app with channel change that you provided actually, it works but again, considering the number of modules, there is a delay required for changing the channel that slows down the whole process.

So I started looking into the code, because if I understand correctly, the only thing that makes this communication possible only between 2 wixels is the handshaking/error handling system. Right? In the system I am working on, there is a “master” wixel that is central and will be the only one communicating with the several slave wixels. There is no broadcasting or talking to several wixels at once. All communications are between 2 wixels only, but there has to be more wixels on the network. Therefore, I can imagine a system where each wixel would have an address like 1,2,3 etc (set in the config utility), and each transmission would begin with two fixed bytes that act as a delimiter, and then that address. The radio link library would have to be modified so that the link layer will ignore any received byte if it has not previously received those 3 delimiting bytes. It would only ACK/NAK a packet once it has received these 3 bytes, and therefore knows the master is talking to “him”.

The master could scan each address every once in a while, counting each “alive” wixel in the network.

Do you think there is something I am missing here, that would make this harder than what I can think of?

Thanks!

The description of your plan seems incomplete to me because it doesn’t talk about what the plan will be for the actual radio packets. The Wixel’s radio operates on packets at the lowest level, not individual bytes. The radio_link library uses data, reset, and ackowledgement packets to make a lossless bidirectional communication pipe. You’ll have to think about what changes to those packets are necessary.

–David

Hi David,

Thanks for your reply. Do you think that it would be simpler and equally functional to implement a handshaking protocol on top of the radio queue library?

You could try something like that and probably get it working, but I don’t think it would be ideal because the radio_queue library does not give you much control over the timing of packets. For example, Wixels should acknowledge packets for them as soon as possible after the packet is received. Also, when you need to resend a packet, you would have the overhead of needing to copy the packet contents again.

–David

Hi David,

During my investigations, I browsed the CC2511 datasheet and found an option for packet filtering based on address. There is an address register (“ADDR”) that is supposed, when the PKTCTRL1 register is configured accordingly, to be tested against the “destination address byte” in an incoming frame (if the PKTCTRL has the packet address filtering option enabled, that would be the 2nd byte, after the length byte if I understand correctly). The incoming data is thus filtered depending on that destination address byte.

That actually sounds exactly like what I was trying to do.

Any experience or thoughts on that option?

Thanks again,

Côme