Controlar Motor Brushless com Arduino + JAVA

Publicado: maio 29, 2012 em Projetos Arduino

Amigos, considero esse projeto um pouco mais complexo que os últimos postados aqui não por se tratar de um código difícil, mas por envolver duas  linguagens JAVA e C(arduino) tive muitas duvidas antes de dominar a API RxTx será ela que usaremos em Java para  comunicação SERIAL com arduino, já o código para arduino é bastante simples usaremos a biblioteca  <Servo.h> que se não me engano já vem na IDE arduino versão 1.0, então vamos lá vou apresentar o material em seguida a montagem e o código de ambos.

Material necessário:

Uma observação nos outros post’s eu usei o arduino duemilanove, mas nesse usarei um arduino nano, não tem problemas pode-se usar qualquer um basta está atendo aos pinos para esse caso já que usamos pinos com PWM.

Foto do Projeto:

Esquema Elétrico:

Considerações Importante:

Na montagem do ESC  temos os pinos lógicos que são três, vermelho, preto e branco onde o preto é GND o brando é input de dados ligado ao Arduino e o vermelho não ligado fornece 5V que pode ser usado pra alimentar o arduino, mas não usaremos nesse projeto já os outros fios são eles dois de potência ligado a bateria vermelho (+) e preto (-) GND e por fim os três fios de cor preto que são ligados ao motor eles não tem uma posição definida porem são eles que determina o sentido da rotação do motor caso a rotação esteja no sentido contrario ao desejado basta inverter dois dos fios, vc verá. Agora no arduino são apenas dois fios o Preto (Lógico) no pino GND e o Branco no pino 9 digital (PWM) com isso feito não precisamos mais fazer nada na parte física, agora é só programação vamos começar pela codificação do arduino.

Código do Arduino:

#include <Servo.h>

Servo myservo;

int pos = 24;

void setup(){
Serial.begin(9600);
myservo.attach(9);
}

void loop(){

while (true){ // Bloco start motor até 40 de velocidade —-
myservo.write(pos);
delay(1000);
if (pos < 40){
pos += 2;
Serial.println(pos);
}
// Bloc de controle velocidade ————-
if(Serial.available( )> 0){
char c = Serial.read();
Serial.println(c);
pos = c;

} // Bloc de controle velocidade FIM ————- /
} // Bloco start motor FIM ———

}

O que esse código faz, vamos lá ele tem basicamente duas funções à primeira é dar partida no motor deixando ele em baixa velocidade (40) e a segunda é ficar ouvindo a porta serial, será pela serial que o programa em Java enviará os dados para o controle. Uma coisa o valor 40 não tem uma definição como se fosse Graus ou outro é apenas Velocidade mesmo que vai de 0 a 100.

Código JAVA:

Usaremos duas classes segue a primeira:

SerialCom

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package ControleMotorBrushless;

import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
*
* @author Rudrigo
*/
public class SerialCom {

static InputStream input;
static OutputStream output;

public void serial(String rate, String porta) throws Exception{

int debug_rate = Integer.parseInt(rate);
String serial_port = (porta);

CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier(serial_port);
SerialPort port = (SerialPort)portId.open(“serial talk”, 4000);

input = port.getInputStream();
output = port.getOutputStream();
port.setSerialPortParams(debug_rate,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);

}

public void close() throws IOException{
input.close();
output.close();
input = null;
output = null;
}
}

Segue a Segunda:

JFrameControleMotor

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package ControleMotorBrushless;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
*
* @author Rudrigo
*/
public class JFrameControleMotor extends javax.swing.JFrame {

/**
* Creates new form JFrameControleMotor
*/
public JFrameControleMotor() {
initComponents();
}

SerialCom sc = new SerialCom();

class valor extends Thread {
public void run() {
try {
while(true){
sc.output.write(jSlider1.getValue());
//System.out.println(jSlider1.getValue());
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(JFrameControleMotor.class.getName()).log(Level.SEVERE, null, ex);
}
}
} catch (IOException ex) {
Logger.getLogger(JFrameControleMotor.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings(“unchecked”)
// <editor-fold defaultstate=”collapsed” desc=”Generated Code”>
private void initComponents() {
bindingGroup = new org.jdesktop.beansbinding.BindingGroup();

jPanel1 = new javax.swing.JPanel();
jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
jTextFieldPorta = new javax.swing.JTextField();
jTextFieldRate = new javax.swing.JTextField();
jButtonStart = new javax.swing.JButton();
jButtonStop = new javax.swing.JButton();
jPanel2 = new javax.swing.JPanel();
jSlider1 = new javax.swing.JSlider();
jLabel3 = new javax.swing.JLabel();
jTextFieldVelocidade = new javax.swing.JTextField();

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder(“Definição de Porta”));

jLabel1.setText(“Porta: “);

jLabel2.setText(“Rate: “);

jTextFieldPorta.setText(“COM10”);

jTextFieldRate.setText(“9600”);

jButtonStart.setText(“Start”);
jButtonStart.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButtonStartActionPerformed(evt);
}
});

jButtonStop.setText(“Stop”);
jButtonStop.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButtonStopActionPerformed(evt);
}
});

javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jTextFieldPorta, javax.swing.GroupLayout.PREFERRED_SIZE, 84, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(jLabel2)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jTextFieldRate, javax.swing.GroupLayout.PREFERRED_SIZE, 74, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(35, 35, 35)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(jButtonStart, javax.swing.GroupLayout.DEFAULT_SIZE, 112, Short.MAX_VALUE)
.addComponent(jButtonStop, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap(22, Short.MAX_VALUE))
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jTextFieldPorta, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jTextFieldRate, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(jButtonStart)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jButtonStop)))
.addContainerGap())
);

jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder(“Controle”));

jSlider1.setMinimum(40);
jSlider1.setPaintTicks(true);
jSlider1.setValue(40);

jLabel3.setText(“Velocidade:”);

org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, jSlider1, org.jdesktop.beansbinding.ELProperty.create(“${value}”), jTextFieldVelocidade, org.jdesktop.beansbinding.BeanProperty.create(“text”));
bindingGroup.addBinding(binding);

jTextFieldVelocidade.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jTextFieldVelocidadeActionPerformed(evt);
}
});

javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
jPanel2.setLayout(jPanel2Layout);
jPanel2Layout.setHorizontalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addComponent(jSlider1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap())
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(jLabel3)
.addGap(18, 18, 18)
.addComponent(jTextFieldVelocidade, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18))))
);
jPanel2Layout.setVerticalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel3)
.addComponent(jTextFieldVelocidade, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jSlider1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap())
);

bindingGroup.bind();

pack();
}// </editor-fold>

private void jButtonStartActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:

try {
String porta = jTextFieldPorta.getText();
String rate =jTextFieldRate.getText();
sc.serial(rate, porta);
Thread threadComRunnable = new Thread(new valor());
threadComRunnable.start();

} catch (Exception ex) {
Logger.getLogger(JFrameControleMotor.class.getName()).log(Level.SEVERE, null, ex);
}
}

private void jTextFieldVelocidadeActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:

}

private void jButtonStopActionPerformed(java.awt.event.ActionEvent evt) {
try {
dispose();
sc.close();
} catch (IOException ex) {
Logger.getLogger(JFrameControleMotor.class.getName()).log(Level.SEVERE, null, ex);
}
}

