element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Open Arduino
  • Challenges & Projects
  • Project14
  • Open Arduino
  • More
  • Cancel
Open Arduino
Blog Arduino Powered MSE-6 (Mouse Droid) - Arduino Uno and FreeRTOS
  • Blog
  • Forum
  • Documents
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Open Arduino to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: jomoenginer
  • Date Created: 18 Apr 2018 4:10 PM Date Created
  • Views 4198 views
  • Likes 15 likes
  • Comments 11 comments
  • arduino uno
  • seeed motor shield v2.2
  • arduino ide
  • openarduinoch
  • freertos
Related
Recommended

Arduino Powered MSE-6 (Mouse Droid) - Arduino Uno and FreeRTOS

jomoenginer
jomoenginer
18 Apr 2018

Star Wars MSE-6 (Mouse Droid) INDEX:

 

Arduino Powered MSE-6 (Mouse Droid)

Arduino Powered MSE-6 (Mouse Droid) - Arduino Yun UI

Arduino Powered MSE-6 (Mouse Droid) - Arduino Uno and FreeRTOS

Arduino Powered MSE-6 (Mouse Droid) - Droid in Action

Arduino Powered MSE-6 (Mouse Droid) – Arduino Code

 

So, I was debating of whether or not to use an UNO or a M Zero Plus for the Motor control and Navigation sensor, but I discovered I could run FreeRTOS with the UNO so I an sticking with that for now.  Thus far I was able to create 4 Tasks that control a Seed Motor Shield, Parallax Ping sensor and a Servo To sweep the area as well as a Task to blink an LED.  The sweep may not be used, and was used to proof out the FreeRTOS usage with the UNO.  One interesting item I ran into was that the Windows version of the Arduino IDE seems to compile more compact code than the Linux version. When I used the Linux version, after just 3 tasks it reported the binary was too large to load into the Uno. The Windows version of the same code reported about 21% of Uno memory usage and I was able to increase the task count up to 4 without issue.

 

Another issue I did run into was that if I tried to run the Arduino Servo library with the Seeed Studio Motor Shield MotorDriver library, neither the Servo nor the Motor Shield would work properly.  Apparently both libraries manipulate the PWM Timer at the AVR level and one will over write the other if both are used.  This seems to be a common issue with no posted resolution that I could find thus far. My solution was to create my own basic MotorShield code based on some examples I had seen and not use the Seeed studio code.  I am not controlling the speed via PWM at this time, but will look into as time permits.

 

My code is based on the 'Blink_AnalogRead' FreeRTOS example from the IDE.  I did have to update the IDE to the latest, 1.8.5 as of this writing, and ensure at least FreeRTOS version v10.0.0-10 which can be updated from the IDE itself.

 

To get started, it is best to download the latest Arduino IDE from the Arduino site:

https://www.arduino.cc/en/Main/Software

image

 

 

Once the Arduino IDE is installed, it is wise to update the Board packages as well as the Libraries in the IDE.

 

To update the Board code in the IDE, click on Tools -> Board: "Arduino/.."->Boards Manager.

image

 

Then, in the Boards Manager window, select the Board or Board grouping for the board being used and either Install it or Update it it it already installed.

image

 

To update the Arduino IDE Libraries, Click on Sketch->Include Library->Manage Libraries. This will present a screen where the various supported libraries are listed and can be installed.

image

 

The Library Manager window should appear.  To locate the FreeRTOS listing, type in freertos in the find textbox at the top of the window.

image

 

The version of FreeRTOS should be seen in the listing for FreeRTOS as:

     Version: 10.0.0-10 INSTALLED

If the version is not 10.0.0-10 or newer, click on the Select Version drop down list box and select the 10.0.0-10 version and then the 'Install' button.

image

 

I also installed 'frt' as well for S&Gs.

 

Once FreeRTOS is updated, shutdown the IDE and reopen it to ensure the libraries are update properly.

When the IDE is up again, click on File->Examples->FreeRTOS->Blink_AnalogRead as a test.

