Go Down

Topic: Cat toy (2 servos) - how to handle data (Read 641 times) previous topic - next topic

Lawrence

Aug 07, 2012, 08:52 am Last Edit: Aug 07, 2012, 11:21 am by Lawrence Reason: 1
Subject: Cat toy (2 servos) - how to handle data
Project Objective:
To learn about the arduino by creating a interactive cat toy.

Vid of project to date

Method:
use 2 servos that move a stick on a flat 2D plane ("x" and "y") with a squirrel tail dangling from it.
I have divided the action into discrete tasks which are comprised of multiple steps where I define the end goal as x, y and define how long it is to take to get there (<x>, <y>, <TimeStepShouldTake>).

The Problem:
I am not very skilled at programming, and have run to my limit on what I can solve with Google.  I am currently stuck on how to define each task.  At the moment I have statically defined 10 tasks that consist of 10 steps each.  This is ok as a proof of concept but lacks the flexibility to grow this project to the next level.  Ideally I would like to have the flexibility to have the sketch read values from a file (defining tasks on a spreadsheet would be so much nicer) and create the correct number of tasks that consist of a varying number of steps.

Projects future development:
If I figure out the above issues, I would then like to start to experiment with using various sensors that will trigger different tasks.  If all goes well, I'm then hoping to learn how to make my own pcb and create a permanent gadget.

Hardware:
-Arduino Duemilanove
-2x Power Sources:
--->USB from computer to drive Arduino
--->Portable USB power(batt running through a regulator).  I added a cap to smooth it out a little
-2x standard sized servos
-breadboard (because I hate soldering stuff)

***EDIT***
I had to delete Code because it causes post to be larger than max char allowed. 

HERE IS CODE

PaulS

Quote
Ideally I would like to have the flexibility to have the sketch read values from a file

This is possible, if the file is on an SD card, and you have an SD shield.

Quote
defining tasks on a spreadsheet would be so much nicer

Than what? Being poked by sharp objects?

Quote
and create the correct number of tasks that consist of a varying number of steps.

How? What would the data in the file look like? How would the "correct number of tasks" be determined? How would the "varying number of steps" (per task?) be determined? Would the number of steps really be varying, or would the number of steps to get a task done be what varies?

I don't do google docs, and I see no particular reason to look at your code, since you didn't ask any questions about it.

Lawrence


Thanks PaulS for your response.  Let me try and address your comments to help clarify things for you.

Quote

Quote
Ideally I would like to have the flexibility to have the sketch read values from a file

This is possible, if the file is on an SD card, and you have an SD shield.

It seems to me to be real messy coding (not to mention not very user friendly) if I have to code in each variable in setup() as I am currently.  Imagine having to type all the following a few hundred times:
Code: [Select]
Task[0].Step[0].xPos = 5;
Task[0].Step[0].yPos = 90;
Task[0].Step[0].TimeToComplete = 1000;

I am thinking if I define the three fields in a spreadsheet and save them as text it would be a slicker method.  If saving a dat or txt file on arduio is not possible I imagine I could just declare it as a string.  Something like this:
Code: [Select]
//data format: <qty of steps in task>,<x>,<y>,<TimeToCompleteStep>,<x>,<y>,<TimeToCompleteStep>,…etc…
string DataString = "7,14,32,11000,170,155,7000,…etc…

not sure if string has a size limit… if it does I'm back to the drawing board.

Quote

Quote
defining tasks on a spreadsheet would be so much nicer

Than what? Being poked by sharp objects?

Lol, not sure what to say… think I delt with it above ;^)

Quote

Quote
and create the correct number of tasks that consist of a varying number of steps.

How? What would the data in the file look like? How would the "correct number of tasks" be determined? How would the "varying number of steps" (per task?) be determined? Would the number of steps really be varying, or would the number of steps to get a task done be what varies?

At the moment I have an array of an array of records.  Let me show you my defining it:
Code: [Select]

typedef struct{
int xPos;  //define ending x position
int yPos;  //define ending y position
unsigned long TimeToComplete; //define length  of time to reach ending position (sets speed of servo)
} TStep;

typedef struct{
TStep Step[10];
int LastStep;
} TTask;

TTask Task[10];

It would be very nice if there was some way to make these arrays dynamic (created during runtime)

Quote

I don't do google docs, and I see no particular reason to look at your code, since you didn't ask any questions about it.

And now you don't have to… :-D

Thanks again for taking the time to look and respond so quickly.

PaulS

Quote
I am thinking if I define the three fields in a spreadsheet and save them as text it would be a slicker method.

OK.

Quote
If saving a dat or txt file on arduio is not possible

On the Arduino, no. On an SD card, yes.

Quote
I imagine I could just declare it as a string.

Why? Then, you need to parse the string, and convert each token to an int. The compiler already knows hoe to do that, and does it at compile time, not run time. Use a struct with int fields. Create an array of struct instances.

Oh, wait, you're already doing that. I don't see where you initialize the Task array, though.

SD card readers are relatively cheap, and very easy to work with. Plug them in, and treat the thing like a hard drive.

It seems to me, though, that you might be over-thinking this. If you are developing an XY plotter that needs time to plot with differing inks, then your approach is ideal. For a cat toy, random motions seem more logical.

Lawrence

Quote
For a cat toy, random motions seem more logical.

