使用openFrameworks和Wekinator来控制舵机

  • 内容
  • 评论
  • 相关

在本文中,我们将学习如何在openFrameworks中创建一个滑块,并使用Wekinator机器学习软件控制连接到Arduino的舵机。

工作原理

openFrameworks应用程序将X和Y的值发送到Wekinator的特定端口6448,并使用OSC通信方式来发送数据。Wekinator将根据X和Y的值来进行学习,并将OCS消息发送回openFrameworks的12000端口。然后openFrameworks通过串口将消息发送给Arduino,并通过串口控制舵机。

电路图

如何用机器学习和openFrameworks来控制伺服电机。

舵机与Arduino的连接如下:

  1. 舵机的黄线是信号线,连接到Arduino上的数字引脚2。
  2. 舵机的棕线是接地线,连接到Arduino上的GND。
  3. 舵机的红线是电源线,连接到Arduino上的5V引脚。

Arduino的代码

在Arduino代码中,我们首先引入了servo库,并为servo初始化了一些变量。然后在setup函数中,我们将舵机附加在Arduino的引脚 2上,开始串口通信。在loop函数中,代码将寻找输入的数据,如果有任何数据可用,就读取它,并根据这个读取的值来控制舵机移动。

// 使用wekinator从openframeworks控制舵机的代码
#include <Servo.h>   //including the servo library
Servo sg90;          //including a variable for servo named sg90
int servo_pin = 2;

void setup() {
  sg90.attach(servo_pin);  //Giving the command to arduino to control pin 2 for servo
  // Start the serial communication
  Serial.begin(9600);
}

void loop() {
  if (Serial.available()) { // If there is any data available
    int inByte = Serial.read(); // Get the incoming data
    sg90.write(inByte);
  }
}

OpenFrameworks的代码

在openFrameworks侧,我们需要三个文件,它们主要用于从Wekinator发送和接收数据,同时实现将数据发送到Arduino。

1、Main.cpp:运行应用程序并打开输出窗口。

#include "ofMain.h"
#include "ofApp.h"

//========================================================================
int main( ){
  ofSetupOpenGL(600, 480, OF_WINDOW);			// <-------- setup the GL context

  // this kicks off the running of my app
  // can be OF_WINDOW or OF_FULLSCREEN
  // pass in width and height too:
  ofRunApp(new ofApp());
}

2、OfApp.cpp:它实现Arduino和openFrameworks之间串口通信,也实现了openFrameworks和Wekinator之间的OSC通信。

#include "ofApp.h"
#include "ofxOsc.h"


//--------------------------------------------------------------
void ofApp::setup(){
    sender.setup(HOST, SENDPORT);
  receiver.setup(RECEIVEPORT);
  ofSetFrameRate(60);
  serial.listDevices();
  vector <ofSerialDeviceInfo> deviceList = serial.getDeviceList();

  // this should be set to whatever com port your serial device is connected to.
  // (ie, COM4 on a pc, /dev/tty.... on linux, /dev/tty... on a mac)
  // arduino users check in arduino app....
  int baud = 9600;
  serial.setup(0, baud); 
  //open the first device
  // windows example
  //serial.setup("COM10", baud); 
  // mac osx example
  //serial.setup("/dev/tty.usbserial-A4001JEC", baud); 
  //linux example
  //serial.setup("/dev/ttyUSB0", baud); 
}

//--------------------------------------------------------------
void ofApp::update(){
  // Sending data to the wekinator
  ofxOscMessage m;
  m.setAddress(string(SENDMESSAGE));
  m.addFloatArg((float)mouseX);
  m.addFloatArg((float)mouseY);
  sender.sendMessage(m, false);

  // looking for incoming messages from wekinator
  while (receiver.hasWaitingMessages()) {
    ofxOscMessage msg;
    receiver.getNextMessage(&msg);  // Get Message
    if (msg.getAddress() == RECEIVEMESSAGE) {
      outputData = msg.getArgAsFloat(0);	// Stored it
    }
  }

  serial.writeByte(outputData); // sending the data to arduino
}

//--------------------------------------------------------------
void ofApp::draw(){
  ofSetColor(255, 0, 0);
    string buf = "Sending message " + string(SENDMESSAGE) + " to " + string(HOST) + " on port " + ofToString(SENDPORT);
    ofDrawBitmapString(buf, 10, 20);
    
  buf = "X=" + ofToString(mouseX) + ", Y=" + ofToString(mouseY);
    ofDrawBitmapString(buf, 10, 50);
  
  ofSetColor(0, 255, 0);
  ofDrawRectangle(mouseX, mouseY, boxSize, boxSize);
}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){
  mouseX = x;
  mouseY = y;
}

代码在setup()函数中,首先设置发送方和接收方,然后开始寻找串口端口号。一旦找到,就会自动连接。在update()函数中,代码首先将滑块的X和Y值发送给Wekinator。然后,寻找来自接收端的传入消息,当接收任何数据时,它将数据存储下来,同时将其发送到Arduino。在draw()函数中,将创建了一个拖动时就会移动的滑块。

OfApp.h:是头文件。

#pragma once

#include "ofMain.h"
#include "ofxOsc.h"

//Defaults for OSC:
#define HOST "127.0.0.1"
#define SENDPORT 6448
#define RECEIVEPORT 12000
#define SENDMESSAGE "/wek/inputs"
#define RECEIVEMESSAGE "/wek/outputs" 

class ofApp : public ofBaseApp{
    
public:
    void setup();
    void update();
    void draw();
    
    void mouseDragged(int x, int y, int button);   
    
    ofxOscSender sender;
  ofxOscReceiver receiver;
  ofSerial	serial;
    
    int mouseX = 0;
    int mouseY = 0;
  int boxSize = 30;
  char outputData;
};

如何运行openFrameworks

在openFrameworks中使用项目生成器创建一个新项目,本项目需要“Ofxosc”插件。将上一节给出的代码复制到相应的文件中并构建项目。在构建项目之后,你将看到如下所示的输出窗口。

openFrameworks项目窗口

在Wekinator中设置项目

在openFrameworks中建立项目后,打开Wekinator并调整设置,如下图所示:将输入设置为2,输出设置为1。选择输出类型为“custom”,点击“configure”。

wekinator创建项目设置

接下来,将最小值设置为0,最大值设置为180,点击“done”。

Wekinator项目设置

单击“next”,将出现新的项目窗口。

Wekinator项目设置

将窗口中的绿色框拖到屏幕左侧中心,点击“randomize”。启动记录一秒,并允许Wekinator记录样本。

Wekinator项目设置

现在将窗口中的绿色框拖到窗口中心,点击“randomize”。开始录音半秒钟。

Wekinator项目设置

最后,将窗口中的绿色框拖到右边中间,然后单击randomize。开始录音半秒钟。

Wekinator项目设置

为Wekinator完成三组学习后,单击“train”,然后单击“run”。现在,当我们在openFrameworks窗口中拖动滑块时,它将能控制连接到Arduino的舵机移动起来。