0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Arduino机器人鼓手DIY图解

454398 来源:工程师吴畏 2019-08-22 10:38 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

步骤1:材料

1x Arduino UNO

3x伺服电机

2x电压调节器模块

1x电压升降器模块

1x驻极体微型电脑

2x压电传感器

1x Tact按钮

1x任何ON/OFF开关

5x 2n3904晶体管

3x 500k电位器

3x 100k电阻器

3x 10k电阻

3x 47k电阻器

1x 1/4“单声道插孔

1x 9v至12v电源

各种电阻器(可能需要进行实验)

各种电容器(可能需要进行实验)

PCB穿孔板,或者面包板。

一些MDF **

**我手工制作了所有木制件,所以我真的没有任何确切的计划我尽可能地画出并解释了所有的东西,我认为复制它们并不困难,莫如果您有cnc或3d打印机,请重新进行操作。

步骤2:一般理念

地方,有必要定义drumkit元素将是什么。遵循频率范围的逻辑,标准鼓组通常由三个基本元素组成;踢(低频范围),小鼓(中距离)和踩镲(高音)。经过几个星期的实验,我决定按照以下安排复制这些声音:

Kick/LowRange: 2个压电,用一小块海绵材料覆盖,它们是用一个柔软的橡胶末端的伺服控制棒击中。

Snare/MidRange:一罐带有小方形锡片的小齿轮,用于共振,也被击中伺服控制棒,橡胶端。然后由驻极体麦克风捕获声音。

HiHat/HighRange:基于晶体管的白噪声发生器电路,由arduino直接控制。

所有上述系统均由arduino板,然后由它们产生的音频信号通过三个简单的放大器电路放大到仪器电平信号。

步骤3:踢鼓

这可以利用直接触碰或击打压电拾音器时产生的低频声音柔软的物体。为了使这个工作,首先我们需要自动匹配压电器,其次,我们需要放大由所述压电器产生的音频信号。

如上所述,我使用伺服控制杆来击中位于伺服运动范围两端的两个不同的压电(为了利用所有的运动)。为了帮助抑制高频,压电器用海绵覆盖,并且杆上有一个柔软的橡胶端。

此时,重要的是要确定伺服器击打时的角度其运动范围的每一端。稍后将需要此信息,并且可以使用基本的arduino代码(如此处所述的代码)和 Serial.print(); 命令轻松获取。

来自压电的音频信号然后由上图所示的电路放大,由来自电源调节器的5v-7v供电,电压调节器由主电源(不是arduino板)供电。这很重要,因为尽管放大器本身能够与arduino提供的5v一起工作,但理想的是保持模拟音频信号尽可能与数字电路分开,以避免任何数字噪声干扰进入最终音频信号的方式。

同样,我没有正式(或任何lol)电子学教育,而且我在这最后一个问题上遇到了很多困难。在任何音频应用中几乎不可能完全消除噪声,但我发现电压调节器中的滤波(以及模拟和数字分离,以及项目的适当电屏蔽)将噪声降低到非常可接受的水平。第2步:小军团

这是一个非常复杂的复制声音,即使现在我仍然对我所取得的声音并不十分满意。为了拾取这个声音,我决定使用驻极体麦克风,因为它们通常更敏感,并且小鼓声的独特声学特性使这成为必要。

正如我们对踢腿系统所做的那样,我们需要一个机械部件和一个音响部件。我附上了我设计的机械系统的图纸。是的,我用Pringles可以颠倒,它是完美的形状,有我能找到的最好的声音,薯片很美味。

就像我们做的一样,我们需要得到每个伺服在休息和击球时的角度。再次,修补电位计+伺服教程,我们可以获得该信息。

来自驻极体的音频信号被踢放大器中使用的同一电路的另一个实例放大,尽管在这种情况下有一个很少修改驻极体麦克风的电源,也没有使用低通滤波器

步骤5:HiHat

