Teach Your Robot a Movement

Did you hear about teaching a robot a move but don't know how to do that?

Did you ever struggle around to make a polished mathematical way/time function more dirty?

Did you ever had a robot part that moved unnatural - not human like but wanted it to appear more human?

 

This tip shows you one of many ways to get a discreete movement profile from human interaction. It shows you how you could teach your robot moves that are from a human being.

 

Content

1. Overview
2. What components do you need?
3. What software do you need? 
4. How do I record the data? 
5. How do I play the data?

 

1. Overview

Basically we record a move, transform that data into executable code and execute it - play it. 

RecordHumanPlayRobot2.png

In this tip we use an ultrasonic sensor to sense the distance between the sensor and my hand. This distance is what is mapped to i.e. servo angles so that the servo follows exactly the given curve.

The tip works fine for single-axis movements (like one wing of the Bøsewicht). Multi-axis movements are more sophisticated and most of the time need a pendant that is mechanical identical (like Walter or the master-slave arm). Multi-axis movements can have a profile in more than one axis - can turn in the X/Y plane and in the Y/Z plane in the same time.

2. What components do you need?

Arduino, Gobetwino, Servo, Ultrasonic Sensor

3. What software do you need?

Use this code to record the motions.

void loop() 
{ 
  val = ultrasonic.Ranging(CM);
  val = map(val, 0, 60, 0, 179);

  myservo.write(val);
  log(value);
  
  delay(20);
}

void log(int value){
  Serial.print("#S|LOGTEST|[");
  Serial.print(val);
  Serial.println("]#");
}

4. How do I record the data?

  1. Start the Arduino.
  2. Ready to Record
  3. Start Gobetwino
  4. Record data into text file
  5. Stop the recording when the move is finished
  6. Copy data into your favorite spreadsheet
  7. Smothen the data (see Appendix B)
  8. Transform data from spreadsheet to C
  9. Embed the C data into your robot code

5. How do I play the data?

  1. Let a loop go over the lookupTable array
  2. Write value from lookupTable[index] to the servo. See Appendix A for a full code sample (Nonblocking).

 

Further Readings

Using Gobetwino to debug your sensor data
   "Being able to see what your robot see’s in realtime is a powerful diagnostic tool when writing your software"

Gobetwino   
   Gobetwino is kind of a “genreric proxy” for Arduino. It’s a program running on a PC, that will act on behalf of Arduino and do some of the things that Arduino can’t do on its own. So it works like a go between, hence the name.

Smooth Head Rotation
   Rotate something with minimal jerk.


Appendix A: Example-Code

/ 
  Plays recorded data.
  more infos: https://www.robotshop.com/letsmakerobots/node/34270
  created by NilsB 
 */

#include <MsTimer2.h>
#include <Servo.h>

const int servoStartAngle = 100;
const int timerInMillies = 20;
const int countSinusSquareLookupTableEntries = 368;
const int sinusSquareLookupTable[] = {67, 67, 67, 69, 69, 67, 69, 69, 69, 69, 67, 67, 67, 65,
65, 65, 65, 65, 65, 65, 65, 63, 65, 65, 67, 69, 69, 65, 65, 65, 65, 65, 65, 61, 59, 59, 57, 57, 57,
57, 57, 57, 57, 57, 57, 57, 57, 56, 54, 54, 52, 52, 52, 54, 50, 50, 46, 46, 46, 44, 44, 42,
40, 40, 38, 57, 65, 57, 37, 35, 35, 33, 33, 31, 31, 31, 31, 31, 33, 33, 33, 35, 35, 35, 35, 37, 37,
40, 42, 42, 44, 46, 50, 56, 56, 54, 57, 57, 59, 65, 67, 69, 67, 73, 73, 73, 80, 82, 78, 80, 80, 82,
82, 84, 88, 92, 92, 92, 92, 90, 88, 82, 80, 76, 75, 75, 69, 69, 67, 63, 61, 59, 59, 57, 57, 52, 57,
42, 40, 38, 35, 35, 33, 37, 31, 31, 31, 31, 33, 38, 33, 33, 35, 38, 38, 42, 46, 52, 54, 57, 59, 67, 69, 69,
71, 78, 78, 80, 82, 86, 88, 90, 92, 90, 90, 90, 84, 78, 75, 69, 69, 67, 69, 54, 48, 71, 57, 38, 33,
31, 31, 31, 31, 31, 31, 29, 29, 31, 31, 33, 35, 38, 57, 42, 46, 50, 56, 57, 59, 65, 69, 69, 75,
80, 80, 84, 92, 92, 95, 97, 97, 99, 99, 103, 92, 95, 88, 95, 80, 78, 69, 69, 63, 61, 56, 90, 57,
69, 40, 57, 40, 38, 35, 33, 33, 31, 31, 33, 33, 35, 37, 35, 57, 37, 42, 38, 38, 42, 44, 50, 52,
54, 57, 57, 59, 63, 82, 67, 69, 75, 80, 80, 80, 82, 86, 90, 95, 97, 99, 97, 103, 105, 105,
111, 114, 120, 120, 116, 118, 118, 118, 118, 118, 118, 118, 116, 118, 118, 118, 118, 116, 118, 116,
118, 118, 118, 118, 118, 118, 118, 118, 118, 120, 112, 109, 107, 101, 99, 92, 88, 82, 78, 75, 69,
114, 69, 59, 57, 57, 50, 42, 40, 38, 35, 38, 31, 29, 29, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 29,
29, 31, 29, 29, 31, 29, 33, 33, 35, 37, 40, 46, 57, 59, 61, 63, 67, 69, 73};
int currentValueIndex = 0;
const int movmentIndicatorPin = 13;

Servo headServo;

void move()
{
  moveServoTo(angle());

  indicateMovement();
  incrementOrStop();
}

void moveServoTo(int angle){
  Serial.println(angle);
  headServo.write(angle);
}

int angle(){
  return sinusSquareLookupTable[currentValueIndex];
}

void indicateMovement()
{
  static boolean output = HIGH;
  
  digitalWrite(movmentIndicatorPin, output);
  output = !output;
}

void incrementOrStop(){
  currentValueIndex++;
  if(currentValueIndex == countSinusSquareLookupTableEntries - 1){
    stopMove();
  }
  Serial.println(currentValueIndex);
}

void stopMove(){
  MsTimer2::stop();
  headServo.detach();
}

void setupMovementIndicator(){
  Serial.begin(9600);
  pinMode(movmentIndicatorPin, OUTPUT);
}

void setupTimer2(){
  MsTimer2::set(timerInMillies, move);
  MsTimer2::start();
}

void setupServo(){
  headServo.attach(9);
  headServo.write(servoStartAngle);
}

void setup(){
  Serial.begin(9600);
  setupMovementIndicator();
  setupServo();  
  setupTimer2();
}

void loop(){;}

Appendix B: Visual comparison of raw and smoothened curve

https://www.youtube.com/watch?v=zPNiUgo03jM

Nice idea¡
thanks for

Nice idea¡
thanks for sharing