Sending OSC commands to ipad

Dear Forum, I am new to the arduino platform and the forum but found it quite straightforward so far to make a sketch that interacts with TouchOSC on iPad/iphone.

I am using the Z_Osc library to communicate between the arduino and iPhone/ipad with an ethernet shield linked to a router.

Getting the iPad to control the arduino is fine and works brilliantly but I want to send information the other way to update various controls. This works to a point but after a few send events, the arduino crashes and TouchOSC might crash as well.

The number of send events required to cause a crash is predictable and consistent (i.e 7 presses of a button and 14 send events). If I cut out a bit of the arduino sketch code to increase the amount of space in memory, then the number of presses required to cause a crash increases.

My guess is that this is caused by overrunning a char array so that eventually I write into an important part of the code leading to a crash.

The problem lies with the following bits of code:

mes.setZ_OSCMessage("/DIO1/led1" ,"s" ,"0"); client.send(&mes);

mes.setZ_OSCMessage("/DIO1/led2" ,"s" ,"1"); client.send(&mes);

If these are commented out, then the sketch runs without problems. Does anyone have any experience of using Z_Osc to send messages. I am really not sure exactly how to use this for sending multiple commands. There are examples but these are for single commands which work fine. I need to send messages after each interaction with the iPad so that I can update the screen.

Having scoured the web, I can't find many people with experience of Z_Osc so if noone can help directly, perhaps someone can anyone suggest a method of tracking down where the problem lies.

Thanks, Nick

Without seeing much code I guess you do not clean up the messages properly in your code. What you should do: create a message object, set it up, send it, check if transmission finished, destroy the message object. Maybe you can reuse the message object, but then you have to check for the end of the transmission before you alter the message object. No idea how to use the library properly.

Another important aspect is that the message object allocates memory dynamically. If you use other memory allocating code fragmentation will occur resulting in out of memory faults. If allocation is followed by deallocation of that memory all is fine.

Thanks for the reply. It confirms that I am doing something wrong!
Below is an example from the author of the library that provides an example of sending a message. It works but it is not really what I want to do. My situation is a bit more complicated because i need to be able to send more than one command in succession and so perhaps need to tidy up the memory and destroy it as you suggested.

#include <SPI.h>
#include <Ethernet.h> // version IDE 0022

#include <Z_OSC.h>

byte myMac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte myIp[]  = { 192, 168, 0, 255 };

byte destIp[] =  { 192, 168, 0, 5 };
int  destPort = 10000;



char oscAdr[] = "/z-osc/test/123";
char oscAdr2[] = "/z-osc/test2/abc";

int      iCount  = 0;     
long int liCount = 0;      
float    fCount  = 0.0;    
char     str[]   = "abcd"; 

Z_OSCClient client;

void setup(){
  
  Serial.begin(19200);

  Ethernet.begin(myMac ,myIp);  
  
}

void loop(){
  
  sendProcess();
  
  Z_OSCMessage mes;  
  
  mes.setAddress(destIp,destPort);
  mes.setZ_OSCMessage(oscAdr2 ,"s" ,"test test");
  
  client.send(&mes);
  
  mes.flush();  
  
  delay(100);
}


void sendProcess(){
  
   
  long int tmp=(long int)iCount; 
  
  Z_OSCMessage message;  
  
  message.setAddress(destIp,destPort);
  message.setZ_OSCMessage(oscAdr ,"iifs" ,&tmp ,&liCount ,&fCount ,str);
  
  client.send(&message);


  if(iCount++  > 1000)  iCount =0;
  if(liCount++ > 1000)  liCount=0;
  fCount += 0.1;
  if(fCount  > 100.0) fCount =0.0;
  
}

I first followed this example more closely but had problems. I found that if I didn’t use the sendprocess() function and missed out the med.flush(), then things worked better. Obviously not correct though.

I have tried various combinations but haven’t got it to work without crashing. I don’t really understand the full process and what each section of code is doing. How can I use this template code to send more than one message in succession so that I can turn off/on various controls on the iPad? My code is defined in if statements so that if I get a particular message, I can control the arduino but also update controls on the iPad.

This is a section of the main loop:

void loop(){

    if(server.available()){
    int counter;
    Z_OSCMessage mes;
    
    mes.setAddress(destIp,destPort);
    
    rcvMes=server.getMessage();
    logMessage();

// This is the code that starts the main pulse events
 if( !strcmp( rcvMes->getZ_OSCAddress() ,  "/DIO1/push1" )) // this would be the first button in the 1st column
     {
     
      Readout = rcvMes->getFloat(0); //Get first value from incoming /arduino/out
      if (Readout == 1)
      {
       
       mes.setZ_OSCMessage("/DIO1/led1" ,"s" ,"0");
       client.send(&mes);
       
       mes.setZ_OSCMessage("/DIO1/led2" ,"s" ,"1");
       client.send(&mes);
        
       float PulseInt = (1/Freq)*1000;
       float IntDelay = Interval*1000;
       int count2;
       
       if (TrigDelay > 0){                  // then we are requesting a trigger and delay before pulses
         digitalWrite(TrigPin,HIGH);
         delay(10);
         digitalWrite(TrigPin,LOW);
         delay((TrigDelay*1000)-10);        // this means the delay will be the correct duration since we subtract the HIGH time for this pin
      }
       
       for (count2 = 0; count2 < Repeat; count2 +=1)
         {
         for (counter = 0; counter < PulseNum; counter +=1)
         {
           digitalWrite(Pinout,HIGH);
           delay(PulseInt*DutyCycle);
           digitalWrite(Pinout,LOW);
           delay(PulseInt*(1-DutyCycle));
        }
       // problem with this structure is that there is a delay at the end of the last set of pulses which is not necessary  
       // therefore do the following which will give a delay but not on the last run of the cycle
       if (count2 < (Repeat-1)){    
         delay(IntDelay);
       }
     }
      }
     
       mes.setZ_OSCMessage("/DIO1/led1" ,"s" ,"1");
       client.send(&mes);
      
       mes.setZ_OSCMessage("/DIO1/led2" ,"s" ,"0");
       client.send(&mes); 
    }

}

I have not included the setup() or declaration of globals
Any help would be much appreciated.
Thanks,
Nick

Please post the whole code - just edit your post. The gloabls are of interest, too, especially rcvMes.

First guess: rcvMes needs to be destroyed/deleted, otherwise you fill your memory with those messages.

I don't understand why people do this:

I have not included the setup() or declaration of globals

Thanks for your patience. I am new to this so not sure of the etiquette.
I can’t send the whole code as a post so am trying to attach the sketch.
Apologies if this is coming through more than once.

Arduino_TouchOSC_LabAssistant.ino (32.9 KB)

float ButtonVal;
float WhichDW = 7;  // use pin 7 as the default

How can the pin number to use be 7.3 or 2.9? Are you expecting to read 0.2 for the switch, if it is only partially pressed?

Using the correct variable types is essential to working code.

float startmilli = 0; // this will be the number previously stored float endmilli = 0; // this is the number of milliseconds since last check float durmilli = 0;

The millis() function returns an unsigned long, not a float.

    if( !strcmp( rcvMes->getZ_OSCAddress() ,  "/DIO1/mtg1/1/1" )) // this would be the first button in the 1st column
     {
     Readout = rcvMes->getFloat(0); //Get first value from incoming /arduino/out
      if (Readout == 1){

Now, I could be all wrong, but DIO implies digital output, so it seems unlikely that the value is sent as a float. If it is, it shouldn't be.

You should look for one of the many posts where the FreeMemory function is discussed, and add that code, and a call to it, to your sketch. All those strings in your sketch suggest that you are running out of memory.

OK, this is a lot of code using a lot of SRAM - you have to tidy everything up like PaulS mentioned.

On the other hand you have some kind of memory leak / heap fragmentation which fills up the small amount of memory left. The Z_OSC library uses frequent memory allocation and deallocation. My guess of deleting rsvMes seems to be wrong. In my opinion the messages to send together with the rsvMes may fragment the heap. I would try to go the route of my first posting with a little function. It will make your code a little bit slower and hopefully prevent heap fragmentation.

void SendZ_OSCMessage(const char *_address, const char *_type, const char *_value)
{
  Z_OSCMessage mes;  
  mes.setAddress(destIp, destPort);
  mes.setZ_OSCMessage(_adress, _type, _value);
  client.send(&mes);
  client.flushSendData();
}

Use this function every time you want to send anything, do not declare any variable of type Z_OSCMessage for sending. Make some checks of free memory to see if my idea works, especially if the free memory is the same before and after my function.

Thanks to Marek080 and PaulS for the replies so far. I will tidy up the code. There are some floats that are not necessary but these crept in when I used some example code and felt at the time I shouldn't change too much. Now I know a little more and realise how critical saving memory is, I will go through this and get rid of unnecessary variables etc.

I have already run into a problem though. I can't compile the function you wrote for me. I get the following errors..

Arduino_TouchOSC_LabAssistant.cpp: In function 'void SendZ_OSCMessage(const char*, const char*, const char*)': Arduino_TouchOSC_LabAssistant:1076: error: invalid conversion from 'const char*' to 'char*' Arduino_TouchOSC_LabAssistant:1076: error: initializing argument 2 of 'int16_t Z_OSCMessage::setZ_OSCMessage(const char*, char*, ...)' /Users/NickHartell/Documents/Arduino/libraries/Z_OSC/Z_OSCCommon/Z_OSCClient.h:42: error: 'void Z_OSCClient::flushSendData()' is private Arduino_TouchOSC_LabAssistant:1078: error: within this context

Hope you can help. Nick

First error is easy - my fault, but correctable. The library seems not to be very sophisticated.

Try the following to get it compiled:

void SendZ_OSCMessage(const char *_address, char *_type, const char *_value)
{
  Z_OSCMessage mes;  
  mes.setAddress(destIp, destPort);
  mes.setZ_OSCMessage(_address, _type, _value);
  client.send(&mes);
  //client.flushSendData();
}

The second problem is a pity. Why is flushSendData private?! Without the flush I am quite sure heap fragmentation will still occur, but at a slower rate maybe. I propose to make flushSendData() public for a fast try (usually flushSendData should be protected allowing to use it in a derived class…). To achieve this you have to modify Z_OSCClient.h. Move the line with “void flushSendData();” from the private to the public section and save the file. After this step you can uncomment the last line of my function and your sketch should still be compilable.

Interestingly there is a similar flush in the server. This could be used to clear another buffer allocated on the heap, but for this to be useful your code needs some more changes. This is for later if necessary.

Hi Marek,
Than you. I will try this and let you know how I goet on. Last night, I ran some tests with memoryfree() and I was loosing memory with each run through the loop and when down to about 150, the returned memory value suddenly becomes large and negative and the sketch crashes.

I partially replicated your function with individual commands within the loop function itself so that I used msg.flush after each client.send. Now I no longer lose memory.

However, the code stops working because the iPad does not respond to or receive the sent message. That is presumably why I originally cut out the flush step to make it work but without realising this step ic important to preserve memory.

Interestingly, other parts of the loop function also use the send method without the flush and they work without loosing memory. I think it is because I send only one command for each cycle of the loop whereas the bit of code that is giving me problems sends 4 times in the same loop.

I finally tried to give each send message it’s own string I.e. By calling Z_OSCMessage mes1; Z_OSCMessage mes2; etc etc at the start of each of the 4 message sections but this caused an immediate crash with odd values for free memory right from the start. I secumbed to sleep at that point…

Hope this information is helpful.
Best,
Nick

. What I found

Finally a solution to my problem. Thanks for the help.

Key to finding the problem was using the memoryfree library and freememory(). By using the following, I could figure out where I was losing memory:

    Serial.print("Loop Start FM()=");
    Serial.println(freeMemory());

Marek, I tried your function. I got it to compile by doing as you suggested. I needed to change the function to remove the const declaration of the second argument. However, using the function caused a crash of both the arduino sketch and TouchOSC.

Therefore, I went back to the original approach of putting the commands directly into the loop function. I don't understand C well so am not sure why but it appears that it essential to call the following to get this to work.

        Z_OSCMessage msg1;
        msg1.setAddress(destIp,destPort);
        msg1.setZ_OSCMessage("/3/led1" ,"s" ,"0");
        client.send(&msg1);
        msg1.flush();

To send another message on the same cycle of the loop, I have to use another variable defined using Z_OSCMessage.

i.e.

        Z_OSCMessage msg2;
        msg2.setAddress(destIp,destPort);
        msg2.setZ_OSCMessage("/3/led2" ,"s" ,"0");
        client.send(&msg2);
        msg2.flush();

Using the same variable more than once doesn't seem to work because the flush seems to get rid of it.

the only way that I could get this to work was to define 4 separate messages and I had to reduce the size of the code to do this. The easiest way to do this was to reduce the length of the control name strings in touchOSC.

Hope this explanation makes sense and that it is useful to others.

Thanks for the help Nick

Heap fragmentation occurs when mixing different allocations and deallocations. An example:

  • allocate 20 bytes for object A1
  • allocate 10 bytes for object B1
  • deallocate A1
  • allocate 10 Bytes for object B2
  • allocate 20 bytes for object A2

This could result in a memory allocation in the form of: 10 Bytes B2 | 10 Bytes free | 10 Bytes B1 | 20 Bytes A2

I am usually programing on x86 win32 where the heap is not my concern. Here it is different and I try to avoid any out of order memory allocation. This is the aim for your code.

The Z_OSC library frequently allocates memory for the messages, sending and receiving. The goal is to free any memory as soon as possible to avoid the fragmentation. It comes down to a stack like usage of the heap - the last object which allocated memory should be the first to free its memory. Hence my approach of using all possible flush functions.

mes.flush() frees any memory the message allocated but also removes all settings made with setAddress() and other functions. That's why you have to use more than one msg variable. You could try to to reuse the msg if you set the address before calling setZ_OSCMessage. What my function basically does is creating a new message object on the stack, using it and when the function quits the message is destroyed (because it is a local variable). I searched the source of the library and my approach has a drawback concerning the destruction of the message object, because the client object still holds a pointer to the message object and there is no checking or other functionality preventing the access to the destroyed object.

Nice to hear that it now seems to work. But I am sure the library will start eating up memory again if you change your code to get different functionality. The only solution then would be to extract what the library does step by step and rebuild only the small part you really need for your project.

Thats a nice explanation. Thank you. And you are correct. I don't need more than one variable. I can use the same one provided I use setAddress() again. This also reduces the amount of memory I need.

I now have a very useful app on my iPad/iphone ;)