我用这种声音的不同方法,一个基于晶体管的白噪声发生器电路和一个LED指示灯,在需要时由arduino激活。白噪声是在不同频率下具有相等强度的随机信号。粗略地说,就像白光包含所有颜色一样,白噪声包含所有频率,它听起来像一个不存在的无线电台(静态)。这是一种常用于电子音乐和音频合成的噪音,我读到它甚至用来制作80年代小鼓和钹的经典声音。

如图所示,在产生噪音之后,然后它通过一个高通滤波器来消除不需要的频率,并强调鼓钹的感觉。

白噪声发生器需要12v或更高功能,由升压电梯提供,它本身由arduino引脚直接供电。这是音频系统直接连接到arduino的唯一情况,因为噪声必须仅在特定时间产生,并且噪声似乎不是产生噪声的电路中的问题。你不能让白色更白吗?

第6步:信号混合和完整图

在产生所有三个鼓组音色之后,每个信号都通过一个电位器和一个基本的无源混音器电路,它混合了最终的音频信号。

我们还需要一种方法来选择要播放的鼓声以及何时开始和结束播放。对于这个指示,我们将分别使用连接的按钮和一个简单的开关(连接到arduino引脚2和3,如上图所示)

步骤7:代码I - 伺服时间校准

现在,鉴于此项目是一种乐器,它需要在合适的时间产生声音。因此,在我们开始编码不同的节奏和功能之前,特别是在踢球和小鼓的情况下,我们需要对舵机的运动进行编程,以便在它们转向声音之前的几毫秒开始,以便补偿杖的时间。为了解决这个问题,我想出了一个简单的系统来测量每个伺服从静止位置到达击中目的地的确切点。我用铝箔覆盖了棍棒和它们所在的区域,并将鳄鱼夹连接到箔片上,创造了一个只有当棍子击中目标时才能用arduino测量的连接。然后我写了一段简单的代码,它做了两件事:首先,让伺服棒反复击中目标,从静止角度到击球角度。其次,打印发送伺服命令的时间,以及棒与目标关闭连接的时间。减去这两个值将给我们时间棒发出声音所需的时间,从休息到击打。

这样做了足够多次之后,你会得到很多大致相似的数字,然后你可以平均,并获得每个伺服的预期相当可用的时间。

步骤8:代码II - 鼓组合

现在,我们为节拍中的kick,snare和hihat的每个组合定义一个数字代码。我们将第一个奇数分配给我们的三个drumkit元素:

Kick Snare HiHat

1 3 5

然后,如果我们需要同时播放多个元素,我们只需添加每个元素的数字元件。 Kick和Snare将是4,kick和HiHat 6,依此类推。零/零是沉默。现在我们为每个可能的鼓元素组合都有一个数字,我们可以将它们存储在变量(cycleNumber变量)中。

3 HiHat x - x x

2 Snare - x x x

1 Kick x x - x

_________________________________________

COMBINATION: 4 3 5 6

步骤9:Code III - Semiquaver循环(按时间命中)

我们现在知道有必要预测kick和snare伺服系统的命令,但我们还必须玩这些命令帽子准时,这是一个几乎立即工作的电路。

为了解决这个问题,这可能会让我感到有些混乱,我决定在每个半音符(或十六分音符)内建立一个检查点系统每个酒吧。我选择了第16个,因为在最常见节奏的节奏中,音符的十六分之一持续约100到150毫秒,这也是较慢的伺服(在我的情况下)从静止到击打的速度,或反之亦然。我们可以通过简单地改变分配给timeTotalCycle变量的毫秒数来改变速度。这是一个有用的速度,音符和毫秒等效表。如果我们试图更快地发挥作用,并且我们将周期的总时间减少到慢于伺服移动的时间,则该伺服可能无法从静止到达击中位置,因此不会产生声音。更详细地看一下我发布的图表,将更好地解释这一点。

