Wixel with m3pi bots for multi agent control

I’m working on a project where we have multiple robots (m3pi bots from Pololu) to whom we want to send data (control signals) from a PC (the central controller). For this, we’re trying to use Pololu wixels for communication between the PC and bots. We don’t need the bots to communicate between themselves so what we require is just one wixel sending data and all others (around 8-10) receiving data. I understand that wixels are now in EOL stage but we already have them in our lab so we have to work with what we’ve got.

However, there doesn’t seem to be much online support/documentation for this purpose. I tried using the wireless-serial (for sending data) and radio-sniffer (for receiving data) example apps provided by Pololu but then there’s a loss of data (example - If I send “Hello” from the central wixel, one will receives “H”, some other receives “ell”, and so on) which is understandable since the radio_queue library’s source code itself mentions its lack of reliability.

I found a discussion on this topic on the forum where Geoff (from Tabletop Robotics) had solved the issue and had even posted his code. But the links for the code he provided in that discussion are not accessible.
Links for the said discussion:

It seems like the domain tabletoprobotics.xyz has gone away. Here are the downloads that used to be on that site:

The Internet Archive provides a copy of the rest of the site:

https://web.archive.org/web/20210421021120/http://tabletoprobotics.xyz/

@Geoff’s videos are still on YouTube:

https://www.youtube.com/user/GeoffNagy

–David

Thanks for the reply. I’ve modified the test_radio_multi source code a bit so that it doesn’t transfer leadership and only one wixel (whose id was set 1 in the wixel configuration utility) is the sender always and it worls fine.

However, thhe app only sends 1 byte of data and that too is used just for deciding the state of LEDs. I want to send and receive data in the form of strings (thus larger than 1 byte) such that I can send data from my PC through USB to the sender wixel and then receive data on the bot from the receiving wixel through UART. I think I’ll need to combine some of wireless_serial’s code with the test_radio_multi program. Could you provide any suggestions for that?

Edit: I tried tweaking the code for the source file such that it sends the received data through UART
and USB myself:

test_radio_multi.c (6.6 KB)

But its not compiling. Output of make_all.bat:

Linking apps/test_radio_multi/test_radio_multi.hex

?ASlink-Warning-Undefined Global ‘_uart1SetBaudRate’ referenced by module ‘test_radio_multi’

?ASlink-Warning-Undefined Global ‘_updateSerialMode’ referenced by module ‘test_radio_multi’

?ASlink-Warning-Undefined Global ‘_radioComRxControlSignals’ referenced by module ‘test_radio_multi’

?ASlink-Warning-Undefined Global ‘_radioComTxControlSignals’ referenced by module ‘test_radio_multi’

?ASlink-Warning-Undefined Global ‘_radioComRxAvailable’ referenced by module ‘test_radio_multi’

?ASlink-Warning-Undefined Global ‘_uart1TxAvailable’ referenced by module ‘test_radio_multi’

?ASlink-Warning-Undefined Global ‘_ISR_URX1’ referenced by module ‘test_radio_multi’

?ASlink-Warning-Undefined Global ‘_ISR_UTX1’ referenced by module ‘test_radio_multi’

?ASlink-Warning-Undefined Global ‘_uart1Init’ referenced by module ‘test_radio_multi’

?ASlink-Warning-Undefined Global ‘_isPinHigh’ referenced by module ‘test_radio_multi’

?ASlink-Warning-Undefined Global ‘_usbToRadioService’ referenced by module ‘test_radio_multi’

?ASlink-Warning-Undefined Global ‘_radioComRxReceiveByte’ referenced by module ‘test_radio_multi’

?ASlink-Warning-Undefined Global ‘_uart1TxSendByte’ referenced by module ‘test_radio_multi’

?ASlink-Warning-Undefined Global ‘_setDigitalOutput’ referenced by module ‘test_radio_multi’
make: *** [apps/test_radio_multi/test_radio_multi.hex] Error 1
You may now close this window.

It looks like the radio_multi library is designed to send messages as long as 19 bytes. For example, the radioMultiTxDataBlocking takes a length parameter specifying how long of a message to send.

An undefined reference error means that the linker was not instructed to link the .lib file that contains the function you are trying to use. If your app is inside the Wixel SDK, this paragraph from the Wixel SDK documentation tells you how to configure the linker:

If your app doesn’t use the default set of libraries defined in libraries/libs.mk, you can specify which libraries your app uses by creating a file called options.mk in your app directory and defining a GNU Make variable in it called APP_LIBS that contains a list of the file names of the libraries your app uses, separated by spaces. See apps/test_board/options.mk for an example.

–David

The test_radio_multi app already had a options.mk file with some entries, so I just appended the additional libraries which I had included in the end:

radio_com.lib radio_link.lib uart.lib

However, now the make_all.bat output is this:

Linking apps/test_radio_multi/test_radio_multi.hex
Multiple definition of _radioMacEventHandler
Multiple definition of XG$radioMacEventHandler$0$0
Multiple definition of G$radioMacEventHandler$0$0
Multiple definition of _param_radio_channel
Multiple definition of G$param_radio_channel$0$0

?ASlink-Warning-Undefined Global ‘_updateSerialMode’ referenced by module ‘test_radio_multi’

?ASlink-Warning-Undefined Global ‘_isPinHigh’ referenced by module ‘test_radio_multi’

?ASlink-Warning-Undefined Global ‘_usbToRadioService’ referenced by module ‘test_radio_multi’

?ASlink-Warning-Undefined Global ‘_setDigitalOutput’ referenced by module ‘test_radio_multi’
make: *** [apps/test_radio_multi/test_radio_multi.hex] Error 1
You may now close this window.

The radio_link library is not compatible with the radio_multi library, so you will have to decide which one of those libraries you are going to use. Both of these libraries want to be in control of the radio, so they each define a radioMacEventHandler, and attempting to link both of them into a program gives multiple definition errors.

Some of your undefined references can be fixed by adding gpio.lib.

I’ll have to use radio_multi library since there are more than 2 wixels in my system. All I need is just transfer the data received through radio (which was the LED states in the test_radio_multi) serially to USB/UART. So I may not need radio_link (and even radio_com). But most of the examples I’ve seen which transfer/receive data serially use these 2 libraries. So could you suggest a function or something similar which could be used for this purpose (Probably something like usbToUartService in usb_serial could work)?

Edit: usb_serial instead of usb_radio.

Yes, you do not need to use radio_link or radio_com. We do not have any example code that does exactly what you want. If you are trying to copy some code from one of our examples, you would need to remove all calls to our radio libraries and replace them with calls to the radio_multi library. If you want to know how to send data to the UART or USB, I recommend reading the documentation of the corresponding libraries using the links below and also looking at the apps in the Wixel SDK that use those libraries:

https://pololu.github.io/wixel-sdk/usb__com_8h.html
https://pololu.github.io/wixel-sdk/uart0_8h.html
https://pololu.github.io/wixel-sdk/uart1_8h.html

–David

I changed the code a bit by removing the radio libraries and including uart1.h.

I’ve also added this while loop in the else (receiving) block of the handleCommunications() function:

radioMultiRxData(&sender, &message, 1); //Was already present in the code
while(uart1TxAvailable())
{
uart1TxSendByte(message);
}

Now the program compiles successfully without any errors but when I upload it on the wixels and run it, nothing is shown on the serial console for any wixel. Though the receiving wixels still alter their green and red LEDs as in the original code.

To debug the issue I played around with some if-else statements in the code (from line 80 in test_radio_multi.c).

  // has someone contacted us?
  if(radioMultiRxAvailable())
  {
  	// read one byte of it, which should be all of the message we expect in this app
  	radioMultiRxData(&sender, &message, 1);
  	//Changed Code at 26 May
  	if (uart1TxAvailable())
  	{

  		LED_RED(1);
  		delayMs(LED_FLASH_TIME);
  		LED_RED(0);
  		
  		uart1TxSendByte(message);
  	}
  	else
  	{
  		if (message == MSG_FLASH_GREEN)
  		{
  			LED_GREEN(1);
  			delayMs(LED_FLASH_TIME);
  			LED_GREEN(0);
  		}
  	}
  }

Also, I modified the uartNTxSendByte function in uart1.c as below (and included wixel.h for the LED) just to see if it is being called or not:

#define FLASH_TIME 100
void uartNTxSendByte(uint8 byte)
{
// Assumption: uartNTxAvailable() was recently called and it returned a non-zero number.
uartTxBuffer[uartTxBufferMainLoopIndex] = byte;
uartTxBufferMainLoopIndex = (uartTxBufferMainLoopIndex + 1) & (sizeof(uartTxBuffer) - 1);
LED_YELLOW(1);
delayMs(FLASH_TIME);
LED_YELLOW(0);
IEN2 |= BV_UTXNIE; // Enable TX interrupt
}

Now when I run the program on the receiving wixel, the yellow and red LEDs blink, which means that uart1TxAvailable() returns a non-zero value and uart1TxSendByte is also called. But still nothing is shown on the serial monitor. How can I fix this?

test_radio_multi.c (3.5 KB)

I think you need to call uart1SetBaudRate to set the baud rate you want to use. Also, please describe what you have connected the Wixel’s TX line (P1_6) to. You will need to connect it to an appropriate serial receiver that is configured with the same baud rate or an oscilloscope in order to see the data it is sending.

–David

So to test and also add a bit more functionality to the program, I tried to check if the receiving wixels can transfer data through USB to the PC. I used XCTU’s serial console on the PC to see the data being received and it works fine - I’m able to see the data on the serial monitor and all the LEDs (Yellow, red and green) also blink correctly (The program below sends 0x88 continuously but it works fine with the wirelessly received message signal also).