NOTE: This requires a switch connected to pin A0 and the use of the BuiltIn LED.

image

 

 

This will bring up a 2 Task example using FreeRTOS that takes input from a switch connected to A0 to control the Blink of the LED connected to Pin13.

image

 

This FreeRTOS Sketch will blink the on board LED (PIN 13) and pint the Switch (A0) value to the console output seemingly not interrupting either task.  That is, the LED should continue to blink when the switch is pressed.

This example was used to create my Ping Sensor and Motor Control code.

 

 

In the code I came up with, I have the 4 Tasks that control the on board LED, Ping Sensor Servo, Ping Sensor, and Motor Control.

 

  • TaskBlink           - Blink the on board LED (PIN13)
  • TaskPingServo  - Ping sensor servo sweep control
  • TaskMotor         - Motor control task
  • TaskPingRead  -  Ping Sensor Task

 

/**@file PWHBotNavigation.ino
 * @author Jon Morss
 * @date 15 Apr 2018
 * @brief  This code controls the navigation of the PWHBot.\n
 *         The Blink_AnalogRead example was used as a model for this code.\n
 */


#include <arduino_freertos.h>
#include "src\MotorShield.h"
#include 


Servo myservo;  // create servo object to control a servo
MotorShield mShield;  // Create Motor Shield object


bool BLINK_STATE = true;


// define two tasks for Blink & AnalogRead
void TaskBlink( void *pvParameters );
void TaskPingServo( void *pvParameters );
void TaskPingRead( void *pvParameters );
void TaskMotor( void *pvParameters );
long microsecondsToCentimeters(long microseconds);
long microsecondsToCentimeters(long microseconds);




// this constant won't change. It's the pin number of the sensor's output:
const int servoPin = 4;
const int BOARDLED = 13;


// the setup function runs once when you press reset or power the board
void setup() {


   //pinMode(servoPin, OUTPUT);


   mShield.motorShieldInit();
   myservo.attach(servoPin);  // attaches the servo on pin 9 to the servo object


  // Task declarations.


  xTaskCreate(
    TaskBlink
    ,  (const portCHAR *)"Blink"   // A name just for humans
    ,  128  // Stack size
    ,  NULL
    ,  2 // priority
    ,  NULL );




  xTaskCreate(
    TaskPingServo
    ,  (const portCHAR *) "PingServo"
    ,  128 // This stack size can be checked & adjusted by reading Highwater
    ,  NULL
    ,  1 // priority
    ,  NULL );




  xTaskCreate(
    TaskPingRead
    ,  (const portCHAR *) "PingRead"
    ,  128 // This stack size can be checked & adjusted by reading Highwater
    ,  NULL
    ,  1 // priority
    ,  NULL );




  xTaskCreate(
    TaskMotor
    ,  (const portCHAR *) "MotorControl"
    ,  128 // This stack size can be checked & adjusted by reading Highwater
    ,  NULL
    ,  1 // priority
    ,  NULL );


  // Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started.
}


void loop()
{
  // Empty. Things are done in Tasks.
}


/*--------------------------------------------------*/
/*---------------------- Tasks ---------------------*/
/*--------------------------------------------------*/


/**
 * @brief LED Blink Task
 */
void TaskBlink(void *pvParameters)  // This is a task.
{
  (void) pvParameters;


  // initialize digital pin 13 as an output.
  pinMode(13, OUTPUT);


  for (;;) // A Task shall never return or exit.
  {

    if(BLINK_STATE)
    {
    digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
    vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
    digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
    vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
    }
    vTaskDelay(1);  // one tick delay (15ms) in between reads for stability
  }
}


/**
 * @brief Ping Servo Sweep Task
 */