如图所示,在我称之为semiquaver-cycle的开始,我们发送用于定位圈套伺服器的命令在他们的休息位置,如果他们被命令在前一个周期击中。此时,我们开始计算在整个半切割周期内设置的毫秒数。

之后,arduino将开始检查循环结束剩余的时间是否等于每个伺服需要产生声音的任何时间。这里的想法是检测我们必须发送命中命令的时间点,以便每个伺服到达并在周期的确切结束时击中它们的目标(并发出它们的声音)。因此,每个元素都必须在循环中的不同检查点开始运动,具体取决于伺服及其机构的速度。另一方面,hihat白噪声电路可以在循环结束时或几毫秒之前打开(推荐20)。它的结尾将在你定义的检查点的下一个循环中被命令,在你设置它的循环开始后多久,将是hihat声音的时间长度(我设置在30到40毫秒之间,但是这个结束了

每当满足其中一个检查点时,arduino将通过将其与存储在cycleNumber变量上的鼓组合号(数字代码)进行比较来检查其相应的元素是否有效。系统先前解释过)。例如,如果圈套的检查点满足,则圈套的数量为3,因此只有当鼓组合具有数字3,4(3 + 1),8(3 + 5)或9(3+)时才会发送命中命令1 + 5)。

3 HiHat x - x x

2 Snare - x x x

1 Kick x x - x

_________________________________________

COMBINATION: 4 3 5 6

为什么在圈套机制中使用两组木棍和伺服?

嗯,如果你考虑一下,如果只使用一个伺服,并且让它的休息时间为100毫秒,那么我们的半定时器周期可以持续的最短时间是200毫秒。 100允许从打击到休息,然后再从休息到休息100。每十六分音符200毫秒相当于约75 bpm的速度(由航空匠“梦想”),这是非常缓慢的并且限制了可能的节奏。

使用两组独立的棍棒和舵机,并交替使用它们,让其中一个在100毫秒内从击中休息,而另一个在相同的时间内击中,将最小的半定时器周期时间从大约200毫秒减少到100毫秒(“给我打电话”)金发女郎),快得多。换句话说,较慢的伺服时间也是半续半周期可以持续的最短时间。

步骤10:代码IV - 使鼓节拍

我们现在有办法确切地定义要生成的声音,并且还可以在同一时间完成所有声音。我们只需要一个接一个地播放这些十六分音符周期中的16个,每个音符组合所需的鼓组合,我们有一个小节。只要我们想要,我们就重复那个吧,而且,我们有一个鼓声。

用简单的代码,我们将16个半序列的条形序列存储在一个数组中,然后制作arduino经历了一遍又一遍。通过设置16个数字的不同数组,可以存储和播放不同的鼓节拍,如下图所示:

3 HiHat x-x-x-x-x-x-x-x-

2 Snare ----x-------x---

1 Kick x-------x-------

ARRAY: 6050805060508050

3 HiHat x-x-x-x-x-x-x-x-

2 Snare ----x-------x---

1 Kick x--x--x--xx---x-

ARRAY: 6051806051608060

要在这些数组之间切换,我们将使用轻触开关按钮连接到引脚3。

步骤11:代码V - 全部放在一起

// DrumCube, an arduino robot drummer

// by Franco Molina @artefrancomolina

// Setting servos

#include

Servo servo1;

Servo servo2;

Servo servo3;

// Servo positions

// this will differ depending on your servos, please test yours to find out the values that best suit you

byte restServo1 = 12;

byte hitServo1 = 21;

byte restServo2 = 123;

byte hitServo2 = 114;

byte restServo3 = 4;

byte hitServo3 = 19;

// Setting the HiHat white noise generator

#define noiseGenerator 12

#define noiseLed 13 //turn on led as a visual representation of the noise being generated

// Setting servo times

// this will also differ depending on your servos, please test yours to find out the values that best suit you

byte timeSnare1 = 110;

byte timeSnare2 = 108;

byte timeKick = 71;

byte timeHihat = 20;

