PCA9685版OTTO开源跳舞机器人

  • 正文
    • 关于OTTO开源跳舞机器人
    • PCA9685库文件
    • Oscillater.cpp文件:
    • Oscillator.h文件
    • 主程序:nanoPca9685ODance.ino
  • 参考文献

当初急用但直接在网上翻遍了也没找到PCA9685版的OTTO机器人,库是从M5stack找的。直接上全部源代码和当初的参考文献吧。需要请自取。

源代码网盘下载地址
提取码:8z71
或者https://codechina.csdn.net/happyjoey217/pca9685-otto/-/tree/master

正文

https://www.ottodiy.com/Otto 机器人的官网。下面的图是官网截图。
这个可爱的小家伙是一个简单的四自由度机器人(两个踝关节和两个髋关节),外壳是3D打印的,官网提供了全部的3D打印文件和源代码。还有论坛。可以让你以非常低廉的成本实现对四自由度机器人的探索。我还曾经把小OTTO倒过用它的一条腿做过云台实验。哈哈哈 上面粘了一个摄像头。有想像没有约束,在没有3D打印机的情况下,也曾用废旧的包装壳实现过。
教程地址

后来我自己在做其他小制作的时候发现了PCA9685,就想着用这个岂不更好用?而且可以外接电源支持更多的舵机。用更少的控制口。也许可以用WemosD1Mini来替代之前的设计。(好吧这是另外一篇帖子的故事了。。。敬请期待)但是在网上找了很久并没有见到有人做过这个尝试(至少2020年5月的时候)。于是就有了这篇帖子。

关于OTTO开源跳舞机器人

src是PCA9685的库文件所在的文件夹,nanoPca9685ODance.ino是主程序。

PCA9685库文件

下面两个文件放在src文件下。

Oscillater.cpp文件:

//--------------------------------------------------------------
//-- Oscillator.pde
//-- Generate sinusoidal oscillations in the servos
//--------------------------------------------------------------
//-- (c) Juan Gonzalez-Gomez (Obijuan), Dec 2011
//-- GPL license
//--------------------------------------------------------------
#include "Oscillator.h"Oscillator::Oscillator(void) {}Oscillator::Oscillator(Adafruit_PWMServoDriver* pwm, int ch, int servomin, int servomax, int trim) {this->_pwm = pwm;this->_ch = ch;this->_servomin = servomin;this->_servomax = servomax;this->_trim     = trim;attach();
}
//-- This function returns true if another sample
//-- should be taken (i.e. the TS time has passed since
//-- the last sample was taken
bool Oscillator::next_sample()
{//-- Read current time_currentMillis = millis();//-- Check if the timeout has passedif(_currentMillis - _previousMillis > _TS) {_previousMillis = _currentMillis;   return true;}return false;
}//-- Attach an oscillator to a servo
//-- Input: pin is the arduino pin were the servo
//-- is connected
void Oscillator::attach(bool rev)
{//-- Attach the servo and move it to the home position
//    servo_write(90);//-- Initialization of oscilaltor parameters_TS=30;_T=2000;_NN = _T/_TS;_inc = 2*M_PI/_NN;_previousMillis=0;//-- Default parameters_A=45;_phase=0;_phase0=0;_O=0;_stop=false;//-- Reverse mode_rev = rev;}//-- Detach an oscillator from his servo
void Oscillator::detach()
{}/*************************************/
/* Set the oscillator period, in ms  */
/*************************************/
void Oscillator::setT(unsigned int T)
{//-- Assign the new period_T=T;//-- Recalculate the parameters_NN = _T/_TS;_inc = 2*M_PI/_NN;
};/*******************************/
/* Manual set of the position  */
/******************************/void Oscillator::setPosition(int position)
{servo_write(position);
};/*******************************************************************/
/* This function should be periodically called                     */
/* in order to maintain the oscillations. It calculates            */
/* if another sample should be taken and position the servo if so  */
/*******************************************************************/
void Oscillator::refresh()
{//-- Only When TS milliseconds have passed, the new sample is obtainedif (next_sample()) {//-- If the oscillator is not stopped, calculate the servo positionif (!_stop) {//-- Sample the sine function and set the servo pos_pos = round(_A * sin(_phase + _phase0) + _O);if (_rev) _pos=-_pos;servo_write(_pos+90);}//-- Increment the phase//-- It is always increased, even when the oscillator is stop//-- so that the coordination is always kept_phase = _phase + _inc;}
}void Oscillator::servo_write(int ang) {ang = ang + _trim;ang = map(ang, 0 , 180 , _servomin, _servomax);_pwm->setPWM(_ch, 0, ang);}

Oscillator.h文件

//--------------------------------------------------------------
//-- Oscillator.pde
//-- Generate sinusoidal oscillations in the servos
//--------------------------------------------------------------
//-- (c) Juan Gonzalez-Gomez (Obijuan), Dec 2011
//-- GPL license
//--------------------------------------------------------------
#include "Oscillator.h"Oscillator::Oscillator(void) {}Oscillator::Oscillator(Adafruit_PWMServoDriver* pwm, int ch, int servomin, int servomax, int trim) {this->_pwm = pwm;this->_ch = ch;this->_servomin = servomin;this->_servomax = servomax;this->_trim     = trim;attach();
}
//-- This function returns true if another sample
//-- should be taken (i.e. the TS time has passed since
//-- the last sample was taken
bool Oscillator::next_sample()
{//-- Read current time_currentMillis = millis();//-- Check if the timeout has passedif(_currentMillis - _previousMillis > _TS) {_previousMillis = _currentMillis;   return true;}return false;
}//-- Attach an oscillator to a servo
//-- Input: pin is the arduino pin were the servo
//-- is connected
void Oscillator::attach(bool rev)
{//-- Attach the servo and move it to the home position
//    servo_write(90);//-- Initialization of oscilaltor parameters_TS=30;_T=2000;_NN = _T/_TS;_inc = 2*M_PI/_NN;_previousMillis=0;//-- Default parameters_A=45;_phase=0;_phase0=0;_O=0;_stop=false;//-- Reverse mode_rev = rev;}//-- Detach an oscillator from his servo
void Oscillator::detach()
{}/*************************************/
/* Set the oscillator period, in ms  */
/*************************************/
void Oscillator::setT(unsigned int T)
{//-- Assign the new period_T=T;//-- Recalculate the parameters_NN = _T/_TS;_inc = 2*M_PI/_NN;
};/*******************************/
/* Manual set of the position  */
/******************************/void Oscillator::setPosition(int position)
{servo_write(position);
};/*******************************************************************/
/* This function should be periodically called                     */
/* in order to maintain the oscillations. It calculates            */
/* if another sample should be taken and position the servo if so  */
/*******************************************************************/
void Oscillator::refresh()
{//-- Only When TS milliseconds have passed, the new sample is obtainedif (next_sample()) {//-- If the oscillator is not stopped, calculate the servo positionif (!_stop) {//-- Sample the sine function and set the servo pos_pos = round(_A * sin(_phase + _phase0) + _O);if (_rev) _pos=-_pos;servo_write(_pos+90);}//-- Increment the phase//-- It is always increased, even when the oscillator is stop//-- so that the coordination is always kept_phase = _phase + _inc;}
}void Oscillator::servo_write(int ang) {ang = ang + _trim;ang = map(ang, 0 , 180 , _servomin, _servomax);_pwm->setPWM(_ch, 0, ang);}

主程序:nanoPca9685ODance.ino

#include "src/Oscillator/Oscillator.h"
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>//---------------------------------
// Servo Settings 舵机设定
//---------------------------------#define N_SERVOS 5 //五自由度舵机 0左脚 1右脚 2左腿 3右腿 4头#define INTERVALTIME 10.0 //这是中断时间为10.0int t = 620;  // 1280; //脉冲宽度?
double pausemillis = 0;int servoMin[N_SERVOS]  = {150, 150, 150, 150, 150}; //舵机的最小输出
int servoMax[N_SERVOS]  = {500, 500, 500, 500, 500}; //舵机的最大输出
int servoTrim[N_SERVOS] = {10, 0, 0, -10, -10};      //
int servoInit[N_SERVOS] = {90, 90, 90, 90, 125};     //舵机初始化
int servoTest[N_SERVOS] = {80, 80, 80, 80, 115};     //舵机测试#define NECKV_CH 4Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40);
Oscillator *servo[N_SERVOS];bool maintenanceMode = true;void setup() {Serial.begin(9600);Serial.println("5 channel Servo test!");Wire.begin();pwm.begin();//启动舵机pwm.setPWMFreq(50);  //模拟伺服在60赫兹更新下运行 此点很重要//-----------舵机初始化---------------------------for (int i = 0; i < N_SERVOS; i ++) {servo[i] = new Oscillator(&pwm, i, servoMin[i], servoMax[i], servoTrim[i]);}Serial.println("Servo init");for (int i = 0; i < N_SERVOS; i++) {servo[i]->setPosition(servoTest[i]);}delay(1000);for (int i = 0; i < N_SERVOS; i++) {servo[i]->setPosition(servoInit[i]);}//---------整机初始化完成,舵机休眠-----------
}void loop() {action1();
}//------------编舞1------------------------
void action1() {displayStatus("Walk");walk(2, t * 3);displayStatus("Back");backyard(2, t * 3);displayStatus("upDown");upDown(3, t * 2);displayStatus("MWalkR");moonWalkRight(1, t*2);moonWalkRight(2, t);displayStatus("MWalkL");moonWalkLeft(1, t*2);moonWalkLeft(2, t);displayStatus("swing");swing(2, t);
}
//---------------输出显示---------------------
void displayStatus(String param) {// Serial.print(param + "    ");}
//-------oscillate函数----------------------
void oscillate(int A[N_SERVOS], int O[N_SERVOS], int T, double phase_diff[N_SERVOS]) {for (int i = 0; i < N_SERVOS; i++) {servo[i]->setO(O[i]);servo[i]->setA(A[i]);servo[i]->setT(T);servo[i]->setPh(phase_diff[i]);}double ref = millis();for (double x = ref; x < T + ref; x = millis()) {for (int i = 0; i < N_SERVOS; i++) {servo[i]->refresh();}}for (int i=0; i< N_SERVOS; i++) {servo[i]->reset();servo[i]->setPosition(90);}}
//-------------------moveNServos函数------------------------
unsigned long final_time;
unsigned long interval_time;
int oneTime;
int iteration;
float increment[N_SERVOS];
int oldPosition[N_SERVOS] = {90, 90, 90, 90, 90};void moveNServos(int time, int  newPosition[]) {for (int i = 0; i < N_SERVOS; i++)  increment[i] = ((newPosition[i]) - oldPosition[i]) / (time / INTERVALTIME);final_time =  millis() + time;iteration = 1;while (millis() < final_time) { //Javi del futuro cambia estointerval_time = millis() + INTERVALTIME;oneTime = 0;while (millis() < interval_time) {if (oneTime < 1) {for (int i = 0; i < N_SERVOS; i++) {servo[i]->setPosition(oldPosition[i] + (iteration * increment[i]));}iteration++;oneTime++;}}}for (int i = 0; i < N_SERVOS; i++) {oldPosition[i] = newPosition[i];}
}
//-------------------------------------------------
// OTTO机器人的基本动作
//-------------------------------------------------
void walk(int steps, int T) {int A[N_SERVOS] = { 15, 15, 30, 30, 25};int O[N_SERVOS] = { 0, 0, 0, 0, 0};double phase_diff[N_SERVOS] = { DEG2RAD(0), DEG2RAD(0), DEG2RAD(90), DEG2RAD(90), DEG2RAD(135) };for (int i = 0; i < steps; i++) {oscillate(A, O, T, phase_diff);}
}void backyard(int steps, int T) {int A[N_SERVOS] = {15, 15, 30, 30, 25};int O[N_SERVOS] = {0, 0, 0, 0, 0};double phase_diff[N_SERVOS] = {DEG2RAD(0), DEG2RAD(0), DEG2RAD(-90), DEG2RAD(-90), DEG2RAD(135)};for (int i = 0; i < steps; i++) oscillate(A, O, T, phase_diff);
}void upDown(int steps, int tempo) {int move1[N_SERVOS] = {50, 130, 90, 90, 115};int move2[N_SERVOS] = {90, 90, 90, 90, 90};for (int x = 0; x < steps; x++) {pausemillis = millis();moveNServos(tempo * 0.2, move1);delay(tempo * 0.4);moveNServos(tempo * 0.2, move2);while (millis() < (pausemillis + tempo));}
}void moonWalkRight(int steps, int T) {Serial.println("moonWalkRight");int A[N_SERVOS] = {15, 15, 0, 0, 0};int O[N_SERVOS] = {5 , 5, 0, 0, 0};double phase_diff[N_SERVOS] = {DEG2RAD(0), DEG2RAD(180 + 120), DEG2RAD(90), DEG2RAD(90), DEG2RAD(90)};for (int i = 0; i < steps; i++) oscillate(A, O, T, phase_diff);
}void moonWalkLeft(int steps, int T) {Serial.println("moonWalkLeft");int A[N_SERVOS] = {15, 15, 0, 0, 0};int O[N_SERVOS] = {5, 5, 0, 0, 0};double phase_diff[6] = {DEG2RAD(0), DEG2RAD(180 - 120), DEG2RAD(90), DEG2RAD(90), DEG2RAD(90)};for (int i = 0; i < steps; i++) oscillate(A, O, T, phase_diff);
}void swing(int steps, int T) {int A[N_SERVOS] = {25, 25, 0, 0, 0};int O[N_SERVOS] = {15, 15, 0, 0, 0};double phase_diff[N_SERVOS] = {DEG2RAD(0), DEG2RAD(0), DEG2RAD(90), DEG2RAD(90), DEG2RAD(90)};for (int i = 0; i < steps; i++) oscillate(A, O, T, phase_diff);
}void headSwing(int steps, int tempo) {int move1[N_SERVOS] = {90, 90, 90, 90, 90};int move2[N_SERVOS] = {90, 90, 90, 90, 45};for (int x = 0; x < steps; x++) {pausemillis = millis();moveNServos(tempo * 0.2, move1);delay(tempo * 0.4);moveNServos(tempo * 0.2, move2);while (millis() < (pausemillis + tempo));}
}void headSwing2(int steps, int T) {int A[N_SERVOS] = {0, 0, 0, 0, 45};int O[N_SERVOS] = {0, 0, 0, 0, 0};double phase_diff[N_SERVOS] = {DEG2RAD(90), DEG2RAD(90), DEG2RAD(90), DEG2RAD(90), DEG2RAD(135) };for (int i = 0; i < steps; i++) oscillate(A, O, T, phase_diff);
}

参考文献

【1】https://github.com/mongonta0716/M5Stack-OttoDIY/tree/master/M5Stack-OttoDIY/src/Oscillator
【2】视频演示:https://www.youtube.com/watch?v=y8X9X10Tn1k
https://steemit.com/utopian-io/@drencolha/adafruit-pca9685-pwm-servo-driver-setup-arduino-library-use-shown-with-an-example-project-tutorial
【3】连接图:https://steemit.com/utopian-io/@drencolha/adafruit-pca9685-pwm-servo-driver-setup-arduino-library-use-shown-with-an-example-project-tutorial

PCA9685版OTTO开源跳舞机器人相关推荐

  1. 呆萌跳舞机器人(OTTO)

    放暑假了,您家的小屁孩儿在家干嘛呢? 如果是整天抱着手机打游戏的哪种,何不尝试用下面的呆萌跳舞机器人吸引下他的注意力? 先放几段跳舞视频吧,后续发机器人制作及相关编程的教程. <iframe h ...

  2. 微信个人网页版API的微信机器人

    微信个人网页版API的微信机器人, github 上有很多轮子了,来一个 electron-vue 版的,完全开源 github 项目地址 https://github.com/joehecn/j 安 ...

  3. python开源聊天机器人ChatterBot——聊天机器人搭建、流程分析、源码分析

    开源聊天机器人ChatterBot 3.1  ChatterBot简介 ChatterBot是一个Python库,可以轻松生成对用户输入的自动响应.ChatterBot使用一系列机器学习算法来产生不同 ...

  4. fluorinefx C# 版的开源rtmp服务器

    fluorinefx C# 版的开源rtmp服务器 - [其它资源] 版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明 http://25swf.blogbus.com/logs/28 ...

  5. python rpa机器人_6个开源工具机器人过程自动化RPA工具

    原标题:6个开源工具机器人过程自动化RPA工具 开源的机器人过程自动化工具(Robotic Process Automation,RPA)使企业可以低成本的使用RPA.随着开源的兴起,与许多的软件实现 ...

  6. 两种开源聊天机器人的性能测试(一)——ChatterBot

    因为最近在学习自然语言处理的相关知识,QQ小冰这个东西最近又很热,所以就试着玩了下两个开源聊天机器人,在这里分享一点小经验,希望对有共同兴趣的人能起到那么一点作用. 我主要测试了两个聊天机器人,一个是 ...

  7. 请列举你所知道的Linux发行版与开源软件

    请列举你所知道的Linux发行版与开源软件 常见的Linux发行版: Red Hat Enterprise Linux 5/6 CentOS 5/6 Suse Linux Enterprise 11 ...

  8. 零点城市社交电商 2.1.7.4 独立版 全开源 含前后端VUE文件 全插件

    零点城市社交电商 2.1.7.4 独立版 全开源 含前后端VUE文件 全插件 前言 产品介绍 开发语音 获取源码 前言 零点城市社交电商最新版,独立版+前后端VUE+全开源+全插件,持续更新中,完美使 ...

  9. 最新首途影视视频网站源码/二十二套带后台版全开源无加密源码

    源码简介: 最新首途二十二套带后台版全开源无加密源码 菜单填写格式:MyTheme主题,/template/mytheme/admin/默认账号:admin默认密码:admin 下载链接 网盘源码  ...

最新文章

  1. 算法--旋转链表(Java)
  2. boost::hana::eval_if用法的测试程序
  3. .Net Core中的Api版本控制
  4. 有人说,30岁是程序员的一个末日期,写给30岁的程序员,到底该怎么做呢
  5. 【转载】Debian 6安装小记
  6. python递归(一分钟读懂)
  7. BUAAOO——UNIT2 SUMMARY
  8. 电能质量分析仪上位机软件安装和使用
  9. 仿英雄联盟LOL网页设计作业 HTML CSS游戏官网网页模板 大学生游戏介绍网站毕业设计 DW游戏主题网页模板下载 游戏娱乐网页成品代码 英雄联盟网页作品下载
  10. Tomcat 500错误:实例化Servlet类异常
  11. 显示器偏色测试软件,显示器显示偏色
  12. Android自定义View——仿QQ等级天数进度
  13. ambari登录页面打不开,报错:postgresql ...... Check that the hostname and port are correct......
  14. 秦曾昌人工智能课程---5、KNN和朴素贝叶斯
  15. 书单 | 无所不能的Python,从技术到办公,总有一款适合你!
  16. GitHub标星8,一文详解
  17. 数字-数字编码和模拟-数字编码
  18. 远程桌面连接时,用电脑名不能连接,用IP就可以,为什么
  19. 第12章 增强现实技术
  20. 企业员工培训团队建设培训PPT模板

热门文章

  1. 新型Android木马伪装成Google Play,兼具多种恶意功能
  2. ssh和scp(未完)
  3. 向服务端上传数据如何确保数据完整性、安全性
  4. 阿里云媒体转码处理方式
  5. 通过修改 DOM 的文本内容,动态改变网页的内容。
  6. [国产PLC]耐特节省能耗PLC在音乐喷泉系统中怎样运用
  7. Joda Time使用小计
  8. 智能合约案例(1)-----永载史册的结婚证书
  9. 业务项目管理软件使用推荐
  10. 图片轮播KinSlideshow注意事项