void TaskPingServo(void *pvParameters)  // This is a task.
{
  (void) pvParameters;


  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  int pingServoPos = 0;
  bool LEFT = true;
  bool RIGHT = false;


  for (;;)
  {

    Serial.println(pingServoPos);

    //  Check if LEFT direction is true and increment position value 
    // If LEFt is false, decrement pos until 0   
    if (LEFT == true)
    {
      pingServoPos += 1;
      if(pingServoPos == 180)
      {
        LEFT = false;
      }
    } 
    else if(LEFT == false)
    {
      pingServoPos -= 1;
      if(pingServoPos == 0)
      {
        LEFT = true;
      }
    } 
    myservo.write(pingServoPos);     // tell servo to go to position in variable 'pos'


    //delay(15);                       // waits 15ms for the servo to reach the position
   
    vTaskDelay(1);  // one tick delay (15ms) in between reads for stability
  }
}


/**
 * @brief Read Ping Task
 */
void TaskPingRead(void *pvParameters)  // This is a task.
{
  (void) pvParameters;
  long duration, inches, cm;
  const int pingPin = 7;
   // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);


  // Loop for Ping sensor
  for(;;)
  {
    // Code borrowed from Parallax
    // http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
    // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
    // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
    pinMode(pingPin, OUTPUT);
    digitalWrite(pingPin, LOW);
    delayMicroseconds(2);
    digitalWrite(pingPin, HIGH);
    delayMicroseconds(5);
    digitalWrite(pingPin, LOW);
  
    // The same pin is used to read the signal from the PING))): a HIGH pulse
    // whose duration is the time (in microseconds) from the sending of the ping
    // to the reception of its echo off of an object.
    pinMode(pingPin, INPUT);
    duration = pulseIn(pingPin, HIGH);
  
    // convert the time into a distance
    inches = microsecondsToInches(duration);
    cm = microsecondsToCentimeters(duration);
  
    Serial.print(inches);
    Serial.print("in, ");
    Serial.print(cm);
    Serial.print("cm");
    Serial.println();


    if(cm < 20)
    {
      //xSemaphoreTake(xLEDSem, 0);
      BLINK_STATE = false;
    }
    else
    {
      //xSemaphoreGive(xLEDSem);
      BLINK_STATE = true;
    }
    delay(100);
    vTaskDelay(1);  // one tick delay (15ms) in between reads for stability
  } 
}


/**
 * @brief Motor Control Task
 */
void TaskMotor( void *pvParameters )
{
  (void) pvParameters;

  // Loop for Ping sensor
  for(;;)
  {
    if(BLINK_STATE)
    {
      // Go forward
      mShield.motorShieldForward(0, 255);
      delay(1000);
    }
    else
    {      
      mShield.motorShieldStop(0);
      delay(500);
      mShield.motorShieldBackward(0, 255);
      delay(1000);
    }
      vTaskDelay(1);  // one tick delay (15ms) in between reads for stability
  }
}


long microsecondsToInches(long microseconds) {
  // According to Parallax's datasheet for the PING))), there are 73.746
  // microseconds per inch (i.e. sound travels at 1130 feet per second).
  // This gives the distance travelled by the ping, outbound and return,
  // so we divide by 2 to get the distance of the obstacle.
  // See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
  return microseconds / 74 / 2;
}


long microsecondsToCentimeters(long microseconds) {
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the object we
  // take half of the distance travelled.
  return microseconds / 29 / 2;
}

 

For the motor control, I had to dump the Seeed Studio Motor Shield  v2.2 since it was interfering with the Servo code causing both to not run.

 

MotorShield.h

/**@file MotorShield.h
 * @author Jon Morss
 * @date 15 Apr 2018
 * @brief This file contains functions to initialize Seeed Motor Shield v2.2 functions\n
    The Seeed Studio Motor Shield v2.2 code was used as a model for this code.
 *
 */

#ifndef  __MOTORSHIELD_H__
#define  __MOTORSHIELD_H__



#include 


/**
 * @brief Defines for motor funtions\n
 * Uno        Motor Shield\n
 * D8           OUT1\n
 * D9           Enable of Channel0\n
 * D10          Enable of Channel1\n
 * D11          OUT2\n
 * D12          OUT3\n
 * D13          OUT4\n
 *
 */