No not aiming for random motions but rather need to call up specific tasks with multiple steps that have very accurate x/y targets and set length of time to get to that point.  Yes, this is currently a cat toy, but in reality it is a practice run for a future project where most of this code will be re-tasked.  If you watched the vid I posted, the cat toy was just the hook for my 7 year old daughter so she would take an interest in an electronics project (with a bonus intro into video editing).

So back to the original problem, is it possible to create dynamic arrays whose length (number items in the array) is set during runtime?

PaulS

Quote
If you watched the vid I posted

Well, I couldn't, because the site is blocked at work.

Quote
So back to the original problem, is it possible to create dynamic arrays whose length (number items in the array) is set during runtime?

Of course. If you are very careful. There is a limit on how much memory the Arduino has (depending on which Arduino you have).

If you are going to re-purpose the code, I'd suggest either a SD card to save the large amounts of data, or a serial connection to have the PC send the data one step at a time.

Lawrence

could you please give an example as I have not had any luck with using "new"

PaulS

Quote
could you please give an example as I have not had any luck with using "new"

How have you used it? You can also use malloc() and free().

michael_x

From your video I see that you do not have a completely wrong idea of a microcontroller.
For anyone else:
An Arduino UNO e.g. has 2048 bytes of RAM, which are used for all variable data, both stack and heap.
512 byte RAM is also a common size for smaller controllers.

Fortunately code does not run in RAM, and the 32kB of Flash memory are rather plenty. With a little trick, you can keep constant data in that flash memory.

Additionally, a microcontroller starts at power up or reset, and runs the little code in flash memory forever, in an endless loop.
As the same code will run again after a few microseconds, there's no need to free memory dynamically, and thus you don't need to allocate dynamic memory neither. ( Agreed, one can argue on this, but I hope one gets the point )

Be happy if you have enough RAM for your array ( No one tells you at run time, BTW ...)
Neither new nor malloc() is too useful.

As you have tasks that are controlled by dynamic parameters, you can sure get those parameters from an SD card as needed.
You might add parameters saying "modify by sensor value" or adding random data.

A  half way reasonable use case for new were to build a chain of Tasks ( instead of a fixed size array ), each having a pointer to the next Task, until
task.next = new Task(); would return a 0, indicating that memory is full. In that case you instead insert the address of the first task and have a ring of the max possible length of tasks.

PaulS

Quote
In that case you instead insert the address of the first task and have a ring of the max possible length of tasks.

Until you call a function, which requires pushing arguments onto the stack, for which there is no room...

michael_x

Quote
for which there is no room...

... and no way of run time error handling.

Agreed, no new nor malloc().

Or:
Do that inside a function which has defined a local byte blocker[300]; variable.
Anyone volunteer to test if malloc() really works ok when it reaches stack ?

Or:
Test if that pointer remains unmodified at run time

Or:
Any other suggestion ...

zoomkat

Simple two servo test code. You can defeat the arduino auto reset with a 100 ohm resistor, and make a simple repeating batch file to operate the servos via the pc serial port.

Code: [Select]

// zoomkat 11-22-10 serial servo (2) test
// for writeMicroseconds, use a value like 1500
// for IDE 0019 and later
// Powering a servo from the arduino usually DOES NOT WORK.
// two servo setup with two servo commands
// send eight character string like 15001500 or 14501550

#include <Servo.h>
String readString, servo1, servo2;
Servo myservo1;  // create servo object to control a servo
Servo myservo2;

void setup() {
  Serial.begin(9600);
  myservo1.attach(6);  //the pin for the servo control
  myservo2.attach(7);
  Serial.println("servo-test-21"); // so I can keep track of what is loaded
}

void loop() {

  while (Serial.available()) {
    delay(1); 
    if (Serial.available() >0) {
      char c = Serial.read();  //gets one byte from serial buffer
      readString += c; //makes the string readString
    }
  }

  if (readString.length() >0) {
      Serial.println(readString); //see what was received
     
      // expect a string like 07002100 containing the two servo positions     
      servo1 = readString.substring(0, 4); //get the first four characters
      servo2 = readString.substring(4, 8); //get the next four characters
     
      Serial.println(servo1);  //print to serial monitor to see results
      Serial.println(servo2);
     
      int n1 = servo1.toInt();
      int n2 = servo2.toInt();
     
      myservo1.writeMicroseconds(n1); //set servo position
      myservo2.writeMicroseconds(n2);
    readString="";
  }
}

Google forum search: Use Google Advanced Search and use Http://forum.arduino.cc/index in the "site or domain:" box.

zoomkat

Below is the looping batch file you can test with when the arduino auto reset is defeated. Copy the code, paste in notepad, and save on the desktop as servoloop.bat. This is set for comport 3 at 9600 bps. Double click (or right click and run) the servoloop.bat file to run.

Code: [Select]

@echo off
mode com3:9600,N,8,1 >nul
echo moving servos
echo 07001500 > com3
echo 8 second delay
ping -n 9 127.0.0.1 >nul
echo 22000700 > com3
echo 5 second delay
ping -n 6 127.0.0.1 >nul
echo 15001500 > com3
echo 5 second delay
ping -n 6 127.0.0.1 >nul
echo 09001800 > com3
echo done
echo Did it work?
pause
servoloop.bat
Google forum search: Use Google Advanced Search and use Http://forum.arduino.cc/index in the "site or domain:" box.

Go Up