byte sustainTimeHihat = 70;

// Setting previous Snare and Kick

byte previousSnare = 2;

byte previousKick = 0;

// Setting cycle times

static unsigned long timeStartCycle;

static unsigned long timeTotalCycle; // changing this, change how fast/slow the rhythm is, you can set a specific value for each drumbeat in the selectDrumBeat() function

// Bar and Cycles variables

int cycleNumber;

int cycleNumbers[] = {6, 0, 5, 0, 8, 0, 5, 0, 6, 0, 5, 0, 8, 0, 5, 0}; // this array stores the drum elements combination for each cycle (semiquaver or sixteenth) of the drumbeat

byte timeSignature = 44;

int drumbeatID = 0; // ID number for each drumbeat

//

int i; // for counting the time in the “for loop” of the cyclePlayer function

int b; // for the “for loop” that counts the number of cycles

// control interface

#define switchPlayStop 2 // switch bettween playing and stop

#define buttonSelect 3 // tact button that select the drumbeat to play

void setup(void) {

// define pins for each servo

pinMode (5, OUTPUT);

pinMode (6, OUTPUT);

pinMode (9, OUTPUT);

// attach servos to those pins

servo1.attach(5); //caja 1

servo2.attach(6); //caja 2

servo3.attach(9); //bombo

delay(150);

// put all servos on rest position

servo1.write(restServo1);

servo2.write(restServo2);

servo3.write(restServo3);

delay(300);

// Setting hihat and led pinmodes

pinMode (noiseGenerator, OUTPUT);

digitalWrite(noiseGenerator, LOW);

pinMode (noiseLed, OUTPUT);

digitalWrite(noiseLed, LOW);

// Setting control interface pinmodes

pinMode (switchPlayStop, INPUT_PULLUP);

pinMode (buttonSelect, INPUT_PULLUP);

}

void loop(void) {

if (switchPlayStop == LOW) { //if the play/stop switch is ON (logical LOW)

//We start a “for loop” to play a semiquaver cycle a maximum of 16 times, for every bar

for (b = 0; b 《 16; b = b + 1) {

selectDrumBeat(); // select the drumbeat based on the drumbeatID selected

cyclePlayer(cycleNumbers[b]); //play the semiquaver cycle for each number stored in the cycleNumbers array

// if we reach the maximum number of cycles (16 for 4/4, 12 for 6/8, 12/8 or 3/4) we start again

if (b == 11 && (timeSignature == 68 || timeSignature == 128)) {

b = -1;

}

if (b == 15) {

b = -1;

}

}

}

// If the play/stop switch is OFF (logical HIGH) we enter settingMode

else {

settingMode(); // function that lets you choose between different drumbeats and wait for the play switch to be activated

}

}

// CYCLE PLAYER

// this functions runs a semiquaver cycle every time is called.

void cyclePlayer(int cycleNumber) { // we store every single value of the cycleNumbers array into the cycleNumber variable

timeStartCycle = millis(); // we save the starting time, to compare it later with the actual time and get the time past

//set both snare servos to rest position in case they were on hit position

servo1.write(restServo1);

servo2.write(restServo2);

//we star a “for loop” for the entire duration of every semiquaver cycle

for (i = 0; i 《 timeTotalCycle; i++) {

//now we send the hitting commands on time so they reach their destination on time (the end of the semiquaver cycle)

// if we reach the time to send the command to the snare on servo1. We start checking the element that takes the longest time to move, in this case is servo1, in yours could be different.

if ((millis() - timeStartCycle 》= timeTotalCycle - timeSnare1)) {

// we check if this is the one snare of the two, that has to be played,

// and also, if in this cycle a snare has to be played at, all based on the cycleNumber number (this number define the cobination of drum elements)

if ((previousSnare == 2) && ((cycleNumber == 9) || (cycleNumber == 8) || (cycleNumber == 4) || (cycleNumber == 3)) ) {

servo1.write(hitServo1 + 5); // we send the servo command

}

// if we reach the time to send the command to the snare on servo2

if (millis() - timeStartCycle 》= timeTotalCycle - timeSnare2) {

// we check if this is the one snare of the two, that has to be played, and also if in this cycle a snare has to be played at all

if ((previousSnare == 1) && ((cycleNumber == 9) || (cycleNumber == 8) || (cycleNumber == 4) || (cycleNumber == 3)) ) {

servo2.write(hitServo2 - 5); // we send the servo command

}

// we now check if we reached the time to send the command to the third servo, the kick

if ((millis() - timeStartCycle 》= timeTotalCycle - timeKick)) {

// we check if in this cycle a snare has to be played

if ( (cycleNumber == 9) || (cycleNumber == 4) || (cycleNumber == 6) || (cycleNumber == 1) ) {

// we check on what position was previosly the servo, either hiting the left or the right piezo, this state will be saved later

if (previousKick == 0) {

servo3.write(hitServo3);

}

else if (previousKick == 1) {

servo3.write(restServo3);

}

}

// finally, we check if the time to turn on the white noise generator was reached, for the hihat

if (millis() - timeStartCycle 》= (timeTotalCycle - timeHihat)) {

// we check if in this cycle the hihat has to be played

if ( (cycleNumber == 9) || (cycleNumber == 8) || (cycleNumber == 6) || (cycleNumber == 5) ) {

digitalWrite(noiseLed, HIGH);

digitalWrite(noiseGenerator, HIGH);

}

}

}

}

}

// This is where the semiquaver cycle ends.

// HIHAT DURATION

// turn off hi-hat noise generator, but only under the following conditions:

// //if the noise-generator was ON //the time past exceed the time set as sustain //the time past does not reach yet the point where a new noise could start

if ( (digitalRead(noiseGenerator) == HIGH) && (millis() - timeStartCycle 》= sustainTimeHihat) && (millis() - timeStartCycle 《 (timeTotalCycle - (timeHihat + 10))) ) {

digitalWrite(noiseGenerator, LOW);

digitalWrite(noiseLed, LOW);

}

// Check if the play/stop switch is switched OFF

if (digitalRead(switchPlayStop) == HIGH) {

i = timeTotalCycle; //reset time counting

digitalWrite(noiseGenerator, LOW); //turn off noise

digitalWrite(noiseLed, LOW); //turn off noise

servo1.write(restServo1); //stop servos

servo2.write(restServo2); //stop servos

}

delay(1);

}

// If one of the Snares was hit, then declare it as the previous one, in order to hit the other one the next time

if ((cycleNumber == 9) || (cycleNumber == 8) || (cycleNumber == 4) || (cycleNumber == 3)) {

switch (previousSnare) {

case 1:

previousSnare = 2;

break;

case 2:

previousSnare = 1;

break;

default:

break;

}

}

// If one of the piezo kick was hit, then declare it as the previous one, in order to hit the other one the next time

if ( (cycleNumber == 9) || (cycleNumber == 4) || (cycleNumber == 6) || (cycleNumber == 1) ) {

switch (previousKick) {

case 0:

previousKick = 1;

break;

case 1:

previousKick = 0;

break;

default:

break;

}

}

}

// SETTING MODE

// this mode is activated when the play/stop switch is swiched OFF (logical LOW)

void settingMode() {

while (digitalRead(switchPlayStop) == HIGH) { // keep doing the following actions while the play/stop switch is OFF

if (digitalRead(buttonSelect) == LOW) { // if the selection button is pressed (logical LOW), we change the drumbeat

drumbeatID ++; // we select the next drumbeat each time the button is pressed

selectDrumBeat(); // select the drumbeat based on the drumbeatID

// OPTIONAL

// Here you can add whatever piece of code to indicate which drumbeat is being selected,

// this could be turning in a led, sending a serial.print(), etc.

if (drumbeatID 》 7) { //in case we exceed the total number of drumbeats availabe (), we go back to 0.

drumbeatID = 0;

}

delay(100); //delay to avoid detecting button twice when pressed once

}

}

}

