Skip to content

Commit accd340

Browse files
committed
small fixes
1 parent 22c05b0 commit accd340

File tree

6 files changed

+148
-53
lines changed

6 files changed

+148
-53
lines changed

src/main/java/org/myrobotlab/framework/Status.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public static Status error(String format, Object... args) {
9595

9696
public static Status warn(String msg) {
9797
Status s = new Status(msg);
98-
s.level = ERROR;
98+
s.level = WARN;
9999
return s;
100100
}
101101

src/main/java/org/myrobotlab/service/Adafruit16CServoDriver.java

Lines changed: 68 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -155,26 +155,26 @@ public double publishServoEvent(ServoControl servo, Integer eventType, Double cu
155155
// want these to be as small/large as possible without hitting the hard stop
156156
// for max range. You'll have to tweak them as necessary to match the servos
157157
// you have!
158-
//
159-
public final static int SERVOMIN = 150; // this
160-
// is
161-
// the
162-
// 'minimum'
163-
// pulse
164-
// length count (out of 4096)
165-
public final static int SERVOMAX = 600; // this
166-
// is
167-
// the
168-
// 'maximum'
169-
// pulse
170-
// length count (out of 4096)
158+
public int SERVOMIN = 150; // this is the 'minimum' pulse length count
159+
// (out of 4096)
160+
// @60Hz this equates to 610uS
161+
public int SERVOMAX = 600; // this is the 'maximum' pulse length count
162+
// (out of 4096)
163+
// @60Hz this equates to 2441uS
164+
165+
// Servo min and max Pulse width
166+
final static int servoMinPulseWidth = 500; // in micro seconds
167+
final static int servoMaxPulseWidth = 2500; // in micro seconds
171168

172169
transient public I2CController controller;
173170

174171
// Constant for default PWM freqency
175172
private static int defaultPwmFreq = 60;
176173
final static int minPwmFreq = 24;
177-
final static int maxPwmFreq = 1526;
174+
// Servos us a PWM signal with a pulse width between 500uS and 2500uS.
175+
// Allowing for 500uS the latest digital servos gives us a max frequence of
176+
// 333 Hz
177+
final static int maxPwmFreq = 333;
178178

179179
int pwmFreq;
180180
boolean pwmFreqSet = false;
@@ -216,16 +216,15 @@ public double publishServoEvent(ServoControl servo, Integer eventType, Double cu
216216
public static final int PCA9685_LED0_OFF_H = 0x09; // First LED addressHigh
217217

218218
public static final int PCA9685_ALL_LED_OFF_H = 0xFD; // All call i2c address
219-
// ( Used for shutdown
220-
// of all pwm )
219+
// ( Used for shutdown of all pwm )
221220
public static final int PCA9685_TURN_ALL_LED_OFF = 0x10; // Command to turn
222-
// all LED off stop
223-
// pwm )
221+
// all LED off stop pwm )
224222

225223
// public static final int PWM_FREQ = 60; // default frequency for servos
226224
public static final float osc_clock = 25000000; // clock frequency of the
227225
// internal clock
228226
public static final float precision = 4096; // pwm_precision
227+
float freqAdjust = (float) 0.9;
229228

230229
/**
231230
* i2c controller
@@ -360,11 +359,37 @@ public void setPWM(String pinLabel, Integer pulseWidthOn, Integer pulseWidthOff)
360359
byte[] buffer = { (byte) (PCA9685_LED0_ON_L + (pin * 4)), (byte) (pulseWidthOn & 0xff), (byte) (pulseWidthOn >> 8), (byte) (pulseWidthOff & 0xff),
361360
(byte) (pulseWidthOff >> 8) };
362361
log.debug("Writing pin {}, pulesWidthOn {}, pulseWidthOff {}", pin, pulseWidthOn, pulseWidthOff);
363-
if (controller != null) {
364-
controller.i2cWrite(this, Integer.parseInt(deviceBus), Integer.decode(deviceAddress), buffer, buffer.length);
362+
controller.i2cWrite(this, Integer.parseInt(deviceBus), Integer.decode(deviceAddress), buffer, buffer.length);
363+
}
364+
365+
/**
366+
* adjust the inbuilt oscilator frequency reference. The PCA9685 inbuilt
367+
* oscilator is listed as 25MHz in the datasheets However, it has found to be
368+
* a little different and is different between batches This allows us to
369+
* adjust the base frequency we use for out timings so the output pulses and
370+
* PWM frequencies are more accurate. This will affect the positioning of
371+
* servos, center and even the upper and lower limits.
372+
*
373+
* @param adjustment
374+
*/
375+
public void setFreqAdjust(float adjustment) {
376+
if (adjustment < 0.5) {
377+
freqAdjust = (float) 0.5;
378+
} else if (adjustment > 1.5) {
379+
freqAdjust = (float) 1.5;
365380
} else {
366-
error("controller not set!");
381+
freqAdjust = adjustment;
367382
}
383+
log.info("pwm frequency adjust %s, resulting a frequency of %s MHz.", freqAdjust, (freqAdjust * osc_clock));
384+
}
385+
386+
/**
387+
* returns the current Frequency Adjustment value.
388+
*
389+
* @return
390+
*/
391+
public float getFreqAdjust() {
392+
return freqAdjust;
368393
}
369394

370395
/**
@@ -407,7 +432,19 @@ public void setPWMFreq(String pin, Integer hz) { // Analog servos run at ~60
407432
// Multiplying with factor 0.9 to correct the frequency
408433
// See
409434
// https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library/issues/11
410-
prescale_value = Math.round(0.9 * osc_clock / precision / hz) - 1;
435+
// The adjustment required varies from batch to batch so is now a variable
436+
// that can be adjusted.
437+
prescale_value = Math.round(freqAdjust * osc_clock / precision / hz) - 1;
438+
439+
// When the PWMfreq is changed, the SERVOMIN and SERVOMAX need to be
440+
// updated as well,
441+
// otherwise if the PWMfreq is increased, the pulse width will be
442+
// decreased and could
443+
// damage the servos by sending pulses that are too short.
444+
// If the PWMfreq is decrease, then the pulse width would be increased,
445+
// again potentially damaging servos.
446+
SERVOMIN = (servoMinPulseWidth * (int) precision * (int) hz) / 1000000;
447+
SERVOMAX = (servoMaxPulseWidth * (int) precision * (int) hz) / 1000000;
411448
}
412449

413450
log.info("pwm frequency {} hz, prescale_value calculated to %s", hz, prescale_value);
@@ -507,7 +544,8 @@ public void onServoWriteMicroseconds(ServoControl servo, int uS) {
507544

508545
int pin = getAddress(servo.getPin());
509546
// 1000 ms => 150, 2000 ms => 600
510-
int pulseWidthOff = (int) (uS * 0.45) - 300;
547+
// This value is calculated based on the pwmFreq setting.
548+
int pulseWidthOff = (uS * (int) precision * pwmFreq) / 1000000;
511549
// since pulseWidthOff can be larger than > 256 it needs to be
512550
// sent as 2 bytes
513551
log.debug("servoWriteMicroseconds {} deviceAddress {} pin {} pulse {}", servo.getName(), deviceAddress, pin, pulseWidthOff);
@@ -1025,18 +1063,18 @@ public String publishServoStarted(String name) {
10251063
public String publishServoStopped(String name) {
10261064
return name;
10271065
}
1028-
1066+
10291067
@Override
10301068
public Adafruit16CServoDriverConfig getConfig() {
1031-
super.getConfig();
1032-
Adafruit16CServoDriverConfig config = (Adafruit16CServoDriverConfig)super.getConfig();
1069+
1070+
Adafruit16CServoDriverConfig config = (Adafruit16CServoDriverConfig) super.getConfig();
10331071
// FIXME remove member vars use config directly
10341072
config.controller = controllerName;
10351073
config.deviceBus = deviceBus;
10361074
config.deviceAddress = deviceAddress;
10371075
return config;
10381076
}
1039-
1077+
10401078
@Override
10411079
public Adafruit16CServoDriverConfig apply(Adafruit16CServoDriverConfig c) {
10421080
super.apply(c);
@@ -1047,16 +1085,16 @@ public Adafruit16CServoDriverConfig apply(Adafruit16CServoDriverConfig c) {
10471085
log.error("attaching controller failed", e);
10481086
}
10491087
}
1050-
1051-
// lame - this shouldn't be "copied" over - everything should just simply use config.deviceAddress
1088+
// lame - this shouldn't be "copied" over - everything should just simply
1089+
// use config.deviceAddress
10521090
if (config.deviceAddress != null) {
10531091
deviceAddress = config.deviceAddress;
10541092
}
10551093

10561094
if (config.deviceBus != null) {
10571095
deviceBus = config.deviceBus;
10581096
}
1059-
1097+
10601098
return c;
10611099
}
10621100

src/main/java/org/myrobotlab/service/AudioFile.java

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@
2525

2626
package org.myrobotlab.service;
2727

28+
import java.io.BufferedInputStream;
2829
import java.io.File;
2930
import java.io.IOException;
31+
import java.io.InputStream;
32+
import java.net.URL;
3033
import java.nio.file.Files;
3134
import java.nio.file.Path;
3235
import java.nio.file.Paths;
@@ -56,6 +59,9 @@
5659
import org.myrobotlab.service.interfaces.AudioListener;
5760
import org.myrobotlab.service.interfaces.AudioPublisher;
5861
import org.slf4j.Logger;
62+
63+
import javazoom.jl.player.Player;
64+
5965
/**
6066
*
6167
* AudioFile - This service can be used to play an audio file such as an mp3.
@@ -123,7 +129,9 @@ public class AudioFile extends Service<AudioFileConfig> implements AudioPublishe
123129
transient Map<String, AudioProcessor> processors = new HashMap<String, AudioProcessor>();
124130

125131
final private transient PlaylistPlayer playlistPlayer = new PlaylistPlayer(this);
126-
132+
133+
private transient Player streamPlayer = null;
134+
127135
/**
128136
* last file played
129137
*/
@@ -134,13 +142,13 @@ public void attach(Attachable attachable) {
134142
attachAudioListener(attachable.getName());
135143
}
136144
}
137-
145+
138146
public void attach(AudioListener listener) {
139147
attachAudioListener(listener.getName());
140148
}
141-
149+
142150
public void setPeakMultiplier(double peakMultiplier) {
143-
AudioFileConfig c = (AudioFileConfig)config;
151+
AudioFileConfig c = (AudioFileConfig) config;
144152
c.peakMultiplier = peakMultiplier;
145153
}
146154

@@ -173,6 +181,9 @@ public void stopService() {
173181
p.interrupt();
174182
}
175183
playlistPlayer.stop();
184+
if (streamPlayer != null) {
185+
streamPlayer.close();
186+
}
176187
}
177188

178189
public AudioData play(String filename) {
@@ -184,7 +195,8 @@ public AudioData play(String filename, boolean blocking) {
184195
return play(filename, blocking, null, null);
185196
}
186197

187-
public AudioData play(String filename, boolean blocking, Integer repeat, String track) {
198+
public AudioData play(final String uri, boolean blocking, Integer repeat, String track) {
199+
String filename = uri;
188200

189201
log.info("Play called for Filename {}", filename);
190202
if (track == null || track.isEmpty()) {
@@ -197,6 +209,34 @@ public AudioData play(String filename, boolean blocking, Integer repeat, String
197209
}
198210

199211
if (filename.toLowerCase().startsWith("http:") || filename.toLowerCase().startsWith("https:")) {
212+
213+
if (config.stream) {
214+
try {
215+
216+
Thread playbackThread = new Thread(() -> {
217+
try (InputStream input = new BufferedInputStream(new URL(uri).openStream())) {
218+
streamPlayer = new Player(input);
219+
System.out.println("Playing stream: " + uri);
220+
streamPlayer.play(); // Playback happens here
221+
} catch (Exception e) {
222+
System.err.println("Error playing stream: " + e.getMessage());
223+
e.printStackTrace();
224+
}
225+
});
226+
playbackThread.start();
227+
228+
AudioData data = new AudioData(filename);
229+
data.mode = blocking ? AudioData.MODE_BLOCKING : AudioData.MODE_QUEUED;
230+
data.track = track;
231+
data.repeat = repeat;
232+
return data;
233+
} catch (Exception e) {
234+
System.err.println("Error playing stream: " + e.getMessage());
235+
e.printStackTrace();
236+
return null;
237+
}
238+
}
239+
200240
// make cache directory if it doesn't exist
201241
File check = new File(getDataDir() + fs + "cache");
202242
if (!check.exists()) {
@@ -325,6 +365,10 @@ public void silence() {
325365
// In your case, an other loop.
326366
}
327367
playlistPlayer.stop();
368+
if (streamPlayer != null) {
369+
streamPlayer.close();
370+
}
371+
328372
}
329373

330374
/*
@@ -371,6 +415,9 @@ public void stop() {
371415
ap.pause(false); // FIXME me shouldn't it be true ?
372416
ap.stopPlaying();
373417
}
418+
if (streamPlayer != null) {
419+
streamPlayer.close();
420+
}
374421
}
375422

376423
// FIXME - implement ???
@@ -396,11 +443,11 @@ public List<File> getFiles(String subDir, boolean recurse) {
396443
@Override
397444
public void releaseService() {
398445
super.releaseService();
399-
for (AudioProcessor processor: processors.values()) {
446+
for (AudioProcessor processor : processors.values()) {
400447
processor.stopPlaying();
401448
}
402449
}
403-
450+
404451
public AudioData repeat(String filename) {
405452
return repeat(filename, -1);
406453
}
@@ -544,6 +591,9 @@ public void startPlaylist(String playlist, boolean shuffle, boolean repeat, Stri
544591

545592
public void stopPlaylist() {
546593
playlistPlayer.stop();
594+
if (streamPlayer != null) {
595+
streamPlayer.close();
596+
}
547597
}
548598

549599
public void skip() {
@@ -554,7 +604,7 @@ public double publishPeak(double peak) {
554604
log.debug("publishPeak {}", peak);
555605
return peak;
556606
}
557-
607+
558608
public static void main(String[] args) {
559609

560610
try {
@@ -566,7 +616,7 @@ public static void main(String[] args) {
566616
Runtime.start("python", "Python");
567617

568618
AudioFile player = (AudioFile) Runtime.start("player", "AudioFile");
569-
619+
570620
// Audio stream
571621
// player.play("http://icecast.radiofrance.fr/fip-midfi.mp3");
572622
player.play("https://upload.wikimedia.org/wikipedia/commons/1/1f/Bach_-_Brandenburg_Concerto.No.1_in_F_Major-_II._Adagio.ogg");
@@ -596,14 +646,15 @@ public static void main(String[] args) {
596646
public void onPlayAudioFile(String file) {
597647
play(file);
598648
}
599-
649+
600650
@Override
601651
public void onPlayRandomAudioFile(String dir) {
602652
playRandom(dir);
603653
}
604654

605655
/**
606656
* Plays a random audio file
657+
*
607658
* @param dir
608659
*/
609660
public void playRandom(String dir) {
@@ -612,22 +663,22 @@ public void playRandom(String dir) {
612663
error("%s is not a valid dir");
613664
return;
614665
}
615-
666+
616667
File[] files = test.listFiles();
617-
668+
618669
if (files.length == 0) {
619670
error("%s contains no files", dir);
620671
return;
621672
}
622-
673+
623674
Random rand = new Random();
624-
File randomFile = files[rand.nextInt(files.length-1)];
675+
File randomFile = files[rand.nextInt(files.length - 1)];
625676
play(randomFile.getAbsolutePath());
626-
677+
627678
}
628-
679+
629680
public double getPeakMultiplier() {
630-
return ((AudioFileConfig)config).peakMultiplier;
681+
return ((AudioFileConfig) config).peakMultiplier;
631682
}
632683

633684
}

0 commit comments

Comments
 (0)