enum motorshield_t{ LEFTMOTOR_IN1 = 8,
                LEFTMOTOR_IN2 = 11,
                LEFTMOTOR_SPEED = 9,
                RIGHTMOTOR_IN1 = 12,
                RIGHTMOTOR_IN2 = 13,
                RIGHTMOTOR_SPEED = 10
            };


/**
 * @brief Motor IDs\n
 */

enum motorid_t { LEFT_MOTOR , RIGHT_MOTOR };


/**
 * @brief Motor Shield Class
 */
class MotorShield
{
private:
    bool mState;
    int  mSpeed0;
    int  mSpeed1;


public:
    void motorShieldInit();
    void motorShieldForward(unsigned char motorID, int speed);
    void motorShieldBackward(unsigned char motorID, int speed);
    void motorShieldStop(unsigned char motorID);
};
#endif

 

 

MotorShield.cpp

/**@file MotorShield.cpp
 * @author Jon Morss
 * @date 15 Apr 2018
 * @brief This file contains functions to initialize Seeed Motor Shield v2.2 functions\n
    The Seeed Studio Motor Shield v2.2 code was used as a model for this code.
 *
 */


#include "MotorShield.h"


void MotorShield::motorShieldInit()
{
    mSpeed0 = 0;
    mSpeed0 = 1;


    pinMode(LEFTMOTOR_IN1, OUTPUT);
    pinMode(LEFTMOTOR_IN2, OUTPUT);
    pinMode(LEFTMOTOR_SPEED, OUTPUT);
    pinMode(RIGHTMOTOR_IN1, OUTPUT);
    pinMode(RIGHTMOTOR_IN2, OUTPUT);
    pinMode(RIGHTMOTOR_SPEED, OUTPUT);
    digitalWrite(LEFTMOTOR_IN1, LOW);
    digitalWrite(LEFTMOTOR_IN2, LOW);
    digitalWrite(LEFTMOTOR_SPEED, LOW);
    digitalWrite(RIGHTMOTOR_IN1, LOW);
    digitalWrite(RIGHTMOTOR_IN2, LOW);
    digitalWrite(RIGHTMOTOR_SPEED, LOW);


}


void MotorShield::motorShieldForward(unsigned char motorID, int speed)
{
switch(motorID)
    {
    case 0:
        analogWrite(LEFTMOTOR_SPEED, speed);
        digitalWrite(LEFTMOTOR_IN1, HIGH);
        digitalWrite(LEFTMOTOR_IN2, LOW);
        break;
    case 1:
        analogWrite(RIGHTMOTOR_SPEED, speed);
        digitalWrite(RIGHTMOTOR_IN1, HIGH);
        digitalWrite(RIGHTMOTOR_IN2, LOW);
        break;
    default:;
    }
}


void MotorShield::motorShieldBackward(unsigned char motorID, int speed)
{
  switch(motorID)
  {
    case 0:
        analogWrite(LEFTMOTOR_SPEED, speed);
        digitalWrite(LEFTMOTOR_IN1, LOW);
        digitalWrite(LEFTMOTOR_IN2, HIGH);
        break;
    case 1:
        analogWrite(RIGHTMOTOR_SPEED, speed);
        digitalWrite(RIGHTMOTOR_IN1, LOW);
        digitalWrite(RIGHTMOTOR_IN2, HIGH);
        break;
    default:;
  }
}


void MotorShield::motorShieldStop(unsigned char motorID)
{
  switch(motorID)
  {
    case 0:
        //analogWrite(LEFTMOTOR_SPEED, 100);
        digitalWrite(LEFTMOTOR_IN1, HIGH);
        digitalWrite(LEFTMOTOR_IN2, HIGH);
        break;
    case 1:
        //analogWrite(RIGHTMOTOR_SPEED, 100);
        digitalWrite(RIGHTMOTOR_IN1, HIGH);
        digitalWrite(RIGHTMOTOR_IN2, HIGH);
        break;
    default:;
  }
}

 

 

 