// SELECT DRUMBEAT

// this functions uses the value stored in drumbeatID, to modify all the variables needed in order to choose between drumbeats.

void selectDrumBeat() {

switch (drumbeatID) {

case 1: // DiscoBasic

timeTotalCycle = 124;

timeSignature = 44;

cycleNumbers[0] = 1;

cycleNumbers[1] = 0;

cycleNumbers[2] = 5;

cycleNumbers[3] = 0;

cycleNumbers[4] = 4;

cycleNumbers[5] = 0;

cycleNumbers[6] = 5;

cycleNumbers[7] = 0;

cycleNumbers[8] = 1;

cycleNumbers[9] = 0;

cycleNumbers[10] = 5;

cycleNumbers[11] = 0;

cycleNumbers[12] = 4;

cycleNumbers[13] = 0;

cycleNumbers[14] = 5;

cycleNumbers[15] = 0;

break;

case 2: // NewBugalú

timeTotalCycle = 155;

timeSignature = 44;

cycleNumbers[0] = 6;

cycleNumbers[1] = 0;

cycleNumbers[2] = 5;

cycleNumbers[3] = 0;

cycleNumbers[4] = 8;

cycleNumbers[5] = 0;

cycleNumbers[6] = 5;

cycleNumbers[7] = 3;

cycleNumbers[8] = 5;

cycleNumbers[9] = 3;

cycleNumbers[10] = 6;

cycleNumbers[11] = 0;

cycleNumbers[12] = 8;

cycleNumbers[13] = 0;

cycleNumbers[14] = 5;

cycleNumbers[15] = 0;

break;

case 3: // HiHat16

timeTotalCycle = 134;

timeSignature = 44;

cycleNumbers[0] = 6;

cycleNumbers[1] = 5;

cycleNumbers[2] = 5;

cycleNumbers[3] = 5;

cycleNumbers[4] = 8;

cycleNumbers[5] = 5;

cycleNumbers[6] = 5;

cycleNumbers[7] = 5;

cycleNumbers[8] = 6;

cycleNumbers[9] = 5;

cycleNumbers[10] = 5;

cycleNumbers[11] = 5;

cycleNumbers[12] = 8;

cycleNumbers[13] = 5;

cycleNumbers[14] = 5;

cycleNumbers[15] = 5;

break;

case 4: // SwingGroove

timeTotalCycle = 153;

timeSignature = 128; // (12/8)

cycleNumbers[0] = 6;

cycleNumbers[1] = 0;

cycleNumbers[2] = 0;

cycleNumbers[3] = 6;

cycleNumbers[4] = 0;

cycleNumbers[5] = 5;

cycleNumbers[6] = 6;

cycleNumbers[7] = 0;

cycleNumbers[8] = 0;

cycleNumbers[9] = 6;

cycleNumbers[10] = 0;

cycleNumbers[11] = 5;

break;

case 5: // BossaNova

timeTotalCycle = 200;

timeSignature = 44;

cycleNumbers[0] = 6;

cycleNumbers[1] = 5;

cycleNumbers[2] = 5;

cycleNumbers[3] = 9;

cycleNumbers[4] = 6;

cycleNumbers[5] = 5;

cycleNumbers[6] = 8;

cycleNumbers[7] = 6;

cycleNumbers[8] = 6;

cycleNumbers[9] = 5;

cycleNumbers[10] = 8;

cycleNumbers[11] = 6;

cycleNumbers[12] = 9;

cycleNumbers[13] = 5;

cycleNumbers[14] = 5;

cycleNumbers[15] = 6;

break;

case 6: // ShuffleGroove

timeTotalCycle = 134;

timeSignature = 128; // (12/8)

cycleNumbers[0] = 6;

cycleNumbers[1] = 0;

cycleNumbers[2] = 5;

cycleNumbers[3] = 9;

cycleNumbers[4] = 0;

cycleNumbers[5] = 5;

cycleNumbers[6] = 6;

cycleNumbers[7] = 0;

cycleNumbers[8] = 5;

cycleNumbers[9] = 9;

cycleNumbers[10] = 0;

cycleNumbers[11] = 5;

break;

case 7: // Franco‘s beat

timeTotalCycle = 142;

timeSignature = 44;

cycleNumbers[0] = 6;

cycleNumbers[1] = 0;

cycleNumbers[2] = 5;

cycleNumbers[3] = 1;

cycleNumbers[4] = 8;

cycleNumbers[5] = 0;

cycleNumbers[6] = 6;

cycleNumbers[7] = 0;

cycleNumbers[8] = 5;

cycleNumbers[9] = 1;

cycleNumbers[10] = 6;

cycleNumbers[11] = 0;

cycleNumbers[12] = 8;

cycleNumbers[13] = 0;

cycleNumbers[14] = 6;

cycleNumbers[15] = 0;

break;

default: // Basic 4/4

timeTotalCycle = 144;

timeSignature = 44;

cycleNumbers[0] = 6;

cycleNumbers[1] = 0;

cycleNumbers[2] = 5;

cycleNumbers[3] = 0;

cycleNumbers[4] = 8;

cycleNumbers[5] = 0;

cycleNumbers[6] = 5;

cycleNumbers[7] = 0;

cycleNumbers[8] = 6;

cycleNumbers[9] = 0;

cycleNumbers[10] = 5;

cycleNumbers[11] = 0;

cycleNumbers[12] = 8;

cycleNumbers[13] = 0;

cycleNumbers[14] = 5;

cycleNumbers[15] = 0;

break;

}

}