/**
* @param args the command line arguments
*/
public static void main(String args[]) {
/*
* Set the Nimbus look and feel
*/
//<editor-fold defaultstate=”collapsed” desc=” Look and feel setting code (optional) “>
/*
* If Nimbus (introduced in Java SE 6) is not available, stay with the
* default look and feel. For details see
* http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if (“Nimbus”.equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(JFrameControleMotor.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(JFrameControleMotor.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(JFrameControleMotor.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(JFrameControleMotor.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>

/*
* Create and display the form
*/
java.awt.EventQueue.invokeLater(new Runnable() {

public void run() {
new JFrameControleMotor().setVisible(true);
}
});
}
// Variables declaration – do not modify
private javax.swing.JButton jButtonStart;
private javax.swing.JButton jButtonStop;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JSlider jSlider1;
private javax.swing.JTextField jTextFieldPorta;
private javax.swing.JTextField jTextFieldRate;
private javax.swing.JTextField jTextFieldVelocidade;
private org.jdesktop.beansbinding.BindingGroup bindingGroup;
// End of variables declaration
}

Essa é a tela do segundo código:

Considerações dos códigos JAVA:

A primeira classe “SerialCom” tem o objetivo de abrir a comunicação com a Serial usando a API RxTx de forma que consigamos enviar e receber dados da COM já a segunda classe JFrameControleMotor gera a interface gráfica em SWING chamando e passando parâmetros para a primeira alem disso nessa classe informamos a porta que o arduino foi reconhecido  “COM10” assim como a velocidade de comunicação que nesse caso usei a “9600” descrevendo o código um pouco o ponto mais relevante é o uso da ferramenta jSlider que chama uma Thread para executar em tempo real o controle de velocidade, não vou explicar linha a linha o código prefiro ir respondendo as duvidas que vão surgindo, deixarei um link para download de todo o código além da biblioteca RxTx, não esqueça de modela o código para o seu ambiente  nesse código eu criei uma pacote chamando “ControleMotorBrushless” vc pode mudar isso e deixar o nome que quiser, pois bem para aqueles que não têm um conhecimento básico em JAVA indico a apostila de Caelum   a FJ-11.

 

Caro Amigo espero que tenham gostado e que a descrição tenha sido boa sem duvidas, mas como todos já sabem fique avontade para pergunta, assim que puder responderei com muito prazer considero todo tipo de perguntas o mais importante é tirar sua duvida lembro quando também não sabia nada e me enrolava em pequenas coisas.

Postarei um vídeo em breve do motor funcionando….

 

Downloads dos código e API RxTx:

Link

comentários
  1. Luciano disse:

    RUDRIGOLIMA,

    Parabens pelo post man, comprei um arduino recentemente e pensar em programar somente em C# estava me desanimando, porem este post e blog me deu até um animo! Maior dificuldade é a configuração do RXTX, mas só configurar dll’s e bibliotecas e tudo certo.

    Thanks man!

  2. Eliseu Ferreira disse:

    Bom post Rudrigo…
    Estou a aprender java, ainda so tive 2 aulas e estou a achar muito interessante a linguagem, porém acho um pouco dificil assim ao principio…
    Entretanto vou ter de fazer um pequeno projecto em java ao qual vou querer usar também o arduino onde consiga receber dados do arduino e depois ter um ambiente grafico em java…
    Consegui por a funcionar o teu projecto para tentar perceber como funciona o RXTX, mas ainda estou muito verde para perceber o que lá está :S

    Já consegui colocar o RXTX (rxtx-2.1-7-bins-r2.zip) a comunicar com o arduino, esta sempre a receber uma string que mostra os estados das entradas digitais do arduino, mas depois tento criar um jframe form como no teu projecto mas não consigo usar a string no jframe form… :S

    No caso do teu projecto para colocares uma Text Field a receber uma string do arduino como farias?
    Se me podesses dar um exemplo irias me ajudar muito pois ia tentar perceber a lógica para ver se consigo me mexer um bocadinho… 🙂

    Parabéns pelo teu site… já é a segunda vez que após algumas pesquisas acabo por achar a melhor informação aqui…

  3. Jessica Roberta disse:

    Adorei… eh parecido com meu trabalho mais estou fazendo em c… me ajudou mt esse site

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s