test_radio_multi.c (4.0 KB)

For UART communication, I’m using the wixel with a lpc1768. P1_6 and P1_7 of the wixel are connected to p27 and p28 of the lpc1768 respectively (through a level shifter). Also the wixel is powered through the VOUT pin of the controller. I’ve uploaded the following code on the controller just to check if any data is being received:

#include "mbed.h"

Serial wixel(p28, p27);
DigitalOut rst1(p26);
 
DigitalOut myled(LED1);
DigitalOut myled2(LED2);

# define BAUDRATE  9600
 
int main() {
    
    rst1 = 0;   //Set reset pin to 0
    myled = 0;
    myled2= 0;
    wait_ms(1);
    rst1 = 1;   //Set reset pin to 1
    wait_ms(1);
    char data;
    wixel.baud(BAUDRATE);
 
    while (1) {
        if(wixel.readable()){
            data = wixel.getc();
            myled = 1;
            wait(0.1);
            myled = 0;
            wait(0.1);
        }
        else {
            myled2 = 1;
            wait(0.1);
            myled2 = 0; 
            wait(0.1);   
        }
    }
}

The wixel runs the following code:

test_radio_multi_uart.c (3.6 KB)

The controller’s LED2 is blinking implying that it is not reading the serial data. But the receiving wixel’s (which receives wireless data and is connected to the controller) yellow LED is blinking which means that uart1TxSendByte(a) is being called. Also, in addition to the yellow LED, only the red LED is blinking (and not the green LED)

I don’t see any obvious problems in your Wixel code or mbed LPC1768 code, but it sounds like the data sent by the Wixel is not being received by the mbed. I recommend probing the Wixel’s TX line (P1_6) with an oscilloscope while its yellow LED is blinking to see if it is sending the expected data. If you do not see a signal on that line, I recommend disconnecting everything that is connected to that pin and trying again.

–David

I reconnected the wixel, level shifter and the controller and now the controller is receiving data! (myled is blinking, will have to hook up the controller with an lcd to check if correct data is received). So I guess the issue may be due to loose connections.
Now I’ve 3 wixels in my systems:

  1. Sender wixel (1) connected to the USB (just for power) sending MSG_FLASH_GREEN sequentially and MSG_FLASH_RED in broadcast.

  2. Wixel (2) connected to USB for veiwing data on serial console on XCTU (running test_radio_multi app).

  3. Wixel (3) connected to controller through UART (running test_radio_multi_uart app).

Edit: So I attached the wixel3 with the m3pi bot (which has a LCD) to see what is being received through the following code:

        if(wixel.readable()){
            data = wixel.getc();
            lcd.cls();
            lcd.locate(0,1);
            lcd.printf("%x", data);
            
            myled = 1;
            wait(0.1);
            myled = 0;
            wait(0.1);
        }
        else {
            myled2 = 1;
            wait(0.1);
            myled2 = 0; 
            wait(0.1);   
        }

myled1 blinks for some time but then it stops receiving any data and myled2 starts blinking. Also, while it is receiving data, it is not same as the message being received by the wixel wirelessly (which should be 0 or 1), it shows some values for some time and the last value shown is ff. Though the wixel3’s red and yellow LEDs are continuously blinking (Green is not since I’m powering the board through VIN and not USB).

What could be the reasons and potential solutions for this?

I don’t see any obvious problems in your code, but it sounds like the data sent by the Wixel is not being received correctly or consistently by the mbed. Similar to my last recommendation, I recommend probing the Wixel’s TX line (P1_6) during both of the states you described to see if it is sending the expected data. If the last value shown on the LCD is 0xFF that makes me wonder if there is an issue with the baud rate of the mbed’s UART not matching the baud rate of the Wixel’s UART.

–David

Hi, so I found some minor bugs in my code and have tried to fixed them. Also, now the sender wixel receives data through USB which is to be transmitted instead of some hardcoded value. Now, there is nothing “not working” as such in my program but there are 2 major issues which remain"

  1. When I use radioMultiTxDataBlocking() function to send data, there is a significant lag in communication and also there is some loss (like 1 byte in 10 packets) of data.

  2. When I use radioMultiTxData(), the lag is much lower but the packet loss increases drastically (although this is expected).

Also, when a wixel is receiving data, even after the sender wixel stops sending any data (I terminate the python script for sending the data through USB to the sender wixel, but the sender wixel is still running), it still seems to keep receiving some data (0x0A).

Is there a fix to reduce the delay and packet loss in radioMultiTxDataBlocking() further?

test_radio_multi.c (4.5 KB)

The logic of the nested loops in handleCommunications and radioMultiTxDataBlocking is a little hard to follow, but it looks like after you receive the first byte from USB and store it in test2, there is nothing that will ever set test2 to 0, so maybe you are continually sending that byte to all the othe Wixels. Your system might behave better if you only send data when there is new data to send.

–David