Video showing all 4 FreeRTOS Tasks running on an Arduino UNO.

 

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

  • Sign in to reply

Top Comments

  • balearicdynamics
    balearicdynamics over 7 years ago +3
    This is a great project and very interesting tutorial. I have worked with an Arduino Mega 2560 to make the project The Lino Project with Arduino Mega 2560: Interrupts and Motors using the interrupts to…
  • mcb1
    mcb1 over 7 years ago in reply to jomoenginer +3
    I'll have to rethink any future posts. Sorry it wasn't meant to offend, but an out-loud observation that I (mistakenly) thought RTOS solved. The timers is one of the items that various libraries use, and…
  • jw0752
    jw0752 over 7 years ago +3
    Hi Jon, This is a great project and well explained. I hope you keep us updated as I am interested to see how your Bot develops. John
Parents
  • mcb1
    mcb1 over 7 years ago

    Interesting.

    While RTOS has it's place, I'm wondering if careful planning won't achieve much the same.

    Those 4 tasks don't appear to be large by any standard, unless the motor library is huge, so the RTOS is using a lot of valuable coding space.

     

    The Arduino is limited in timers and you've already discovered that RTOS didn't resolve that, so it's not a magic bullet.

     

    I've decided that a ping sensor fitted to a servo is just too distracting, and there is no easy way to make it look good ... so I won't be rotating mine.

    I always understood that fixing them to a bracket resulted in ringing in the transducer which limited their close range detection, so it will be interesting to see what you've found.

     

     

    Cheers

    Mark

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • jomoenginer
    jomoenginer over 7 years ago in reply to mcb1

    I do not believe I stated that FreeRTOS had anything to do with the timers or that it was a solution.  The issue between the Servo lib and the MotorDriver from Seeed Studio has nothing to do with an RTOS, but rather one or the other or both are coded in a non-friendly manner so they can not be used together. That is why I created my own code to control the motor shield regardless of whether or not FreeRTOS is used.

     

    Yeah, there are many ways to code the same solution, but I was not looking for a "magic bullet". I posted this as an exercise to just show what could be done with FreeRTOS and an Arduino UNO not what should be done.  

     

    I'll have to rethink any future posts.

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • mcb1
    mcb1 over 7 years ago in reply to jomoenginer

    I'll have to rethink any future posts.

    Sorry it wasn't meant to offend, but an out-loud observation that I (mistakenly) thought RTOS solved.

     

    The timers is one of the items that various libraries use, and sometimes the person writing the sketch may not know about.

    To them, they join some code and magic happens.

     

    So a RTOS would appear to resolve all those issues, and allow them to run the tasks they want, and have it do all the underlying work.

    Well that was one of my understandings of it ....

     

     

     

    So your post has been enlightning.

     

    Thanks

    Mark

    • Cancel
    • Vote Up +3 Vote Down
    • Sign in to reply
    • More
    • Cancel
Comment
  • mcb1
    mcb1 over 7 years ago in reply to jomoenginer

    I'll have to rethink any future posts.

    Sorry it wasn't meant to offend, but an out-loud observation that I (mistakenly) thought RTOS solved.

     

    The timers is one of the items that various libraries use, and sometimes the person writing the sketch may not know about.

    To them, they join some code and magic happens.

     

    So a RTOS would appear to resolve all those issues, and allow them to run the tasks they want, and have it do all the underlying work.

    Well that was one of my understandings of it ....

     

     

     

    So your post has been enlightning.

     

    Thanks

    Mark

    • Cancel
    • Vote Up +3 Vote Down
    • Sign in to reply
    • More
    • Cancel
Children
  • jomoenginer
    jomoenginer over 7 years ago in reply to mcb1

    Either I am doing a poor job explaining the post or you are just not getting it.

     

    I am quite aware of how to implement timers on a system, however what I shown with the use of FreeRTOS is just a way to schedule Tasks with an Arduino; nothing to do with timers was mentioned outside of the issue I ran into with the two Libraries which is outside of any implementation.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube