我在使用 IOIO 板控制步进电机时遇到了一些麻烦。我从 HelloIOIOPower 示例开始并添加了我的代码。当按下切换按钮时,程序将运行并打开/关闭 LED,但如果按下按钮改变 UI 线程中 motor_command 的值,则电机控制信号未设置,程序似乎挂起。它不会崩溃,但 LED 控制会丢失。
我尝试在 run 方法中的 switch 语句上使用 synchronized 以在允许更改 UI 线程中的 motor_control 之前评估整个 switch 语句。
我相信实现这一点的正确方法是绑定到 IOIO 线程,但我未能成功使其正常工作。
我希望能够更改“motor_control”的值,以创建对 IOIO 线程的控制命令以移动步进电机。一旦命令被执行,IOIO 线程将“motor_control”设置为零,这是一个注意或保持状态。
在服务中运行 IOIO 是首选但不是必需的。
我计划让这个应用程序 24/7 全天候运行,并向步进电机发送间歇性命令。当只有间歇性命令将发送到 IOIO 时,通过 IOIO 控制步进电机的正确方法是什么?
这是我在 Java/Android/IOIO 的第一次尝试,请随时指出所有错误,我很想了解我可以改进的地方......
谢谢...
` 包 com.medo.testmotor4;
import ioio.lib.api.DigitalOutput;
import ioio.lib.api.IOIO;
import ioio.lib.api.IOIOFactory;
import ioio.lib.api.exception.ConnectionLostException;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
public class TestMotor4 extends Activity {
/** The text displayed at the top of the page. */
private TextView title_;
/** The toggle button used to control the LED. */
private ToggleButton button_;
Button full;
Button half;
Button step16th;
Button cup;
Button dish;
TextView cup_count;
TextView random_num;
int traycount = 0; // try cup position
int motor_command = 0; //motor command index value for switch statement
/** The thread that interacts with the IOIO. */
private IOIOThread ioio_thread_;
/**
* Called when the activity is first created. Here we normally initialize
* our GUI.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_motor4);
title_ = (TextView) findViewById(R.id.title);
button_ = (ToggleButton) findViewById(R.id.button);
// Assign value to Text Views:
cup_count = (TextView)findViewById(R.id.tv_cup_count);
cup_count.setText(Integer.toString(traycount));
random_num = (TextView)findViewById(R.id.tv_random_number);
random_num.setText("no number");
// Set up buttons
dish = (Button) findViewById(R.id.btn_dish);
dish.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View arg0) {
// call method that moves motor one full step
motor_command = 4;
Toast.makeText(TestMotor4.this, "Motor_Command Set to: " + motor_command,Toast.LENGTH_SHORT).show();
}
});
full = (Button) findViewById(R.id.btn_fullstep);
full.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View arg0) {
// call method that moves motor one full step
motor_command = 1;
Toast.makeText(TestMotor4.this, "Motor_Command Set to: " + motor_command,Toast.LENGTH_SHORT).show();
}
});
cup = (Button) findViewById(R.id.btn_cup);
cup.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View arg0) {
// call method that moves motor one full step
traycount ++;
if (traycount % 3 == 0 )
motor_command = 3; // every 3rd tray cup move 54 1/8 steps
// all others move 53 1/8 steps
else motor_command = 2;
Toast.makeText(TestMotor4.this, "Motor_Command Set to: " + motor_command,Toast.LENGTH_SHORT).show();
cup_count.setText(Integer.toString(traycount));
}
});
half = (Button) findViewById(R.id.btnhalfstep);
half.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View arg0) {
// call method that moves motor one half step
motor_command = 3;
Toast.makeText(TestMotor4.this, "Motor_Command Set to: " + motor_command,Toast.LENGTH_SHORT).show();
}
});
} //onCreate
/**
* Called when the application is resumed (also when first started). Here is
* where we'll create our IOIO thread.
*/
@Override
protected void onResume() {
super.onResume();
ioio_thread_ = new IOIOThread();
ioio_thread_.start();
}
/**
* Called when the application is paused. We want to disconnect with the
* IOIO at this point, as the user is no longer interacting with our
* application.
*/
@Override
protected void onPause() {
super.onPause();
ioio_thread_.abort();
try {
ioio_thread_.join();
} catch (InterruptedException e) {
}
}
/**
* This is the thread that does the IOIO interaction.
*
* It first creates a IOIO instance and wait for a connection to be
* established. Then it starts doing the main work of opening the LED pin
* and constantly updating it to match the toggle button's state.
*
* Whenever a connection drops, it tries to reconnect, unless this is a
* result of abort().
*/
class IOIOThread extends Thread {
private IOIO ioio_;
private boolean abort_ = false;
DigitalOutput led;
private DigitalOutput dir;
private DigitalOutput stp;
private DigitalOutput slp_,rst_, ms3, ms2, ms1,en_;
private DigitalOutput led_;
private DigitalOutput dish;
private static final int STEP_WAIT = 5;
/** Thread body. */
@Override
public void run() {
super.run();
while (true) {
synchronized (this) {
if (abort_) {
break;
}
ioio_ = IOIOFactory.create();
}
try {
setText(R.string. wait_ioio);
ioio_.waitForConnect();
setText(R.string.ioio_connected);
//IOIO pin setup:
//DigitalOutput led = ioio_.openDigitalOutput(0, true);
rst_ = ioio_.openDigitalOutput(13, true); // /RESET
ms3 = ioio_.openDigitalOutput(14, true); // ms3 set step size L L L full step
ms2 = ioio_.openDigitalOutput(15, true); // ms2
ms1 = ioio_.openDigitalOutput(16, true); // ms1 H H H 1/16 step
en_ = ioio_.openDigitalOutput(17, false); // /enable
dir = ioio_.openDigitalOutput(18, false); // DIRECTION - set initial direction of motor rotation
stp = ioio_.openDigitalOutput(19, false); // STEP
slp_ = ioio_.openDigitalOutput(20, true); // /SLEEP -
led = ioio_.openDigitalOutput(IOIO.LED_PIN);
dish = ioio_.openDigitalOutput(9, false); // Dish - linear actuator activate signal
Log.d ("IOIOLooper setup", "Complete");
int test = 0;
Toast.makeText(TestMotor4.this, "Starting while loop",Toast.LENGTH_SHORT).show();
while (true) {
led.write(!button_.isChecked());
switch(motor_command){
case 0: // hold - do nothing for 5 sec.
this.timeout(100);
break;
case 1: //full step on motor
full();
Log.d("STEPPER-FULL","Complete");
motor_command = 0;
break;
case 2: // move motor 1 cup - (53) 1/8 steps
cup(53);
motor_command = 0;
Log.d("STEPPER-CUP - 53","Complete" );
break;
case 3: // move motor 1 cup (54) 1/8 steps
cup(54);
motor_command = 0;
Log.d("STEPPER-CUP - 54","Complete" );
break;
case 4: // dump scoop dish
dish.write(true);
//Toast.makeText(TestMotor4.this, "Dish set HIGH: ",Toast.LENGTH_SHORT).show();
this.timeout(5000);
dish.write(false);
//Toast.makeText(TestMotor4.this, "Dish set LOW " + motor_command,Toast.LENGTH_SHORT).show();
motor_command = 0;
break;
} // switch
sleep(10);
}
} catch (ConnectionLostException e) {
setText(R.string.connectionLost);
} catch (Exception e) {
Log.e("TestMotor4", "Unexpected exception caught", e);
ioio_.disconnect();
break;
} finally {
if (ioio_ != null) {
try {
ioio_.waitForDisconnect();
} catch (InterruptedException e) {
}
}
synchronized (this) {
ioio_ = null;
}
}
} // while(true)
}// Run
/**
* Abort the connection.
*
* This is a little tricky synchronization-wise: we need to be handle
* the case of abortion happening before the IOIO instance is created or
* during its creation.
*/
synchronized public void abort() {
abort_ = true;
if (ioio_ != null) {
ioio_.disconnect();
}
}// abort
/**
* Set the text line on top of the screen.
*
* @param id
* The string ID of the message to present.
*/
private void setText(final int id) {
runOnUiThread(new Runnable() {
@Override
public void run() {
title_.setText(getString(id));
}
});
} //setText
public void full ()throws ConnectionLostException{
// move motor 1 full step (1.8 degrees)
// requires stp to be LOW before entering method - leaves stp LOW on exit of method
try{
en_.write(false); // enable MC outputs
// configure for full step ( L L L)
ms1.write(false);
ms2.write(false);
ms3.write(false);
Log.d("Set FULL", "L L L");
//send step signal with LOW To HIGH transition
stp.write(true);
timeout(STEP_WAIT);
stp.write(false);
this.timeout(STEP_WAIT);
}catch(ConnectionLostException e) {
//enableUi(false);
Toast.makeText(TestMotor4.this, "IOIO Connection Lost ",Toast.LENGTH_LONG).show();
throw e;
}
} // full
public void cup(int num) throws ConnectionLostException{
try{
// set step size to 1/8 step
ms1.write(true);
ms2.write(true);
ms3.write(false);
Log.d("Set 1/8 step size ", "H H L");
// set up wait for signals to stabilize
this.timeout(STEP_WAIT);
//move motor 53 steps
for (int i = 0; i<num; i++){
stp.write(true);
this.timeout(STEP_WAIT);
stp.write(false);
this.timeout(STEP_WAIT);
}
}catch (ConnectionLostException e){
Toast.makeText(TestMotor4.this, "IOIO Connection Lost ",Toast.LENGTH_LONG).show();
throw e;
}
} //cup
private void timeout(int ms) {
try {
sleep(ms);
} catch (InterruptedException e) {
// Do nothing...
}
}
} //IOIOThread
}`