Problem running many commands that take time to execute


#1

I have modified the run forward, backward, right and left (F,B,R,L) commands in mbot_firmware.ino so they run for a specified time (about 1000 ms) and then stop the motors. This works fine if not many commands are programmed in sequence (for example, F,R,F,R,F,R,F,R makes mbot make a square) but when more commands than about 10-12 are executed in sequence, the bot either runs continuously or just stops after about 9 commands. But for another command, buzzer (or TONE), one can add as many commands in sequence (at least up to 30) with no problems. How should the run command (called JOYSTICK in mbot_firmware.ino be modified to allow this? Currently, I modified it as follows ( here leaving out the dc.reset commands to address each motor):
dc.run(leftspeed); //M1
dc.run(right speed); //M2
delay(1000); //run the motors for 100o ms
dc.run(0); //M1
dc.run(0); //M2
This works fine up to 8-10 sequential commands, but then fails. The command sequence on the computer lights up during the sequence, staying lit for the full time of the sequence, but when too many commands are programed, the light turns off at about the time the bot stops executing the commands. Does that mean the computer is sending more commands even while the JOYSTICK command is executing, therefore losing the rest of the sequence?
Checking the buzzer subroutine (TONE, calling MEbuzzer commands), the tone duration is produced with a delayMicroseconds() call in a loop, and that works fine. So I tried that in the JOYSTICK routine instead of just delay(), but the crashing problem still occurs.
Can someone suggest how to make this work? Chuck? utowoo?


#2

Hi @eric03,

I’d need to see the code to try to figure out the issue. I think the delay is a blocking call (have to investigate), but the only other thing I can think of is that somehow memory is getting overflowed. There is only about 1K of SRAM available after the Makeblock libraries load and a common cause of failure is using more SRAM than is available. Caching into a list or strings are the usual suspects.

Chuck


#3

Here is the JOYSTICK code, almost unchanged from mbot_firmware.ino, that causes the problem. In the code I will eventually use, I pass a third parameter, runtime, that specifies the # of ms that the motors run, but in this simplified version, I just define runtime locally. This code runs properly when called sequentially about 8 times and then fails (same if I pass the 3rd parameter- runtime):
case JOYSTICK:{
int leftSpeed = readShort(6);
dc.reset(M1);
dc.run(leftSpeed);
int rightSpeed = readShort(8);
dc.reset(M2);
dc.run(rightSpeed);
int runtime = 2000; //run motors for 2 secs
delay(runtime);
dc.reset(M1);
dc.run(0);
dc.reset(M2);
dc.run(0);
}
break;

On the chance that delay() is not blocking correctly, I looked at another blocking routine - TONE. buzzer.tone(hz,tone_time) blocks for tone_time while it is making the tone. And one can call TONE sequentially as many times as you like and it never blocks. So I looked at how that was implemented in MeBuzzer.cpp in the Makeblock library. Interesting! It uses a command I had never used: wdt_reset().

void MeBuzzer::tone(uint16_t frequency, uint32_t duration)
{
int period = 1000000L / frequency;
int pulse = period / 2;
pinMode(buzzer_pin, OUTPUT);
for (long i = 0; i < duration * 1000L; i += period)
{
digitalWrite(buzzer_pin, HIGH);
delayMicroseconds(pulse);
digitalWrite(buzzer_pin, LOW);
delayMicroseconds(pulse);
wdt_reset();
}
}

Could that be a way of blocking serial transfer? So I used this in the code above instead of delay(). To make that work, I had to load #include <avr/wdt.h> in the mbot firmware (normally it is loaded just in MeBuzzer.cpp), but then it compiled and ran fine.

int period = 100; // length of delay in each execution of the loop, in microseconds
uint32_t duration = 2000; //delay for a total of 2 secs
for (long i = 0; i < duration * 10L; i += period) //so a total of 2000 * 10 = 20000 loops
{
delayMicroseconds(period);
wdt_reset();
}

This code works fine as a delay in JOYSTICK but still fails to work in a sequential call to more than about 15 commands of “run forward”. Also, I tried this using both the serial cable connection to the mbot or the wireless 2.4GHz connection, and it works the same.

Is it possible that serial.read() keeps reading the commands from the computer even during the delay. Can that process be paused? Is that what wdt_reset() does in TONE?

Thanks for taking the time to look at this!


#4

Oops! a typo. Should be
I had to load “#include <avr/wdt.h>” in the mbot firmware (normally it is loaded just in MeBuzzer.cpp)


Non-blocking sound functionalities
#5

“#include <avr/wdt/h>” Why is this not copying correctly here?


#6

The dialog uses Markdown syntax. Try putting 4 spaces at the beginning of the line, i.e.,

#include <MyBigFatHeaderFile.h>

:smiley:

wdt_reset() seems to be a macro that makes an assembler call (link). Per this discussion (link), the wdt_reset() macro resets the watchdog counter to zero so that the microcontroller doesn’t reset itself.


#7
#include <avr/wdt.h>    Thanks!  This is the file I was trying to show.

A slightly earlier version of wdt.cpp doesn’t even have the wdt_reset() command in the MEbuzzer.cpp file, so I doubt that is the reason for the problem. Plus using it in my code didn’t fix the problem.

Further exploration of the delay problem suggests that the size of the RX buffer may be too small. With the current version of the Arduino IDE, it appears to be possible to adjust the sizes of the RX and TX buffers separately. Also, I can make the mbot firmware.ino file smaller by eliminating commands (and modules) that my students will never use. The files to set this is called HardwareSerial.h and HardwareSerial.cpp (there are multiple versions of that: 1, 2, and 3). So by making the mbot_firmware.ino file smaller and then increasing the size of the RX buffer, that might fix the problem. Not sure how to do this - do I edit the HardwareSerial file directly or #include HardwareSerial.h in the mbot arduino program and execute the setting buffer size command within the mbot_firmware.ino file directly? Do you have experience with that?


#8

I don’t, but @tec_support might be able to help.


#9

Chuck suggested that @tec_support might be able to explain how I can increase the RX serial buffer size to make a sequence of blocking commands not cause a problem. See earlier explanation of the problem.

Further exploration of the delay problem suggests that the size of the RX buffer may be too small. With the current version of the Arduino IDE, it appears to be possible to adjust the sizes of the RX and TX buffers separately. Also, I can make the mbot firmware.ino file smaller by eliminating commands (and modules) that my students will never use. The files to set this is called HardwareSerial.h and HardwareSerial.cpp (there are multiple versions of that: 1, 2, and 3). So by making the mbot_firmware.ino file smaller and then increasing the size of the RX buffer, that might fix the problem. Not sure how to do this - do I edit the HardwareSerial file directly or #include HardwareSerial.h in the mbot arduino program and execute the setting buffer size command within the mbot_firmware.ino file directly? Do you have experience with that?


#10

A couple of links related to controlling buffer sizes (link) (link).


#11

Success! I couldn’t understand the HardwareSerial files well enough to make an appropriate change, but inside the current Wire.h file (in the makeblock/utilities folder) there was a place to change the size of both the RX and TX buffers. So I increase them to 256 (from 64), commenting out a few commands that I never use (and don’t seem to be implemented in the mbot), and now it works fine at least up to 32 consecutive F, B, R, and L commands. The light on the program on the computer does turn off at some point during the execution, suggesting it has sent all the commands, but there is enough space in the RX buffer to hold them. Thanks for your help with this!


#12

Still the same problem with a failure to execute a long list of robot movement commands. Since the last comment in this topic, I’ve implemented stepper motors which allow very precise movements. And have incorporated more complicated movements into single commands, like make an arc with specified radius and # of degrees - a 30 cm radius of 360° takes about 30 seconds. By the end of that time, any subsequent commands have overrun the RX buffer on the mbot and so are not executed. Question: is there a way of pausing the commands coming from the laptop when executing a movement that takes a long time? For example, in the mbot.js extension, where these commands are located, the command is sent with the function:
function sendPackage(argList, type){
var bytes = [0xff, 0x55, 0, 0, type];
for(var i=0;i<argList.length;++i){
var val = argList[i];
if(val.constructor == “[class Array]”){
bytes = bytes.concat(val);
}else{
bytes.push(val);
}
}
bytes[2] = bytes.length - 3;
device.send(bytes);
}
Could a delay be inserted here after the device.send(bytes) do the trick? The SetTimeout command in Javascript causes a fatal error in Makeblock, but is there something else that would work?
I am happy to share the changes to convert the mbot to stepper motors (cheap ones) if anyone is interested. Eric


#13

Just a quick thought, but you might want to try writing your methods with a custom handshake to control actual execution. The sequence would be something like:

send command
wait for response before sending the next command

Whether or not you choose to make it a blocking call would be up to you. My suggestion would be to avoid using a blocking timer (like sleep or its ilk) in favor of something like millis() (or its ilk).


#14

Exactly. But that would need to be sent from the laptop, not from the mbot. Blocking it from the mbot (which I can do) won’t delay the laptop from sending the next command. So I tried putting a delay in the mbot.js file where the command is sent (from the laptop) but when I then try to open mBlock, it won’t run (jumps to my browser with the page that requests I write about the problem to Makeblock). Is there a way of sending a response from the mbot back to the laptop that keeps the laptop from sending the next command? That would do it, But I don’t know how to implement it. Is there a way that mbot can send a command back to the laptop?


#15

Hmm, without seeing the code you are using it’s tough to speculate. One approach, if you are using timers to control movement would be to set up a state machine that will change the state to issue the next command when the timer has expired. Just a thought.


#16

You are very likely correct - this is a blocking problem. If I send more than 4-5 stepping commands to mbot from the laptop, the first few are executed and then execution stops until I push the reset button on the mbot. Interestingly the glowing light around the command sequence on the laptop, which is normally on for the whole sequence of other types of commands (which don’t take long to execute), stays on until those commands are executed on the mbot. But the mbot is certainly capable of executing slow commands: if one sends tones with the buzzer (and each tone can be fairly long (“double” is 2 secs), then the glowing light is on for the whole duration, and you can have s many tones as you want, For example, put a “double” tone inside a “repeat” or “forever” loop, and things work fine. What’s different here? Well, these tones are generated in a special way - check out MeBuzzer.cpp, which executes them. The tone length is determined by a FOR loop that makes the buzzer HI, then does a delayMicroseconds for a short time, then buzzer LOW, then another delayMicroseconds and repeats that loop as many times as needed to run for 2 seconds. The interesting thing is that at the end of each loop, there is a wdt_reset() command. Somehow, that seems to “block” the sending of more commands from the laptop, so the laptop waits for that tone to be finished before trying to execute the next one. It all works fine.
I have been trying to do the same thing within the mbot code (mbot_firmware.ino) with a delay (i.e. the ms delay. That delays OK, but does not stop the laptop from sending more commands during the delay. So I think the serial RX buffer on the mbot just overflows or wraps around. So learning about the wdt_reset() command for the buzzer, I put the same code right in the mbot_firmware, thinking that the fast loops in delayMicroseconds and with the wdt_reset command would also block the sending of more commands. But that doesn’t work.
Any ideas how to “block” the sending of more laptop commands from within the mbot_firmware.ino file? Maybe write a .ccp file analogous to the MeBuzzer file but specifically for my stepping commands? What is going on here.
Sorry to bother you with this, but the Makeblock tech folks just don’t seem to be interested in responding.


#17

The tone command uses a blocking wait as near as I can tell. I’m playing with a general-purpose method of avoiding the dread delay() method that essentially tracks a duration against a starting time. So far it lets me blink LEDs and play a tune fairly smoothly, but it’s still pretty beta right now. I’ll be working on it more tomorrow and will report back on the results when I get them


#18

To test your idea, I modified the tone subroutine (MEBuzzer.cpp) so that instead of using the delayMicroseconds command (which is used to generate tones with on/off buzzer, thus generating tones of different frequencies, I just used a simple delay command. Of course then it doesn’t make a tone, but I could test if it did make the delays I sent it (using the duration variable in the tone command). I could even put my stepper commands (using I2C to send the command to my stepper arduino, which drives the stepper motors) and that worked as well. What didn’t work was also driving the MeRGBLed.cpp command (“show”), which I use to illuminate those LED’s appropriately for right, left, forward, backward commands to the steppers. Could not find a way of including the show (for the LEDs) command into the MeBuzzer.cpp subroutine, even if I put #include MeRGBLed.h at the beginning of MeBuzzer.h
So I would be very interested even in your beta version that lets you play a tune while using the RGBLed command “show”. Have you found a way of using “show” while inside the tone subroutine, or how are you doing it?
Right now I am in Pisa, Italy, getting ready to demonstrate my stepper mbot in a first-grade classroom. My daughter is a Math Ed professor at the University of Pisa and wants to use the stepper robot as an improvement over the BeeBot, which is now used in many Italian classrooms. So this will be a Beebot but with the commands sent from a laptop rather than just pushing buttons on the Beebot to make a simple set of F, B, R and L movements. Happy to share what I have done if people are interested.


#19

Hi Eric,

This is the code that I’m currently fiddling with. The trick is that I only play the tone for one millisecond but use the millis() function to track how much time has elapsed rather than use the blocking delay() method. The code is not particularly optimized right now because it’s more of a proof of concept. One thing I did notice was that inserting logging statements to print on the serial monitor causes a noticeable pause between the notes. Let me know if you have any questions.

#include <Arduino.h>
#include <Wire.h>
#include <SoftwareSerial.h>

#include <MeMCore.h>

MeRGBLed led(7, 7==7?2:4);

MeBuzzer buzzer;

const int DEVICE_OFF = false;
const int DEVICE_ON = true;

int ledState = DEVICE_OFF;
int buzzerState = DEVICE_OFF;

unsigned long ledTimer = 0;
unsigned long buzzerTimer = 0;

unsigned long ledDuration = 0;
unsigned long buzzerDuration = 0;

char msg[80];

void ledOff() {
  led.setColor(0,0,0,0);
  led.show();
}

void ledOn() {
  led.setColor(0,0,0,20);
  led.show();
}

void updateLED() {
  unsigned long tmpTime = millis();

  if (tmpTime > ledTimer + ledDuration) {

    // toggle the state
    ledState = !ledState;

    // update the trigger
    ledTimer = millis();
  }  

  // set the LED state
  (ledState == DEVICE_OFF) ? ledOn() : ledOff();
}

void updateBuzzer() {
  unsigned long tmpTime = millis();

  if (tmpTime > buzzerTimer + buzzerDuration) {
    buzzerState = !buzzerState;
    buzzerTimer = millis();
  }

  (buzzerState == DEVICE_OFF) ? buzzerOn() : buzzerOff();

}

void buzzerOn() {
  buzzer.tone(262,5);
}

void buzzerOff() {
  buzzer.noTone();
}

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

  ledState = DEVICE_OFF;
  buzzerState = DEVICE_OFF;

  ledDuration  = 1000; // 1 second
  buzzerDuration   = 2000; // 2 seconds

  // set the initial LED timer value
  ledTimer = buzzerTimer = millis();
}

void loop() {

  unsigned long tmpTime = millis();

  updateLED();
  updateBuzzer();
 }

Chuck


HELP! please help me set up the correct program to play tune while mbot runs line follow?
#20

@eric03, I just uploaded an Arduino library for an ActionTimer that streamlines what I’m doing in the previously posted code. The library is at Github (link) and has a simple example of how to use the ActionTimer object. This allows one to use multiple ActionTimers to control different types of actions.