第12步:与机器人鼓手一起播放音乐!

就是这样,拿起您的首选乐器,插上机器人鼓手,打开播放/停止开关,然后开始播放。

步骤13:下一步是什么?

替代 行级别输出

这是现在最多的我需要的功能,因为它可以提高机器的便携性。我可以简单地将它插入一个普通的蓝牙便携式扬声器。

MIDI输入

我正在努力使这个东西受MIDI控制,使其更加通用在现场情况。这个想法的主要挑战是这个鼓手所需的预期时间,midi协议不起作用。

电池操作

这是事情最让人头疼的是。我一直无法弄清楚电池是如何工作的。我需要一种可靠且可充电的方式来提供这个东西所需的12v功能,但到目前为止还没有任何工作。在我愚蠢的尝试中,我尝试了一对带有TP4056模块和电压升降模块的18650 。..。..失败了。有什么想法吗?

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 机器人
    +关注

    关注

    213

    文章

    30654

    浏览量

    219889
  • Arduino
    +关注

    关注

    190

    文章

    6516

    浏览量

    196065
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    RK3576机器人核心:三屏异显+八路摄像头,重塑机器人交互与感知

    瑞芯微RK3576 AIoT处理器处理器凭借其卓越的多屏异显与8路摄像头接入能力,为机器人领域带来革新。米尔电子MYD-LR3576开发板实测数据显示,在高负载下CPU占用仅34%,完美实现多路视觉
    发表于 10-29 16:41

    小萝卜机器人的故事

    经过我的申请, 马老师发放了, 小萝卜机器人的, 开发权限, 原来的小萝卜公司, 因为经营不善倒闭, 作为科研产品, 几个技术对此惋惜, 自掏腰包, 要让小萝卜机器人, 再生, 每次听到小萝卜说
    发表于 10-23 05:24

    自制巡线解迷宫机器人(上)

    Arduino语法的静态链接库,取名为RVStarArduino,这样不仅我可以将自己之前基于Arduino所做的机器人项目中的一些代码无缝地移植过来,从而大大提高了项目的开发效率,还使得一些刚接触
    发表于 10-20 10:39

    Arduino Uno l两轮自平衡机器人 电机驱动无输出求解

    Arduino Uno l两轮自平衡机器人 电机驱动无输出求解
    发表于 10-15 06:36

    机器人竞技幕后:磁传感器芯片激活 “精准感知力”

    2025 世界人形机器人运动会于 8 月 17 日圆满收官,赛场上机器人在跑步、跳跃、抓取等项目中的精彩表现,背后是运动控制、环境感知等技术的迭代升级。而在这些技术中,磁传感器芯片凭借独特优势,成为
    发表于 08-26 10:02

    工业机器人的特点

    的基础,也是三者的实现终端,智能制造装备产业包括高档数控机床、工业机器人、自动化成套生产线、精密仪器仪表、智能传感器、汽车自动化焊接线、柔性自动化生产线、智能农机、3D 打印机等领域。而智能制造装备中工业
    发表于 07-26 11:22

    盘点#机器人开发平台

    地瓜机器人RDK X5开发套件地瓜机器人RDK X5开发套件产品介绍 旭日5芯片10TOPs算力-电子发烧友网机器人开发套件 Kria KR260机器人开发套件 Kria KR260-
    发表于 05-13 15:02

    【「# ROS 2智能机器人开发实践」阅读体验】机器人入门的引路书

    ROS的全称:Robot Operating System 机器人操作系统 ROS的 目的 :ROS支持通用库,是通信总线,协调多个传感器 为了解决机器人里各厂商模块不通用的问题,让机器人快速开发
    发表于 04-30 01:05

    海康机器人布局关节机器人业务

    关节机器人领域迎来一位实力选手。继布局移动机器人机器视觉业务后,海康机器人正在拓展新的产品线。
    的头像 发表于 03-20 10:47 1231次阅读

    名单公布!【书籍评测活动NO.58】ROS 2智能机器人开发实践

    资格! 从 PC 到智能手机,下一个更大的计算平台是什么? 最佳答案可能是 机器人 ! 如果设想成真,则需要有人为机器人“造脑”,即打造适配的计算平台及操作系统。 就像以计算机为平台的计算机时代,和以
    发表于 03-03 14:18

    开源项目!基于Arduino控制的六足机器人

    步骤,完整复现这款低成本、高性能的六足机器人。开发过程中建议使用支架辅助调试,避免足部意外触地。如需进一步优化步态或扩展功能,可基于提供的Arduino代码进行二次开发。 其他代码资料:*附件:机器人
    发表于 03-03 11:25

    【「具身智能机器人系统」阅读体验】2.具身智能机器人的基础模块

    具身智能机器人的基础模块,这个是本书的第二部分内容,主要分为四个部分:机器人计算系统,自主机器人的感知系统,自主机器人的定位系统,自主机器人
    发表于 01-04 19:22

    【「具身智能机器人系统」阅读体验】2.具身智能机器人大模型

    近年来,人工智能领域的大模型技术在多个方向上取得了突破性的进展,特别是在机器人控制领域展现出了巨大的潜力。在“具身智能机器人大模型”部分,作者研究并探讨了大模型如何提升机器人的能力,大模型存在
    发表于 12-29 23:04

    【「具身智能机器人系统」阅读体验】1.初步理解具身智能

    感谢 感谢电子发烧友网社区给予《具身智能机器人系统》试读机会。在这知识的盛宴中,我感受到社区的关怀与支持。定不负期望,认真研读,分享所学,回馈社区。 一、本书大纲 《具身智能机器人系统》是一本
    发表于 12-28 21:12

    【「具身智能机器人系统」阅读体验】+初品的体验

    《具身智能机器人系统》 一书由甘一鸣、俞波、万梓燊、刘少山老师共同编写,其封面如图1所示。 本书共由5部分组成,其结构和内容如图2所示。 该书可作为高校和科研机构的教材,为学生和研究人员提供系统
    发表于 12-20 19:17