I am trying to construct an automatic flow rack system to replace a manual Kanban system. I works by using an Arduino with an ultrasonic sensor attached to back of a rack. The sensor reads the distance from the last box in the rack to it.
the idea behind this is that when someone removes a box from the rack, the other boxes slide forward and the distance from the last box to the back of the rack gets larger. The amount of distance triggers a signal to the restocker. The signal is green if the rack is full, yellow if there are still a few boxes left, and red if there is one or no boxes left.
The Arduino code is working fine and serial prints "Green", "Yellow", or "Red" depending on distance.
Where I am having issues is translating that readout into a visual system. I want a display of the rack on the computer screen with each shelf having a color to show how stocked it is. I'm using Processing to make this and I've had success getting it to print the output instead of Arduino, however when I make an "if" statement to check if the string being read from the Arduino matches a predetermined string, I get a null pointer exception and am not sure how to fix it.
I need the if statement so that it will show green box on that shelf if the serial print reads "Green", and the same for yellow and red.
import processing.serial.*;
Serial myPort; //Create object from serial class
String val;
String str1;
void setup()
{
str1 = "Green";
String portName = Serial.list()[1];
myPort = new Serial(this, portName, 115200);
size(500, 500);
line(5, 5, 5, 495); //these lines construct the flow rack diagram
line(5, 5, 495, 5);
line(495, 5, 495, 495);
line(5, 495, 495, 495);
line(250, 5, 250, 495);
line(5, 250, 495, 250);
}
void draw()
{
if (myPort.available()>0)
{
val = myPort.readStringUntil('\n');
}
if(val.equals(str1) == true){ //checks if val is Green
println(str1);
}
}
NullPointerExceptions are usually easy to fix. All you have to do is check if the variable your are trying to access is null before accessing it or you could initialize your variables on top :
//check if var is null trick
void draw()
{
if (myPort.available()>0)
{
val = myPort.readStringUntil('\n');
}
if (val != null)
{
if(val.equals(str1) == true){ //checks if val is Green
println(str1);
}
}
}
// initializing trick
Serial myPort = new Serial();
String val = "";
String str1 = "";
Btw should should do the same if (... != null) trick for you first if statement since myport could be null too!
I think your problem is not the NullPointerException but the fact that your readStringUntill function returns null. You should look into that function and make sure it works correctly (and that you give it the right parameter).
Related
I have board for game tic-tac-toe. When I'm tryna add new board to list of boards it's always overwrites
fun String.replaceUnusualSymbols() =
replace(", ", "").replace("[", "").replace("]", "")
fun Array<Array<Char>>.printBoard(board: Array<Array<Char>>) = indices.forEach {
println("|${board[it].contentToString().replaceUnusualSymbols()}|")
}
fun main() {
var board = Array(3) { Array(3) { ' ' } }
val game: ArrayList<Array<Array<Char>>> = arrayListOf()
board[0][0] = 'X'
game.add(board) // add first board
board[1][1] = 'X'
game.add(board) // add second board
println(game.size)
game.forEach {
it.printBoard(board) // but outputs always second board
}
}
How to fix this?
There are two problems.
Array is a mutable collection. Since you only created one var board, there's only once instance - which is mutated every time you do board[0][0] = 'X' or board[0][1] = '0'.
it.printBoard(board) isn't printing each board, it's only printing the same board.
Copying the mutable Array
You can try copying the board every time you want to add the current board state to game.
Note that because board is a nested array, just doing board.copyOf() isn't enough - this won't copy recursively. So we have to specifically copy each row of board as well.
Because map {} returns a List and board is an Array, we have to convert the copied result using toTypedArray().
board[0][0] = 'X'
game.add(board.map { row -> row.copyOf() }.toTypedArray()) // add first board
board[1][1] = '0'
game.add(board.map { row -> row.copyOf() }.toTypedArray()) // add second board
What we end up with is something that's pretty clunky and verbose. We can try making an extension function for the copy, but then we'll still have the risk involved with mutable collections. What happens if at some point you forget to copy the board?
To keep this answer short and focused, I'll leave refactoring to use immutable collections as an exercise for the reader, with some hints:
How can you use a class to encapsulate the game logic?
Instead of using a List<List<Char>>, can you create a data class?
Can you create a function that both 1. adds a new symbol to the board, and 2. saves the current game state, in one go?
printBoard()
printBoard() is an extension function has both a receiver and an argument of type Array<Array<Char>>, which is unusual.
// receiver
// ↓
fun Array<Array<Char>>.printBoard(board: Array<Array<Char>>)
// ↑
// argument
This is causing one bug. When you call it.printBoard(board), it will use the indices of it, but it will print the values of board.
// the indices come from the receiver
// ↓
fun Array<Array<Char>>.printBoard(board: Array<Array<Char>>) = indices.forEach {
println("|${board[it].contentToString().replaceUnusualSymbols()}|")
} // ↑
// the values come from the argument
So when you use it in a loop like this
game.forEach {
// argument
// ↓
it.printBoard(board)
// ↑
// receiver
}
it won't print each board.
Here's a fixed version that will only print the receiver.
fun Array<Array<Char>>.printBoard() = indices.forEach {
println("|${this[it].contentToString().replaceUnusualSymbols()}|")
}
Replace replaceUnusualSymbols() with joinToString()
And I'll go one step further - we can get rid of contentToString() and replaceUnusualSymbols() and use the Kotlin stdlib function joinToString():
fun Array<Array<Char>>.printBoard() {
val boardString = joinToString(
separator = "\n",
prefix = "\n",
) { row ->
row.joinToString(" ", prefix = "|", postfix = "|")
}
println(boardString)
}
I'm trying to make my custom item place water when used:
public class Beaker extends Item implements IHasModel {
public Beaker(String name, CreativeTabs tab, int maxStackSize) {
setUnlocalizedName(name);
setRegistryName(name);
setCreativeTab(tab);
setMaxStackSize(maxStackSize);
ItemInit.ITEMS.add(this);
}
#Override
public void registerModels() {
Main.proxy.registerItemRenderer(this, 0, "inventory");
}
#Override
public EnumActionResult onItemUse(EntityPlayer player, World worldIn, BlockPos pos, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
BlockPos clickedBlock = new BlockPos(hitX, hitY, hitZ);
worldIn.setBlockState(clickedBlock, Blocks.WATER.getDefaultState());
return EnumActionResult.SUCCESS;
}
}
However, when I right click, the item gets used (animation plays) but the water is not placed, I'm using Minecraft 1.12.2 and Forge 14.23.2.2613.
hitX hitY and hitZ have no relation to the world location where the action was performed. They are partial values within the clicked block for performing actions based on where the block was clicked (e.g. which button on a number pad).
If we look at ItemBlockSpecial (which handles items like Cake, Repeaters, Brewing Stands, and Cauldrons) we find this code:
public EnumActionResult onItemUse(EntityPlayer player, World worldIn, BlockPos pos, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ)
{
IBlockState iblockstate = worldIn.getBlockState(pos);
Block block = iblockstate.getBlock();
// snow layer stuff we don't care about
if (!block.isReplaceable(worldIn, pos))
{
pos = pos.offset(facing);
}
// placement code
}
The important thing to note here is that the pos parameter is used directly, while being modified by the facing parameter in the event that the block clicked is not replaceable (e.g. Tall Grass is replaceable, Stone is not).
If ItemBlockSpecial isn't sufficient for you (i.e. you can't make your item an instance of ItemBlockSpecial), then the code it uses to do things probably still will be.
I have developed an Android App which runs on both a smartphone and a smartwatch in parallel. On both devices, (let's say) it reads certain sensor data, processes that data (calculate its mean), and then store that results. The watch sends this result to the phone so all storing takes place on the phone. I used buffer writer to write a number into a text file every 5 seconds.
Now after every 320 data items exchanges from watch to the phone, my app on the phone gets killed and I get "the name of the app" is unfortunately stopped as a message. I can't figure it what why they stop exactly after this time? The app running on the watch continues to work fine. However, I cannot store its data because it cannot communicate to the phone version so I get this message "the app is unfortunately stopped as a message" every time the watch sends a number to phone for storing. The app has one activity which has a service (foreground).
Could it be that there is a limit on the amount of data being shared?
The code on watch:
// Create a data map and put data in it
private void increaseCounter() {
PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/count");
putDataMapReq.getDataMap().putInt(COUNT_KEY, count++); // I add current time here as well
PutDataRequest putDataReq = putDataMapReq.asPutDataRequest();
PendingResult<DataApi.DataItemResult> pendingResult =
Wearable.DataApi.putDataItem(mGoogleApiClient, putDataReq);
}
Code on phone (possible problematic area):
#Override
public void onDataChanged(DataEventBuffer dataEvents) {
for (DataEvent event : dataEvents) {
if (event.getType() == DataEvent.TYPE_CHANGED) {
// DataItem changed
DataItem item = event.getDataItem();
if (item.getUri().getPath().compareTo("/count") == 0) {
DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap();
updateCount(dataMap.getInt(COUNT_KEY));
}
} else if (event.getType() == DataEvent.TYPE_DELETED) {
// DataItem deleted
}
}
}
You have to use Service with StartForeground notification to be sure app is always working.
and try to use START_STICKY flag while staring.
UPDATE
You have to dealloc memory of dataevent:
#Override
public void onDataChanged(DataEventBuffer dataEvents) {
try{
for(DataEvent dataEvent: dataEvents){
if(dataEvent.getType() != DataEvent.TYPE_CHANGED){
continue;
}
////... code
dataEvents.release();
}catch (Exception e){
Log.v("SunshineWatchFace",e.getMessage());
}
}
I've got a working autohotkey script which brings up the Windows Speech Recognition Training interface with custom text for input.
If you've ever done the training for Windows Speech Recognition, you know it has you say a short line of text, then once it recognizes that line, goes to a new screen with another short line of text.
I can't figure out how to "break" my two-sentence text into two separate training screens so the user won't have to read thousands of lines of training text all in the same breath with no mistakes.
If anyone figures this out I'll love you forever
Untested
hwnd:=WinExist("A")
Title:="My App's Training"
RC := ComObjCreate("SAPI.SpSharedRecoContext")
MyTrainingText := new TrainingText("Some custom text", Title)
MyTrainingText.get_MyMethod()
MyTrainingText := new TrainingText("Some more training text", Title)
MyTrainingText.get_MyMethod()
Class TrainingText
{
__New(x, y)
{
this.Text := x
this.Title := y
}
get_MyMethod()
{
Title := this.Title
trainingText := this.Text
if RC.Recognizer.IsUISupported("UserTraining")
{
RC.Recognizer.DisplayUI(ComObj(3,hwnd), Title, "UserTraining", traningText)
}
else MsgBox, Not supported
}
}
The user training text needs to be a double-null terminated string, also known as a multistring. Each null-terminated substring will be a separate utterance. I'm not familiar enough with AutoHotKey to know how to build one in that language.
In C#, a function to convert a string array to a multistring would look something like this:
static string StringArrayToMultiString(params string[] values)
{
if (values == null) throw new ArgumentNullException("values");
StringBuilder multiString = new StringBuilder();
foreach (string s in values)
{
multiString.Append(s);
multiString.Append('\0');
}
return multiString.ToString();
}
I am trying to get my arduino uno to display the altitude from a GPS module, without any other data. I am still learning the code, but I've run into a problem where I can't seem to find what command is used to pull the altitude from the GPS string. I know it is pulling the data successfully, as I ran the example code from http://learn.parallax.com/kickstart/28500 and it read the first bit of the string, though I moved onto trying to get the altitude before getting it to scroll the whole string.
I am using a basic 16x2 LCD display, and the display I have working fine.
The end goal of this project is a GPS/gyroscope altimeter that can record to an SD card and record temperature, and deploy a parachute at apogee (15,000ft) and a larger parachute at 1,000ft.
Here is the code I am using for the altitude, I've marked the section I can't figure out. (probably just missing a term, or I might have really messed something up)
Any help would be appreciated, have a great day.
#include <SoftwareSerial.h>
#include "./TinyGPS.h" // Special version for 1.0
#include <LiquidCrystal.h>
TinyGPS gps;
SoftwareSerial nss(0, 255); // Yellow wire to pin 6
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
void gpsdump(TinyGPS &gps);
bool feedgps();
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// initialize the serial communications:
Serial.begin(9600);
Serial.begin(115200);
nss.begin(4800);
lcd.print("Reading GPS");
lcd.write(254); // move cursor to beginning of first line
lcd.write(128);
lcd.write(" "); // clear display
lcd.write(" ");
}
void loop() {
bool newdata = false;
unsigned long start = millis();
while (millis() - start < 5000) { // Update every 5 seconds
if (feedgps())
newdata = true;
}
gpsdump(gps);
}
// Get and process GPS data
void gpsdump(TinyGPS &gps) {
// problem area
float falt, flat, flon;
unsigned long age;
gps.f_get_position(&flat, &flon);
inline long altitude (return _altitude);
long _altitude
;lcd.print(_altitude, 4);
}//end problem area
// Feed data as it becomes available
bool feedgps() {
while (nss.available()) {
if (gps.encode(nss.read()))
return true;
}
return false;
}
lcd.print(x,4) prints base-4. Did you want that, or do you want ordinary base-10 (decimal)?
Secondly, where do you expect _altitude to come from? It's uninitialized. There's also an uninitialized falt, and a weird inline long altitude line which doesn't mean anything.
You might be better of learning C++ first, in a desktop environment. Debugging an embedded device is a lot harder, and you're still producing quite a few bugs.